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

Last change on this file since 34246 was 34246, checked in by ak19, 4 years ago

Still part of commit 34241 and now also 34245.

  • Property svn:keywords set to Author Date Id Revision
File size: 9.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.DebugStream;
10import org.greenstone.gatherer.metadata.FilenameEncoding;
11import org.greenstone.gatherer.util.ArrayTools;
12
13
14public abstract class FileNode
15 implements MutableTreeNode
16{
17 protected boolean allows_children = true;
18 protected ArrayList child_nodes = null;
19 protected ArrayList child_nodes_unfiltered = null;
20 protected File file = null;
21 protected FileSystemModel model = null;
22 protected MutableTreeNode parent = null;
23
24 protected String urlEncodedFileName = "";
25 protected String urlEncodedFilePath = "";
26 protected String filenameEncoding = "";
27 /** The string that is displayed as the filename. Attempts to be in the correct encoding. */
28 protected String displayFileName = null;
29
30
31 public FileNode(File file)
32 {
33 this.file = file;
34
35 if (file != null) {
36 // Files cannot have children
37 if(file.isFile()) {
38 // Cache this result to prevent unceasing missing disk messages being thrown if the
39 // removable media was, um, removed after directory mapped
40 this.allows_children = false;
41 }
42 filenameEncoding = "";
43 urlEncodedFilePath = FilenameEncoding.calcURLEncodedFilePath(file);
44 urlEncodedFileName = FilenameEncoding.calcURLEncodedFileName(urlEncodedFilePath);
45
46 // work out the display string (extra special processing for CollectionTreeNodes)
47 displayFileName = calcDisplayString();
48 }
49 }
50
51 public String getURLEncodedFileName() { return urlEncodedFileName; }
52
53 public String getURLEncodedFilePath() { return urlEncodedFilePath; }
54
55 public String getFilenameEncoding() { return filenameEncoding; }
56
57
58 /** This method returns a string representation of the filenodes in the tree,
59 * that can then be displayed in the tree. Overridden in subclass CollectionTreeNode.
60 * Turn FilenameEncoding.DEBUGGING on to see URLEncoded filenames.
61 */
62 protected String calcDisplayString() {
63 if(FilenameEncoding.DEBUGGING) {
64 return getURLEncodedFileName();
65 } else {
66 return file.getName();
67 }
68 }
69
70 /** Returns the children of the node as an Enumeration. */
71 public Enumeration children()
72 {
73 return new FileEnumeration();
74 }
75
76
77 /** Returns true if the receiver allows children. */
78 public boolean getAllowsChildren()
79 {
80 return allows_children;
81 }
82
83
84 /** Returns the child TreeNode at index childIndex. */
85 public TreeNode getChildAt(int index)
86 {
87 return (TreeNode) child_nodes.get(index);
88 }
89
90
91 /** Returns the number of children TreeNodes the receiver contains. */
92 public int getChildCount()
93 {
94 map();
95
96 // Use the number of (filtered) child nodes
97 if (child_nodes != null) {
98 return child_nodes.size();
99 }
100
101 return 0;
102 }
103
104
105 /** Returns the index of node in the receivers children. */
106 public int getIndex(TreeNode node)
107 {
108 if (child_nodes != null) {
109 return child_nodes.indexOf(node);
110 }
111
112 return -1;
113 }
114
115
116 /** Returns the parent TreeNode of the receiver. */
117 public TreeNode getParent()
118 {
119 return parent;
120 }
121
122
123 /** Adds child to the receiver at index. */
124 public void insert(MutableTreeNode child, int index)
125 {
126 DebugStream.println("Insert " + child + " in " + this + " at index " + index + " [Model: " + model + "]");
127 if (child == null) {
128 return;
129 }
130
131 try {
132 FileNode child_node = (FileNode) child;
133 child_nodes.add(index, child_node);
134 child_node.model = model;
135 child_node.parent = this;
136 }
137 catch (Exception exception) {
138 DebugStream.printStackTrace(exception);
139 }
140 }
141
142
143 /** Returns true if the receiver is a leaf. */
144 public boolean isLeaf()
145 {
146 return (allows_children == false);
147 }
148
149
150 /** Removes the child at index from the receiver. */
151 public void remove(int index)
152 {
153 if (index >= 0 && index < child_nodes.size()) {
154 child_nodes.remove(index);
155 }
156 }
157
158
159 /** Removes node from the receiver. */
160 public void remove(MutableTreeNode node)
161 {
162 remove(getIndex(node));
163 }
164
165
166 /** Removes the receiver from its parent. */
167 public void removeFromParent()
168 {
169 parent.remove(this);
170 parent = null;
171 }
172
173
174 /** Resets the user object of the receiver to object. */
175 public void setUserObject(Object object) {
176 try {
177 file = (File) object;
178 }
179 catch (Exception exception) {
180 DebugStream.printStackTrace(exception);
181 }
182 }
183
184
185 // -------------------------------------------------------------------------------
186
187
188 public void add(MutableTreeNode child)
189 {
190 insert(child, child_nodes.size());
191 }
192
193
194 protected abstract FileNode addChildNode(File file);
195
196
197 /** Compare two FileNodes for equality. */
198 public boolean equals(FileNode node)
199 {
200 if (node == null) {
201 // Definitely not a match
202 return false;
203 }
204
205 if (file != null) {
206 return file.equals(node.getFile());
207 }
208 else {
209 return toString().equals(node.toString());
210 }
211 }
212
213
214 /** Retrieve the file node at the given index, regardless of filters set. */
215 public FileNode getChildAtUnfiltered(int index)
216 {
217 if (index >= 0 && index < size()) {
218 return (FileNode) child_nodes_unfiltered.get(index);
219 }
220 return null;
221 }
222
223
224 public File getFile() {
225 return file;
226 }
227
228
229 /** Retrieves the tree path from the root node to this node. */
230 public TreeNode[] getPath() {
231 int count = 0;
232 TreeNode current = this;
233 while(current != null) {
234 count++;
235 current = current.getParent();
236 }
237 TreeNode[] path = new TreeNode[count];
238 current = this;
239 while(current != null) {
240 path[count - 1] = current;
241 count--;
242 current = current.getParent();
243 }
244 return path;
245 }
246
247
248 public boolean isFileSystemRoot() {
249 if (file != null) {
250 return FileSystemView.getFileSystemView().isFileSystemRoot(file);
251 }
252 else {
253 return false;
254 }
255 }
256
257
258 /** Overridden if necessary by subclasses. */
259 public boolean isInLoadedCollection()
260 {
261 return false;
262 }
263
264
265 /** Overridden if necessary by subclasses. */
266 public boolean isReadOnly()
267 {
268 return false;
269 }
270
271
272 public void map()
273 {
274 // If this node has already been mapped, don't bother doing it again
275 if (child_nodes != null) {
276 return;
277 }
278 child_nodes = new ArrayList();
279
280 // General case, only map if children are allowed
281 if (file != null && getAllowsChildren()) {
282 File[] files = file.listFiles();
283 if (files != null && files.length > 0) {
284 // Sort the child files
285 ArrayTools.sort(files);
286
287 // Now add them to child_nodes_unfiltered
288 child_nodes_unfiltered = new ArrayList();
289 for (int i = 0; i < files.length; i++) {
290 FileNode child_node = this.addChildNode(files[i]);
291 child_nodes_unfiltered.add(child_node);
292 }
293
294 // Apply the filters set in the model
295 FileFilter[] filters = model.getFilters();
296 for (int i = 0; filters != null && i < filters.length; i++) {
297 files = ArrayTools.filter(files, filters[i].filter, filters[i].exclude);
298 }
299
300 // Add the files left after filtering to child_nodes
301 for (int i = 0, j = 0; (i < child_nodes_unfiltered.size() && j < files.length); i++) {
302 // Use the FileNode object in child_nodes_unfiltered rather than creating another
303 FileNode file_node = (FileNode) child_nodes_unfiltered.get(i);
304 if (file_node.getFile().equals(files[j])) {
305 child_nodes.add(file_node);
306 j++;
307 }
308 }
309
310 // in case any filename encodings had gone stale,
311 // (recalculate these and) refresh the display name
312 refreshDescendantEncodings();
313
314 }
315
316 model.nodeStructureChanged(this);
317 }
318 }
319
320
321 public void refresh()
322 {
323 unmap();
324 map();
325 }
326
327 // overridden in subclass CollectionTreeNode to reset and reencode display strings
328 public void resetDescendantEncodings() {}
329 public void refreshDescendantEncodings() {}
330
331
332 public void setModel(FileSystemModel model) {
333 this.model = model;
334 }
335
336 public void setParent(MutableTreeNode parent) {
337 this.parent = parent;
338 }
339
340
341 /** Return the total number of child files for the file this node represents, irrespective of filters set. */
342 public int size() {
343 if (child_nodes_unfiltered != null) {
344 return child_nodes_unfiltered.size();
345 }
346 return 0;
347 }
348
349
350 public String toString()
351 {
352 if (isFileSystemRoot()) {
353 return file.getAbsolutePath();
354 }
355 else {
356 if(displayFileName == null) {
357 displayFileName = calcDisplayString();
358 }
359 return displayFileName; //return file.getName();
360 }
361 }
362
363
364 /** Unmap this node's children. */
365 public void unmap()
366 {
367 DebugStream.println("Unmapping " + this + "...");
368 child_nodes_unfiltered = null;
369 child_nodes = null;
370 }
371
372
373 private class FileEnumeration
374 implements Enumeration
375 {
376 private int index = 0;
377
378 /** Tests if this enumeration contains more elements. */
379 public boolean hasMoreElements() {
380 if(child_nodes == null) { // special case needed handling
381 return false;
382 }
383 return (index < child_nodes.size());
384 }
385
386 /** Returns the next element of this enumeration if this enumeration object has at least one more element to provide. */
387 public Object nextElement() {
388 Object result = null;
389 if (index < child_nodes.size()) {
390 result = child_nodes.get(index);
391 index++;
392 }
393 return result;
394 }
395 }
396}
Note: See TracBrowser for help on using the repository browser.