1 package wjhk.jupload2.gui.filepanel.treeview;
2
3 import java.lang.reflect.Array;
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import javax.swing.JTree;
8 import javax.swing.event.EventListenerList;
9 import javax.swing.event.TreeModelEvent;
10 import javax.swing.event.TreeModelListener;
11 import javax.swing.tree.TreeModel;
12 import javax.swing.tree.TreePath;
13
14 import wjhk.jupload2.policies.UploadPolicy;
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public abstract class MyAbstractTreeTableModel<T extends MyTreeNode> implements MyTreeTableModel<T> {
39
40 UploadPolicy uploadPolicy = null;
41
42
43 MyTreeTableCellRenderer tree = null;
44
45
46
47
48
49
50
51 protected T absoluteRoot = null;
52
53 protected T visibleRoot;
54
55 protected EventListenerList listenerList = new EventListenerList();
56
57 private static final int CHANGED = 0;
58
59 private static final int INSERTED = 1;
60
61 private static final int REMOVED = 2;
62
63 private static final int STRUCTURE_CHANGED = 3;
64
65 public MyAbstractTreeTableModel(UploadPolicy uploadPolicy, T root) {
66 this.uploadPolicy = uploadPolicy;
67 this.absoluteRoot = root;
68 this.visibleRoot = root;
69 this.absoluteRoot.setTreeModel(this);
70 this.visibleRoot.setTreeModel(this);
71 }
72
73
74
75
76 public MyTreeTableCellRenderer getTree() {
77 return tree;
78 }
79
80
81
82
83 public void setTree(MyTreeTableCellRenderer tree) {
84 this.tree = tree;
85 }
86
87 public T getAbsoluteRoot() {
88 return this.absoluteRoot;
89 }
90
91
92 public T getRoot() {
93 return visibleRoot;
94 }
95
96
97
98
99
100 public synchronized void setRoot(T root) {
101 this.uploadPolicy.displayInfo("Setting visible Root to file " + root.toString());
102 this.visibleRoot = root;
103 reload();
104 }
105
106
107 public synchronized void remove(T item) {
108 remove(item, true);
109 }
110
111
112 public synchronized void removeAndClean(T item) {
113 removeAndClean(item, true);
114 }
115
116
117
118
119
120
121
122
123 @SuppressWarnings("unchecked")
124 synchronized void remove(T item, boolean callReloadAfterRemoval) {
125 if (item == absoluteRoot) {
126 throw new IllegalArgumentException("The absoluteRoot may not be removed");
127 }
128 if (item == visibleRoot) {
129 setRoot((T) visibleRoot.getParent());
130 }
131
132 FolderNode parent = (FolderNode) item.getParent();
133 if (parent != null) {
134
135 parent.removeChild(item);
136
137 if (callReloadAfterRemoval) {
138 reload();
139 }
140 }
141 }
142
143
144
145
146
147
148
149
150 @SuppressWarnings("unchecked")
151 synchronized void removeAndClean(T item, boolean callReloadAfterRemoval) {
152 if (item == absoluteRoot) {
153 throw new IllegalArgumentException("The absoluteRoot may not be removed");
154 }
155 if (item == visibleRoot) {
156 setRoot((T) visibleRoot.getParent());
157 }
158
159 T parentNode = (T) item.getParent();
160
161
162 remove(item, false);
163
164
165 if (parentNode.getChildCount() == 0) {
166
167 removeAndClean(parentNode, false);
168 } else if (callReloadAfterRemoval) {
169 reload();
170 }
171 }
172
173
174 @SuppressWarnings("unchecked")
175 public TreePath getTreePath(T item) {
176 if (item == null) {
177
178 return null;
179 } else if (item == this.absoluteRoot) {
180 return new TreePath(this.absoluteRoot);
181 } else if (item.getParent() == null) {
182 throw new IllegalArgumentException("Root not found for node " + item);
183 } else {
184 return getTreePath((T) item.getParent()).pathByAddingChild(item);
185 }
186 }
187
188 public void addTreeModelListener(TreeModelListener l) {
189 listenerList.add(TreeModelListener.class, l);
190 }
191
192 public void removeTreeModelListener(TreeModelListener l) {
193 listenerList.remove(TreeModelListener.class, l);
194 }
195
196 private void fireTreeNode(int changeType, Object source, TreePath path, int[] childIndices, T[] children) {
197 Object[] listeners = listenerList.getListenerList();
198 TreeModelEvent e = new TreeModelEvent(source, path, childIndices, children);
199 for (int i = listeners.length - 2; i >= 0; i -= 2) {
200 if (listeners[i] == TreeModelListener.class) {
201 switch (changeType) {
202 case CHANGED:
203 ((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
204 break;
205 case INSERTED:
206 ((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
207 break;
208 case REMOVED:
209 ((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
210 break;
211 case STRUCTURE_CHANGED:
212 ((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
213 break;
214 default:
215 break;
216 }
217 }
218 }
219 }
220
221
222 synchronized public boolean cleanHierarchy() {
223 return cleanHierarchy(absoluteRoot, true);
224 }
225
226
227
228
229
230
231
232 synchronized public boolean cleanHierarchy(T node) {
233 return cleanHierarchy(node, true);
234 }
235
236
237
238
239
240
241
242
243
244 @SuppressWarnings("unchecked")
245 synchronized private boolean cleanHierarchy(T node, boolean callReloadAfterRemoval) {
246 boolean ret = false;
247 if (node != null) {
248 if (node.getChildren().size() > 0) {
249
250
251 List<T> children = new ArrayList<T>();
252 for (MyTreeNode child : node.getChildren()) {
253 children.add((T) child);
254 }
255
256 for (T child : children) {
257 if (cleanHierarchy(child, false)) {
258 ret = true;
259 }
260
261 if (!child.isLeaf() && child.getChildCount() == 0) {
262 node.removeChild(child);
263 ret = true;
264 }
265 }
266 }
267 }
268
269 if (ret && callReloadAfterRemoval) {
270 reload();
271 }
272 return ret;
273 }
274
275
276 public synchronized void reload() {
277 reload(visibleRoot);
278 }
279
280
281 @SuppressWarnings("unchecked")
282 public synchronized void reload(T node) {
283
284 int n = getChildCount(node);
285 int[] childIdx = new int[n];
286 T[] children = (T[]) (T[]) Array.newInstance(MyTreeNode.class, n);
287
288 for (int i = 0; i < n; i++) {
289 childIdx[i] = i;
290 children[i] = getChild(node, i);
291 }
292
293 fireTreeStructureChanged(this, getPathToRoot(node), childIdx, (T[]) children);
294 }
295
296
297
298
299
300
301
302
303
304 private TreePath getPathToRoot(MyTreeNode node) {
305 if (node == visibleRoot) {
306 return new TreePath(visibleRoot);
307 } else if (node == absoluteRoot) {
308 throw new IllegalArgumentException("The visibleRoot is not an ancestror of the given node");
309 } else {
310 MyTreeNode parent = (MyTreeNode) node.getParent();
311 if (parent == null) {
312 return null;
313 } else {
314 return getPathToRoot(parent).pathByAddingChild(node);
315 }
316 }
317 }
318
319
320 public void fireTreeNodesChanged(Object source, TreePath path, int[] childIndices, T[] children) {
321 fireTreeNode(CHANGED, source, path, childIndices, children);
322 }
323
324
325 public void fireTreeNodesInserted(Object source, TreePath path, int[] childIndices, T[] children) {
326 fireTreeNode(INSERTED, source, path, childIndices, children);
327 }
328
329
330 public void fireTreeNodesRemoved(Object source, TreePath path, int[] childIndices, T[] children) {
331 fireTreeNode(REMOVED, source, path, childIndices, children);
332 }
333
334
335 public void fireTreeStructureChanged(Object source, TreePath path, int[] childIndices, T[] children) {
336 fireTreeNode(STRUCTURE_CHANGED, source, path, childIndices, children);
337 }
338
339
340
341
342
343
344
345 @SuppressWarnings("unchecked")
346 public final T getChild(Object parent, int index) {
347 return (T) ((T) parent).getChild(index);
348 }
349
350
351 @SuppressWarnings("unchecked")
352 public final int getChildCount(Object child) {
353 return ((T) child).getChildCount();
354 }
355
356
357 @SuppressWarnings("unchecked")
358 public final boolean isLeaf(Object node) {
359 return ((T) node).isLeaf();
360 }
361
362
363
364
365
366
367 public final void valueForPathChanged(TreePath path, Object newValue) {
368 uploadPolicy.displayErr("The method MyAbstractTreeTableModel.valueForPathChanged should not be called");
369 }
370
371
372
373
374
375
376 @SuppressWarnings("unchecked")
377 public final int getIndexOfChild(Object parent, Object child) {
378 return ((T) parent).getChildren().indexOf((T) child);
379 }
380
381 public abstract Object getValueAt(T nodeForRow, int column);
382
383 }