source: trunk/gli/src/org/greenstone/gatherer/file/FileSystemModel.java@ 7281

Last change on this file since 7281 was 7208, checked in by mdewsnip, 20 years ago

Fixed refreshing problem (Linux only?) where the collection tree is not refreshed correctly when dragging over the first file into a collection.

  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1package org.greenstone.gatherer.file;
2
3import java.io.File;
4import java.util.*;
5import java.util.regex.*;
6import javax.swing.event.*;
7import javax.swing.tree.*;
8import org.greenstone.gatherer.Dictionary;
9import org.greenstone.gatherer.Gatherer;
10import org.greenstone.gatherer.file.FileFilter;
11import org.greenstone.gatherer.file.FileNode;
12import org.greenstone.gatherer.file.FileOpenActionListener;
13import org.greenstone.gatherer.gui.tree.DragTree;
14import org.greenstone.gatherer.util.SynchronizedTreeModelTools;
15
16public class FileSystemModel
17 extends DefaultTreeModel
18 implements TreeExpansionListener, TreeWillExpandListener {
19
20 private int counter = 0;
21 private DragTree tree;
22 private FileFilter current_filter;
23 private FileFilter[] filters;
24 /** The filters in place for any file system model. */
25 private FileFilter[] default_filters = { new FileFilter("\\..*", true), new FileFilter("metadata\\.xml", true) };
26
27 public FileSystemModel(FileNode root) {
28 super(root);
29 current_filter = null;
30 filters = null;
31 tree = null;
32 root.setModel(this);
33 root.map();
34 }
35
36 public int getChildCount(Object parent) {
37 return ((TreeNode)parent).getChildCount();
38 }
39
40 public FileFilter[] getFilters() {
41 if(filters == null) {
42 if(current_filter != null) {
43 filters = new FileFilter[default_filters.length + 1];
44 filters[default_filters.length] = current_filter;
45 }
46 else {
47 filters = new FileFilter[default_filters.length];
48 }
49 System.arraycopy(default_filters, 0, filters, 0, default_filters.length);
50 }
51 return filters;
52 }
53
54 /** Retrieve the node denoted by the given tree path. Note that this isn't equivelent to saying path.lastPathComponent, as the references within the path may be stale. */
55 public FileNode getNode(TreePath path) {
56 ///atherer.println("**** getNode(" + path + ") ****");
57 FileNode current = (FileNode)root;
58 // Special case for the root node. Check the first path component is the root node.
59 FileNode first_node = (FileNode)path.getPathComponent(0);
60 if(current.equals(first_node)) {
61 Gatherer.println("First path component matches root node.");
62 // For each path with this tree path
63 for(int i = 1; current != null && i < path.getPathCount(); i++) {
64 // Retrieve the stale path
65 Object stale_object = path.getPathComponent(i);
66 FileNode stale_node = null;
67 if(stale_object instanceof FileNode) {
68 stale_node = (FileNode) stale_object;
69 }
70 Gatherer.print("Searching for '" + stale_object + "': ");
71 // Locate the fresh node by searching current's children. Remember to ensure that current is mapped.
72 //current.unmap();
73 boolean found = false;
74
75 // First we search through the mapped children
76 for(int j = 0; !found && j < current.getChildCount(); j++) {
77 FileNode child_node = (FileNode) current.getChildAt(j);
78 Gatherer.print(child_node + " ");
79 if((stale_node != null && stale_node.equals(child_node)) || stale_object.toString().equals(child_node.toString())) {
80 found = true;
81 current = child_node;
82 Gatherer.println("Found!");
83 }
84 child_node = null;
85 }
86 // Failing that we search through all the children, including filtered files
87 for(int j = 0; !found && j < current.size(); j++) {
88 FileNode child_node = (FileNode) current.get(j);
89 Gatherer.print(child_node + " ");
90 if((stale_node != null && stale_node.equals(child_node)) || stale_object.toString().equals(child_node.toString())) {
91 found = true;
92 current = child_node;
93 Gatherer.println("Found!");
94 }
95 child_node = null;
96 }
97 // If no match is found, then set current to null and exit.
98 if(!found) {
99 current = null;
100 Gatherer.println("Not Found!");
101 }
102 else {
103 Gatherer.println("Returning node: " + new TreePath(current.getPath()));
104 }
105 // Repeat as necessary
106 }
107 }
108 return current;
109 }
110
111 public void insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) {
112 ///ystem.err.println("insertNodeInto(" + newChild + ", " + parent + ", " + index + ")");
113 super.insertNodeInto(newChild, parent, index);
114 }
115
116 public void mapDirectory(File directory, String title) {
117 FileNode node = new FileNode(directory, this, title, true);
118 SynchronizedTreeModelTools.insertNodeInto(this, (FileNode)root, node);
119 }
120
121
122 public void refresh(TreePath path)
123 {
124 // Can only refresh if the model is currently being displayed in a tree
125 if (tree == null) {
126 return;
127 }
128
129 // If no path is set, take the path to the root node (ie. update the whole tree)
130 if (path == null) {
131 // System.err.println("\nFileSystemModel.refresh(entire tree).");
132 path = new TreePath(((FileNode) root).getPath());
133
134 // Make sure the root node is expanded
135 tree.expandPath(path);
136 }
137 // else {
138 // System.err.println("\nFileSystemModel.refresh(" + path + ").");
139 // }
140
141 // Record all the expanded paths under this node
142 Enumeration old_expanded_paths_enumeration = tree.getExpandedDescendants(path);
143 if (old_expanded_paths_enumeration == null) {
144 return;
145 }
146
147 // Map and unmap the node to refresh its contents
148 FileNode node = (FileNode) path.getLastPathComponent();
149 node.unmap();
150 node.map();
151
152 // Fire the appropriate event
153 nodeStructureChanged(node);
154
155 // Sort the old expanded paths by length, smallest first
156 ArrayList old_expanded_paths_list = Collections.list(old_expanded_paths_enumeration);
157 Collections.sort(old_expanded_paths_list, new TreePathComparator());
158
159 // Restore each of the expanded paths
160 for (int i = 0; i < old_expanded_paths_list.size(); i++) {
161 TreePath old_expanded_path = (TreePath) old_expanded_paths_list.get(i);
162 // System.err.println("Expanded path: " + old_expanded_path);
163
164 // Build up the new path in the tree
165 TreePath current_path = new TreePath(path.getPath());
166 FileNode current_node = node;
167
168 // Traverse the tree to find the node to expand (or find it no longer exists)
169 while (!current_path.toString().equals(old_expanded_path.toString())) {
170 // System.err.println("Current path: " + current_path);
171
172 FileNode old_expanded_node =
173 (FileNode) old_expanded_path.getPathComponent(current_path.getPathCount());
174 // System.err.println("Looking for: " + old_expanded_node);
175
176 // Find the child node that matches the next element in the path
177 boolean found = false;
178 for (int j = 0; j < current_node.getChildCount(); j++) {
179 FileNode child_node = (FileNode) current_node.getChildAt(j);
180 // System.err.println("Child node: " + child_node);
181 if (child_node.equals(old_expanded_node)) {
182 // System.err.println("Found!");
183 current_path = current_path.pathByAddingChild(child_node);
184 current_node = child_node;
185 found = true;
186 break;
187 }
188 }
189
190 // The node was not found, so we cannot expand this path
191 if (!found) {
192 // System.err.println("Not found...");
193 break;
194 }
195 }
196
197 // If we have built up the correct path, expand it
198 if (current_path.toString().equals(old_expanded_path.toString())) {
199 tree.expandPath(current_path);
200 }
201 }
202 }
203
204
205 private class TreePathComparator
206 implements Comparator {
207
208 public int compare(Object o1, Object o2)
209 {
210 return (((TreePath) o1).getPathCount() - ((TreePath) o2).getPathCount());
211 }
212 }
213
214
215 // /** Used to refresh the contents of the FileNode indicated by the tree path. While the refresh itself is a piece of the proverbial, the restoring of expanded folders afterwards is a nightmare, mainly because all of the tree paths are no longer valid (remember that refresh involves throwing away the node currents children and remapping them).
216 // * @param path The TreePath to the node to be refreshed.
217 // */
218// public void oldRefresh(TreePath path) {
219// // If no path is set, take the path to the root node (ie update the whole tree)
220// if(path == null) {
221// System.err.println("Refresh entire tree.");
222// path = new TreePath(((FileNode)root).getPath());
223// }
224// else {
225// System.err.println("FileSystemModel.refresh: " + path.getLastPathComponent());
226// }
227// // Only a valid action if this model is currently being displayed in a tree.
228// if(tree != null) {
229// System.err.println("Refreshing tree " + tree);
230// // Retrieve the error node.
231// FileNode node = (FileNode) path.getLastPathComponent();
232// // If this error node is a dummy node (ie has no associated file) we can't unmap it, so we iterate through its children refreshing each in turn. The exception being Greenstone Collections, as it is a dummy node but we can map/unmap it
233// if(node.getFile() == null && !node.toString().equals(Dictionary.get("Tree.World"))) {
234// for(int i = 0; i < node.getChildCount(); i++) {
235// FileNode child = (FileNode) node.getChildAt(i);
236// refresh(new TreePath(child.getPath()));
237// child = null;
238// }
239// }
240// // Otherwise we refresh this node.
241// else {
242// // Record all of the expanded paths under this node. How come getExpandedDescendants returns more results each time.
243// Enumeration old_tree_paths = tree.getExpandedDescendants(path);
244// // Refresh the tree structure.
245// node.unmap();
246// node.map();
247// // Fire the appropriate event.
248// nodeStructureChanged(node);
249// // Then (painfully) restore the expanded paths. Note that the paths stored in the enumeration no longer exist, so I have to restore by node matching.
250// //counter = 0;
251// ///ystem.err.println("After:");
252// while(old_tree_paths != null && old_tree_paths.hasMoreElements()) {
253// //counter++;
254// FileNode current_node = node;
255// TreePath old_tree_path = (TreePath) old_tree_paths.nextElement();
256// ///ystem.err.println(counter + ". " + old_tree_path);
257// TreePath new_tree_path = new TreePath(path.getPath()); // Why isn't there a treepath copy constructor!
258// boolean not_found = false;
259// while(!not_found && old_tree_path.getPathCount() > new_tree_path.getPathCount()) {
260// // Retrieve the new node in the old tree path
261// FileNode old_path_node = (FileNode) old_tree_path.getPathComponent(new_tree_path.getPathCount());
262// // Ensure the current node is mapped
263// current_node.map();
264// // Now attempt to match it to a child of the new paths last node.
265// boolean found = false;
266// for(int i = 0; !found && i < current_node.getChildCount(); i++) {
267// FileNode target = (FileNode) current_node.getChildAt(i);
268// ///ystem.err.println("Comparing " + old_path_node.toString() + " with " + target);
269// if(target.toString().equals(old_path_node.toString())) {
270// current_node = target;
271// found = true;
272// }
273// target = null;
274// }
275// old_path_node = null;
276// // If we found a match, we add that to the new Tree Path and continue.
277// if(found) {
278// ///ystem.err.println("Found a match!");
279// new_tree_path = new_tree_path.pathByAddingChild(current_node);
280// }
281// // We also have to record if we were unable to find a match in the current nodes children.
282// else {
283// ///ystem.err.println("Node not found.");
284// not_found = true;
285// }
286// }
287// old_tree_path = null;
288// // If we've got this far, and haven't hit a not found, then we can assume we have the appropriate path, and ask the program to expand the new tree path
289// if(!not_found) {
290// tree.expandPath(new_tree_path);
291// ///ystem.err.println(" -> Expanded " + new_tree_path);
292// }
293// else {
294// ///ystem.err.println(" -> Cannot Expand " + new_tree_path);
295// }
296// new_tree_path = null;
297// current_node = null;
298// }
299// node = null;
300// }
301// }
302// else {
303// ///ystem.err.println("No Tree!");
304// }
305// }
306
307 public void setFilter(String pattern) {
308 if(pattern != null) {
309 current_filter = new FileFilter(pattern, false);
310 }
311 else {
312 current_filter = null;
313 }
314 filters = null;
315 }
316
317 /* private void setPermanentFilter(String pattern) {
318 if(pattern != null) {
319 FileFilter new_filter = new FileFilter(pattern, false);
320 FileFilter temp[] = new FileFilter[default_filters.length + 1];
321 System.arraycopy(default_filters, 0, temp, 0, default_filters.length);
322 temp[default_filters.length] = new_filter;
323 default_filters = temp;
324 temp = null;
325 }
326 filters = null;
327 } */
328
329 public void setTree(DragTree tree) {
330 this.tree = tree;
331 }
332
333 public String toString() {
334 if(tree != null) {
335 return tree.toString();
336 }
337 return "FileSystemModel";
338 }
339
340 /** Called whenever an item in the tree has been collapsed. */
341 public void treeCollapsed(TreeExpansionEvent event) {
342 // Deallocate the affected nodes children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
343 TreePath path = event.getPath();
344 FileNode node = (FileNode) path.getLastPathComponent();
345 ///ystem.err.println("Unmap: " + node);
346 node.unmap();
347 // Fire the appropriate event.
348 nodeStructureChanged(node);
349 }
350
351 /** Called whenever an item in the tree has been expanded. */
352 public void treeExpanded(TreeExpansionEvent event) {
353 }
354
355 /** Invoked whenever a node in the tree is about to be collapsed. */
356 public void treeWillCollapse(TreeExpansionEvent event)
357 throws ExpandVetoException {
358 // Veto the event if the user is attempting to collapse the root node (regardless of whether it is visible).
359 TreePath path = event.getPath();
360 if(path.getPathCount() == 1) {
361 throw new ExpandVetoException(event, "Cannot collapse root node!");
362 }
363 }
364
365 /** Invoked whenever a node in the tree is about to be expanded. */
366 public void treeWillExpand(TreeExpansionEvent event)
367 throws ExpandVetoException {
368 // Set the wait cursor.
369 Gatherer.g_man.wait(true);
370 // Allocate the children. Don't need to do this in a swing worker, as the nodes children are currently not visable.
371 TreePath path = event.getPath();
372 FileNode node = (FileNode) path.getLastPathComponent();
373 ///ystem.err.println("Mapping: " + node);
374 node.map();
375 ///ystem.err.println(" -> node has " + node.getChildCount() + " children");
376 nodeStructureChanged(node);
377 // Restore the cursor.
378 Gatherer.g_man.wait(false);
379 }
380}
Note: See TracBrowser for help on using the repository browser.