Commit | Line | Data |
---|---|---|
a3b510ab NR |
1 | package com.googlecode.lanterna.gui2.table; |
2 | ||
3 | import java.util.*; | |
4 | ||
5 | /** | |
6 | * A {@code TableModel} contains the data model behind a table, here is where all the action cell values and header | |
7 | * labels are stored. | |
8 | * | |
9 | * @author Martin | |
10 | */ | |
11 | public class TableModel<V> { | |
12 | private final List<String> columns; | |
13 | private final List<List<V>> rows; | |
14 | ||
15 | /** | |
16 | * Default constructor, creates a new model with same number of columns as labels supplied | |
17 | * @param columnLabels Labels for the column headers | |
18 | */ | |
19 | public TableModel(String... columnLabels) { | |
20 | this.columns = new ArrayList<String>(Arrays.asList(columnLabels)); | |
21 | this.rows = new ArrayList<List<V>>(); | |
22 | } | |
23 | ||
24 | /** | |
25 | * Returns the number of columns in the model | |
26 | * @return Number of columns in the model | |
27 | */ | |
28 | public synchronized int getColumnCount() { | |
29 | return columns.size(); | |
30 | } | |
31 | ||
32 | /** | |
33 | * Returns number of rows in the model | |
34 | * @return Number of rows in the model | |
35 | */ | |
36 | public synchronized int getRowCount() { | |
37 | return rows.size(); | |
38 | } | |
39 | ||
40 | /** | |
41 | * Returns all rows in the model as a list of lists containing the data as elements | |
42 | * @return All rows in the model as a list of lists containing the data as elements | |
43 | */ | |
44 | public synchronized List<List<V>> getRows() { | |
45 | List<List<V>> copy = new ArrayList<List<V>>(); | |
46 | for(List<V> row: rows) { | |
47 | copy.add(new ArrayList<V>(row)); | |
48 | } | |
49 | return copy; | |
50 | } | |
51 | ||
52 | /** | |
53 | * Returns all column header label as a list of strings | |
54 | * @return All column header label as a list of strings | |
55 | */ | |
56 | public synchronized List<String> getColumnLabels() { | |
57 | return new ArrayList<String>(columns); | |
58 | } | |
59 | ||
60 | /** | |
61 | * Returns a row from the table as a list of the cell data | |
62 | * @param index Index of the row to return | |
63 | * @return Row from the table as a list of the cell data | |
64 | */ | |
65 | public synchronized List<V> getRow(int index) { | |
66 | return new ArrayList<V>(rows.get(index)); | |
67 | } | |
68 | ||
69 | /** | |
70 | * Adds a new row to the table model at the end | |
71 | * @param values Data to associate with the new row, mapped column by column in order | |
72 | * @return Itself | |
73 | */ | |
74 | public synchronized TableModel<V> addRow(V... values) { | |
75 | addRow(Arrays.asList(values)); | |
76 | return this; | |
77 | } | |
78 | ||
79 | /** | |
80 | * Adds a new row to the table model at the end | |
81 | * @param values Data to associate with the new row, mapped column by column in order | |
82 | * @return Itself | |
83 | */ | |
84 | public synchronized TableModel<V> addRow(Collection<V> values) { | |
85 | insertRow(getRowCount(), values); | |
86 | return this; | |
87 | } | |
88 | ||
89 | /** | |
90 | * Inserts a new row to the table model at a particular index | |
91 | * @param index Index the new row should have, 0 means the first row and <i>row count</i> will append the row at the | |
92 | * end | |
93 | * @param values Data to associate with the new row, mapped column by column in order | |
94 | * @return Itself | |
95 | */ | |
96 | public synchronized TableModel<V> insertRow(int index, Collection<V> values) { | |
97 | ArrayList<V> list = new ArrayList<V>(values); | |
98 | rows.add(index, list); | |
99 | return this; | |
100 | } | |
101 | ||
102 | /** | |
103 | * Removes a row at a particular index from the table model | |
104 | * @param index Index of the row to remove | |
105 | * @return Itself | |
106 | */ | |
107 | public synchronized TableModel<V> removeRow(int index) { | |
108 | rows.remove(index); | |
109 | return this; | |
110 | } | |
111 | ||
112 | /** | |
113 | * Returns the label of a column header | |
114 | * @param index Index of the column to retrieve the header label for | |
115 | * @return Label of the column selected | |
116 | */ | |
117 | public synchronized String getColumnLabel(int index) { | |
118 | return columns.get(index); | |
119 | } | |
120 | ||
121 | /** | |
122 | * Updates the label of a column header | |
123 | * @param index Index of the column to update the header label for | |
124 | * @param newLabel New label to assign to the column header | |
125 | * @return Itself | |
126 | */ | |
127 | public synchronized TableModel<V> setColumnLabel(int index, String newLabel) { | |
128 | columns.set(index, newLabel); | |
129 | return this; | |
130 | } | |
131 | ||
132 | /** | |
133 | * Adds a new column into the table model as the last column. You can optionally supply values for the existing rows | |
134 | * through the {@code newColumnValues}. | |
135 | * @param label Label for the header of the new column | |
136 | * @param newColumnValues Optional values to assign to the existing rows, where the first element in the array will | |
137 | * be the value of the first row and so on... | |
138 | * @return Itself | |
139 | */ | |
140 | public synchronized TableModel<V> addColumn(String label, V[] newColumnValues) { | |
141 | return insertColumn(getColumnCount(), label, newColumnValues); | |
142 | } | |
143 | ||
144 | /** | |
145 | * Adds a new column into the table model at a specified index. You can optionally supply values for the existing | |
146 | * rows through the {@code newColumnValues}. | |
147 | * @param index Index for the new column | |
148 | * @param label Label for the header of the new column | |
149 | * @param newColumnValues Optional values to assign to the existing rows, where the first element in the array will | |
150 | * be the value of the first row and so on... | |
151 | * @return Itself | |
152 | */ | |
153 | public synchronized TableModel<V> insertColumn(int index, String label, V[] newColumnValues) { | |
154 | columns.add(index, label); | |
155 | for(int i = 0; i < rows.size(); i++) { | |
156 | List<V> row = rows.get(i); | |
157 | ||
158 | //Pad row with null if necessary | |
159 | for(int j = row.size(); j < index; j++) { | |
160 | row.add(null); | |
161 | } | |
162 | ||
163 | if(newColumnValues != null && i < newColumnValues.length && newColumnValues[i] != null) { | |
164 | row.add(index, newColumnValues[i]); | |
165 | } | |
166 | else { | |
167 | row.add(index, null); | |
168 | } | |
169 | } | |
170 | return this; | |
171 | } | |
172 | ||
173 | /** | |
174 | * Removes a column from the table model | |
175 | * @param index Index of the column to remove | |
176 | * @return Itself | |
177 | */ | |
178 | public synchronized TableModel<V> removeColumn(int index) { | |
179 | columns.remove(index); | |
180 | for(List<V> row : rows) { | |
181 | row.remove(index); | |
182 | } | |
183 | return this; | |
184 | } | |
185 | ||
186 | /** | |
187 | * Returns the cell value stored at a specific column/row coordinate. | |
188 | * @param columnIndex Column index of the cell | |
189 | * @param rowIndex Row index of the cell | |
190 | * @return The data value stored in this cell | |
191 | */ | |
192 | public synchronized V getCell(int columnIndex, int rowIndex) { | |
193 | if(rowIndex < 0 || columnIndex < 0) { | |
194 | throw new IndexOutOfBoundsException("Invalid row or column index: " + rowIndex + " " + columnIndex); | |
195 | } | |
196 | else if (rowIndex >= getRowCount()) { | |
197 | throw new IndexOutOfBoundsException("TableModel has " + getRowCount() + " rows, invalid access at rowIndex " + rowIndex); | |
198 | } | |
199 | if(columnIndex >= getColumnCount()) { | |
200 | throw new IndexOutOfBoundsException("TableModel has " + columnIndex + " columns, invalid access at columnIndex " + columnIndex); | |
201 | } | |
202 | return rows.get(rowIndex).get(columnIndex); | |
203 | } | |
204 | ||
205 | /** | |
206 | * Updates the call value stored at a specific column/row coordinate. | |
207 | * @param columnIndex Column index of the cell | |
208 | * @param rowIndex Row index of the cell | |
209 | * @param value New value to assign to the cell | |
210 | * @return Itself | |
211 | */ | |
212 | public synchronized TableModel<V> setCell(int columnIndex, int rowIndex, V value) { | |
213 | getCell(columnIndex, rowIndex); | |
214 | List<V> row = rows.get(rowIndex); | |
215 | ||
216 | //Pad row with null if necessary | |
217 | for(int j = row.size(); j < columnIndex; j++) { | |
218 | row.add(null); | |
219 | } | |
220 | ||
221 | V existingValue = row.get(columnIndex); | |
222 | if(existingValue == value) { | |
223 | return this; | |
224 | } | |
225 | row.set(columnIndex, value); | |
226 | return this; | |
227 | } | |
228 | } |