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

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

Replaced all Gatherer.print* with DebugStream.print*.

  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 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.Configuration;
10import org.greenstone.gatherer.DebugStream;
11import org.greenstone.gatherer.Dictionary;
12import org.greenstone.gatherer.Gatherer;
13import org.greenstone.gatherer.collection.BasicCollectionConfiguration;
14import org.greenstone.gatherer.collection.Collection;
15import org.greenstone.gatherer.file.FileFilter;
16import org.greenstone.gatherer.file.FileSystemModel;
17import org.greenstone.gatherer.util.ArrayTools;
18import org.greenstone.gatherer.util.StaticStrings;
19import org.greenstone.gatherer.util.Utility;
20
21public class FileNode
22 implements MutableTreeNode {
23
24 static final private int FALSE = 0;
25 static final private int TRUE = 1;
26 static final private int UNKNOWN = 2;
27
28 private ArrayList children;
29 private ArrayList raw_children;
30 private boolean children_readonly = true;
31 private boolean current_collection = false;
32 private boolean readonly = true;
33 private File file;
34 private FileSystemModel model;
35 private int allows_children = UNKNOWN;
36 private MutableTreeNode parent;
37 private String title;
38 private boolean gs3_site = false;
39
40 public FileNode(File file) {
41 // System.err.println("New FileNode(" + file.getAbsolutePath() + ")");
42 this.file = file;
43 }
44
45 public FileNode(File file, boolean readonly) {
46 this(file);
47 this.children_readonly = readonly;
48 this.readonly = readonly;
49 }
50
51 public FileNode(File file, FileSystemModel model) {
52 this(file);
53 this.model = model;
54 }
55
56 public FileNode(File file, FileSystemModel model, boolean readonly) {
57 this(file, readonly);
58 this.model = model;
59 }
60
61 public FileNode(File file, FileSystemModel model, String title) {
62 this(file, model);
63 this.title = title;
64 }
65
66 public FileNode(File file, String title) {
67 this(file);
68 this.title = title;
69 }
70
71 public FileNode(File file, String title, boolean readonly) {
72 this(file, readonly);
73 this.title = title;
74 }
75
76 public FileNode(File file, FileSystemModel model, String title, boolean readonly) {
77 this(file, model, readonly);
78 this.title = title;
79 }
80
81 /** The special 'dummy' root node, that is not based on a particular file, but instead holds several special directory mappings. */
82 public FileNode(String title) {
83 this.children = new ArrayList();
84 this.title = title;
85 }
86
87 /** Returns the children of the receiver as an Enumeration. */
88 public Enumeration children() {
89 return new FileEnumeration();
90 }
91
92 /** Compare two filenodes for equality. */
93 public boolean equals(FileNode node) {
94 boolean result = false;
95 if(node != null) {
96 if(file != null) {
97 result = (file.equals(node.getFile()));
98 }
99 else {
100 result = toString().equals(node.toString());
101 }
102 }
103 return result;
104 }
105
106 /** Retrieve the filenode at the given index, regardless of filters set.
107 * @param index int
108 */
109 public FileNode get(int index) {
110 if(0 <= index && index < size() && file != null) {
111 return (FileNode) raw_children.get(index);
112 }
113 return null;
114 }
115
116 /** 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. */
117 public boolean getAllowsChildren() {
118 if(readonly) {
119 if(allows_children == UNKNOWN) {
120 // If the file is non-null but doesn't exist (as is the case for removable media), return true anyway.
121 if(file != null) {
122 if(isFileSystemRoot()) {
123 allows_children = TRUE;
124 }
125 else if(file.exists() && file.isDirectory()) {
126 allows_children = TRUE;
127 }
128 // Any mapped directories always allow children.
129 else if(getParent() != null && getParent().getParent() == null) {
130 allows_children = TRUE;
131 }
132 else {
133 allows_children = FALSE;
134 }
135 }
136 // Allows children is always true for dummy nodes.
137 else {
138 allows_children = TRUE;
139 }
140 }
141 return (allows_children == TRUE);
142 }
143 else {
144 return (file == null || file.isDirectory());
145 }
146 }
147
148 /** Returns the child TreeNode at index childIndex. */
149 public TreeNode getChildAt(int index) {
150 TreeNode result = null;
151 map();
152 if(0 <= index && index < children.size()) {
153 result = (TreeNode) children.get(index);
154 }
155 else {
156 result = new DefaultMutableTreeNode("Error");
157 }
158 ///ystem.err.println(this + ".getChildAt(" + index + ") = " + result);
159 return result;
160 }
161
162 /** Returns the number of children TreeNodes the receiver contains. */
163 public int getChildCount() {
164 int size = 0;
165 // We don't automatically map if this is a system root, or we risk the 50,000 Disk not found error messages of death.
166 if(isFileSystemRoot()) {
167 size = 1; // Size is always non-zero for a system root
168 }
169 else {
170 map();
171 }
172 if(children != null) {
173 size = children.size();
174 }
175 ///ystem.err.println(this + ".getChildCount() = " + size);
176 return size;
177 }
178
179 public File getFile() {
180 return file;
181 }
182
183 /** Returns the index of node in the receivers children. */
184 public int getIndex(TreeNode node) {
185 map();
186 return children.indexOf(node);
187 }
188
189 /** Returns the parent TreeNode of the receiver. */
190 public TreeNode getParent() {
191 return parent;
192 }
193
194 /** Retrieves the tree path from the root node to this node. */
195 public TreeNode[] getPath() {
196 int count = 0;
197 TreeNode current = this;
198 while(current != null) {
199 count++;
200 current = current.getParent();
201 }
202 TreeNode[] path = new TreeNode[count];
203 current = this;
204 while(current != null) {
205 path[count - 1] = current;
206 count--;
207 current = current.getParent();
208 }
209 return path;
210 }
211
212 public void insert(MutableTreeNode child) {
213 insert(child, children.size());
214 }
215
216 /** Adds child to the receiver at index. */
217 public void insert(MutableTreeNode child, int index) {
218 DebugStream.println("Insert " + child + " in " + this + " at index " + index + " [Model: " + model + "]");
219 if (child == null) {
220 return;
221 }
222 try {
223 children.add(index, child);
224 // Set parent and model.
225 FileNode new_child = (FileNode) child;
226 new_child.setModel(model);
227 new_child.setParent(this);
228 new_child.setReadOnly(readonly);
229 }
230 catch(Exception error) {
231 error.printStackTrace();
232 }
233 }
234
235 /** Is this file node within the currently open collection? */
236 public boolean isInCurrentCollection() {
237 if(current_collection) {
238 return true;
239 }
240 else {
241 FileNode parent = (FileNode) getParent();
242 if(parent != null) {
243 return parent.isInCurrentCollection();
244 }
245 }
246 return false;
247 }
248
249 /** Returns true if the receiver is a leaf. */
250 public boolean isLeaf() {
251 return !getAllowsChildren();
252 }
253
254 public boolean isReadOnly() {
255 return readonly;
256 }
257
258 public boolean isFileSystemRoot() {
259 boolean result = false;
260 if(file != null) {
261 result = FileSystemView.getFileSystemView().isFileSystemRoot(file);
262 }
263 return result;
264 }
265
266 public void map() {
267 if(children != null) {
268 return;
269 }
270 children = new ArrayList();
271 // 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 be the collect directory of greenstone.
272 if(file == null) { // a special mapping folder
273 if (title.equals(Dictionary.get("Tree.World")) && Gatherer.GS3) {
274 // the Greenstone collections folder for GS3 - this contains a
275 // folder for each site
276 File start = new File(Utility.getSitesDir(Configuration.gsdl3_path));
277 File sites[] = start.listFiles();
278 ArrayTools.sort(sites);
279 for (int i=0; sites != null && i < sites.length; i++) {
280 //File site = sites[i];
281 File collect_dir = new File(sites[i], Utility.COL_DIR);
282 if(!collect_dir.exists()) {
283 continue;
284 }
285
286 FileNode child = new FileNode(sites[i].getName());
287 child.setGS3Site(true);
288 child.unmap();
289 child.setParent(this);
290 child.setModel(model);
291 child.map();
292 children.add(child);
293 }
294
295 } else if (title.equals(Dictionary.get("Tree.World")) || gs3_site) {
296 // the collect dir for gs2 or a site dir for gs3
297 ///atherer.println("Map the 'Greenstone Collections' node.");
298 // For each of the children directories, which are collections...
299 File start;
300 if (gs3_site) {
301 start = new File(Utility.getCollectDir(Configuration.gsdl3_path, title));
302 } else {
303 start = new File(Utility.getCollectDir(Configuration.gsdl_path));
304 }
305 File cols[] = start.listFiles();
306 ArrayTools.sort(cols);
307 // We add their import directories, except for the model collection
308 for(int i = 0; cols != null && i < cols.length; i++) {
309 if (!cols[i].getName().equals(StaticStrings.MODEL_COLLECTION_NAME)) {
310 //File dirs[] = cols[i].listFiles();
311 //ArrayTools.sort(dirs);
312 File import_dir = new File(cols[i], StaticStrings.IMPORT_FOLDER);
313 if(!import_dir.exists()) {
314 continue;
315 }
316 // we don't care if there is no config file
317 BasicCollectionConfiguration collect_cfg = new BasicCollectionConfiguration(new File(cols[i], Utility.CONFIG_FILE));
318 FileNode collection_root = new FileNode(import_dir, collect_cfg.toString(), true);
319 collection_root.setParent(this);
320 collection_root.setModel(model);
321 // One last piece of magic so we can determine the current collection
322 Collection collection = Gatherer.c_man.getCollection();
323 if(collection != null) {
324 collection_root.setCurrentCollection(cols[i].getName().equals(collection.getName()));
325 }
326 children.add(collection_root);
327 collection_root = null;
328 import_dir = null;
329 //dirs = null;
330 }
331 } // for each coll
332 cols = null;
333 model.nodeStructureChanged(this);
334 }
335 } // if file == null
336 // General case: Only map if there are no children.
337 else { // file !=null
338 if(getAllowsChildren()) {
339 File[] files = file.listFiles();
340 if(files != null && files.length > 0) {
341 // Sort the remaining files.
342 DebugStream.println("Number of files to sort: " + files.length);
343 ArrayTools.sort(files);
344 DebugStream.println("Files sorted.");
345 // Now add them to children.
346 raw_children = new ArrayList();
347 for(int i = 0; i < files.length; i++) {
348 FileNode child = new FileNode(files[i], model, children_readonly);
349 child.setParent(this);
350 raw_children.add(child);
351 }
352
353 // Apply the filters set in the model.
354 //if(model != null) {
355 FileFilter[] filters = model.getFilters();
356 for(int i = 0; filters != null && i < filters.length; i++) {
357 files = ArrayTools.filter(files, filters[i].filter, filters[i].exclude);
358 }
359 //}
360
361 // Now add them to children.
362 for(int i = 0; i < files.length; i++) {
363 FileNode child = new FileNode(files[i], model, children_readonly);
364 int index = -1;
365 if((index = raw_children.indexOf(child)) != -1) {
366 children.add(raw_children.get(index));
367 }
368 else {
369 child.setParent(this);
370 children.add(child);
371 }
372 }
373 }
374 model.nodeStructureChanged(this);
375 }
376 }
377
378 }
379
380 /** Removes the child at index from the receiver. */
381 public void remove(int index) {
382 if(0 <= index && index < children.size()) {
383 children.remove(index);
384 }
385 }
386
387 /** Removes node from the receiver. */
388 public void remove(MutableTreeNode node){
389 int index = getIndex(node);
390 if(index != -1) {
391 children.remove(index);
392 }
393 }
394
395 /** Removes the receiver from its parent. */
396 public void removeFromParent() {
397 parent.remove(this);
398 parent = null;
399 }
400
401 public void setCurrentCollection(boolean current_collection) {
402 this.current_collection = current_collection;
403 }
404
405 public void setFile(File file) {
406 this.file = file;
407 }
408
409 public void setGS3Site(boolean is_site) {
410 this.gs3_site = is_site;
411 }
412
413 public void setModel(FileSystemModel model) {
414 this.model = model;
415 }
416
417 public void setParent(MutableTreeNode parent) {
418 this.parent = parent;
419 }
420
421 public void setReadOnly(boolean readonly) {
422 this.readonly = readonly;
423 }
424
425 /** Resets the user object of the receiver to object. */
426 public void setUserObject(Object object) {
427 try {
428 file = (File) object;
429 title = null;
430 }
431 catch(Exception error) {
432 error.printStackTrace();
433 }
434 }
435
436 /** Retrieve the total number of child files for the file this node represents, irrespective of filters set
437 * @return int
438 */
439 public int size() {
440 if(raw_children != null) {
441 return raw_children.size();
442 }
443 return 0;
444 }
445
446 public String toString() {
447 if(title == null) {
448 if(isFileSystemRoot()) {
449 title = file.getAbsolutePath();
450 }
451 else {
452 title = file.getName();
453 }
454 }
455 return title;
456 }
457
458 /** Unmap this nodes children. */
459 public void unmap() {
460 // You cannot unmap nodes that have no file basis.
461 if(file != null || title.equals(Dictionary.get("Tree.World")) || gs3_site) {
462 ///atherer.println("Unmap: " + this);
463 children = null;
464 raw_children = null;
465 }
466 else {
467 ///ystem.err.println("No file for " + this + " - can't unmap.");
468 }
469 }
470
471
472 public void refresh()
473 {
474 unmap();
475 map();
476 }
477
478
479 private class FileEnumeration
480 implements Enumeration {
481 private int index = 0;
482 /** Tests if this enumeration contains more elements. */
483 public boolean hasMoreElements() {
484 return (index < children.size());
485 }
486 /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
487 public Object nextElement() {
488 Object result = null;
489 if(index < children.size()) {
490 result = children.get(index);
491 index++;
492 }
493 return result;
494 }
495 }
496}
Note: See TracBrowser for help on using the repository browser.