001: package net.suberic.pooka.gui.filechooser;
002:
003: import javax.swing.*;
004: import java.io.*;
005: import javax.mail.*;
006: import net.suberic.pooka.Pooka;
007:
008: // TODO make StoreFileWrapper for selecting from available stores
009: // --jphekman
010:
011: /**
012: * This wraps a Folder or Store in a File object.
013: */
014: public class FolderFileWrapper extends File {
015: private Folder folder;
016: private FolderFileWrapper parent;
017: private FolderFileWrapper[] children = null;
018: private String path;
019: private Object mRunLock = null;
020:
021: /**
022: * Creates a new FolderFileWrapper from a Folder. This should only
023: * be used for direct children of the Folder.
024: */
025: public FolderFileWrapper(Folder f, FolderFileWrapper p) {
026: super (f.getName());
027: folder = f;
028: parent = p;
029: path = f.getName();
030: mRunLock = p.getRunLock();
031: if (Pooka.isDebug())
032: if (p != null)
033: System.out
034: .println("creating FolderFileWrapper from parent '"
035: + p.getAbsolutePath()
036: + "' from folder '" + f.getName() + "'");
037: else
038: System.out
039: .println("creating FolderFileWrapper from parent 'null' from folder '"
040: + f.getName() + "'");
041: }
042:
043: /**
044: * Creates a new FolderFileWrapper from a Folder with the given path
045: * and parent. This is used for making relative paths to files, i.e.
046: * a child of '/foo' called 'bar/baz'.
047: */
048: public FolderFileWrapper(Folder f, FolderFileWrapper p,
049: String filePath) {
050: super (f.getName());
051: folder = f;
052: parent = p;
053: mRunLock = p.getRunLock();
054: path = filePath;
055: if (Pooka.isDebug())
056: if (p != null)
057: System.out
058: .println("creating FolderFileWrapper from parent '"
059: + p.getAbsolutePath()
060: + "' called '"
061: + filePath + "'");
062: else
063: System.out
064: .println("creating FolderFileWrapper from parent 'null' called '"
065: + filePath + "'");
066: }
067:
068: /**
069: * Creates a new FolderFileWrapper from a Folder with the given path
070: * and parent. This is used for making relative paths to files, i.e.
071: * a child of '/foo' called 'bar/baz'.
072: */
073: public FolderFileWrapper(Folder f, String filePath, Object pRunLock) {
074: super (f.getName());
075: folder = f;
076: parent = null;
077: mRunLock = pRunLock;
078: path = filePath;
079: if (Pooka.isDebug())
080: System.out
081: .println("creating FolderFileWrapper from parent 'null' called '"
082: + filePath + "'");
083: }
084:
085: /**
086: * returns true.
087: */
088: public boolean canRead() {
089: return true;
090: }
091:
092: /**
093: * returns true.
094: */
095: public boolean canWrite() {
096: return true;
097: }
098:
099: /**
100: * If the wrapped Folder does not exist, creates the new Folder
101: * and returns true. If it does exist, returns false. If a
102: * MessagingException is thrown, wraps it with an IOException.
103: */
104: public boolean createNewFile() {
105: try {
106: if (folder.exists())
107: return false;
108: else {
109: folder.create(Folder.HOLDS_MESSAGES);
110: return true;
111: }
112: } catch (MessagingException me) {
113: System.out.println("caught exception: " + me.getMessage());
114: me.printStackTrace();
115: return false;
116: }
117: }
118:
119: /**
120: * Attempts to delete the Folder.
121: */
122: public boolean delete() {
123: try {
124: return folder.delete(true);
125: } catch (MessagingException me) {
126: System.out.println("caughed exception: " + me.getMessage());
127: me.printStackTrace();
128: return false;
129: }
130: }
131:
132: /**
133: * A no-op; we're not deleting any Mail folders on exit.
134: */
135: public void deleteOnExit() {
136: }
137:
138: /**
139: * Equals if the underlying Folder objects are equal.
140: */
141: public boolean equals(Object obj) {
142: if (obj instanceof FolderFileWrapper)
143: return (folder == ((FolderFileWrapper) obj).folder);
144: else
145: return false;
146: }
147:
148: /**
149: * Returns folder.exists().
150: */
151: public boolean exists() {
152: try {
153: return folder.exists();
154: } catch (MessagingException me) {
155: return false;
156: }
157: }
158:
159: /**
160: * Returns this object.
161: */
162: public File getAbsoluteFile() {
163: if (Pooka.isDebug())
164: System.out.println("calling getAbsoluteFile() on "
165: + getAbsolutePath());
166: if (this .isAbsolute())
167: return this ;
168: else
169: return new FolderFileWrapper(getFolder(), getRoot(),
170: getAbsolutePath());
171: }
172:
173: /**
174: * returns the root of this tree.
175: */
176: private FolderFileWrapper getRoot() {
177: FolderFileWrapper parent = this ;
178: while (parent.getParent() != null) {
179: parent = (FolderFileWrapper) parent.getParentFile();
180: }
181: return parent;
182: }
183:
184: /**
185: * Returns the Folder's full name. It does this recursively, by calling
186: * the this on the parent and then appending this name.
187: */
188: public String getAbsolutePath() {
189: if (Pooka.isDebug())
190: System.out.println("calling getAbsolutePath() on " + path);
191:
192: if (isAbsolute()) {
193: if (Pooka.isDebug())
194: System.out.println("returning " + getPath());
195: return getPath();
196: } else {
197: if (parent != null) {
198: String parentPath = parent.getAbsolutePath();
199: if (parentPath != "/") {
200: if (Pooka.isDebug())
201: System.out
202: .println("returning parentPath + slash + getPath() ("
203: + parentPath
204: + "/"
205: + getPath()
206: + ")");
207:
208: return parentPath + "/" + getPath();
209: } else {
210: if (Pooka.isDebug())
211: System.out
212: .println("returning just slash + getPath() (/"
213: + getPath() + ")");
214: return "/" + getPath();
215: }
216: } else {
217: if (Pooka.isDebug())
218: System.out.println("returning just /.");
219: return "/";
220: }
221: }
222: }
223:
224: /**
225: * returns this.
226: */
227: public File getCanonicalFile() {
228: return this ;
229: }
230:
231: /**
232: * returns getAbsolutePath();
233: */
234: public String getCanonicalPath() {
235: return getAbsolutePath();
236: }
237:
238: /**
239: * Returns the Folder's name.
240: */
241: public String getName() {
242: String name = folder.getName();
243: if (name == null || name.length() < 1) {
244: // this is probably a store.
245: return path;
246: }
247: return name;
248: }
249:
250: /**
251: * Returns the parent's name.
252: */
253: public String getParent() {
254: if (parent != null)
255: return parent.getAbsolutePath();
256: else
257: return null;
258: }
259:
260: /**
261: * This returns the parent Folder as a FolderFileWrapper.
262: */
263: public File getParentFile() {
264: return parent;
265: }
266:
267: /**
268: * Returns the filePath variable.
269: */
270: public String getPath() {
271: return path;
272: }
273:
274: /**
275: * Returns true if this is an absolute reference, false otherwise.
276: */
277: public boolean isAbsolute() {
278: return (parent == null);
279: }
280:
281: /**
282: * Tests to see if this can act as a directory.
283: */
284: public boolean isDirectory() {
285: try {
286: return ((folder.getType() & Folder.HOLDS_FOLDERS) != 0);
287: } catch (MessagingException me) {
288: return false;
289: }
290: }
291:
292: /**
293: * Tests to see if we should call this a File.
294: */
295: public boolean isFile() {
296: try {
297: return ((folder.getType() & Folder.HOLDS_MESSAGES) != 0);
298: } catch (MessagingException me) {
299: return false;
300: }
301: }
302:
303: /**
304: * Returns false.
305: */
306: public boolean isHidden() {
307: return false;
308: }
309:
310: /**
311: * Returns 0.
312: */
313: public long lastModified() {
314: return 0;
315: }
316:
317: /**
318: * returns the children of the File.
319: */
320: public String[] list() {
321: if (isDirectory()) {
322: if (children == null)
323: loadChildren();
324: if (children != null) {
325: String[] returnValue = new String[children.length];
326: for (int i = 0; i < children.length; i++) {
327: returnValue[i] = children[i].getName();
328: }
329: return returnValue;
330: }
331: }
332:
333: return null;
334:
335: }
336:
337: /**
338: * Returns the children of the File, filterd by the FilenameFilter.
339: */
340: public String[] list(FilenameFilter filter) {
341: String[] children = list();
342: String[] matching = new String[children.length];
343: int retValueCounter = 0;
344: for (int i = 0; i < children.length; i++) {
345: if (filter.accept(this , children[i])) {
346: matching[retValueCounter++] = children[i];
347: }
348: }
349:
350: String[] returnValue = new String[retValueCounter];
351:
352: for (int i = 0; i < retValueCounter; i++)
353: returnValue[i] = matching[i];
354:
355: return returnValue;
356: }
357:
358: /**
359: * This returns the children of the File as Files.
360: */
361: public File[] listFiles() {
362: if (Pooka.isDebug()) {
363: System.out.println("Running listFiles() on '"
364: + getAbsolutePath() + "'");
365: //Thread.dumpStack();
366: }
367:
368: if (isDirectory()) {
369: if (children == null) {
370: if (Pooka.isDebug()) {
371: System.out.println("about to load children.");
372: }
373: loadChildren();
374: }
375:
376: if (children != null)
377: return children;
378: }
379:
380: return new FolderFileWrapper[0];
381: }
382:
383: public File[] listFiles(FileFilter filter) {
384: if (Pooka.isDebug())
385: System.out.println("Running listFiles(FileFilter) on '"
386: + getAbsolutePath() + "'");
387:
388: File[] children = listFiles();
389: File[] matching = new File[children.length];
390: int retValueCounter = 0;
391: for (int i = 0; i < children.length; i++) {
392: if (filter.accept(children[i])) {
393: matching[retValueCounter++] = children[i];
394: }
395: }
396:
397: File[] returnValue = new File[retValueCounter];
398:
399: for (int i = 0; i < retValueCounter; i++)
400: returnValue[i] = matching[i];
401:
402: return returnValue;
403: }
404:
405: public File[] listFiles(FilenameFilter filter) {
406: if (Pooka.isDebug())
407: System.out.println("Running listFiles(FilenameFilter) on '"
408: + getAbsolutePath() + "'");
409:
410: File[] children = listFiles();
411: File[] matching = new File[children.length];
412: int retValueCounter = 0;
413: for (int i = 0; i < children.length; i++) {
414: if (filter.accept(this , children[i].getName())) {
415: matching[retValueCounter++] = children[i];
416: }
417: }
418:
419: File[] returnValue = new File[retValueCounter];
420:
421: for (int i = 0; i < retValueCounter; i++)
422: returnValue[i] = matching[i];
423:
424: return returnValue;
425: }
426:
427: /**
428: * This creates a new directory.
429: */
430: public boolean mkdir() {
431: try {
432: if (folder.exists())
433: return false;
434: else {
435: folder.create(Folder.HOLDS_FOLDERS);
436: return true;
437: }
438: } catch (MessagingException me) {
439: return false;
440: }
441: }
442:
443: /**
444: * This creates a new directory, also creating any higher-level
445: * directories if needed.
446: */
447: public boolean mkdirs() {
448: try {
449: if (folder.exists())
450: return false;
451:
452: boolean create = true;
453: if (!parent.exists())
454: create = parent.mkdirs();
455:
456: if (create) {
457: folder.create(Folder.HOLDS_FOLDERS);
458: return true;
459: } else
460: return false;
461: } catch (MessagingException me) {
462: return false;
463: }
464: }
465:
466: /**
467: * This renames the underlying Folder.
468: */
469: public boolean renameTo(File dest) {
470: try {
471: if (dest instanceof FolderFileWrapper) {
472: boolean returnValue = folder
473: .renameTo(((FolderFileWrapper) dest)
474: .getFolder());
475: if (parent != null)
476: parent.refreshChildren();
477: return returnValue;
478: } else
479: return false;
480: } catch (MessagingException me) {
481: Pooka.getUIFactory().showError(
482: Pooka.getProperty("error.renamingFolder",
483: "Error renaming folder ")
484: + getName(), me);
485: return false;
486: }
487: }
488:
489: /**
490: * This returns the wrapped Folder.
491: */
492: public Folder getFolder() {
493: return folder;
494: }
495:
496: /**
497: * This loads the children of the Folder.
498: */
499: private synchronized void loadChildren() {
500: synchronized (getRunLock()) {
501: if (Pooka.isDebug()) {
502: System.out.println(Thread.currentThread().getName()
503: + ": calling loadChildren() on "
504: + getAbsolutePath());
505: //Thread.dumpStack();
506: }
507:
508: if (children == null) {
509: if (Pooka.isDebug()) {
510: System.out.println(Thread.currentThread().getName()
511: + ": children is null on "
512: + getAbsolutePath()
513: + ". loading children.");
514: }
515: if (isDirectory() || !exists()) {
516: try {
517: if (Pooka.isDebug())
518: System.out.println(Thread.currentThread()
519: .getName()
520: + ": checking for connection.");
521:
522: if (!folder.getStore().isConnected()) {
523: if (Pooka.isDebug()) {
524: System.out
525: .println(Thread.currentThread()
526: .getName()
527: + ": parent store of "
528: + getAbsolutePath()
529: + " is not connected. reconnecting.");
530: }
531: folder.getStore().connect();
532: } else {
533: if (Pooka.isDebug())
534: System.out.println(Thread
535: .currentThread().getName()
536: + ": connection is ok.");
537: }
538:
539: if (Pooka.isDebug())
540: System.out.println(Thread.currentThread()
541: .getName()
542: + ": calling folder.list()");
543: Folder[] childList = folder.list();
544:
545: if (parent == null) {
546: // add for namespaces.
547: try {
548: Folder[] namespaces = folder.getStore()
549: .getSharedNamespaces();
550: if (namespaces != null
551: && namespaces.length > 0) {
552: Folder[] newChildList = new Folder[childList.length
553: + namespaces.length];
554: System.arraycopy(namespaces, 0,
555: newChildList, 0,
556: namespaces.length);
557: System.arraycopy(childList, 0,
558: newChildList,
559: namespaces.length,
560: childList.length);
561: childList = newChildList;
562: }
563: } catch (Exception e) {
564: // FIXME do nothing for now.
565: }
566: }
567: if (Pooka.isDebug())
568: System.out
569: .println(Thread.currentThread()
570: .getName()
571: + ": folder.list() returned "
572: + childList
573: + "; creating new folderFileWrapper.");
574:
575: FolderFileWrapper[] tmpChildren = new FolderFileWrapper[childList.length];
576: for (int i = 0; i < childList.length; i++) {
577: if (Pooka.isDebug())
578: System.out
579: .println(Thread.currentThread()
580: .getName()
581: + ": calling new FolderFileWrapper for "
582: + childList[i]
583: .getName()
584: + " (entry # " + i);
585:
586: tmpChildren[i] = new FolderFileWrapper(
587: childList[i], this );
588: }
589:
590: children = tmpChildren;
591: } catch (MessagingException me) {
592: if (Pooka.isDebug())
593: System.out
594: .println("caught exception during FolderFileWrapper.loadChildren() on "
595: + getAbsolutePath() + ".");
596: me.printStackTrace();
597: }
598: }
599: }
600: }
601: }
602:
603: /**
604: * This refreshes the children of the Folder.
605: */
606: public synchronized void refreshChildren() {
607: synchronized (getRunLock()) {
608: if (Pooka.isDebug()) {
609: System.out.println(Thread.currentThread().getName()
610: + ": calling refreshChildren() on "
611: + getAbsolutePath());
612: //Thread.dumpStack();
613: }
614:
615: if (children == null) {
616: if (Pooka.isDebug()) {
617: System.out.println(Thread.currentThread().getName()
618: + ": children is null on "
619: + getAbsolutePath()
620: + ". calling loadChildren().");
621: }
622: loadChildren();
623: } else {
624: if (isDirectory() || !exists()) {
625: try {
626: if (Pooka.isDebug())
627: System.out.println(Thread.currentThread()
628: .getName()
629: + ": checking for connection.");
630:
631: if (!folder.getStore().isConnected()) {
632: if (Pooka.isDebug()) {
633: System.out
634: .println(Thread.currentThread()
635: .getName()
636: + ": parent store of "
637: + getAbsolutePath()
638: + " is not connected. reconnecting.");
639: }
640: folder.getStore().connect();
641: } else {
642: if (Pooka.isDebug())
643: System.out.println(Thread
644: .currentThread().getName()
645: + ": connection is ok.");
646: }
647:
648: if (Pooka.isDebug())
649: System.out.println(Thread.currentThread()
650: .getName()
651: + ": calling folder.list()");
652: Folder[] childList = folder.list();
653: if (Pooka.isDebug())
654: System.out
655: .println(Thread.currentThread()
656: .getName()
657: + ": folder.list() returned "
658: + childList
659: + "; creating new folderFileWrapper.");
660:
661: FolderFileWrapper[] tmpChildren = new FolderFileWrapper[childList.length];
662: for (int i = 0; i < childList.length; i++) {
663: if (Pooka.isDebug())
664: System.out
665: .println(Thread.currentThread()
666: .getName()
667: + ": calling new FolderFileWrapper for "
668: + childList[i]
669: .getName()
670: + " (entry # " + i);
671:
672: // yeah, this is n! or something like that. shouldn't matter--
673: // if we have somebody running with that many folders, or with
674: // that slow of a machine, we're in trouble anyway.
675:
676: //try to get a match.
677: boolean found = false;
678: for (int j = 0; !found
679: && j < children.length; j++) {
680: if (children[j].getName().equals(
681: childList[i].getName())) {
682: tmpChildren[i] = children[j];
683: found = true;
684: }
685: }
686:
687: if (!found) {
688: tmpChildren[i] = new FolderFileWrapper(
689: childList[i], this );
690: }
691: }
692:
693: children = tmpChildren;
694: } catch (MessagingException me) {
695: Pooka
696: .getUIFactory()
697: .showError(
698: Pooka
699: .getProperty(
700: "error.refreshingFolder",
701: "error refreshing folder's children: "),
702: me);
703: }
704: }
705: }
706: }
707:
708: }
709:
710: /* Only accepts relative filenames. */
711: public FolderFileWrapper getFileByName(String filename) {
712:
713: if (Pooka.isDebug())
714: System.out.println("calling getFileByName(" + filename
715: + ") on folder " + getName() + " (" + getPath()
716: + ") (abs " + getAbsolutePath() + ")");
717:
718: String origFilename = new String(filename);
719: if (filename == null || filename.length() < 1
720: || (filename.equals("/") && getParentFile() == null)) {
721: if (Pooka.isDebug())
722: System.out
723: .println("returning this for getFileByName()");
724: return this ;
725: }
726:
727: if (this .isAbsolute(filename)) {
728: return null; // FIXME error
729: }
730:
731: // strip out the /'s
732:
733: String subdirFile = null;
734:
735: int dirMarker = filename.indexOf('/');
736: while (dirMarker == 0) {
737: filename = filename.substring(1);
738: dirMarker = filename.indexOf('/');
739: }
740:
741: // divide into first component and rest of components
742: if (dirMarker > 0) {
743: subdirFile = filename.substring(dirMarker + 1);
744: filename = filename.substring(0, dirMarker);
745: }
746:
747: FolderFileWrapper currentFile = getChildFile(filename);
748: if (currentFile != null && subdirFile != null) {
749: // recurse with rest of components
750: FolderFileWrapper tmp = currentFile
751: .getFileByName(subdirFile);
752: // tmp.path = origFilename;
753:
754: if (Pooka.isDebug())
755: System.out.println("created file " + tmp.getName()
756: + " (" + tmp.getPath() + ") (abs "
757: + tmp.getAbsolutePath() + ") from string "
758: + origFilename + " on folder " + getName()
759: + " (" + getPath() + ") (abs "
760: + getAbsolutePath() + ")");
761:
762: return tmp;
763:
764: } else {
765: return currentFile;
766: }
767:
768: }
769:
770: FolderFileWrapper getChildFile(String filename) {
771: if (Pooka.isDebug())
772: System.out.println("calling getChildFile on " + getName()
773: + " with filename " + filename);
774:
775: if (children == null)
776: loadChildren();
777:
778: if (children != null) {
779: for (int i = 0; i < children.length; i++) {
780: if (children[i].getName().equals(filename))
781: return children[i];
782: }
783:
784: FolderFileWrapper[] newChildren = new FolderFileWrapper[children.length + 1];
785: for (int i = 0; i < children.length; i++)
786: newChildren[i] = children[i];
787:
788: try {
789: newChildren[children.length] = new FolderFileWrapper(
790: folder.getFolder(filename), this );
791: } catch (MessagingException me) {
792: }
793:
794: children = newChildren;
795: return children[children.length - 1];
796: }
797:
798: return this ;
799:
800: }
801:
802: private boolean isAbsolute(String filename) {
803: return filename.startsWith("/");
804: }
805:
806: public String filenameAsRelativeToRoot(String filename) {
807: String relative = filename;
808: while (relative.length() > 0 & isAbsolute(relative)) {
809: relative = relative.substring(1);
810: }
811:
812: return relative;
813: }
814:
815: /**
816: * Returns the object that we use for a run lock.
817: */
818: public Object getRunLock() {
819: return mRunLock;
820: }
821:
822: }
|