001: /*
002: * Copyright Javelin Software, All rights reserved.
003: */
004:
005: package com.javelin.swinglets.table;
006:
007: import java.lang.reflect.*;
008: import java.awt.event.*;
009: import java.util.Vector;
010:
011: import javax.swing.event.*;
012: import javax.swing.table.*;
013:
014: //import com.sun.java.util.collections.Comparator;
015: import java.util.Comparator;
016:
017: /**
018: * The SortedTableModel provides a TableModel that sorts using a
019: * java 11 collections Comparator or java.util.Comparator.
020: * <p>
021: * @author Robin Sharp
022: */
023:
024: public class SortedTableModel extends AbstractTableModel implements
025: TableModelListener, SortByColumn {
026: public SortedTableModel(TableModel model) {
027: this .model = model;
028: this .model.addTableModelListener(this );
029: reallocateIndexes();
030: }
031:
032: // TABLE MODEL ////////////////////////////////////////////////////////////
033:
034: /**
035: * Delegate method the the underlying model.
036: */
037: public Object getValueAt(int aRow, int aColumn) {
038: if (ascending == NATURAL) {
039: return model.getValueAt(aRow, aColumn);
040: } else {
041: checkModel();
042: return model.getValueAt(indexes[aRow], aColumn);
043: }
044: }
045:
046: /**
047: * Delegate method the the underlying model.
048: */
049: public void setValueAt(Object aValue, int aRow, int aColumn) {
050: checkModel();
051: model.setValueAt(aValue, indexes[aRow], aColumn);
052: }
053:
054: /**
055: * Delegate method the the underlying model.
056: */
057: public int getRowCount() {
058: return model.getRowCount();
059: }
060:
061: /**
062: * Delegate method the the underlying model.
063: */
064: public int getColumnCount() {
065: return model.getColumnCount();
066: }
067:
068: /**
069: * Delegate method the the underlying model.
070: */
071: public String getColumnName(int aColumn) {
072: return model.getColumnName(aColumn);
073: }
074:
075: /**
076: * Delegate method the the underlying model.
077: */
078: public Class getColumnClass(int aColumn) {
079: return model.getColumnClass(aColumn);
080: }
081:
082: /**
083: * Delegate method the the underlying model.
084: */
085: public boolean isCellEditable(int row, int column) {
086: return model.isCellEditable(row, column);
087: }
088:
089: // SORTED TABLE MODEL //////////////////////////////////////////////////////
090:
091: /**
092: * Get the comparator used to do the Sorting.
093: * This defaults to JDK11Comparator.
094: */
095: public Object getComparator() {
096: return comparator;
097: }
098:
099: /**
100: * Set a new Comparator.
101: * <p>
102: * @exception IllegalArgumentException if the class does not implement
103: * the com.sun.java.util.collections.Comparator or the
104: * java.util.Comparator.
105: */
106: public void setComparator(Object comparator)
107: throws IllegalArgumentException {
108: this .comparator = comparator;
109:
110: if (!(comparator instanceof Comparator)) {
111: throw new IllegalArgumentException(
112: "Object does not implement the Comparator interface.");
113: }
114:
115: }
116:
117: /**
118: * Get the delegate table model.
119: */
120: public TableModel getModel() {
121: return model;
122: }
123:
124: public final static int ASCENDING = 1;
125: public final static int NATURAL = 0;
126: public final static int DESCENDING = -1;
127:
128: /**
129: * @return ASCENDING, NATURAL, DESCENDING
130: */
131: public int getSortType() {
132: return ascending;
133: }
134:
135: /**
136: * Set the lowIndex for the sort.
137: */
138: public void setLowIndex(int lowIndex) {
139: this .lowIndex = lowIndex;
140: }
141:
142: public int getSortedIndex() {
143: return sortedIndex;
144: }
145:
146: public int compareRowsByColumn(int row1, int row2, int column) {
147: Class type = model.getColumnClass(column);
148: TableModel data = model;
149:
150: // Check for nulls.
151:
152: Object o1 = data.getValueAt(row1, column);
153: Object o2 = data.getValueAt(row2, column);
154:
155: if (o1 == null && o2 == null) {
156: // If both values are null, return 0.
157: return 0;
158: } else if (o1 == null) {
159: // Define null less than everything.
160: return -1;
161: } else if (o2 == null) {
162: return 1;
163: }
164:
165: if (comparator != null) {
166: if (comparator instanceof Comparator) {
167: return ((Comparator) comparator).compare(o1, o2);
168: }
169: }
170:
171: //Can't compare
172: return 0;
173: }
174:
175: public int compare(int row1, int row2) {
176: compares++;
177: for (int level = 0; level < sortingColumns.size(); level++) {
178: Integer column = (Integer) sortingColumns.elementAt(level);
179: int result = compareRowsByColumn(row1, row2, column
180: .intValue());
181: if (result != 0) {
182: return ascending == ASCENDING ? result : -result;
183: }
184: }
185:
186: return 0;
187: }
188:
189: public void reallocateIndexes() {
190: int rowCount = model.getRowCount();
191:
192: // Set up a new array of indexes with the right number of elements
193: // for the new data model.
194: indexes = new int[rowCount];
195:
196: // Initialise with the identity mapping.
197: for (int row = 0; row < rowCount; row++) {
198: indexes[row] = row;
199: }
200: }
201:
202: public void checkModel() {
203: if (indexes.length != model.getRowCount()) {
204: System.err
205: .println("Sorter not informed of a change in model.");
206: }
207: }
208:
209: public void sort() {
210: checkModel();
211: compares = 0;
212: sort((int[]) indexes.clone(), indexes, lowIndex, indexes.length);
213: }
214:
215: public void sort(int from[], int to[], int low, int high) {
216: if (high - low < 2) {
217: return;
218: }
219: int middle = (low + high) / 2;
220: sort(to, from, low, middle);
221: sort(to, from, middle, high);
222:
223: int p = low;
224: int q = middle;
225:
226: if (high - low >= 4
227: && compare(from[middle - 1], from[middle]) <= 0) {
228: for (int i = low; i < high; i++) {
229: to[i] = from[i];
230: }
231: return;
232: }
233:
234: // A normal merge.
235: for (int i = low; i < high; i++) {
236: if (q >= high
237: || (p < middle && compare(from[p], from[q]) <= 0)) {
238: to[i] = from[p++];
239: } else {
240: to[i] = from[q++];
241: }
242: }
243: }
244:
245: public void swap(int i, int j) {
246: int tmp = indexes[i];
247: indexes[i] = indexes[j];
248: indexes[j] = tmp;
249: }
250:
251: public void sortByColumn(int column) {
252: if (lastSortedColumn == column) {
253: if (ascending == DESCENDING)
254: ascending = ASCENDING;
255: else if (ascending == ASCENDING)
256: ascending = DESCENDING;
257: else if (ascending == NATURAL)
258: ascending = ASCENDING;
259:
260: } else {
261: ascending = ASCENDING;
262: }
263:
264: lastSortedColumn = column;
265:
266: sortedIndex = column;
267: sortingColumns.removeAllElements();
268: sortingColumns.addElement(new Integer(column));
269: sort();
270: fireTableChanged(new TableModelEvent(this ));
271: }
272:
273: // TABLE MODEL LISTENER ////////////////////////////////////////
274:
275: public void tableChanged(TableModelEvent e) {
276: reallocateIndexes();
277: fireTableChanged(e);
278: }
279:
280: // PRIVATE /////////////////////////////////////////////////////
281:
282: protected TableModel model;
283:
284: //The type of sorting to be done
285: private int ascending = DESCENDING;
286:
287: private int indexes[];
288: private Vector sortingColumns = new Vector();
289: private int compares;
290: private int sortedIndex;
291: private int lowIndex;
292:
293: private int lastSortedColumn;
294:
295: private Object comparator = new JDK11Comparator();
296:
297: }
|