1 package groovy.inspect.swingui;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 /***
43 * A sorter for TableModels. The sorter has a model (conforming to TableModel)
44 * and itself implements TableModel. TableSorter does not store or copy
45 * the data in the TableModel, instead it maintains an array of
46 * integers which it keeps the same size as the number of rows in its
47 * model. When the model changes it notifies the sorter that something
48 * has changed eg. "rowsAdded" so that its internal array of integers
49 * can be reallocated. As requests are made of the sorter (like
50 * getValueAt(row, col) it redirects them to its model via the mapping
51 * array. That way the TableSorter appears to hold another copy of the table
52 * with the rows in a different order. The sorting algorthm used is stable
53 * which means that it does not move around rows when its comparison
54 * function returns 0 to denote that they are equivalent.
55 *
56 * @version 1.12 01/23/03
57 * @author Philip Milne
58 * @author Minimal adjustments by Dierk Koenig, June 2005
59 */
60
61 import java.awt.event.MouseAdapter;
62 import java.awt.event.MouseEvent;
63 import java.util.Date;
64 import java.util.Vector;
65
66 import javax.swing.JTable;
67 import javax.swing.event.TableModelEvent;
68 import javax.swing.table.JTableHeader;
69 import javax.swing.table.TableColumnModel;
70 import javax.swing.table.TableModel;
71
72 public class TableSorter extends TableMap
73 {
74 int indexes[];
75 Vector sortingColumns = new Vector();
76 boolean ascending = true;
77 int lastSortedColumn = -1;
78
79 public TableSorter()
80 {
81 indexes = new int[0];
82 }
83
84 public TableSorter(TableModel model)
85 {
86 setModel(model);
87 }
88
89 public void setModel(TableModel model) {
90 super.setModel(model);
91 reallocateIndexes();
92 }
93
94 public int compareRowsByColumn(int row1, int row2, int column)
95 {
96 Class type = model.getColumnClass(column);
97 TableModel data = model;
98
99
100
101 Object o1 = data.getValueAt(row1, column);
102 Object o2 = data.getValueAt(row2, column);
103
104
105 if (o1 == null && o2 == null) {
106 return 0;
107 }
108 else if (o1 == null) {
109 return -1;
110 }
111 else if (o2 == null) {
112 return 1;
113 }
114
115
116
117
118
119
120
121 if (type.getSuperclass() == java.lang.Number.class)
122 {
123 Number n1 = (Number)data.getValueAt(row1, column);
124 double d1 = n1.doubleValue();
125 Number n2 = (Number)data.getValueAt(row2, column);
126 double d2 = n2.doubleValue();
127
128 if (d1 < d2)
129 return -1;
130 else if (d1 > d2)
131 return 1;
132 else
133 return 0;
134 }
135 else if (type == java.util.Date.class)
136 {
137 Date d1 = (Date)data.getValueAt(row1, column);
138 long n1 = d1.getTime();
139 Date d2 = (Date)data.getValueAt(row2, column);
140 long n2 = d2.getTime();
141
142 if (n1 < n2)
143 return -1;
144 else if (n1 > n2)
145 return 1;
146 else return 0;
147 }
148 else if (type == String.class)
149 {
150 String s1 = (String)data.getValueAt(row1, column);
151 String s2 = (String)data.getValueAt(row2, column);
152 int result = s1.compareTo(s2);
153
154 if (result < 0)
155 return -1;
156 else if (result > 0)
157 return 1;
158 else return 0;
159 }
160 else if (type == Boolean.class)
161 {
162 Boolean bool1 = (Boolean)data.getValueAt(row1, column);
163 boolean b1 = bool1.booleanValue();
164 Boolean bool2 = (Boolean)data.getValueAt(row2, column);
165 boolean b2 = bool2.booleanValue();
166
167 if (b1 == b2)
168 return 0;
169 else if (b1)
170 return 1;
171 else
172 return -1;
173 }
174 else
175 {
176 Object v1 = data.getValueAt(row1, column);
177 String s1 = v1.toString();
178 Object v2 = data.getValueAt(row2, column);
179 String s2 = v2.toString();
180 int result = s1.compareTo(s2);
181
182 if (result < 0)
183 return -1;
184 else if (result > 0)
185 return 1;
186 else return 0;
187 }
188 }
189
190 public int compare(int row1, int row2)
191 {
192 for(int level = 0; level < sortingColumns.size(); level++)
193 {
194 Integer column = (Integer)sortingColumns.elementAt(level);
195 int result = compareRowsByColumn(row1, row2, column.intValue());
196 if (result != 0)
197 return ascending ? result : -result;
198 }
199 return 0;
200 }
201
202 public void reallocateIndexes()
203 {
204 int rowCount = model.getRowCount();
205
206
207
208 indexes = new int[rowCount];
209
210
211 for(int row = 0; row < rowCount; row++)
212 indexes[row] = row;
213 }
214
215 public void tableChanged(TableModelEvent e)
216 {
217 System.out.println("Sorter: tableChanged");
218 reallocateIndexes();
219
220 super.tableChanged(e);
221 }
222
223 public void checkModel()
224 {
225 if (indexes.length != model.getRowCount()) {
226 System.err.println("Sorter not informed of a change in model.");
227 }
228 }
229
230 public void sort(Object sender)
231 {
232 checkModel();
233 shuttlesort((int[])indexes.clone(), indexes, 0, indexes.length);
234 }
235
236 public void n2sort() {
237 for(int i = 0; i < getRowCount(); i++) {
238 for(int j = i+1; j < getRowCount(); j++) {
239 if (compare(indexes[i], indexes[j]) == -1) {
240 swap(i, j);
241 }
242 }
243 }
244 }
245
246
247
248
249
250
251
252
253 public void shuttlesort(int from[], int to[], int low, int high) {
254 if (high - low < 2) {
255 return;
256 }
257 int middle = (low + high)/2;
258 shuttlesort(to, from, low, middle);
259 shuttlesort(to, from, middle, high);
260
261 int p = low;
262 int q = middle;
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279 if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
280 for (int i = low; i < high; i++) {
281 to[i] = from[i];
282 }
283 return;
284 }
285
286
287
288 for(int i = low; i < high; i++) {
289 if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
290 to[i] = from[p++];
291 }
292 else {
293 to[i] = from[q++];
294 }
295 }
296 }
297
298 public void swap(int i, int j) {
299 int tmp = indexes[i];
300 indexes[i] = indexes[j];
301 indexes[j] = tmp;
302 }
303
304
305
306
307 public Object getValueAt(int aRow, int aColumn)
308 {
309 checkModel();
310 return model.getValueAt(indexes[aRow], aColumn);
311 }
312
313 public void setValueAt(Object aValue, int aRow, int aColumn)
314 {
315 checkModel();
316 model.setValueAt(aValue, indexes[aRow], aColumn);
317 }
318
319 public void sortByColumn(int column) {
320 sortByColumn(column, true);
321 }
322
323 public void sortByColumn(int column, boolean ascending) {
324 this.ascending = ascending;
325 sortingColumns.removeAllElements();
326 sortingColumns.addElement(new Integer(column));
327 sort(this);
328 super.tableChanged(new TableModelEvent(this));
329 }
330
331
332
333
334 public void addMouseListenerToHeaderInTable(JTable table) {
335 final TableSorter sorter = this;
336 final JTable tableView = table;
337 tableView.setColumnSelectionAllowed(false);
338 MouseAdapter listMouseListener = new MouseAdapter() {
339 public void mouseClicked(MouseEvent e) {
340 TableColumnModel columnModel = tableView.getColumnModel();
341 int viewColumn = columnModel.getColumnIndexAtX(e.getX());
342 int column = tableView.convertColumnIndexToModel(viewColumn);
343 if(e.getClickCount() == 1 && column != -1) {
344 if (lastSortedColumn == column) ascending = !ascending;
345 sorter.sortByColumn(column, ascending);
346 lastSortedColumn = column;
347 }
348 }
349 };
350 JTableHeader th = tableView.getTableHeader();
351 th.addMouseListener(listMouseListener);
352 }
353
354
355
356 }
357