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

Last change on this file since 4397 was 4395, checked in by jmt12, 21 years ago

FileNode now check, when mapping their children, for symbolic links so as to avoid infinite copy loops. However this may cause the ugly 'Disk Not Found in Drive A:' bug to resurface. Watch this space.

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