KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > Directory


1 /*
2  * Directory.java
3  *
4  * Copyright (C) 1998-2004 Peter Graves
5  * $Id: Directory.java,v 1.28 2004/05/22 00:04:59 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j;
23
24 import gnu.regexp.RE;
25 import gnu.regexp.REMatch;
26 import gnu.regexp.RESyntax;
27 import gnu.regexp.UncheckedRE;
28 import java.awt.AWTEvent JavaDoc;
29 import java.awt.event.MouseEvent JavaDoc;
30 import java.io.BufferedReader JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.InputStreamReader JavaDoc;
33 import java.io.StringReader JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Collections JavaDoc;
36 import java.util.Comparator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Vector JavaDoc;
39 import javax.swing.Icon JavaDoc;
40 import javax.swing.SwingUtilities JavaDoc;
41
42 public final class Directory extends Buffer
43 {
44     private static final Preferences preferences = Editor.preferences();
45
46     // This is the flag for this particular directory buffer.
47
private boolean usingNativeFormat;
48
49     public static final int SORT_BY_NAME = 0;
50     public static final int SORT_BY_DATE = 1;
51     public static final int SORT_BY_SIZE = 2;
52
53     private int sortBy = SORT_BY_NAME;
54
55     private String JavaDoc limitPattern;
56
57     private ArrayList JavaDoc entries = new ArrayList JavaDoc();
58
59     private int numMarked = 0;
60
61     private DirectoryHistory history = new DirectoryHistory();
62
63     private static final RE nativeMoveToFilenameRegExp;
64     private static final RE internalMoveToFilenameRegExp;
65
66     private boolean loadError;
67
68     static {
69         // Letters.
70
final String JavaDoc letter = "[[:alpha:]]";
71
72         // Month is 2 or more letters, possibly padded on the right with spaces.
73
final String JavaDoc month = letter + letter + "+";
74
75         // Year.
76
final String JavaDoc yyyy = "[0-9][0-9][0-9][0-9]";
77
78         // Day of month.
79
final String JavaDoc dd = "[ 0-3][0-9][.]?";
80
81         // Month and day (includes following space character).
82
final String JavaDoc monthAndDay =
83             "(" + month + " *" + dd + " " + "|" + dd + " " + month + " *" + ")";
84
85         // Time of day.
86
final String JavaDoc HHMM = "[ 0-2][0-9]:[0-5][0-9]";
87
88         // Time or year.
89
final String JavaDoc timeOrYear =
90             "(" + HHMM + "|" + " " + yyyy + "|" + yyyy + " " + ")";
91
92         RESyntax syntax = new RESyntax(RESyntax.RE_SYNTAX_PERL5);
93         syntax.set(RESyntax.RE_CHAR_CLASSES);
94
95         String JavaDoc traditional = "[0-9]+" + " " + monthAndDay + timeOrYear + " ";
96
97         // --time-style=long-iso
98
// -rw-r--r-- 1 peter peter 147 2002-11-13 13:10 notes
99
// --time-style=iso
100
// -rw-r--r-- 1 peter peter 69016 11-16 18:29 Directory.java
101
// -rw-r--r-- 1 peter peter 13274 2001-09-08 thinbox.tar.gz
102
final String JavaDoc isoMaybeYear = "(" + yyyy + "-)?";
103         final String JavaDoc isoMonthAndDay = "[01][0-9]-[0-3][0-9]";
104         final String JavaDoc isoMaybeTime = "(" + HHMM + ")?";
105         String JavaDoc iso = "[0-9]+" + " " + isoMaybeYear + isoMonthAndDay + " " +
106             isoMaybeTime + " *";
107
108         // Mac OS X (Pete Kirkham)
109
// --time-style="+%e %b %Y"
110
// -rw-r--r-- 1 pete pete 6065 23 Oct 2003 Directories.java
111
// --time-style="+%e %b %H:%M"
112
// -rw-r--r-- 1 pete pete 75350 21 May 19:58 Directory.java
113
String JavaDoc osx = "[0-9]+" + " " + dd + " " + month + " " + timeOrYear + " ";
114
115         nativeMoveToFilenameRegExp =
116             new UncheckedRE("(" + traditional + ")|(" + iso + ")|(" + osx + ")",
117                             0,
118                             syntax);
119
120         internalMoveToFilenameRegExp = new UncheckedRE(":[0-5][0-9]" + " ");
121     }
122
123     public static final RE getNativeMoveToFilenameRegExp()
124     {
125         return nativeMoveToFilenameRegExp;
126     }
127
128     public static final RE getInternalMoveToFilenameRegExp()
129     {
130         return internalMoveToFilenameRegExp;
131     }
132
133     public Directory(File dir)
134     {
135         super();
136         supportsUndo = false;
137         setFile(dir);
138         type = TYPE_DIRECTORY;
139         readOnly = true;
140         mode = DirectoryMode.getMode();
141         formatter = mode.getFormatter(this);
142         setInitialized(true);
143     }
144
145     public Directory(File dir, String JavaDoc listing)
146     {
147         this(dir);
148         setListing(listing);
149     }
150
151     public final boolean isUsingNativeFormat()
152     {
153         return usingNativeFormat;
154     }
155
156     public File getCurrentDirectory()
157     {
158         return getFile();
159     }
160
161     public int getSortBy()
162     {
163         return sortBy;
164     }
165
166     public Position getInitialDotPos()
167     {
168         Line line = getFirstLine();
169         Line upLine = null; // We'll put dot here if directory is empty.
170
while (true) {
171             if (line.next() == null)
172                 break;
173             String JavaDoc name = getName(line);
174             if (name != null) {
175                 if (name.equals(".."))
176                     upLine = line;
177                 else if (!name.equals("."))
178                     return new Position(line, getNameOffset(line));
179             }
180             line = line.next();
181         }
182         // Directory is empty.
183
if (upLine != null)
184             return new Position(upLine, getNameOffset(upLine));
185         else
186             return new Position(line, getNameOffset(line));
187     }
188
189     private void setLimitPattern(String JavaDoc s)
190     {
191         if (s == null || s.length() == 0)
192             limitPattern = null;
193         else
194             limitPattern = s;
195     }
196
197     public final String JavaDoc getLimitPattern()
198     {
199         return limitPattern;
200     }
201
202     public static void dirLimit()
203     {
204         final Editor editor = Editor.currentEditor();
205         final Buffer buffer = editor.getBuffer();
206         if (buffer instanceof Directory) {
207             Directory directory = (Directory) buffer;
208             InputDialog dialog = new InputDialog(editor, "Pattern:", "Limit",
209                                                  directory.getLimitPattern());
210             dialog.setHistory(new History("dirLimit"));
211             editor.centerDialog(dialog);
212             dialog.show();
213             String JavaDoc pattern = dialog.getInput();
214             // A null pattern means the user cancelled the input dialog.
215
if (pattern != null) {
216                 editor.repaintNow();
217                 directory.limit(pattern);
218             }
219         }
220     }
221
222     public static void dirLimit(String JavaDoc pattern)
223     {
224         final Editor editor = Editor.currentEditor();
225         final Buffer buffer = editor.getBuffer();
226         if (buffer instanceof Directory)
227             ((Directory)buffer).limit(pattern);
228     }
229
230     public static void dirUnlimit()
231     {
232         final Editor editor = Editor.currentEditor();
233         final Buffer buffer = editor.getBuffer();
234         if (buffer instanceof Directory) {
235             Directory directory = (Directory) buffer;
236             if (directory.getLimitPattern() != null)
237                 directory.limit(null);
238         }
239     }
240
241     private void limit(String JavaDoc pattern)
242     {
243         if (pattern != null) {
244             pattern = pattern.trim();
245             if (pattern.length() == 0)
246                 pattern = null;
247         }
248         boolean reload = false;
249         if (pattern == null && limitPattern != null)
250             reload = true;
251         else if (pattern != null && !pattern.equals(limitPattern))
252             reload = true;
253         if (reload) {
254             final Editor editor = Editor.currentEditor();
255             editor.setWaitCursor();
256             String JavaDoc name = null;
257             Line dotLine = editor.getDotLine();
258             if (dotLine instanceof DirectoryLine)
259                 name = getName(dotLine);
260             setLimitPattern(pattern);
261             if (getListing() != null)
262                 reloadFromListing();
263             else
264                 reload();
265             Line line = findName(name);
266             Position pos;
267             if (line != null)
268                 pos = new Position(line, getNameOffset(line));
269             else
270                 pos = getInitialDotPos();
271             for (EditorIterator it = new EditorIterator(); it.hasNext();) {
272                 Editor ed = it.nextEditor();
273                 if (ed.getBuffer() == this) {
274                     ed.setTopLine(getFirstLine());
275                     ed.setDot(pos);
276                     ed.setMark(null);
277                     ed.moveCaretToDotCol();
278                     ed.setUpdateFlag(REFRAME | REPAINT);
279                 }
280             }
281             editor.setDefaultCursor();
282         }
283     }
284
285     public void rescan()
286     {
287         final File file = getFile();
288         if (file.isRemote())
289             DirectoryCache.getDirectoryCache().purge(file.getHostName());
290         reload();
291         if (loadError)
292             return;
293         boolean rescanned = false;
294         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
295             Editor ed = it.nextEditor();
296             if (ed.getBuffer() == this) {
297                 if (ed.getSidebar() != null) {
298                     NavigationComponent c = ed.getSidebar().getBottomComponent();
299                     if (c instanceof DirectoryTree) {
300                         DirectoryTree tree = (DirectoryTree) c;
301                         DirectoryTreeModel treeModel = tree.getTreeModel();
302                         if (!rescanned) {
303                             treeModel.rescan(file);
304                             rescanned = true;
305                         }
306                         tree.refresh();
307                     }
308                 }
309             }
310         }
311     }
312
313     public synchronized void reload()
314     {
315         ArrayList JavaDoc editors = new ArrayList JavaDoc();
316
317         // Remember the name of the current file in every editor.
318
ArrayList JavaDoc names = new ArrayList JavaDoc();
319
320         // Remember the line number in every editor.
321
ArrayList JavaDoc lineNumbers = new ArrayList JavaDoc();
322
323         // Remember the top line of the display in every editor.
324
ArrayList JavaDoc topLineNumbers = new ArrayList JavaDoc();
325
326         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
327             Editor ed = it.nextEditor();
328             String JavaDoc name = null;
329             int lineNumber = 0;
330             int topLineNumber = 0;
331             if (ed.getBuffer() == this) {
332                 name = getName(ed.getDotLine());
333                 lineNumber = ed.getDotLineNumber();
334                 topLineNumber = ed.getDisplay().getTopLineNumber();
335             }
336             editors.add(ed);
337             names.add(name);
338             lineNumbers.add(new Integer JavaDoc(lineNumber));
339             topLineNumbers.add(new Integer JavaDoc(topLineNumber));
340         }
341
342         empty();
343         entries.clear();
344         numMarked = 0;
345         setListing(null);
346
347         load();
348
349         // Restore the status quo in every window.
350
for (int i = 0; i < editors.size(); i++) {
351             final Editor ed = (Editor) editors.get(i);
352             if (ed.getBuffer() == this) {
353                 Line dotLine = findName((String JavaDoc)names.get(i));
354                 if (dotLine == null) {
355                     dotLine =
356                         getLine(((Integer JavaDoc)lineNumbers.get(i)).intValue());
357                     if (dotLine == null) {
358                         if (getFirstLine() == null) {
359                             Debug.bug();
360                             appendLine("");
361                         }
362                         dotLine = getFirstLine();
363                         while (dotLine.next() != null)
364                             dotLine = dotLine.next();
365                     }
366                 }
367                 ed.setDot(dotLine, getNameOffset(dotLine));
368                 ed.setMark(null);
369                 final Display display = ed.getDisplay();
370                 display.setShift(0);
371                 display.moveCaretToDotCol();
372
373                 Line line =
374                     getLine(((Integer JavaDoc)topLineNumbers.get(i)).intValue());
375                 if (line == null) {
376                     Debug.assertTrue(getFirstLine() != null);
377                     line = getFirstLine();
378                     while (line.next() != null)
379                         line = line.next();
380                 }
381                 display.setTopLine(line);
382                 display.setUpdateFlag(REPAINT);
383                 ed.updateLocation();
384             }
385         }
386     }
387
388     private synchronized void reloadFromListing()
389     {
390         Debug.assertTrue(getListing() != null);
391         empty();
392         entries.clear();
393         numMarked = 0;
394         load();
395         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
396             Editor ed = it.nextEditor();
397             if (ed.getBuffer() == this) {
398                 final Line line = getFirstLine();
399                 ed.setDot(line, getNameOffset(line));
400                 ed.setMark(null);
401                 final Display display = ed.getDisplay();
402                 display.setShift(0);
403                 display.moveCaretToDotCol();
404                 display.setTopLine(getFirstLine());
405                 display.setUpdateFlag(REPAINT);
406                 ed.updateLocation();
407             }
408         }
409     }
410
411     // Called only from synchronized methods.
412
private void addEntry(String JavaDoc name)
413     {
414         Debug.assertTrue(!usingNativeFormat);
415         File f = File.getInstance(getFile(), name);
416         if (f == null)
417             return;
418         DirectoryEntry de;
419         if (f.isDirectory())
420             de = new DirectoryEntry(name, f.lastModified(), 0, true);
421         else
422             de = new DirectoryEntry(name, f.lastModified(), f.length());
423         if (!name.equals(".") && !name.equals("..")) {
424             try {
425                 String JavaDoc cp = f.getCanonicalPath();
426                 String JavaDoc ap = f.getAbsolutePath();
427                 if (!cp.equals(ap)) {
428                     final String JavaDoc canonicalPath = getFile().canonicalPath();
429                     if (cp.startsWith(canonicalPath + LocalFile.getSeparator()))
430                         de.setLinkedTo(cp.substring(canonicalPath.length()+1));
431                     else
432                         de.setLinkedTo(cp);
433                 }
434             }
435             catch (IOException JavaDoc e) {
436                 Log.error(e);
437             }
438         }
439         entries.add(de);
440     }
441
442     private final void appendLine(DirectoryEntry entry)
443     {
444         appendLine(new DirectoryLine(entry));
445     }
446
447     private synchronized DirectoryEntry findEntry(String JavaDoc name)
448     {
449         for (int i = 0; i < entries.size(); i++) {
450             DirectoryEntry entry = (DirectoryEntry) entries.get(i);
451             if (name.equals(entry.getName()))
452                 return entry;
453         }
454         return null;
455     }
456
457     private synchronized DirectoryEntry findNativeEntry(String JavaDoc string)
458     {
459         for (int i = 0; i < entries.size(); i++) {
460             DirectoryEntry entry = (DirectoryEntry) entries.get(i);
461             if (string.equals(entry.getString()))
462                 return entry;
463         }
464         return null;
465     }
466
467     private synchronized void sort()
468     {
469         if (usingNativeFormat) {
470             Debug.bug();
471             return;
472         }
473         if (sortBy == SORT_BY_NAME)
474             sortByName();
475         else if (sortBy == SORT_BY_DATE)
476             sortByDate();
477         else if (sortBy == SORT_BY_SIZE)
478             sortBySize();
479     }
480
481     // Called only from sort().
482
private void sortByName()
483     {
484         Debug.assertTrue(!usingNativeFormat);
485         Comparator JavaDoc comparator = new Comparator JavaDoc() {
486             public int compare(Object JavaDoc o1, Object JavaDoc o2)
487             {
488                 String JavaDoc name1 = ((DirectoryEntry)o1).getName();
489                 String JavaDoc name2 = ((DirectoryEntry)o2).getName();
490                 return name1.compareToIgnoreCase(name2);
491             }
492         };
493         Collections.sort(entries, comparator);
494     }
495
496     // Called only from sort().
497
private void sortByDate() {
498         Comparator JavaDoc comparator = new Comparator JavaDoc() {
499             public int compare(Object JavaDoc o1, Object JavaDoc o2)
500             {
501                 // Most recent dates first.
502
long date1 = ((DirectoryEntry)o1).getDate();
503                 long date2 = ((DirectoryEntry)o2).getDate();
504                 if (date1 > date2)
505                     return -1;
506                 if (date1 < date2)
507                     return 1;
508                 return 0;
509             }
510         };
511         Collections.sort(entries, comparator);
512     }
513
514     // Called only from sort().
515
private void sortBySize()
516     {
517         Comparator JavaDoc comparator = new Comparator JavaDoc() {
518             public int compare(Object JavaDoc o1, Object JavaDoc o2)
519             {
520                 // Biggest files first.
521
long size1 = ((DirectoryEntry)o1).getSize();
522                 long size2 = ((DirectoryEntry)o2).getSize();
523                 if (size1 > size2)
524                     return -1;
525                 if (size1 < size2)
526                     return 1;
527                 return 0;
528             }
529         };
530         Collections.sort(entries, comparator);
531     }
532
533     // Called only from synchronized methods.
534
private void addEntriesToBuffer()
535     {
536         final int size = entries.size();
537         if (preferences.getBooleanProperty(Property.DIR_SORT_DIRECTORIES_FIRST, !usingNativeFormat)) {
538             // Add lines to the buffer in two passes so directories will always be on top.
539
for (int i = 0; i < size; i++) {
540                 DirectoryEntry entry = (DirectoryEntry) entries.get(i);
541                 if (entry.isDirectory())
542                     appendLine(entry);
543             }
544             for (int i = 0; i < size; i++) {
545                 DirectoryEntry entry = (DirectoryEntry) entries.get(i);
546                 if (!entry.isDirectory())
547                     appendLine(entry);
548             }
549         } else {
550             for (int i = 0; i < size; i++) {
551                 DirectoryEntry entry = (DirectoryEntry) entries.get(i);
552                 appendLine(entry);
553             }
554         }
555         if (getFirstLine() == null)
556             appendLine("");
557         setLoaded(true);
558     }
559
560     public static void dirCycleSortBy()
561     {
562         final Editor editor = Editor.currentEditor();
563         final Buffer buffer = editor.getBuffer();
564         if (buffer instanceof Directory) {
565             editor.setWaitCursor();
566             ((Directory)buffer).cycleSortBy();
567             editor.setDefaultCursor();
568         }
569     }
570
571     private synchronized void cycleSortBy()
572     {
573         if (sortBy == SORT_BY_NAME)
574             sortBy = SORT_BY_DATE;
575         else if (sortBy == SORT_BY_DATE)
576             sortBy = SORT_BY_SIZE;
577         else
578             sortBy = SORT_BY_NAME;
579         resort();
580     }
581
582     public void resort(int sortBy)
583     {
584         if (this.sortBy != sortBy) {
585             this.sortBy = sortBy;
586             resort();
587         }
588     }
589
590     private void resort()
591     {
592         if (usingNativeFormat) {
593             reload();
594         } else {
595             sort();
596             try {
597                 lockWrite();
598             }
599             catch (InterruptedException JavaDoc e) {
600                 Log.error(e);
601                 return; // Shouldn't happen.
602
}
603             try {
604                 empty();
605                 addEntriesToBuffer();
606                 renumber();
607             }
608             finally {
609                 unlockWrite();
610             }
611             for (EditorIterator it = new EditorIterator(); it.hasNext();) {
612                 Editor ed = it.nextEditor();
613                 if (ed.getBuffer() == this) {
614                     ed.setDot(getFirstLine(), 0);
615                     ed.setMark(null);
616                     final Display display = ed.getDisplay();
617                     display.setTopLine(getFirstLine());
618                     display.setShift(0);
619                     display.setCaretCol(0);
620                     display.setUpdateFlag(REPAINT);
621                     ed.updateLocation();
622                 }
623             }
624         }
625     }
626
627     private synchronized void loadInternal()
628     {
629         // Default is true for Unix, false otherwise. User can override default.
630
boolean useNativeFormat =
631             preferences.getBooleanProperty(Property.DIR_USE_NATIVE_FORMAT,
632                                            Platform.isPlatformUnix());
633         if (useNativeFormat) {
634             if (!Utilities.haveLs())
635                 useNativeFormat = false;
636         }
637         loadError = false;
638         try {
639             final DirectoryFilenameFilter dff;
640             if (limitPattern != null)
641                 dff = new DirectoryFilenameFilter(limitPattern);
642             else
643                 dff = null;
644             final File file = getFile();
645             if (useNativeFormat || file.isRemote()) {
646                 usingNativeFormat = true;
647                 String JavaDoc flags = "-la"; // Default is sort by name.
648
if (sortBy == SORT_BY_DATE)
649                     flags = "-lat";
650                 else if (sortBy == SORT_BY_SIZE)
651                     flags = "-laS";
652                 String JavaDoc extraOptions =
653                     getStringProperty(Property.LS_EXTRA_OPTIONS);
654                 if (extraOptions != null) {
655                     flags += " ";
656                     flags += extraOptions;
657                     Log.debug("Directory.loadInternal flags = " + flags);
658                 }
659                 BufferedReader JavaDoc reader = null;
660                 if (getListing() != null) {
661                     reader = new BufferedReader JavaDoc(new StringReader JavaDoc(getListing()));
662                 } else if (file instanceof FtpFile || file instanceof SshFile) {
663                     setListing(file.getDirectoryListing());
664                     if (getListing() != null)
665                         reader = new BufferedReader JavaDoc(new StringReader JavaDoc(getListing()));
666                     else
667                         loadError = true;
668                 } else {
669                     // Local file.
670
Process JavaDoc process = null;
671                     if (Platform.isPlatformUnix()) {
672                         String JavaDoc cmd =
673                             "(\\cd \"" + file.canonicalPath() + "\" && \\ls " +
674                             flags + ")";
675                         String JavaDoc[] cmdarray = {"/bin/sh", "-c", cmd};
676                         process = Runtime.getRuntime().exec(cmdarray);
677                     } else {
678                         // Windows.
679
String JavaDoc cp = file.canonicalPath();
680                         // Convert "C:\" into "//c" for Cygwin ls.
681
if (cp.length() == 3 && cp.charAt(1) == ':' && cp.charAt(2) == '\\')
682                             cp = "//" + Character.toLowerCase(cp.charAt(0));
683                         String JavaDoc[] cmdarray = {"ls", flags, cp};
684                         process = Runtime.getRuntime().exec(cmdarray);
685                     }
686                     reader =
687                         new BufferedReader JavaDoc(new InputStreamReader JavaDoc(process.getInputStream()));
688                 }
689                 if (reader != null) {
690                     String JavaDoc s;
691                     while ((s = reader.readLine()) != null) {
692                         DirectoryEntry entry =
693                             DirectoryEntry.getDirectoryEntry(s, dff);
694                         if (entry != null)
695                             entries.add(entry);
696                     }
697                 }
698             } else {
699                 usingNativeFormat = false;
700                 boolean dirIsRoot = false;
701                 if (Platform.isPlatformWindows()) {
702                     String JavaDoc cp = file.canonicalPath();
703                     if (cp.length() == 3 && cp.endsWith(":\\")) // "C:\"
704
dirIsRoot = true;
705                 }
706                 if (!dirIsRoot) {
707                     addEntry(".");
708                     addEntry("..");
709                 }
710                 String JavaDoc[] names = file.list();
711                 if (names != null) {
712                     if (dff == null) {
713                         for (int i = 0; i < names.length; i++)
714                             addEntry(names[i]);
715                     } else {
716                         for (int i = 0; i < names.length; i++) {
717                             if (dff.accepts(names[i]))
718                                 addEntry(names[i]);
719                             else {
720                                 File f = File.getInstance(file, names[i]);
721                                 if (f != null && f.isDirectory())
722                                     addEntry(names[i]);
723                             }
724                         }
725                     }
726                 }
727                 sort();
728             }
729             try {
730                 lockWrite();
731             }
732             catch (InterruptedException JavaDoc e) {
733                 Log.error(e);
734                 return; // Shouldn't happen.
735
}
736             try {
737                 addEntriesToBuffer();
738                 long totalSize = getTotalSize();
739                 if (totalSize > 0) {
740                     int end;
741                     if (usingNativeFormat) {
742                         end = getFileSizeEndOffset();
743                         if (end <= 0)
744                             end = 45;
745                     } else {
746                         int nameOffset = getNameOffset();
747                         end = nameOffset - 19;
748                         if (end <= 0)
749                             end = 13;
750                     }
751                     String JavaDoc s = String.valueOf(totalSize);
752                     int begin = end - s.length();
753                     if (begin < 0)
754                         begin = 0;
755                     FastStringBuffer sb = new FastStringBuffer(80);
756                     sb.append(Utilities.spaces(begin));
757                     for (int i = s.length(); i > 0; i--)
758                         sb.append('-');
759                     appendLine(sb.toString());
760                     sb.setLength(0);
761                     sb.append(Utilities.spaces(begin));
762                     sb.append(s);
763                     appendLine(sb.toString());
764                 }
765                 renumber();
766             }
767             finally {
768                 unlockWrite();
769             }
770         }
771         catch (Exception JavaDoc e) {
772             Log.error(e);
773         }
774     }
775
776     private long getTotalSize()
777     {
778         long totalSize = 0;
779         int endOffset = -1;
780         final int limit = entries.size();
781         for (int i = 0; i < limit; i++) {
782             DirectoryEntry entry = (DirectoryEntry) entries.get(i);
783             long size = entry.getSize();
784             if (size >= 0) {
785                 totalSize += size;
786                 continue;
787             }
788             String JavaDoc text = entry.getString();
789             if (endOffset < 0) {
790                 REMatch match = nativeMoveToFilenameRegExp.getMatch(text);
791                 if (match != null) {
792                     // The file size is followed by a single space.
793
endOffset = text.indexOf(' ', match.getStartIndex());
794                 }
795                 if (endOffset < 0)
796                     endOffset = 42;
797             }
798             if (endOffset < text.length()) {
799                 int end;
800                 if (text.charAt(endOffset) == ' ') {
801                     // Expected.
802
end = endOffset;
803                 } else {
804                     // Encountered unexpected char at endOffset.
805
REMatch match = nativeMoveToFilenameRegExp.getMatch(text);
806                     if (match == null)
807                         return totalSize = -1;
808                     end = text.indexOf(' ', match.getStartIndex());
809                     if (end < endOffset) {
810                         // Correct anomaly.
811
endOffset = end;
812                         Log.debug("endOffset = " + endOffset);
813                     }
814                 }
815                 int begin = text.lastIndexOf(' ', end - 1);
816                 if (begin < 0)
817                     return -1;
818                 try {
819                     size = Long.parseLong(text.substring(begin + 1, end));
820                     entry.setSize(size);
821                     totalSize += size;
822                 }
823                 catch (NumberFormatException JavaDoc e) {
824                     Log.error(e);
825                     return -1;
826                 }
827             } else
828                 return -1; // Shouldn't happen.
829
}
830         return totalSize;
831     }
832
833     public int load()
834     {
835         if (!isLoaded()) {
836             final Editor editor = Editor.currentEditor();
837             String JavaDoc reading = "Reading directory...";
838             if (editor != null)
839                 editor.status(reading);
840             loadInternal();
841             if (editor != null)
842                 editor.status(reading + "done");
843         }
844         return LOAD_COMPLETED;
845     }
846
847     public void tagFileAtDot()
848     {
849         final Editor editor = Editor.currentEditor();
850         Line line = editor.getDotLine();
851         if (!(line instanceof DirectoryLine))
852             return;
853         String JavaDoc name = getName(line);
854         if (name == null)
855             return;
856         if (name.equals("."))
857             return;
858         if (name.equals(".."))
859             return;
860         DirectoryEntry de = null;
861         if (usingNativeFormat) {
862             // Text of line has "T " or " " prepended to DirectoryEntry string.
863
de = findNativeEntry(line.substring(2));
864         } else {
865             de = findEntry(name);
866         }
867         if (de != null) {
868             if (de.isMarked()) {
869                 de.setMarked(false);
870                 --numMarked;
871             } else {
872                 de.setMarked(true);
873                 ++numMarked;
874             }
875             line.setText(de.toString());
876             editor.update(line);
877             editor.down();
878             resetUndo();
879         }
880     }
881
882     public void upDir()
883     {
884         final Editor editor = Editor.currentEditor();
885         editor.setWaitCursor();
886         final File parent = getFile().getParentFile();
887         if (parent == null)
888             return;
889         history.truncate();
890         history.append(getFile(), getName(editor.getDotLine()), editor.getDotOffset());
891         history.reset();
892         String JavaDoc name = getFile().getName();
893         setFile(parent);
894         reload();
895         Line line = findName(name);
896         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
897             Editor ed = it.nextEditor();
898             if (ed.getBuffer() == this) {
899                 if (line != null)
900                     ed.setDot(line, getNameOffset(line));
901                 else
902                     ed.setDot(getFirstLine(), getNameOffset(getFirstLine()));
903                 ed.moveCaretToDotCol();
904             }
905         }
906         Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
907     }
908
909     public String JavaDoc getPathAtDot()
910     {
911         Editor editor = Editor.currentEditor();
912         if (!(editor.getDotLine() instanceof DirectoryLine))
913             return null;
914         String JavaDoc name = getName(editor.getDotLine());
915         if (name == null)
916             return null;
917         final File dir = getFile();
918         if (name.equals("."))
919             return dir.netPath();
920         if (name.equals("..")) {
921             File parent = dir.getParentFile();
922             if (parent == null)
923                 return null;
924             else
925                 return parent.netPath();
926         }
927         File file = File.getInstance(dir, name);
928         if (file == null)
929             return null;
930         else
931             return file.netPath();
932     }
933
934     public static void dir()
935     {
936         final Editor editor = Editor.currentEditor();
937         final Buffer buffer = editor.getBuffer();
938         if (buffer instanceof Directory)
939             return;
940         File directory = editor.getCurrentDirectory();
941         if (directory == null)
942             return;
943         if (directory.getProtocol() == File.PROTOCOL_HTTP)
944             return;
945         // FTP, SSH or local.
946
Buffer buf = Editor.getBuffer(directory);
947         // buf may be a RemoteBuffer and not specifically a Directory.
948
if (buf != null) {
949             File file = buffer.getFile();
950             editor.makeNext(buf);
951             editor.switchToBuffer(buf);
952             if (buf instanceof Directory && file != null) {
953                 Directory dir = (Directory) buf;
954                 Line line = dir.findName(file.getName());
955                 if (line != null) {
956                     editor.setDot(new Position(line, dir.getNameOffset(line)));
957                     editor.setUpdateFlag(REFRAME);
958                     editor.reframe();
959                 }
960             }
961         }
962     }
963
964     public static void dirOpenFile()
965     {
966         _dirOpenFile(false);
967     }
968
969     public static void dirOpenFileAndKillDirectory()
970     {
971         _dirOpenFile(true);
972     }
973
974     private static void _dirOpenFile(boolean killDirectory)
975     {
976         final Editor editor = Editor.currentEditor();
977         final Buffer buffer = editor.getBuffer();
978         if (buffer instanceof Directory) {
979             // If this method is invoked via a mouse event mapping, move dot to
980
// location of mouse click first.
981
AWTEvent JavaDoc e = editor.getDispatcher().getLastEvent();
982             if (e instanceof MouseEvent JavaDoc)
983                 editor.mouseMoveDotToPoint((MouseEvent JavaDoc) e);
984             ((Directory)buffer).openFileAtDot(killDirectory);
985         }
986     }
987
988     private synchronized void openFileAtDot(boolean killDirectory)
989     {
990         final Editor editor = Editor.currentEditor();
991         editor.setWaitCursor();
992         if (!(editor.getDotLine() instanceof DirectoryLine))
993             return;
994         String JavaDoc name = getName(editor.getDotLine());
995         if (name == null)
996             return;
997         if (name.equals("."))
998             return;
999         if (name.equals("..")) {
1000            upDir();
1001            return;
1002        }
1003        final File dir = getFile();
1004        if (dir.isRemote()) {
1005            String JavaDoc fullpath = dir.canonicalPath();
1006            if (!fullpath.endsWith("/"))
1007                fullpath += "/";
1008            fullpath += name;
1009            File newFile = File.getInstance(dir, fullpath);
1010            Buffer buf = Editor.getBufferList().findBuffer(newFile);
1011            if (buf != null) {
1012                editor.makeNext(buf);
1013                editor.activate(buf);
1014                return;
1015            }
1016            DirectoryLine line = (DirectoryLine) editor.getDotLine();
1017            DirectoryEntry de = line.getDirectoryEntry();
1018            boolean isDirectory = false;
1019            if (de.isDirectory())
1020                isDirectory = true;
1021            else if (de.isLink())
1022                isDirectory = newFile.isDirectory();
1023            if (isDirectory) {
1024                setBusy(true);
1025                history.truncate();
1026                history.append(dir, getName(editor.getDotLine()),
1027                    editor.getDotOffset());
1028                history.reset();
1029                empty();
1030                entries.clear();
1031                numMarked = 0;
1032                setListing(null);
1033                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1034                    Editor ed = it.nextEditor();
1035                    if (ed.getBuffer() == this) {
1036                        ed.setTopLine(null);
1037                        ed.setDot(null);
1038                        ed.setMark(null);
1039                    }
1040                }
1041                setFile(newFile);
1042                Runnable JavaDoc reloadRunnable = new Runnable JavaDoc() {
1043                    public void run()
1044                    {
1045                        load();
1046                        Runnable JavaDoc updateRunnable = new Runnable JavaDoc() {
1047                            public void run()
1048                            {
1049                                setBusy(false);
1050                                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1051                                    Editor ed = it.nextEditor();
1052                                    if (ed.getBuffer() == Directory.this) {
1053                                        ed.setTopLine(getFirstLine());
1054                                        ed.setDot(getInitialDotPos());
1055                                        ed.setMark(null);
1056                                        ed.moveCaretToDotCol();
1057                                        ed.setUpdateFlag(REPAINT);
1058                                        ed.updateDisplay();
1059                                        ed.updateLocation();
1060                                    }
1061                                }
1062                                Sidebar.setUpdateFlagInAllFrames(SIDEBAR_ALL);
1063                            }
1064                        };
1065                        SwingUtilities.invokeLater(updateRunnable);
1066                    }
1067                };
1068                new Thread JavaDoc(reloadRunnable).start();
1069            } else {
1070                // Not a directory.
1071
if (newFile instanceof FtpFile)
1072                    buf = new RemoteBuffer((FtpFile) newFile,
1073                        FtpSession.getSession((FtpFile) newFile));
1074                else if (newFile instanceof SshFile)
1075                    buf = new RemoteBuffer(newFile);
1076                else
1077                    Debug.assertTrue(false);
1078                editor.makeNext(buf);
1079                editor.activate(buf);
1080            }
1081            return;
1082        }
1083
1084        // Local file.
1085
File f = File.getInstance(getFile(), name);
1086        if (!f.exists()) {
1087            editor.status("File not found");
1088            return;
1089        }
1090        if (f.isDirectory()) {
1091            changeDirectory(f);
1092            return;
1093        }
1094        Buffer buf = editor.getBuffer(f);
1095        if (buf != null) {
1096            editor.makeNext(buf);
1097            editor.activate(buf);
1098        }
1099        if (killDirectory)
1100            kill();
1101    }
1102
1103    public synchronized void changeDirectory(File f)
1104    {
1105        if (f.isDirectory()) {
1106            final Editor editor = Editor.currentEditor();
1107            if (f.isLocal() && !f.canRead()) {
1108                showMessageDialog("Directory is not readable");
1109                return;
1110            }
1111            final String JavaDoc name;
1112            final int offset;
1113            if (editor.getDot() != null) {
1114                name = getName(editor.getDotLine());
1115                offset = editor.getDotOffset();
1116            } else {
1117                name = null;
1118                offset = 0;
1119            }
1120            history.truncate();
1121            history.append(getFile(), name, offset);
1122            history.reset();
1123            empty();
1124            entries.clear();
1125            numMarked = 0;
1126            setListing(null);
1127            setFile(f);
1128            load();
1129            for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1130                Editor ed = it.nextEditor();
1131                if (ed.getBuffer() == this) {
1132                    ed.setTopLine(getFirstLine());
1133                    ed.setDot(getInitialDotPos());
1134                    ed.setMark(null);
1135                    ed.moveCaretToDotCol();
1136                    ed.setUpdateFlag(REPAINT);
1137                    ed.updateLocation();
1138                }
1139            }
1140            Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
1141        }
1142    }
1143
1144    // No history.
1145
private synchronized void changeDirectory(DirectoryHistoryEntry entry)
1146    {
1147        empty();
1148        entries.clear();
1149        numMarked = 0;
1150        setListing(null);
1151        setFile(entry.file);
1152        load();
1153        Line line = findName(entry.name);
1154        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1155            Editor ed = it.nextEditor();
1156            if (ed.getBuffer() == this) {
1157                ed.getDisplay().setTopLine(getFirstLine());
1158                ed.setUpdateFlag(REPAINT);
1159                if (line != null)
1160                    ed.setDot(line, entry.offset);
1161                else
1162                    ed.setDot(getFirstLine(), getNameOffset(getFirstLine()));
1163                ed.setMark(null);
1164                ed.moveCaretToDotCol();
1165                ed.updateLocation();
1166            }
1167        }
1168        Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
1169    }
1170
1171    public static void dirBack()
1172    {
1173        final Editor editor = Editor.currentEditor();
1174        final Buffer buffer = editor.getBuffer();
1175        if (buffer instanceof Directory) {
1176            editor.setWaitCursor();
1177            ((Directory)buffer).back(editor);
1178            editor.setDefaultCursor();
1179        }
1180    }
1181
1182    private void back(Editor editor)
1183    {
1184        boolean atEnd = history.atEnd();
1185        DirectoryHistoryEntry entry = history.getPrevious();
1186        if (entry != null) {
1187            if (atEnd) {
1188                String JavaDoc name = getName(editor.getDotLine());
1189                int offset = editor.getDotOffset();
1190                history.append(getFile(), name, offset);
1191            }
1192            changeDirectory(entry);
1193        } else
1194            editor.status("Can't go back");
1195    }
1196
1197    public static void dirForward()
1198    {
1199        final Editor editor = Editor.currentEditor();
1200        final Buffer buffer = editor.getBuffer();
1201        if (buffer instanceof Directory) {
1202            editor.setWaitCursor();
1203            ((Directory)buffer).forward(editor);
1204            editor.setDefaultCursor();
1205        }
1206    }
1207
1208    private void forward(Editor editor)
1209    {
1210        DirectoryHistoryEntry entry = history.getNext();
1211        if (entry != null)
1212            changeDirectory(entry);
1213        else
1214            editor.status("Can't go forward");
1215    }
1216
1217    public void browseFileAtDot()
1218    {
1219        Editor editor = Editor.currentEditor();
1220        String JavaDoc name = getName(editor.getDotLine());
1221        if (name == null)
1222            return;
1223        File f = File.getInstance(getFile(), name);
1224        if (!f.exists()) {
1225            editor.status("File not found");
1226            return;
1227        }
1228        if (f.isFile()) {
1229            String JavaDoc browser = preferences.getStringProperty(Property.BROWSER);
1230            if (browser == null || browser.equals("j")) {
1231                WebBuffer.browse(editor, f, null);
1232                return;
1233            }
1234            // Use external browser.
1235
try {
1236                String JavaDoc url = "file://".concat(f.canonicalPath());
1237                String JavaDoc browserOpts =
1238                    preferences.getStringProperty(Property.BROWSER_OPTS);
1239                if (browserOpts != null) {
1240                    String JavaDoc[] cmdarray = {browser, browserOpts, url};
1241                    Process JavaDoc process = Runtime.getRuntime().exec(cmdarray);
1242                } else {
1243                    String JavaDoc[] cmdarray = {browser, url};
1244                    Process JavaDoc process = Runtime.getRuntime().exec(cmdarray);
1245                }
1246            }
1247            catch (Exception JavaDoc e) {
1248                Log.error(e);
1249            }
1250        }
1251    }
1252
1253    public void deleteFiles()
1254    {
1255        if (numMarked > 0)
1256            deleteMarkedFiles();
1257        else
1258            deleteFileAtDot();
1259    }
1260
1261    private void showMessageDialog(String JavaDoc message)
1262    {
1263        MessageDialog.showMessageDialog(message, "Error");
1264    }
1265
1266    private synchronized void deleteMarkedFiles()
1267    {
1268        if (numMarked == 0)
1269            return;
1270        Debug.assertTrue(numMarked > 0);
1271        String JavaDoc message = null;
1272        final Editor editor = Editor.currentEditor();
1273        if (numMarked > 1)
1274            message = "Delete " + numMarked + " tagged files?";
1275        else
1276            message = "Delete 1 tagged file?";
1277        boolean confirmed = editor.confirm("Delete Files", message);
1278        if (!confirmed)
1279            return;
1280        boolean directoryWasDeleted = false;
1281        FtpSession session = null;
1282        for (int i = 0; i < entries.size(); i++) {
1283            DirectoryEntry entry = (DirectoryEntry) entries.get(i);
1284            if (!entry.isMarked())
1285                continue;
1286            String JavaDoc name = entry.extractName();
1287            if (name == null) {
1288                // Shouldn't happen.
1289
Debug.assertTrue(false);
1290                continue;
1291            }
1292            File file = File.getInstance(getFile(), name);
1293            if (!file.isRemote() && !file.exists()) {
1294                showMessageDialog(file.canonicalPath() + " not found");
1295                return;
1296            }
1297            String JavaDoc displayName = file.canonicalPath();
1298            boolean isDirectory;
1299            if (file.isRemote()) {
1300                displayName += " on " + file.getHostName();
1301                isDirectory = entry.isDirectory();
1302            }
1303            else
1304                isDirectory = file.isDirectory();
1305            boolean succeeded = false;
1306            if (file instanceof FtpFile) {
1307                if (session == null)
1308                    session = FtpSession.getSession((FtpFile)file);
1309                if (session != null) {
1310                    if (isDirectory)
1311                        succeeded = session.removeDirectory(file.canonicalPath());
1312                    else
1313                        succeeded = session.deleteFile(file.canonicalPath());
1314                }
1315            } else {
1316                // Local file.
1317
// Delete the file on disk.
1318
file.delete();
1319
1320                // Did it work?
1321
succeeded = !file.exists();
1322            }
1323            if (succeeded) {
1324                if (isDirectory)
1325                    directoryWasDeleted = true;
1326            } else {
1327                // Deletion failed.
1328
if (isDirectory) {
1329                    confirmed = editor.confirm("Delete Files",
1330                        "Unable to remove directory " + displayName + ". Continue?");
1331                } else {
1332                    confirmed = editor.confirm("Delete Files",
1333                        "Unable to delete " + displayName + ". Continue?");
1334                }
1335                if (!confirmed)
1336                    break;
1337            }
1338        }
1339        if (session != null)
1340            session.unlock();
1341        if (directoryWasDeleted) {
1342            rescan();
1343        } else {
1344            if (getFile().isRemote())
1345                DirectoryCache.getDirectoryCache().purge(getFile());
1346            reload();
1347        }
1348    }
1349
1350    private void deleteFileAtDot()
1351    {
1352        final Editor editor = Editor.currentEditor();
1353        String JavaDoc name = getName(editor.getDotLine());
1354        if (name == null)
1355            return;
1356        if (name.equals("."))
1357            return;
1358        if (name.equals(".."))
1359            return;
1360        File file = File.getInstance(getFile(), name);
1361        if (!file.isRemote() && !file.exists()) {
1362            showMessageDialog("File not found");
1363            return;
1364        }
1365        String JavaDoc displayName = file.getName();
1366        final boolean isDirectory;
1367        if (file.isRemote()) {
1368            displayName += " on " + file.getHostName();
1369            isDirectory = editor.getDotLine().getText().trim().startsWith("d");
1370        } else
1371            isDirectory = file.isDirectory();
1372        final String JavaDoc title, prompt;
1373        if (isDirectory) {
1374            title = "Remove Directory";
1375            prompt = "Remove directory " + displayName + "?";
1376        } else {
1377            title = "Delete File";
1378            prompt = "Delete " + displayName + "?";
1379        }
1380        if (!editor.confirm(title, prompt))
1381            return;
1382        boolean succeeded = false;
1383        editor.setWaitCursor();
1384        if (file instanceof FtpFile) {
1385            FtpSession session = FtpSession.getSession((FtpFile) file);
1386            if (session != null) {
1387                if (isDirectory)
1388                    succeeded = session.removeDirectory(file.canonicalPath());
1389                else
1390                    succeeded = session.deleteFile(file.canonicalPath());
1391                session.unlock();
1392            }
1393        } else {
1394            // Local file.
1395
file.delete();
1396            succeeded = !file.exists();
1397        }
1398        if (succeeded) {
1399            if (isDirectory) {
1400                rescan();
1401            } else {
1402                if (getFile().isRemote())
1403                    DirectoryCache.getDirectoryCache().purge(getFile());
1404                reload();
1405            }
1406        }
1407        editor.setDefaultCursor();
1408        if (!succeeded) {
1409            if (isDirectory)
1410                showMessageDialog("Unable to remove directory " + displayName);
1411            else
1412                showMessageDialog("Unable to delete " + displayName);
1413        }
1414    }
1415
1416    public static void dirDoShellCommand()
1417    {
1418        if (!Editor.checkExperimental())
1419            return;
1420        if (!Platform.isPlatformUnix())
1421            return;
1422        final Editor editor = Editor.currentEditor();
1423        final Buffer buffer = editor.getBuffer();
1424        if (buffer instanceof Directory) {
1425            if (buffer.getFile().isRemote()) {
1426                MessageDialog.showMessageDialog(editor,
1427                    "Shell commands are not supported in remote directory buffers.",
1428                    "Error");
1429                return;
1430            }
1431            ((Directory)buffer).doShellCommand(editor);
1432        }
1433    }
1434
1435    private void doShellCommand(Editor editor)
1436    {
1437        List JavaDoc names = getMarkedNames();
1438        if (names == null) {
1439            names = new ArrayList JavaDoc();
1440            names.add(getName(editor.getDotLine()));
1441        }
1442        String JavaDoc prompt = null;
1443        if (names.size() == 1)
1444            prompt = "Command (on " + (String JavaDoc) names.get(0) + "):";
1445        else if (names.size() > 1)
1446            prompt = "Command (on " + names.size() + " tagged files):";
1447        else
1448            prompt = "Command:";
1449        InputDialog d = new InputDialog(editor, prompt, "Shell Command", null);
1450        d.setHistory(new History("dirDoShellCommand.command"));
1451        editor.centerDialog(d);
1452        d.show();
1453        String JavaDoc command = d.getInput();
1454        if (command == null)
1455            return;
1456        command = command.trim();
1457        if (command.length() == 0)
1458            return;
1459        editor.setWaitCursor();
1460        editor.repaintNow();
1461        String JavaDoc output = null;
1462        if (names != null) {
1463            if (command.indexOf('*') >= 0) {
1464                output = doCommandOnMultipleFiles(command, names);
1465            } else {
1466                FastStringBuffer sb = new FastStringBuffer();
1467                for (int i = 0; i < names.size(); i++) {
1468                    String JavaDoc filename = (String JavaDoc) names.get(i);
1469                    String JavaDoc s = doCommandOnFile(command, filename);
1470                    if (s != null && s.length() > 0)
1471                        sb.append(s);
1472                }
1473                output = sb.toString();
1474            }
1475        }
1476        reload();
1477        if (output != null && output.length() > 0) {
1478            OutputBuffer buf = OutputBuffer.getOutputBuffer(output);
1479            if (buf != null) {
1480                buf.setTitle(command);
1481                editor.makeNext(buf);
1482                editor.displayInOtherWindow(buf);
1483            }
1484        }
1485        editor.setDefaultCursor();
1486    }
1487
1488    private String JavaDoc doCommandOnFile(String JavaDoc command, String JavaDoc filename)
1489    {
1490        FastStringBuffer sb = new FastStringBuffer(command);
1491        sb.append(' ');
1492        if (filename.indexOf(' ') >= 0) {
1493            sb.append('"');
1494            sb.append(filename);
1495            sb.append('"');
1496        } else
1497            sb.append(filename);
1498        ShellCommand shellCommand = new ShellCommand(sb.toString(), getFile());
1499        shellCommand.run();
1500        return shellCommand.getOutput();
1501    }
1502
1503    private String JavaDoc doCommandOnMultipleFiles(String JavaDoc command, List JavaDoc files)
1504    {
1505        if (files.size() < 1)
1506            return null;
1507        String JavaDoc before, after;
1508        int index = command.indexOf('*');
1509        if (index >= 0) {
1510            before = command.substring(0, index).trim();
1511            after = command.substring(index + 1).trim();
1512        } else {
1513            before = command.trim();
1514            after = "";
1515        }
1516        if (before.length() == 0) {
1517            showMessageDialog("No command specified");
1518            return null;
1519        }
1520        FastStringBuffer sb = new FastStringBuffer(before);
1521        for (int i = 0; i < files.size(); i++) {
1522            sb.append(' ');
1523            String JavaDoc filename = (String JavaDoc) files.get(i);
1524            if (filename.indexOf(' ') >= 0) {
1525                sb.append('"');
1526                sb.append(filename);
1527                sb.append('"');
1528            } else
1529                sb.append(filename);
1530        }
1531        if (after.length() > 0) {
1532            sb.append(' ');
1533            sb.append(after);
1534        }
1535        ShellCommand shellCommand = new ShellCommand(sb.toString(), getFile());
1536        shellCommand.run();
1537        return shellCommand.getOutput();
1538    }
1539
1540    private synchronized List JavaDoc getMarkedNames()
1541    {
1542        if (numMarked > 0) {
1543            ArrayList JavaDoc names = new ArrayList JavaDoc(numMarked);
1544            final int size = entries.size();
1545            for (int i = 0; i < size; i++) {
1546                DirectoryEntry de = (DirectoryEntry) entries.get(i);
1547                if (de.isMarked()) {
1548                    String JavaDoc name = de.extractName();
1549                    if (name != null)
1550                        names.add(name);
1551                }
1552            }
1553            return names;
1554        }
1555        return null;
1556    }
1557
1558    public void copyFileAtDot()
1559    {
1560        copyFiles();
1561    }
1562
1563    public void moveFileAtDot()
1564    {
1565        moveFiles();
1566    }
1567
1568    private List JavaDoc getSourceFiles(Editor editor)
1569    {
1570        ArrayList JavaDoc sources = new ArrayList JavaDoc();
1571        if (numMarked > 0) {
1572            List JavaDoc names = getMarkedNames();
1573            for (int i = 0; i < names.size(); i++) {
1574                String JavaDoc name = (String JavaDoc) names.get(i);
1575                if (name != null)
1576                    sources.add(File.getInstance(getFile(), name));
1577            }
1578        } else if (editor.getDotLine() instanceof DirectoryLine) {
1579            String JavaDoc name = getName(editor.getDotLine());
1580            if (name != null)
1581                sources.add(File.getInstance(getFile(), name));
1582        }
1583        return sources;
1584    }
1585
1586    private File getDestinationForCopy(Editor editor, List JavaDoc sources)
1587    {
1588        return getDestination(editor, sources, "Copy");
1589    }
1590
1591    private File getDestinationForMove(Editor editor, List JavaDoc sources)
1592    {
1593        return getDestination(editor, sources, "Move");
1594    }
1595
1596    private File getDestination(Editor editor, List JavaDoc sources, String JavaDoc operation)
1597    {
1598        String JavaDoc title = operation + " File";
1599        String JavaDoc prompt = operation + " ";
1600        String JavaDoc name = null;
1601        if (sources.size() == 1) {
1602            File source = (File) sources.get(0);
1603            name = source.getName();
1604            prompt += name;
1605        } else
1606            prompt += String.valueOf(sources.size()) + " tagged files";
1607        prompt += " to: ";
1608        CopyFileDialog d = new CopyFileDialog(editor, title, prompt, name);
1609        editor.centerDialog(d);
1610        d.show();
1611        editor.repaintNow();
1612        return d.getDestination();
1613    }
1614
1615    private void copyFiles()
1616    {
1617        final Editor editor = Editor.currentEditor();
1618        List JavaDoc sources = getSourceFiles(editor);
1619        File destination = getDestinationForCopy(editor, sources);
1620        if (destination == null)
1621            return;
1622        final String JavaDoc title = "Copy Files";
1623        if (destination.isLocal())
1624            copyLocalToLocal(sources, destination, editor, title);
1625        else
1626            MessageDialog.showMessageDialog(editor, "Destination must be local!", title);
1627    }
1628
1629    private void copyLocalToLocal(List JavaDoc sources, File destination, Editor editor, String JavaDoc title)
1630    {
1631        int numFilesCopied = 0;
1632        boolean mustConfirm = true;
1633        boolean cancelled = false;
1634        final int limit = sources.size();
1635        File destDir = destination.isDirectory() ? destination : destination.getParentFile();
1636        for (int i = 0; i < limit; i++) {
1637            File from = (File) sources.get(i);
1638            File to;
1639            if (destination.isDirectory())
1640                to = File.getInstance(destination, from.getName());
1641            else
1642                to = destination;
1643            if (mustConfirm && to.isFile()) {
1644                String JavaDoc message = "Overwrite existing file " + to.canonicalPath() + "?";
1645                if (i < limit-1) {
1646                    // More than one file is left. Provide "Yes To All" and
1647
// "Cancel" buttons.
1648
int response = editor.confirmAll(title, message);
1649                    switch (response) {
1650                        case RESPONSE_YES:
1651                            break;
1652                        case RESPONSE_NO:
1653                            continue;
1654                        case RESPONSE_YES_TO_ALL:
1655                            mustConfirm = false;
1656                            break;
1657                        case RESPONSE_CANCEL:
1658                            cancelled = true;
1659                            break;
1660                        default:
1661                            break;
1662                    }
1663                    if (cancelled)
1664                        break;
1665                } else if (!editor.confirm(title, message)) {
1666                    // Last file (or only file).
1667
break;
1668                }
1669            }
1670            if (Utilities.copyFile(from, to)) {
1671                ++numFilesCopied;
1672            } else {
1673                String JavaDoc text = "Unable to copy " + from.getName() + " to " + to.canonicalPath() + ".";
1674                if (i < limit-1) {
1675                    text += " Continue?";
1676                    if (!editor.confirm(title, text))
1677                        break;
1678                } else
1679                    MessageDialog.showMessageDialog(editor, text, title);
1680            }
1681        }
1682        String JavaDoc statusText = String.valueOf(numFilesCopied) + " file";
1683        if (numFilesCopied > 1)
1684            statusText += 's';
1685        statusText += " copied";
1686        editor.status(statusText);
1687        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1688            Editor ed = it.nextEditor();
1689            if (destDir.equals(ed.getBuffer().getFile())) {
1690                ((Directory)ed.getBuffer()).reload();
1691                if (ed != Editor.currentEditor())
1692                    ed.updateDisplay();
1693            }
1694        }
1695    }
1696
1697    private void moveFiles()
1698    {
1699        final Editor editor = Editor.currentEditor();
1700        List JavaDoc sources = getSourceFiles(editor);
1701        File destination = getDestinationForMove(editor, sources);
1702        if (destination == null)
1703            return;
1704        Log.debug("ready to move");
1705        if (destination.isRemote()) {
1706            MessageDialog.showMessageDialog(editor,
1707                "Destination must be local!", "Move Files");
1708            return;
1709        }
1710        final int count = sources.size();
1711        for (int i = 0; i < count; i++) {
1712            File source = (File) sources.get(i);
1713
1714            // Move.
1715
boolean success = source.renameTo(destination);
1716
1717            if (!success) {
1718                Log.warn("renameTo failed; trying copyFile...");
1719                success = Utilities.copyFile(source, destination);
1720                if (success) {
1721                    Log.debug("copyFile succeeded, deleting source...");
1722                    source.delete();
1723                    success = !source.exists();
1724                }
1725                else
1726                    Log.error("copyFile failed");
1727            }
1728            else
1729                Log.debug("renameTo succeeded");
1730
1731            if (success) {
1732                // Change file information for any buffers (there should only
1733
// be one!) associated with moved file.
1734
for (BufferIterator it = new BufferIterator(); it.hasNext();) {
1735                    Buffer buf = it.nextBuffer();
1736                    if (source.equals(buf.getFile()))
1737                        buf.changeFile(destination);
1738                }
1739            } else {
1740                MessageDialog.showMessageDialog(editor, "Move failed", "Error");
1741                break;
1742            }
1743        }
1744
1745        // Current directory may have changed.
1746
reload();
1747    }
1748
1749    public void getFileAtDot()
1750    {
1751        final Editor editor = Editor.currentEditor();
1752        final Line dotLine = editor.getDotLine();
1753        final String JavaDoc name = getName(dotLine);
1754        if (name == null)
1755            return;
1756
1757        final FtpFile sourceFile = (FtpFile) File.getInstance(getFile(), name);
1758        if (sourceFile == null)
1759            return;
1760
1761        int status = -1;
1762
1763        // We'll get in trouble here if the directory format changes.
1764
if (editor.getDotLine().length() >= 3) {
1765            char c = dotLine.charAt(2);
1766            if (c == 'd') {
1767                status = 2; // Directory.
1768
} else if (c == '-') {
1769                status = 1; // Normal file.
1770
}
1771        }
1772
1773        if (status == -1) {
1774            // Symbolic link.
1775
MessageDialog.showMessageDialog("Unknown file type", "Get File");
1776            return;
1777        }
1778        if (status == 2) {
1779            MessageDialog.showMessageDialog(
1780                sourceFile.canonicalPath() + " is a directory",
1781                "Get File");
1782            return;
1783        }
1784        if (status != 1) {
1785            MessageDialog.showMessageDialog("File not found", "Get File");
1786            return;
1787        }
1788
1789        CopyFileDialog d = new CopyFileDialog(editor, "Get File", "Destination:", name);
1790        d.setConfirmOverwrite(true);
1791        editor.centerDialog(d);
1792        d.show();
1793        final File destination = d.getDestination();
1794        editor.repaintNow();
1795        if (destination == null)
1796            return;
1797        if (destination.isRemote()) {
1798            MessageDialog.showMessageDialog(editor, "Destination must be local!", title);
1799            return;
1800        }
1801        final File destinationFile = destination.isDirectory() ? File.getInstance(destination, name) : destination;
1802        final FtpSession session = FtpSession.getSession((FtpFile)getFile());
1803        if (session == null)
1804            return;
1805        final long fileSize = getFileSize(dotLine.getText());
1806        final FtpLoadProcess loadProcess = new FtpLoadProcess(this, sourceFile, session);
1807        final Runnable JavaDoc successRunnable = new Runnable JavaDoc() {
1808            public void run()
1809            {
1810                File cache = loadProcess.getCache();
1811                if (cache != null)
1812                    Utilities.deleteRename(cache, destination);
1813                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1814                    Editor ed = it.nextEditor();
1815                    if (ed.getBuffer() == Directory.this)
1816                        ed.setDefaultCursor();
1817                }
1818            }
1819        };
1820        final ErrorRunnable errorRunnable = new ErrorRunnable("Operation failed") {
1821            public void run()
1822            {
1823                File cache = loadProcess.getCache();
1824                if (cache != null && cache.isFile())
1825                    cache.delete();
1826                for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1827                    Editor ed = it.nextEditor();
1828                    if (ed.getBuffer() == Directory.this)
1829                        ed.setDefaultCursor();
1830                }
1831                String JavaDoc text = session.getErrorText();
1832                if (text == null || text.length() == 0)
1833                    text = "Unable to retrieve " + name;
1834                MessageDialog.showMessageDialog(text, "Error");
1835            }
1836        };
1837        loadProcess.setSuccessRunnable(successRunnable);
1838        loadProcess.setErrorRunnable(errorRunnable);
1839        loadProcess.setProgressNotifier(new StatusBarProgressNotifier(this));
1840        loadProcess.start();
1841    }
1842
1843    public boolean isModified()
1844    {
1845        return false;
1846    }
1847
1848    public String JavaDoc getTitle()
1849    {
1850        File dir = getFile();
1851        title = dir.canonicalPath();
1852        if (limitPattern != null) {
1853            title += LocalFile.getSeparator();
1854            title += limitPattern;
1855        }
1856        title += " (sorted by ";
1857        if (sortBy == SORT_BY_NAME)
1858            title += "name)";
1859        else if (sortBy == SORT_BY_DATE)
1860            title += "date)";
1861        else if (sortBy == SORT_BY_SIZE)
1862            title += "size)";
1863        if (dir.isRemote())
1864            title += " " + dir.getHostName();
1865        return title;
1866    }
1867
1868    private String JavaDoc getName(Line line)
1869    {
1870        return getName(line.getText());
1871    }
1872
1873    private String JavaDoc getName(String JavaDoc s)
1874    {
1875        // Strip symbolic link (if any) from end of line.
1876
int end = s.indexOf(" ->");
1877
1878        if (end >= 0)
1879            s = s.substring(0, end);
1880
1881        REMatch match;
1882
1883        if (usingNativeFormat)
1884            match = nativeMoveToFilenameRegExp.getMatch(s);
1885        else
1886            match = internalMoveToFilenameRegExp.getMatch(s);
1887
1888        if (match != null)
1889            return s.substring(match.getEndIndex());
1890
1891        return null;
1892    }
1893
1894    private long getFileSize(String JavaDoc s)
1895    {
1896        if (usingNativeFormat) {
1897            try {
1898                REMatch match = nativeMoveToFilenameRegExp.getMatch(s);
1899                if (match != null) {
1900                    String JavaDoc toBeParsed = s.substring(match.getStartIndex());
1901                    int index = toBeParsed.indexOf(' ');
1902                    if (index >= 0) {
1903                        toBeParsed = toBeParsed.substring(0, index);
1904                        return Long.parseLong(toBeParsed);
1905                    }
1906                }
1907            }
1908            catch (Exception JavaDoc e) {
1909                Log.error(e);
1910            }
1911        }
1912        return 0;
1913    }
1914
1915    public void home()
1916    {
1917        final Editor editor = Editor.currentEditor();
1918        if (editor.getDotOffset() == 0)
1919            return;
1920        editor.addUndo(SimpleEdit.MOVE);
1921        editor.beginningOfBlock();
1922        int offset = getNameOffset(editor.getDotLine());
1923
1924        // If we're already at the first character of the name (or to the left
1925
// of it), go to column 0.
1926
if (editor.getDotOffset() <= offset)
1927            offset = 0;
1928
1929        editor.getDot().setOffset(offset);
1930        editor.moveCaretToDotCol();
1931    }
1932
1933    public static void chmod()
1934    {
1935        final Editor editor = Editor.currentEditor();
1936        if (!(editor.getDotLine() instanceof DirectoryLine))
1937            return;
1938        final Buffer buffer = editor.getBuffer();
1939        if (!(buffer instanceof Directory))
1940            return;
1941        final Directory directory = (Directory) buffer;
1942        String JavaDoc name = directory.getName(editor.getDotLine());
1943        if (name == null)
1944            return;
1945        final File file = File.getInstance(directory.getFile(), name);
1946        if (file == null)
1947            return;
1948        // Verify that operation is supported.
1949
if (file.isLocal()) {
1950            if (!Platform.isPlatformUnix())
1951                return;
1952        } else if (file.isRemote()) {
1953            int protocol = file.getProtocol();
1954            if (protocol != File.PROTOCOL_FTP && protocol != File.PROTOCOL_SSH)
1955                return;
1956        }
1957        FastStringBuffer sb = new FastStringBuffer("Change mode of ");
1958        sb.append(file.getName());
1959        sb.append(" to:");
1960        final String JavaDoc input =
1961            InputDialog.showInputDialog(editor, sb.toString(), "Change Mode");
1962        if (input == null || input.length() == 0)
1963            return;
1964        int n = 0;
1965        try {
1966            n = Integer.parseInt(input, 8);
1967        }
1968        catch (NumberFormatException JavaDoc e) {
1969            Log.error(e);
1970        }
1971        if (n == 0) {
1972            MessageDialog.showMessageDialog("Invalid mode string", "Change Mode");
1973            return;
1974        }
1975        final int permissions = n;
1976        if (file.isLocal()) {
1977            editor.setWaitCursor();
1978            file.setPermissions(permissions);
1979            editor.setDefaultCursor();
1980        } else if (file instanceof FtpFile) {
1981            final FtpSession session = FtpSession.getSession((FtpFile)file);
1982            if (session != null) {
1983                final Runnable JavaDoc completionRunnable = new Runnable JavaDoc() {
1984                    public void run()
1985                    {
1986                        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1987                            Editor ed = it.nextEditor();
1988                            if (ed.getBuffer() == directory)
1989                                ed.setDefaultCursor();
1990                        }
1991                    }
1992                };
1993                final Runnable JavaDoc chmodRunnable = new Runnable JavaDoc() {
1994                    public void run()
1995                    {
1996                        directory.setBusy(true);
1997                        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
1998                            Editor ed = it.nextEditor();
1999                            if (ed.getBuffer() == directory)
2000                                ed.setWaitCursor();
2001                        }
2002                        if (session.verifyConnected()) {
2003                            session.chmod((FtpFile)file, permissions);
2004                            session.unlock();
2005                        }
2006                        directory.setBusy(false);
2007                        SwingUtilities.invokeLater(completionRunnable);
2008                    }
2009                };
2010                new Thread JavaDoc(chmodRunnable).start();
2011            }
2012        } else if (file instanceof SshFile) {
2013            final SshSession session = SshSession.getSession((SshFile)file);
2014            if (session != null) {
2015                final Runnable JavaDoc completionRunnable = new Runnable JavaDoc() {
2016                    public void run()
2017                    {
2018                        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
2019                            Editor ed = it.nextEditor();
2020                            if (ed.getBuffer() == directory)
2021                                ed.setDefaultCursor();
2022                        }
2023                    }
2024                };
2025                final Runnable JavaDoc chmodRunnable = new Runnable JavaDoc() {
2026                    public void run()
2027                    {
2028                        directory.setBusy(true);
2029                        for (EditorIterator it = new EditorIterator(); it.hasNext();) {
2030                            Editor ed = it.nextEditor();
2031                            if (ed.getBuffer() == directory)
2032                                ed.setWaitCursor();
2033                        }
2034                        if (session.connect()) {
2035                            session.chmod((SshFile)file, permissions);
2036                            session.unlock();
2037                        }
2038                        directory.setBusy(false);
2039                        SwingUtilities.invokeLater(completionRunnable);
2040                    }
2041                };
2042                new Thread JavaDoc(chmodRunnable).start();
2043            }
2044        }
2045    }
2046
2047    private int getNameOffset(Line line)
2048    {
2049        if (line != null) {
2050            REMatch match;
2051            if (usingNativeFormat)
2052                match = nativeMoveToFilenameRegExp.getMatch(line.getText());
2053            else
2054                match = internalMoveToFilenameRegExp.getMatch(line.getText());
2055            if (match != null)
2056                return match.getEndIndex();
2057        }
2058        return 0;
2059    }
2060
2061    private int getNameOffset()
2062    {
2063        return getNameOffset(getFirstLine());
2064    }
2065
2066    private int getFileSizeEndOffset()
2067    {
2068        Line line = getFirstLine();
2069        if (line != null) {
2070            final String JavaDoc text = line.getText();
2071            REMatch match;
2072            if (usingNativeFormat)
2073                match = nativeMoveToFilenameRegExp.getMatch(text);
2074            else
2075                match = internalMoveToFilenameRegExp.getMatch(text);
2076            if (match != null) {
2077                int start = match.getStartIndex();
2078                // The file size is followed by a single space.
2079
return text.indexOf(' ', start);
2080            }
2081        }
2082        return -1; // Error!
2083
}
2084
2085    private Line findName(String JavaDoc name)
2086    {
2087        if (name != null) {
2088            if (Platform.isPlatformWindows()) {
2089                // Case-insensitive filesystem.
2090
name = name.toLowerCase();
2091                for (Line line = getFirstLine(); line != null; line = line.next()) {
2092                    String JavaDoc text = line.getText().toLowerCase();
2093                    if (text.indexOf(name) >= 0) // Performance!
2094
if (name.equalsIgnoreCase(getName(line)))
2095                            return line;
2096                }
2097            } else {
2098                for (Line line = getFirstLine(); line != null; line = line.next()) {
2099                    if (line.getText().indexOf(name) >= 0) // Performance!
2100
if (name.equals(getName(line)))
2101                            return line;
2102                }
2103            }
2104        }
2105        return null;
2106    }
2107
2108    public final String JavaDoc toString()
2109    {
2110        File file = getFile();
2111        if (file.isRemote()) {
2112            FastStringBuffer sb = new FastStringBuffer(file.canonicalPath());
2113            sb.append(" [");
2114            sb.append(file.netPath());
2115            sb.append(']');
2116            return sb.toString();
2117        }
2118        if (Platform.isPlatformUnix()) {
2119            String JavaDoc userHome = Utilities.getUserHome();
2120            if (userHome != null && userHome.length() > 0) {
2121                String JavaDoc s = file.canonicalPath();
2122                if (s.equals(userHome))
2123                    return "~";
2124                if (s.startsWith(userHome.concat("/")))
2125                    return "~".concat(s.substring(userHome.length()));
2126            }
2127        }
2128        return file.canonicalPath();
2129    }
2130
2131    // For the buffer list.
2132
public final Icon JavaDoc getIcon()
2133    {
2134        return Utilities.getIconFromFile("directory.png");
2135    }
2136}
2137
2138class DirectoryHistory
2139{
2140    private Vector JavaDoc v = new Vector JavaDoc();
2141    private int index = -1;
2142
2143    DirectoryHistory()
2144    {
2145    }
2146
2147    boolean atEnd()
2148    {
2149        return index == -1;
2150    }
2151
2152    void truncate()
2153    {
2154        if (index != -1)
2155            v.setSize(index);
2156    }
2157
2158    void append(File file, String JavaDoc name, int offset)
2159    {
2160        v.add(new DirectoryHistoryEntry(file, name, offset));
2161    }
2162
2163    DirectoryHistoryEntry getPrevious()
2164    {
2165        if (v.size() == 0)
2166            return null;
2167        if (index == -1)
2168            index = v.size();
2169        if (index > 0)
2170            return (DirectoryHistoryEntry) v.get(--index);
2171        return null;
2172    }
2173
2174    DirectoryHistoryEntry getNext()
2175    {
2176        if (v.size() == 0)
2177            return null;
2178        if (index == -1)
2179            return null;
2180        if (index < v.size()-1)
2181            return (DirectoryHistoryEntry) v.get(++index);
2182        return null;
2183    }
2184
2185    public void reset()
2186    {
2187        index = -1;
2188    }
2189}
2190
2191class DirectoryHistoryEntry
2192{
2193    File file;
2194    String JavaDoc name;
2195    int offset;
2196
2197    DirectoryHistoryEntry(File file, String JavaDoc name, int offset)
2198    {
2199        this.file = file;
2200        this.name = name;
2201        this.offset = offset;
2202    }
2203}
2204
Popular Tags