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

Last change on this file since 6148 was 6148, checked in by jmt12, 20 years ago

Greenstone Collection children nodes now appear with their full title followed by the filename in curved brackets

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