source: trunk/gli/src/org/greenstone/gatherer/file/FileNode.java@ 6035

Last change on this file since 6035 was 5884, checked in by jmt12, 21 years ago

FileNodes now know whether they are in the currently open collection

  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1package org.greenstone.gatherer.file;
2
3import java.io.*;
4import java.util.ArrayList;
5import java.util.Enumeration;
6import javax.swing.*;
7import javax.swing.filechooser.*;
8import javax.swing.tree.*;
9import org.greenstone.gatherer.Dictionary;
10import org.greenstone.gatherer.Gatherer;
11import org.greenstone.gatherer.collection.Collection;
12import org.greenstone.gatherer.file.FileFilter;
13import org.greenstone.gatherer.file.FileSystemModel;
14import org.greenstone.gatherer.util.ArrayTools;
15import org.greenstone.gatherer.util.StaticStrings;
16import org.greenstone.gatherer.util.Utility;
17
18public class FileNode
19 implements MutableTreeNode {
20
21 static final private int FALSE = 0;
22 static final private int TRUE = 1;
23 static final private int UNKNOWN = 2;
24
25 private ArrayList children;
26 private boolean children_readonly = true;
27 private boolean current_collection = false;
28 private boolean readonly = true;
29 private File file;
30 private FileSystemModel model;
31 private int allows_children = UNKNOWN;
32 private MutableTreeNode parent;
33 private String title;
34
35 public FileNode(File file) {
36 ///ystem.err.println("New FileNode(" + file.getAbsolutePath() + ")");
37 this.file = file;
38 }
39
40 public FileNode(File file, boolean readonly) {
41 this(file);
42 this.children_readonly = readonly;
43 this.readonly = readonly;
44 }
45
46 public FileNode(File file, FileSystemModel model) {
47 this(file);
48 this.model = model;
49 }
50
51 public FileNode(File file, FileSystemModel model, boolean readonly) {
52 this(file, readonly);
53 this.model = model;
54 }
55
56 public FileNode(File file, FileSystemModel model, String title) {
57 this(file, model);
58 this.title = title;
59 }
60
61 public FileNode(File file, String title) {
62 this(file);
63 this.title = title;
64 }
65
66 public FileNode(File file, String title, boolean readonly) {
67 this(file, readonly);
68 this.title = title;
69 }
70
71 public FileNode(File file, FileSystemModel model, String title, boolean readonly) {
72 this(file, model, readonly);
73 this.title = title;
74 }
75
76 /** The special 'dummy' root node, that is not based on a particular file, but instead holds several special directory mappings. */
77 public FileNode(String title) {
78 this.children = new ArrayList();
79 this.title = title;
80 }
81
82 /** Returns the children of the receiver as an Enumeration. */
83 public Enumeration children() {
84 return new FileEnumeration();
85 }
86
87 /** Compare two filenodes for equality. */
88 public boolean equals(FileNode node) {
89 boolean result = false;
90 if(node != null) {
91 if(file != null) {
92 result = (file.equals(node.getFile()));
93 }
94 else {
95 result = toString().equals(node.toString());
96 }
97 }
98 return result;
99 }
100
101 /** Returns true if the receiver allows children. We have to cache the result of this call to prevent unceasing missing disk messages being thrown if the removable media was, um, removed after directory mapped. */
102 public boolean getAllowsChildren() {
103 if(readonly) {
104 if(allows_children == UNKNOWN) {
105 // If the file is non-null but doesn't exist (as is the case for removable media), return true anyway.
106 if(file != null) {
107 if(isFileSystemRoot()) {
108 allows_children = TRUE;
109 }
110 else if(file.exists() && file.isDirectory()) {
111 allows_children = TRUE;
112 }
113 // Any mapped directories always allow children.
114 else if(getParent() != null && getParent().getParent() == null) {
115 allows_children = TRUE;
116 }
117 else {
118 allows_children = FALSE;
119 }
120 }
121 // Allows children is always true for dummy nodes.
122 else {
123 allows_children = TRUE;
124 }
125 }
126 return (allows_children == TRUE);
127 }
128 else {
129 return (file == null || file.isDirectory());
130 }
131 }
132
133 /** Returns the child TreeNode at index childIndex. */
134 public TreeNode getChildAt(int index) {
135 TreeNode result = null;
136 map();
137 if(0 <= index && index < children.size()) {
138 result = (TreeNode) children.get(index);
139 }
140 else {
141 result = new DefaultMutableTreeNode("Error");
142 }
143 return result;
144 }
145
146 /** Returns the number of children TreeNodes the receiver contains. */
147 public int getChildCount() {
148 int size = 0;
149 // We don't automatically map if this is a system root, or we risk the 50,000 Disk not found error messages of death.
150 if(isFileSystemRoot()) {
151 size = 1; // Size is always non-zero for a system root
152 }
153 else {
154 map();
155 }
156 ///ystem.err.println(this + ".getChildCount() = " + children.size());
157 if(children != null) {
158 size = children.size();
159 }
160 return size;
161 }
162
163 public File getFile() {
164 return file;
165 }
166
167 /** Retrieve the icon the system thinks should be assigned to this node. If this node has no file then the icon will be null. */
168 public ImageIcon getIcon() {
169 return null;
170 }
171
172 /** Returns the index of node in the receivers children. */
173 public int getIndex(TreeNode node) {
174 map();
175 return children.indexOf(node);
176 }
177
178 /** Returns the parent TreeNode of the receiver. */
179 public TreeNode getParent() {
180 return parent;
181 }
182
183 /** Retrieves the tree path from the root node to this node. */
184 public TreeNode[] getPath() {
185 int count = 0;
186 TreeNode current = this;
187 while(current != null) {
188 count++;
189 current = current.getParent();
190 }
191 TreeNode[] path = new TreeNode[count];
192 current = this;
193 while(current != null) {
194 path[count - 1] = current;
195 count--;
196 current = current.getParent();
197 }
198 return path;
199 }
200
201 public void insert(MutableTreeNode child) {
202 insert(child, children.size());
203 }
204
205 /** Adds child to the receiver at index. */
206 public void insert(MutableTreeNode child, int index) {
207 ///ystem.err.println("Insert " + child + " in " + this + " at index " + index + " [Model: " + model + "]");
208 //map();
209 try {
210 children.add(index, child);
211 // Set parent and model.
212 FileNode new_child = (FileNode) child;
213 new_child.setModel(model);
214 new_child.setParent(this);
215 new_child.setReadOnly(readonly);
216 }
217 catch(Exception error) {
218 error.printStackTrace();
219 }
220 }
221
222 /** Is this file node within the currently open collection? */
223 public boolean isInCurrentCollection() {
224 if(current_collection) {
225 return true;
226 }
227 else {
228 FileNode parent = (FileNode) getParent();
229 if(parent != null) {
230 return parent.isInCurrentCollection();
231 }
232 }
233 return false;
234 }
235
236 /** Returns true if the receiver is a leaf. */
237 public boolean isLeaf() {
238 return !getAllowsChildren();
239 }
240
241 public boolean isReadOnly() {
242 return readonly;
243 }
244
245 public boolean isFileSystemRoot() {
246 boolean result = false;
247 if(file != null) {
248 result = FileSystemView.getFileSystemView().isFileSystemRoot(file);
249 }
250 return result;
251 }
252
253 public void map() {
254 if(children == null) {
255 children = new ArrayList();
256 // Super Special Case: if the name of this node is the Tree.World string, then we actually map the collections installed in greenstone. The file in this case will actually by the collect directory of greenstone.
257 if(file == null && title.equals(Dictionary.get("Tree.World"))) {
258 ///atherer.println("Map the 'Greenstone Collections' node.");
259 // For each of the children directories, which are collections...
260 File start = new File(Utility.getCollectionDir(Gatherer.config.gsdl_path));
261 File cols[] = start.listFiles();
262 ArrayTools.sort(cols);
263 // We add their import directories, except for the model collection
264 for(int i = 0; cols != null && i < cols.length; i++) {
265 if (!cols[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
266 File dirs[] = cols[i].listFiles();
267 ArrayTools.sort(dirs);
268 File import_dir = new File(cols[i], StaticStrings.IMPORT_FOLDER);
269 if(import_dir.exists()) {
270 FileNode collection_root = new FileNode(import_dir, cols[i].getName(), true);
271 collection_root.setParent(this);
272 collection_root.setModel(model);
273 // One last piece of magic so we can determine the current collection
274 Collection collection = Gatherer.c_man.getCollection();
275 if(collection != null) {
276 collection_root.setCurrentCollection(cols[i].getName().equals(collection.getName()));
277 }
278 children.add(collection_root);
279 collection_root = null;
280 }
281 import_dir = null;
282 dirs = null;
283 }
284 }
285 cols = null;
286 model.nodeStructureChanged(this);
287 }
288 // General case: Only map if there are no children.
289 else if(file != null && getAllowsChildren()) {
290 File[] files = file.listFiles();
291 if(files != null && files.length > 0) {
292 ArrayTools tools = new ArrayTools();
293 // Apply the filters set in the model.
294 //if(model != null) {
295 FileFilter[] filters = model.getFilters();
296 for(int i = 0; filters != null && i < filters.length; i++) {
297 files = tools.filter(files, filters[i].filter, filters[i].exclude);
298 }
299 //}
300
301 // Finally remove any files whose canonical path do not match their absolute one (ie symbolic links). We only do this test under linux, because under windows there is no such thing as a symbolic link, and instead we suffer difficulties with the 16bit truncated file paths not being the same as the canonical ones (i.e Program Files => Progra~1).
302 /* This test to eliminate infinite recursions causes more problems than it solves
303 if(!Utility.isWindows()) {
304 for(int k = files.length; k != 0; k--) {
305 try {
306 if(!files[k-1].getAbsolutePath().equals(files[k-1].getCanonicalPath())) {
307 ///ystem.err.println("For file: " + files[k-1].getName());
308 ///ystem.err.println("Absolute Path: " + files[k-1].getAbsolutePath());
309 ///ystem.err.println("Canonical Path: " + files[k-1].getCanonicalPath());
310 files = ArrayTools.remove(files, (k-1));
311 }
312 }
313 catch (IOException exception) {
314 Gatherer.printStackTrace(exception);
315 }
316 }
317 }
318 */
319 // Sort the remaining files.
320 tools.sort(files, true);
321 // Now add them to children.
322 for(int i = 0; i < files.length; i++) {
323 FileNode child = new FileNode(files[i], model, children_readonly);
324 child.setParent(this);
325 children.add(child);
326 }
327 }
328 model.nodeStructureChanged(this);
329 }
330 }
331 }
332
333 /** Removes the child at index from the receiver. */
334 public void remove(int index) {
335 if(0 <= index && index < children.size()) {
336 children.remove(index);
337 }
338 }
339
340 /** Removes node from the receiver. */
341 public void remove(MutableTreeNode node){
342 int index = getIndex(node);
343 if(index != -1) {
344 children.remove(index);
345 }
346 }
347
348 /** Removes the receiver from its parent. */
349 public void removeFromParent() {
350 parent.remove(this);
351 parent = null;
352 }
353
354 public void setCurrentCollection(boolean current_collection) {
355 this.current_collection = current_collection;
356 }
357
358 /* private void setChildrenReadOnly(boolean children_readonly) {
359 this.children_readonly = children_readonly;
360 } */
361
362 public void setFile(File file) {
363 this.file = file;
364 }
365
366 public void setModel(FileSystemModel model) {
367 this.model = model;
368 }
369
370 public void setParent(MutableTreeNode parent) {
371 this.parent = parent;
372 }
373
374 public void setReadOnly(boolean readonly) {
375 this.readonly = readonly;
376 }
377
378 /** Resets the user object of the receiver to object. */
379 public void setUserObject(Object object) {
380 try {
381 file = (File) object;
382 title = null;
383 }
384 catch(Exception error) {
385 error.printStackTrace();
386 }
387 }
388
389 public String toString() {
390 if(title == null) {
391 if(isFileSystemRoot()) {
392 title = file.getAbsolutePath();
393 }
394 else {
395 title = file.getName();
396 }
397 }
398 return title;
399 }
400
401 /** Unmap this nodes children. */
402 public void unmap() {
403 // You cannot unmap nodes that have no file basis.
404 if(file != null || title.equals(Dictionary.get("Tree.World"))) {
405 ///atherer.println("Unmap: " + this);
406 children = null;
407 }
408 else {
409 ///ystem.err.println("No file for " + this + " - can't unmap.");
410 }
411 }
412
413 private class FileEnumeration
414 implements Enumeration {
415 private int index = 0;
416 /** Tests if this enumeration contains more elements. */
417 public boolean hasMoreElements() {
418 return (index < children.size());
419 }
420 /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
421 public Object nextElement() {
422 Object result = null;
423 if(index < children.size()) {
424 result = children.get(index);
425 index++;
426 }
427 return result;
428 }
429 }
430}
Note: See TracBrowser for help on using the repository browser.