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: * PagedTableModel is a TableModel that can page.
019: *
020: * @author Robin Sharp
021: */
022:
023: public class PagedTableModel extends AbstractTableModel implements
024: TableModelListener, SortByColumn {
025: public PagedTableModel(TableModel model, int pageSize) {
026: this .pageSize = pageSize;
027: this .model = model;
028: this .model.addTableModelListener(this );
029: reallocateIndexes();
030: }
031:
032: public PagedTableModel(TableModel model) {
033: this (model, 10);
034: }
035:
036: // TABLE MODEL ////////////////////////////////////////////////////////////
037:
038: /**
039: * Delegate method the the underlying model.
040: */
041: public Object getValueAt(int aRow, int aColumn) {
042: if (ascending == NATURAL) {
043: return model.getValueAt(aRow + offset, aColumn);
044: } else {
045: checkModel();
046: int idx = Math.min(aRow + offset, indexes.length - 1);
047: //System.out.println(aRow+" "+offset+" "+(indexes.length-1));
048: return model.getValueAt(indexes[idx], aColumn);
049: }
050: }
051:
052: /**
053: * Delegate method the the underlying model.
054: */
055: public void setValueAt(Object aValue, int aRow, int aColumn) {
056: checkModel();
057: model.setValueAt(aValue, indexes[aRow], aColumn);
058: }
059:
060: /**
061: * Delegate method the the underlying model.
062: */
063: public int getRowCount() {
064: return Math.min(pageSize, model.getRowCount() - offset);
065: }
066:
067: /**
068: * Delegate method the the underlying model.
069: */
070: public int getColumnCount() {
071: return model.getColumnCount();
072: }
073:
074: /**
075: * Delegate method the the underlying model.
076: */
077: public String getColumnName(int aColumn) {
078: return model.getColumnName(aColumn);
079: }
080:
081: /**
082: * Delegate method the the underlying model.
083: */
084: public Class getColumnClass(int aColumn) {
085: return model.getColumnClass(aColumn);
086: }
087:
088: /**
089: * Delegate method the the underlying model.
090: */
091: public boolean isCellEditable(int row, int column) {
092: return model.isCellEditable(row, column);
093: }
094:
095: // SORTED TABLE MODEL //////////////////////////////////////////////////////
096:
097: /**
098: * Get the comparator used to do the Sorting.
099: * This defaults to JDK11Comparator.
100: */
101: public Object getComparator() {
102: return comparator;
103: }
104:
105: /**
106: * Set a new Comparator.
107: * <p>
108: * @exception IllegalArgumentException if the class does not implement
109: * the com.sun.java.util.collections.Comparator or the
110: * java.util.Comparator.
111: */
112: public void setComparator(Object comparator)
113: throws IllegalArgumentException {
114: this .comparator = comparator;
115:
116: if (!(comparator instanceof Comparator)) {
117: throw new IllegalArgumentException(
118: "Object does not implement the Comparator interface.");
119: }
120:
121: }
122:
123: /**
124: * Get the delegate table model.
125: */
126: public TableModel getModel() {
127: return model;
128: }
129:
130: public final static int ASCENDING = 1;
131: public final static int NATURAL = 0;
132: public final static int DESCENDING = -1;
133:
134: /**
135: * @return ASCENDING, NATURAL, DESCENDING
136: */
137: public int getSortType() {
138: return ascending;
139: }
140:
141: /**
142: * Set the lowIndex for the sort.
143: */
144: public void setLowIndex(int lowIndex) {
145: this .lowIndex = lowIndex;
146: }
147:
148: public int getSortedIndex() {
149: return sortedIndex;
150: }
151:
152: public int compareRowsByColumn(int row1, int row2, int column) {
153: Class type = model.getColumnClass(column);
154: TableModel data = model;
155:
156: // Check for nulls.
157:
158: Object o1 = data.getValueAt(row1, column);
159: Object o2 = data.getValueAt(row2, column);
160:
161: if (o1 == null && o2 == null) {
162: // If both values are null, return 0.
163: return 0;
164: } else if (o1 == null) {
165: // Define null less than everything.
166: return -1;
167: } else if (o2 == null) {
168: return 1;
169: }
170:
171: if (comparator != null) {
172: if (comparator instanceof Comparator) {
173: return ((Comparator) comparator).compare(o1, o2);
174: }
175: }
176:
177: //Can't compare
178: return 0;
179: }
180:
181: public int compare(int row1, int row2) {
182: compares++;
183: for (int level = 0; level < sortingColumns.size(); level++) {
184: Integer column = (Integer) sortingColumns.elementAt(level);
185: int result = compareRowsByColumn(row1, row2, column
186: .intValue());
187: if (result != 0) {
188: return ascending == ASCENDING ? result : -result;
189: }
190: }
191:
192: return 0;
193: }
194:
195: public void reallocateIndexes() {
196: int rowCount = model.getRowCount();
197:
198: // Set up a new array of indexes with the right number of elements
199: // for the new data model.
200: indexes = new int[rowCount];
201:
202: // Initialise with the identity mapping.
203: for (int row = 0; row < rowCount; row++) {
204: indexes[row] = row;
205: }
206: }
207:
208: public void checkModel() {
209: if (indexes.length != model.getRowCount()) {
210: System.err
211: .println("Sorter not informed of a change in model!");
212: }
213: }
214:
215: public void sort() {
216: checkModel();
217: compares = 0;
218: sort((int[]) indexes.clone(), indexes, lowIndex, indexes.length);
219: }
220:
221: public void sort(int from[], int to[], int low, int high) {
222: if (high - low < 2) {
223: return;
224: }
225: int middle = (low + high) / 2;
226: sort(to, from, low, middle);
227: sort(to, from, middle, high);
228:
229: int p = low;
230: int q = middle;
231:
232: if (high - low >= 4
233: && compare(from[middle - 1], from[middle]) <= 0) {
234: for (int i = low; i < high; i++) {
235: to[i] = from[i];
236: }
237: return;
238: }
239:
240: // A normal merge.
241: for (int i = low; i < high; i++) {
242: if (q >= high
243: || (p < middle && compare(from[p], from[q]) <= 0)) {
244: to[i] = from[p++];
245: } else {
246: to[i] = from[q++];
247: }
248: }
249: }
250:
251: public void swap(int i, int j) {
252: int tmp = indexes[i];
253: indexes[i] = indexes[j];
254: indexes[j] = tmp;
255: }
256:
257: public void sortByColumn(int column) {
258: if (lastSortedColumn == column) {
259: if (ascending == DESCENDING)
260: ascending = ASCENDING;
261: else if (ascending == ASCENDING)
262: ascending = DESCENDING;
263: else if (ascending == NATURAL)
264: ascending = ASCENDING;
265:
266: } else {
267: ascending = ASCENDING;
268: }
269:
270: lastSortedColumn = column;
271:
272: sortedIndex = column;
273: sortingColumns.removeAllElements();
274: sortingColumns.addElement(new Integer(column));
275: sort();
276: fireTableChanged(new TableModelEvent(this ));
277: gotoStart();
278: }
279:
280: /**
281: * Set the size of each page.
282: */
283: public void setPageSize(int pageSize) {
284: this .pageSize = pageSize;
285: }
286:
287: /**
288: * Get the size of each page.
289: */
290: public int getPageSize() {
291: return pageSize;
292: }
293:
294: public void setOffset(int Offset) {
295: this .offset = offset;
296: }
297:
298: public int getOffset() {
299: return offset;
300: }
301:
302: public void gotoStart() {
303: offset = 0;
304: }
305:
306: public void gotoEnd() {
307: int count = model.getRowCount();
308: offset = count - count % pageSize;
309: if (offset < 0) {
310: gotoStart();
311: }
312: }
313:
314: public void gotoNext() {
315: offset += pageSize;
316: if (offset > model.getRowCount()) {
317: gotoEnd();
318: }
319: }
320:
321: public void gotoPrev() {
322: offset -= pageSize;
323: if (offset < 0) {
324: gotoStart();
325: }
326: }
327:
328: // TABLE MODEL LISTENER ////////////////////////////////////////
329:
330: public void tableChanged(TableModelEvent e) {
331: reallocateIndexes();
332: fireTableChanged(e);
333: }
334:
335: // PRIVATE /////////////////////////////////////////////////////
336:
337: protected TableModel model;
338:
339: //The type of sorting to be done
340: private int ascending = DESCENDING;
341:
342: private int indexes[];
343: private Vector sortingColumns = new Vector();
344: private int compares;
345: private int sortedIndex;
346: private int lowIndex;
347:
348: private int lastSortedColumn;
349:
350: private Object comparator = new JDK11Comparator();
351:
352: protected int pageSize = 10;
353:
354: protected int offset = 0;
355:
356: }
|