KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > adminGui > widget > TableSorter


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Library License version 1 published by ozone-db.org.
3
//
4
// The original code and portions created by SMB are
5
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
6
//
7
// $Id: $
8
package org.ozoneDB.adminGui.widget;
9
10 import java.awt.event.InputEvent JavaDoc;
11 import java.awt.event.MouseAdapter JavaDoc;
12 import java.awt.event.MouseEvent JavaDoc;
13 import java.util.Date JavaDoc;
14 import java.util.Vector JavaDoc;
15 import javax.swing.*;
16 import javax.swing.event.TableModelEvent JavaDoc;
17 import javax.swing.table.JTableHeader JavaDoc;
18 import javax.swing.table.TableColumnModel JavaDoc;
19 import javax.swing.table.TableModel JavaDoc;
20
21 /**
22  * A sorter for TableModels. The sorter has a model (conforming to TableModel)
23  * and itself implements TableModel. TableSorter does not store or copy
24  * the data in the TableModel, instead it maintains an array of
25  * integers which it keeps the same size as the number of rows in its
26  * model. When the model changes it notifies the sorter that something
27  * has changed eg. "rowsAdded" so that its internal array of integers
28  * can be reallocated. As requests are made of the sorter (like
29  * getValueAt(row, col) it redirects them to its model via the mapping
30  * array. That way the TableSorter appears to hold another copy of the table
31  * with the rows in a different order. The sorting algorthm used is stable
32  * which means that it does not move around rows when its comparison
33  * function returns 0 to denote that they are equivalent.
34  */

35 public class TableSorter extends TableMap {
36
37     protected int indexes[];
38     protected Vector JavaDoc sortingColumns = new Vector JavaDoc();
39     protected boolean ascending = true;
40     protected int compares;
41
42     public TableSorter() {
43         indexes = new int[0];
44     }
45
46     public TableSorter(TableModel JavaDoc model) {
47         setModel(model);
48     }
49
50     public void setModel(TableModel JavaDoc model) {
51         super.setModel(model);
52         reallocateIndexes();
53     }
54
55     public int compareRowsByColumn(int row1, int row2, int column) {
56         Class JavaDoc type = model.getColumnClass(column);
57         TableModel JavaDoc data = model;
58
59         // Check for nulls
60
Object JavaDoc o1 = data.getValueAt(row1, column);
61         Object JavaDoc o2 = data.getValueAt(row2, column);
62
63         if (o1 == null && o2 == null) { // If both values are null return 0
64
return 0;
65         } else if (o1 == null) { // Define null less than everything.
66
return -1;
67         } else if (o2 == null) {
68             return 1;
69         }
70
71         /* We copy all returned values from the getValue call in case
72         an optimised model is reusing one object to return many values.
73         The Number subclasses in the JDK are immutable and so will not be used in
74         this way but other subclasses of Number might want to do this to save
75         space and avoid unnecessary heap allocation.
76         */

77         if (type.getSuperclass() == java.lang.Number JavaDoc.class) {
78             Number JavaDoc n1 = (Number JavaDoc) data.getValueAt(row1, column);
79             double d1 = n1.doubleValue();
80             Number JavaDoc n2 = (Number JavaDoc) data.getValueAt(row2, column);
81             double d2 = n2.doubleValue();
82
83             if (d1 < d2)
84                 return -1;
85             else if (d1 > d2)
86                 return 1;
87             else
88                 return 0;
89         } else if (type == java.util.Date JavaDoc.class) {
90             Date JavaDoc d1 = (Date JavaDoc) data.getValueAt(row1, column);
91             long n1 = d1.getTime();
92             Date JavaDoc d2 = (Date JavaDoc) data.getValueAt(row2, column);
93             long n2 = d2.getTime();
94
95             if (n1 < n2)
96                 return -1;
97             else if (n1 > n2)
98                 return 1;
99             else
100                 return 0;
101         } else if (type == String JavaDoc.class) {
102             String JavaDoc s1 = (String JavaDoc) data.getValueAt(row1, column);
103             String JavaDoc s2 = (String JavaDoc) data.getValueAt(row2, column);
104             int result = s1.compareTo(s2);
105
106             if (result < 0)
107                 return -1;
108             else if (result > 0)
109                 return 1;
110             else
111                 return 0;
112         } else if (type == Boolean JavaDoc.class) {
113             Boolean JavaDoc bool1 = (Boolean JavaDoc) data.getValueAt(row1, column);
114             boolean b1 = bool1.booleanValue();
115             Boolean JavaDoc bool2 = (Boolean JavaDoc) data.getValueAt(row2, column);
116             boolean b2 = bool2.booleanValue();
117
118             if (b1 == b2)
119                 return 0;
120             else if (b1)
121                 return 1;
122             else
123                 return -1;
124         } else {
125             Object JavaDoc v1 = data.getValueAt(row1, column);
126             String JavaDoc s1 = v1.toString();
127             Object JavaDoc v2 = data.getValueAt(row2, column);
128             String JavaDoc s2 = v2.toString();
129             int result = s1.compareTo(s2);
130
131             if (result < 0)
132                 return -1;
133             else if (result > 0)
134                 return 1;
135             else
136                 return 0;
137         }
138     }
139
140     public int compare(int row1, int row2) {
141         compares++;
142         for (int level = 0; level < sortingColumns.size(); level++) {
143             Integer JavaDoc column = (Integer JavaDoc) sortingColumns.elementAt(level);
144             int result = compareRowsByColumn(row1, row2, column.intValue());
145             if (result != 0) {
146                 return ascending ? result : -result;
147             }
148         }
149         return 0;
150     }
151
152     public void reallocateIndexes() {
153         int rowCount = model.getRowCount();
154
155         // Set up a new array of indexes with the right number of elements
156
// for the new data model.
157
indexes = new int[rowCount];
158
159         // Initialise with the identity mapping.
160
for (int row = 0; row < rowCount; row++) {
161             indexes[row] = row;
162         }
163     }
164
165     public void tableChanged(TableModelEvent JavaDoc e) {
166         reallocateIndexes();
167         super.tableChanged(e);
168     }
169
170     public void checkModel() {
171         if (indexes.length != model.getRowCount()) {
172             System.err.println("Sorter not informed of a change in model.");
173         }
174     }
175
176     public void sort(Object JavaDoc sender) {
177         checkModel();
178
179         compares = 0;
180         shuttleSort((int[]) indexes.clone(), indexes, 0, indexes.length);
181     }
182
183     public void shuttleSort(int from[], int to[], int low, int high) {
184         if (high - low < 2) {
185             return;
186         }
187         int middle = (low + high) / 2;
188         shuttleSort(to, from, low, middle);
189         shuttleSort(to, from, middle, high);
190
191         int p = low;
192         int q = middle;
193
194         for (int i = low; i < high; i++) {
195             if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
196                 to[i] = from[p++];
197             } else {
198                 to[i] = from[q++];
199             }
200         }
201     }
202
203     public void swap(int i, int j) {
204         int tmp = indexes[i];
205         indexes[i] = indexes[j];
206         indexes[j] = tmp;
207     }
208
209     // The mapping only affects the contents of the data rows.
210
// Pass all requests to these rows through the mapping array: "indexes".
211

