1 package org.lcsim.plugin.browser.sort;
2
3 import java.util.Comparator;
4
5 import javax.swing.event.EventListenerList;
6 import javax.swing.event.TableModelEvent;
7 import javax.swing.event.TableModelListener;
8 import javax.swing.table.TableModel;
9
10
11
12
13
14
15 public class DefaultSortableTableModel implements SortableTableModel
16 {
17 private Comparator comparator = new DefaultComparator();
18 private TableModel source;
19 private EventListenerList listeners = new EventListenerList();
20 private TableModelListener internalListener = new InternalTableModelListener();
21 private int sortColumn = UNSORTED;
22 private String sortColumnName;
23 private boolean ascending = true;
24 private int[] rowMap;
25 private int[] reverseMap;
26 boolean reverseMapValid = false;
27 private int nRows;
28
29
30
31
32
33 public DefaultSortableTableModel(TableModel source)
34 {
35 this.source = source;
36 }
37 private int mapFromSorted(int rowIndex)
38 {
39 return rowMap == null ? rowIndex : rowMap[rowIndex];
40 }
41 private int mapToSorted(int rowIndex)
42 {
43 if (rowMap != null && !reverseMapValid)
44 {
45 if (reverseMap == null || reverseMap.length < nRows)
46 {
47 reverseMap = new int[rowMap.length];
48 }
49 for (int i=0; i<nRows; i++) reverseMap[rowMap[i]] = i;
50 reverseMapValid = true;
51 }
52 return rowMap == null ? rowIndex : reverseMap[rowIndex];
53 }
54
55 public void addTableModelListener(TableModelListener l)
56 {
57 if (listeners.getListenerCount() == 0)
58 {
59
60
61 dataChanged();
62 source.addTableModelListener(internalListener);
63 }
64 listeners.add(TableModelListener.class, l);
65 }
66
67 public Class getColumnClass(int columnIndex)
68 {
69 return source.getColumnClass(columnIndex);
70 }
71
72 public int getColumnCount()
73 {
74 return source.getColumnCount();
75 }
76
77 public String getColumnName(int columnIndex)
78 {
79 return source.getColumnName(columnIndex);
80 }
81
82 public int getRowCount()
83 {
84 return source.getRowCount();
85 }
86
87 public Object getValueAt(int rowIndex, int columnIndex)
88 {
89 return source.getValueAt(mapFromSorted(rowIndex),columnIndex);
90 }
91
92 public boolean isCellEditable(int rowIndex, int columnIndex)
93 {
94 return source.isCellEditable(mapFromSorted(rowIndex),columnIndex);
95 }
96
97 public void removeTableModelListener(TableModelListener l)
98 {
99 listeners.remove(TableModelListener.class, l);
100 if (listeners.getListenerCount() == 0) source.removeTableModelListener(internalListener);
101 }
102
103 public void sort(int column, boolean ascending)
104 {
105 if (column == UNSORTED)
106 {
107 if (this.sortColumn != UNSORTED)
108 {
109 rowMap = null;
110 reverseMap = null;
111 reverseMapValid = false;
112 this.sortColumn = column;
113 this.sortColumnName = null;
114 TableModelEvent ee = new TableModelEvent(this,0,source.getRowCount()-1,TableModelEvent.ALL_COLUMNS);
115 fireTableChanged(ee);
116 }
117 }
118 else if (column == this.sortColumn)
119 {
120 if (ascending != this.ascending)
121 {
122 this.ascending = ascending;
123 for (int i=0; i<nRows/2; i++) swap(i,nRows-1-i);
124 reverseMapValid = false;
125 TableModelEvent ee = new TableModelEvent(this,0,nRows-1,TableModelEvent.ALL_COLUMNS);
126 fireTableChanged(ee);
127 }
128 }
129 else
130 {
131 if (rowMap == null)
132 {
133 nRows = source.getRowCount();
134 rowMap = new int[nRows+10];
135 for (int i=0; i<nRows; i++) rowMap[i] = i;
136 }
137 this.sortColumn = column;
138 this.sortColumnName = getColumnName(column);
139 this.ascending = ascending;
140 reverseMapValid = false;
141 sort1(0,nRows);
142 TableModelEvent ee = new TableModelEvent(this,0,nRows-1,TableModelEvent.ALL_COLUMNS);
143 fireTableChanged(ee);
144 }
145 }
146 private void reSort()
147 {
148 reverseMapValid = false;
149 sort1(0,nRows);
150 TableModelEvent ee = new TableModelEvent(this,0,nRows-1,TableModelEvent.ALL_COLUMNS);
151 fireTableChanged(ee);
152 }
153 private void dataChanged()
154 {
155
156 nRows = source.getRowCount();
157 if (sortColumn != UNSORTED)
158 {
159 rowMap = new int[nRows+10];
160 for (int i=0; i<nRows; i++) rowMap[i] = i;
161 reverseMapValid = false;
162 sort1(0,nRows);
163 }
164 TableModelEvent ee = new TableModelEvent(this,0,Integer.MAX_VALUE,TableModelEvent.ALL_COLUMNS);
165 fireTableChanged(ee);
166 }
167
168 private int rowWasInserted(int row)
169 {
170 int insertPoint;
171 if (sortColumn != UNSORTED)
172 {
173 if (nRows >= rowMap.length)
174 {
175 int[] newMap = new int[nRows+10];
176 System.arraycopy(rowMap,0,newMap,0,rowMap.length);
177 rowMap = newMap;
178 }
179
180 for (int i=0; i<nRows; i++)
181 {
182 if (rowMap[i] >= row) rowMap[i]++;
183 }
184 rowMap[nRows] = row;
185
186 insertPoint = binarySearch(nRows,0,nRows);
187 if (insertPoint != nRows)
188 {
189 System.arraycopy(rowMap,insertPoint, rowMap, insertPoint+1,nRows-insertPoint);
190 rowMap[insertPoint] = row;
191 }
192 }
193 else
194 {
195 insertPoint = row;
196 }
197 nRows++;
198 reverseMapValid = false;
199 return insertPoint;
200 }
201 private int binarySearch(int newRow, int start, int end)
202 {
203 if (start-end < 5)
204 {
205 for (int i=start; i<end; i++)
206 {
207 if (compare(newRow,i) <= 0 ) return i;
208 }
209 return end;
210 }
211 int mid = end-start >> 1;
212 int result = compare(newRow,mid);
213 if (result == 0) return mid;
214 else if (result > 0) return binarySearch(newRow,mid,end);
215 else return binarySearch(newRow,start,mid);
216 }
217 private int rowWasDeleted(int row)
218 {
219 int sortedRow;
220 if (sortColumn != UNSORTED)
221 {
222 sortedRow = mapToSorted(row);
223 System.arraycopy(rowMap,sortedRow+1,rowMap,sortedRow,nRows-sortedRow-1);
224 nRows--;
225 for (int i=0; i<nRows; i++)
226 {
227 if (rowMap[i] > row) rowMap[i]--;
228 }
229 }
230 else
231 {
232 sortedRow = row;
233 }
234 reverseMapValid = false;
235 return sortedRow;
236 }
237
238 public void setValueAt(Object aValue, int rowIndex, int columnIndex)
239 {
240 source.setValueAt(aValue, mapFromSorted(rowIndex), columnIndex);
241 }
242
243 private Object get(int index)
244 {
245 return source.getValueAt(mapFromSorted(index), sortColumn);
246 }
247 private int compare(int i, int j)
248 {
249 return comparator.compare(get(i),get(j)) * (ascending ? 1 : -1);
250 }
251 private int compare(Object o, int j)
252 {
253 return comparator.compare(o,get(j)) * (ascending ? 1 : -1);
254 }
255 private void swap(int i, int j)
256 {
257 int tmp = rowMap[i];
258 rowMap[i] = rowMap[j];
259 rowMap[j] = tmp;
260 }
261 private int med3(int a, int b, int c)
262 {
263 return compare(a,b)<0 ?
264 compare(b,c)<0 ? b : compare(a,c)<0 ? c : a :
265 compare(b,c)>0 ? b : compare(a,c)>0 ? c : a;
266 }
267 private void vecswap(int a, int b, int n)
268 {
269 for (int i=0; i<n; i++, a++, b++)
270 swap(a, b);
271 }
272 private void sort1(int off, int len)
273 {
274
275 if (len < 7)
276 {
277 for (int i=off; i<len+off; i++)
278 for (int j=i; j>off && compare(j-1,j)>0; j--)
279 swap(j, j-1);
280 return;
281 }
282
283
284 int m = off + (len >> 1);
285 if (len > 7)
286 {
287 int l = off;
288 int n = off + len - 1;
289 if (len > 40)
290 {
291 int s = len/8;
292 l = med3(l, l+s, l+2*s);
293 m = med3(m-s, m, m+s);
294 n = med3(n-2*s, n-s, n);
295 }
296 m = med3(l, m, n);
297 }
298 Object v = get(m);
299
300
301 int a = off, b = a, c = off + len - 1, d = c;
302 int comp;
303 while(true)
304 {
305 while (b <= c && (comp = compare(v,b)) >= 0)
306 {
307 if (comp == 0) swap(a++, b);
308 b++;
309 }
310 while (c >= b && (comp = compare(v,c)) <= 0)
311 {
312 if (comp == 0) swap(c, d--);
313 c--;
314 }
315 if (b > c) break;
316 swap(b++, c--);
317 }
318
319
320 int s, n = off + len;
321 s = Math.min(a-off, b-a ); vecswap(off, b-s, s);
322 s = Math.min(d-c, n-d-1); vecswap(b, n-s, s);
323
324
325 if ((s = b-a) > 1) sort1(off, s);
326 if ((s = d-c) > 1) sort1(n-s, s);
327 }
328
329
330
331
332
333 protected void fireTableChanged(TableModelEvent event)
334 {
335 TableModelListener[] l = (TableModelListener[]) listeners.getListeners(TableModelListener.class);
336 for (int i=0; i<l.length; i++)
337 {
338 l[i].tableChanged(event);
339 }
340 }
341
342 public boolean isSortAscending()
343 {
344 return ascending;
345 }
346
347 public int getSortOnColumn()
348 {
349 return sortColumn;
350 }
351 private class InternalTableModelListener implements TableModelListener
352 {
353 public void tableChanged(TableModelEvent e)
354 {
355 int column = e.getColumn();
356 int first = e.getFirstRow();
357 int last = e.getLastRow();
358 int type = e.getType();
359 if (sortColumn == UNSORTED)
360 {
361 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,first,last,column,type);
362 fireTableChanged(ee);
363 }
364 else if (first == TableModelEvent.HEADER_ROW)
365 {
366
367 if (type == TableModelEvent.DELETE)
368 {
369 if (column < sortColumn) sortColumn--;
370 else if (column == sortColumn)
371 {
372 sort(UNSORTED,true);
373 }
374 }
375 else if (type == TableModelEvent.INSERT)
376 {
377 if (column <= sortColumn && sortColumn != UNSORTED) sortColumn++;
378 }
379 else if (type == TableModelEvent.UPDATE)
380 {
381 if (column == sortColumn)
382 {
383 reSort();
384 }
385 else if (column == TableModelEvent.ALL_COLUMNS)
386 {
387
388 sortColumn = UNSORTED;
389 reverseMapValid = false;
390 rowMap = null;
391 nRows = source.getRowCount();
392
393 if (sortColumnName != null)
394 {
395 int n = getColumnCount();
396 for (int i=0; i<n; i++)
397 {
398 if (sortColumnName.equals(getColumnName(i)))
399 {
400 sort(i,ascending);
401 }
402 }
403 }
404 }
405 }
406 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,first,last,column,type);
407 fireTableChanged(ee);
408 }
409 else if (column == TableModelEvent.ALL_COLUMNS)
410 {
411
412
413 if (type == TableModelEvent.DELETE)
414 {
415 for (int i=first; i<=last; i++)
416 {
417 int sortedRow = rowWasDeleted(first);
418 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,sortedRow,sortedRow,column,type);
419 fireTableChanged(ee);
420 }
421 }
422 else if (type == TableModelEvent.INSERT)
423 {
424 for (int i=first; i<=last; i++)
425 {
426 int sortedRow = rowWasInserted(i);
427 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,sortedRow,sortedRow,column,type);
428 fireTableChanged(ee);
429 }
430 }
431 else if (type == TableModelEvent.UPDATE)
432 {
433 if (Integer.MAX_VALUE == last)
434 {
435 dataChanged();
436 }
437 else
438 {
439 for (int i=first; i<=last; i++)
440 {
441 int oldRow = rowWasDeleted(i);
442 int newRow = rowWasInserted(i);
443 if (oldRow == newRow)
444 {
445 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,newRow,newRow,column,type);
446 fireTableChanged(ee);
447 }
448 else
449 {
450 TableModelEvent ee1 = new TableModelEvent(DefaultSortableTableModel.this,oldRow,oldRow,TableModelEvent.ALL_COLUMNS,TableModelEvent.DELETE);
451 fireTableChanged(ee1);
452 TableModelEvent ee2 = new TableModelEvent(DefaultSortableTableModel.this,newRow,newRow,TableModelEvent.ALL_COLUMNS,TableModelEvent.INSERT);
453 fireTableChanged(ee2);
454 }
455 }
456 }
457 }
458 }
459 else if (type == TableModelEvent.UPDATE)
460 {
461 if (column == sortColumn)
462 {
463 for (int i=first; i<=last; i++)
464 {
465 int oldRow = rowWasDeleted(i);
466 int newRow = rowWasInserted(i);
467 if (oldRow == newRow)
468 {
469 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,newRow,newRow,column,type);
470 fireTableChanged(ee);
471 }
472 else
473 {
474 TableModelEvent ee1 = new TableModelEvent(DefaultSortableTableModel.this,oldRow,oldRow,TableModelEvent.ALL_COLUMNS,TableModelEvent.DELETE);
475 fireTableChanged(ee1);
476 TableModelEvent ee2 = new TableModelEvent(DefaultSortableTableModel.this,newRow,newRow,TableModelEvent.ALL_COLUMNS,TableModelEvent.INSERT);
477 fireTableChanged(ee2);
478 }
479 }
480 }
481 else
482 {
483 for (int i=first; i<=last; i++)
484 {
485 int sortedRow = mapToSorted(i);
486 TableModelEvent ee = new TableModelEvent(DefaultSortableTableModel.this,sortedRow,sortedRow,column,type);
487 fireTableChanged(ee);
488 }
489 }
490 }
491 else throw new UnsupportedOperationException("An unsupported TableModelEvent was found: "+e);
492 }
493 }
494 private class DefaultComparator implements Comparator
495 {
496 public int compare(Object o1, Object o2)
497 {
498 if ((o1 instanceof Comparable) && (o2 instanceof Comparable))
499 return ((Comparable) o1).compareTo((Comparable) o2);
500 else return String.valueOf(o1).compareTo(String.valueOf(o2));
501 }
502 }
503 }