1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui.table;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Iterator;
26
27 public class DefaultColumnTreeTableModel extends AbstractColumnTreeTableModel
28 implements SortableModel {
29
30
31
32
33
34 private boolean ascending;
35 private boolean maintainSortOrder;
36 private int sortedColumn = -1;
37
38 /***
39 * Stores the data.
40 */
41 private ArrayList rows = new ArrayList();
42
43
44
45 public DefaultColumnTreeTableModel()
46 {
47 }
48
49
50
51 /***
52 * Removes all nodes.
53 */
54 void clear()
55 {
56 rows.clear();
57 fireTreeStructureChanged(this, new Object[] { this }, null, null);
58 }
59
60 /***
61 * Invoked by a {@link TreeTableNode} object when a child item was
62 * added.
63 */
64 void childInserted(TreeTableNode node, int index, Object child)
65 {
66 fireTreeNodesInserted(this, new Object[] { this, node },
67 new int[] { index },
68 new Object[] { child });
69 }
70
71 /***
72 * Invoked by a {@link TreeTableNode} object when a child item has
73 * changed its state.
74 */
75 void childChanged(TreeTableNode node, int index, Object child)
76 {
77 fireTreeNodesChanged(this, new Object[] { this, node },
78 new int[] { index },
79 new Object[] { child });
80 }
81
82 /***
83 * Invoked by a {@link TreeTableNode} object when a child item was
84 * removed.
85 */
86 void childRemoved(TreeTableNode node, int index, Object child)
87 {
88 fireTreeNodesRemoved(this, new Object[] { this, node },
89 new int[] { index },
90 new Object[] { child });
91 }
92
93 /***
94 * Invoked by a {@link TreeTableNode} object when it has
95 * changed its state.
96 */
97 void nodeChanged(TreeTableNode node)
98 {
99 int index = rows.indexOf(node);
100 if (index != -1) {
101 fireTreeNodesChanged(this, new Object[] { this },
102 new int[] { index },
103 new Object[] { node });
104 }
105 }
106
107 public void add(TreeTableNode node)
108 {
109 rows.add(node);
110 fireTreeNodesInserted(this, new Object[] { this },
111 new int[] { rows.size() - 1 },
112 new Object[] { node });
113
114 if (maintainSortOrder && sortedColumn != -1) {
115 sortByColumn(sortedColumn, ascending, false);
116 }
117 }
118
119 public Object getChild(Object node, int index)
120 {
121 if (node == this) {
122 return rows.get(index);
123 }
124 else {
125 return ((TreeTableNode)node).getChildAt(index);
126 }
127 }
128
129 public int getChildCount(Object node)
130 {
131 if (node == this) {
132 return rows.size();
133 }
134 else if (node instanceof TreeTableNode) {
135 return ((TreeTableNode)node).getChildCount();
136 }
137 else {
138 return 0;
139 }
140 }
141
142 /***
143 * Returns the node that stores <code>data</code>.
144 *
145 * @return -1, if data could not be found
146 */
147 public int indexOfByData(Object data)
148 {
149 for (int i = 0; i < rows.size(); i++) {
150 TreeTableNode node = (TreeTableNode)rows.get(i);
151 if (node.getData() == data) {
152 return i;
153 }
154 }
155 return -1;
156 }
157
158 public Object getValueAt(Object node, int column)
159 {
160 return null;
161 }
162
163 public Iterator iterator()
164 {
165 return rows.iterator();
166 }
167
168 public void remove(TreeTableNode node)
169 {
170 int index = rows.indexOf(node);
171 if (index != -1) {
172 remove(index);
173 }
174 }
175
176 public void remove(int index)
177 {
178 Object node = rows.get(index);
179 rows.remove(index);
180 fireTreeNodesRemoved(this, new Object[] { this },
181 new int[] { index },
182 new Object[] { node });
183 }
184
185 public int getSortedColumn()
186 {
187 return sortedColumn;
188 }
189
190 public boolean isSortedAscending()
191 {
192 return ascending;
193 }
194
195 /***
196 * Sets the maintain sort order flag.
197 */
198 public void setMaintainSortOrder(boolean newValue)
199 {
200 maintainSortOrder = newValue;
201 }
202
203 /***
204 * Sorts the table by <code>column</code>.
205 */
206 public boolean sortByColumn(int column, boolean ascending, boolean revert)
207 {
208 if (column < 0 || column >= getColumnCount()) {
209 throw new IllegalArgumentException();
210 }
211
212 this.ascending = ascending;
213 sortedColumn = column;
214
215 ArrayList copy = null;
216 if (revert) {
217 copy = (ArrayList)rows.clone();
218 }
219
220
221
222 boolean hack
223 = (sortedColumn == 0 && getColumnAt(0).getKey().equals("icon"));
224 Comparator comparator = new TreeNodeComparator(hack ? 1 : sortedColumn);
225 Collections.sort(rows, comparator);
226
227 if (revert && rows.equals(copy)) {
228 this.ascending = !ascending;
229 Collections.reverse(rows);
230 }
231
232 for (Iterator i = rows.iterator(); i.hasNext();) {
233 ((TreeTableNode)i.next()).sort(comparator);
234 }
235
236 fireTreeStructureChanged(this, new Object[] { getRoot() }, null, null);
237 return this.ascending;
238 }
239
240 /***
241 * Compares {@link TreeTableNode} data objects.
242 */
243 private class TreeNodeComparator implements Comparator
244 {
245
246 private int column;
247
248 public TreeNodeComparator(int column)
249 {
250 this.column = column;
251 }
252
253 public int compare(Object node1, Object node2)
254 {
255 int order = compareByData(node1, node2);
256 return ascending ? order : -order;
257 }
258
259 public int compareByData(Object node1, Object node2)
260 {
261 Class type = getColumnClass(column);
262
263
264 Object o1 = getValueAt(node1, column);
265 Object o2 = getValueAt(node2, column);
266
267
268
269 if (o1 == null && o2 == null) {
270 return 0;
271 } else if (o1 == null) {
272 return -1;
273 } else if (o2 == null) {
274 return 1;
275 }
276
277 if (type.equals(String.class)) {
278 String s1 = (String)o1;
279 String s2 = (String)o2;
280 int result = s1.compareToIgnoreCase(s2);
281
282
283 if (s1.length() == 0 ^ s2.length() == 0) {
284 result = -result;
285 }
286
287 return result;
288 }
289 else if (o1 instanceof Comparable) {
290 return ((Comparable)o1).compareTo(o2);
291 }
292 else if (type == Boolean.class) {
293 boolean b1 = ((Boolean)o1).booleanValue();
294 boolean b2 = ((Boolean)o2).booleanValue();
295
296
297 if (b1 == b2) {
298 return 0;
299 } else if (b1) {
300 return 1;
301 } else {
302 return -1;
303 }
304 }
305 else {
306
307 return o1.toString().compareTo(o2.toString());
308 }
309 }
310 }
311
312 }