212     public Object JavaDoc getValueAt(int aRow, int aColumn) {
213         checkModel();
214         return model.getValueAt(indexes[aRow], aColumn);
215     }
216
217     public void setValueAt(Object JavaDoc aValue, int aRow, int aColumn) {
218         checkModel();
219         model.setValueAt(aValue, indexes[aRow], aColumn);
220     }
221
222     public int translateIndex(int index) {
223         return indexes[index];
224     }
225
226     public void sortByColumn(int column) {
227         sortByColumn(column, true);
228     }
229
230     public void sortByColumn(int column, boolean ascending) {
231         this.ascending = ascending;
232         sortingColumns.removeAllElements();
233         sortingColumns.addElement(new Integer JavaDoc(column));
234         sort(this);
235         super.tableChanged(new TableModelEvent JavaDoc(this));
236     }
237
238     // Add a mouse listener to the Table to trigger a table sort
239
// when a column heading is clicked in the JTable.
240
public void addMouseListenerToHeaderInTable(JTable table) {
241         final TableSorter sorter = this;
242         final JTable tableView = table;
243         tableView.setColumnSelectionAllowed(false);
244         MouseAdapter JavaDoc listMouseListener = new MouseAdapter JavaDoc() {
245             public void mouseClicked(MouseEvent JavaDoc e) {
246                 TableColumnModel JavaDoc columnModel = tableView.getColumnModel();
247                 int viewColumn = columnModel.getColumnIndexAtX(e.getX());
248                 int column = tableView.convertColumnIndexToModel(viewColumn);
249                 if (e.getClickCount() == 1 && column != -1) {
250                     int shiftPressed = e.getModifiers() & InputEvent.SHIFT_MASK;
251                     boolean ascending = (shiftPressed == 0);
252                     sorter.sortByColumn(column, ascending);
253                 }
254             }
255         };
256         JTableHeader JavaDoc th = tableView.getTableHeader();
257         th.addMouseListener(listMouseListener);
258     }
259 }
260
Popular Tags