Java/SWT JFace Eclipse/File Browser

Материал из Java эксперт
Перейти к: навигация, поиск

File Viewer example in SWT

   <source lang="java">

import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.text.DateFormat; import java.text.MessageFormat; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Vector; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.events.TreeAdapter; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.program.Program; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.rubo; import org.eclipse.swt.widgets.ruposite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.ProgressBar; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; /**

* File Viewer example
*/

public class SWTFileViewerDemo {

 private final static String DRIVE_A = "a:" + File.separator;
 private final static String DRIVE_B = "b:" + File.separator;
 /* UI elements */
 private Display display;
 private Shell shell;
 private ToolBar toolBar;
 private Label numObjectsLabel;
 private Label diskSpaceLabel;
 private File currentDirectory = null;
 private boolean initial = true;
 /* Drag and drop optimizations */
 private boolean isDragging = false; // if this app is dragging
 private boolean isDropping = false; // if this app is dropping
 private File[] processedDropFiles = null; // so Drag only deletes what it
                       // needs to
 private File[] deferredRefreshFiles = null; // to defer notifyRefreshFiles
                       // while we do DND
 private boolean deferredRefreshRequested = false; // to defer
                           // notifyRefreshFiles
                           // while we do DND
 private ProgressDialog progressDialog = null; // progress dialog for
                         // locally-initiated
                         // operations
 /* Combo view */
 private static final String COMBODATA_ROOTS = "Combo.roots";
 // File[]: Array of files whose paths are currently displayed in the combo
 private static final String COMBODATA_LASTTEXT = "Combo.lastText";
 // String: Previous selection text string
 private Combo combo;
 /* Tree view */
 private IconCache iconCache = new IconCache();
 private static final String TREEITEMDATA_FILE = "TreeItem.file";
 // File: File associated with tree item
 private static final String TREEITEMDATA_IMAGEEXPANDED = "TreeItem.imageExpanded";
 // Image: shown when item is expanded
 private static final String TREEITEMDATA_IMAGECOLLAPSED = "TreeItem.imageCollapsed";
 // Image: shown when item is collapsed
 private static final String TREEITEMDATA_STUB = "TreeItem.stub";
 // Object: if not present or null then the item has not been populated
 private Tree tree;
 private Label treeScopeLabel;
 /* Table view */
 private static final DateFormat dateFormat = DateFormat
     .getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
 private static final String TABLEITEMDATA_FILE = "TableItem.file";
 // File: File associated with table row
 private static final String TABLEDATA_DIR = "Table.dir";
 // File: Currently visible directory
 private static final int[] tableWidths = new int[] { 150, 60, 75, 150 };
 private final String[] tableTitles = new String[] {
     SWTFileViewerDemo.getResourceString("table.Name.title"),
     SWTFileViewerDemo.getResourceString("table.Size.title"),
     SWTFileViewerDemo.getResourceString("table.Type.title"),
     SWTFileViewerDemo.getResourceString("table.Modified.title") };
 private Table table;
 private Label tableContentsOfLabel;
 /* Table update worker */
 // Control data
 private final Object workerLock = new Object();
 // Lock for all worker control data and state
 private volatile Thread workerThread = null;
 // The worker"s thread
 private volatile boolean workerStopped = false;
 // True if the worker must exit on completion of the current cycle
 private volatile boolean workerCancelled = false;
 // True if the worker must cancel its operations prematurely perhaps due to
 // a state update
 // Worker state information -- this is what gets synchronized by an update
 private volatile File workerStateDir = null;
 // State information to use for the next cycle
 private volatile File workerNextDir = null;
 /* Simulate only flag */
 // when true, disables actual filesystem manipulations and outputs results
 // to standard out
 private boolean simulateOnly = true;
 /**
  * Runs main program.
  */
 public static void main(String[] args) {
   Display display = new Display();
   SWTFileViewerDemo application = new SWTFileViewerDemo();
   Shell shell = application.open(display);
   while (!shell.isDisposed()) {
     if (!display.readAndDispatch())
       display.sleep();
   }
   application.close();
   display.dispose();
 }
 /**
  * Opens the main program.
  */
 public Shell open(Display display) {
   // Create the window
   this.display = display;
   iconCache.initResources(display);
   shell = new Shell();
   createShellContents();
   notifyRefreshFiles(null);
   shell.open();
   return shell;
 }
 /**
  * Closes the main program.
  */
 void close() {
   workerStop();
   iconCache.freeResources();
 }
 /**
  * Returns a string from the resource bundle. We don"t want to crash because
  * of a missing String. Returns the key if not found.
  */
 static String getResourceString(String key) {
     return key;
 }
 /**
  * Returns a string from the resource bundle and binds it with the given
  * arguments. If the key is not found, return the key.
  */
 static String getResourceString(String key, Object[] args) {
   try {
     return MessageFormat.format(getResourceString(key), args);
   } catch (MissingResourceException e) {
     return key;
   } catch (NullPointerException e) {
     return "!" + key + "!";
   }
 }
 /**
  * Construct the UI
  * 
  * @param container
  *            the ShellContainer managing the Shell we are rendering inside
  */
 private void createShellContents() {
   shell.setText(getResourceString("Title", new Object[] { "" }));
   shell.setImage(iconCache.stockImages[iconCache.shellIcon]);
   Menu bar = new Menu(shell, SWT.BAR);
   shell.setMenuBar(bar);
   createFileMenu(bar);
   createHelpMenu(bar);
   GridLayout gridLayout = new GridLayout();
   gridLayout.numColumns = 3;
   gridLayout.marginHeight = gridLayout.marginWidth = 0;
   shell.setLayout(gridLayout);
   GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
   gridData.widthHint = 185;
   createComboView(shell, gridData);
   gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
   gridData.horizontalSpan = 2;
   createToolBar(shell, gridData);
   SashForm sashForm = new SashForm(shell, SWT.NONE);
   sashForm.setOrientation(SWT.HORIZONTAL);
   gridData = new GridData(GridData.FILL_HORIZONTAL
       | GridData.FILL_VERTICAL);
   gridData.horizontalSpan = 3;
   sashForm.setLayoutData(gridData);
   createTreeView(sashForm);
   createTableView(sashForm);
   sashForm.setWeights(new int[] { 2, 5 });
   numObjectsLabel = new Label(shell, SWT.BORDER);
   gridData = new GridData(GridData.FILL_HORIZONTAL
       | GridData.VERTICAL_ALIGN_FILL);
   gridData.widthHint = 185;
   numObjectsLabel.setLayoutData(gridData);
   diskSpaceLabel = new Label(shell, SWT.BORDER);
   gridData = new GridData(GridData.FILL_HORIZONTAL
       | GridData.VERTICAL_ALIGN_FILL);
   gridData.horizontalSpan = 2;
   diskSpaceLabel.setLayoutData(gridData);
 }
 /**
  * Creates the File Menu.
  * 
  * @param parent
  *            the parent menu
  */
 private void createFileMenu(Menu parent) {
   Menu menu = new Menu(parent);
   MenuItem header = new MenuItem(parent, SWT.CASCADE);
   header.setText(getResourceString("menu.File.text"));
   header.setMenu(menu);
   final MenuItem simulateItem = new MenuItem(menu, SWT.CHECK);
   simulateItem.setText(getResourceString("menu.File.SimulateOnly.text"));
   simulateItem.setSelection(simulateOnly);
   simulateItem.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       simulateOnly = simulateItem.getSelection();
     }
   });
   MenuItem item = new MenuItem(menu, SWT.PUSH);
   item.setText(getResourceString("menu.File.Close.text"));
   item.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       shell.close();
     }
   });
 }
 /**
  * Creates the Help Menu.
  * 
  * @param parent
  *            the parent menu
  */
 private void createHelpMenu(Menu parent) {
   Menu menu = new Menu(parent);
   MenuItem header = new MenuItem(parent, SWT.CASCADE);
   header.setText(getResourceString("menu.Help.text"));
   header.setMenu(menu);
   MenuItem item = new MenuItem(menu, SWT.PUSH);
   item.setText(getResourceString("menu.Help.About.text"));
   item.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       MessageBox box = new MessageBox(shell, SWT.ICON_INFORMATION
           | SWT.OK);
       box.setText(getResourceString("dialog.About.title"));
       box.setMessage(getResourceString("dialog.About.description",
           new Object[] { System.getProperty("os.name") }));
       box.open();
     }
   });
 }
 /**
  * Creates the toolbar
  * 
  * @param shell
  *            the shell on which to attach the toolbar
  * @param layoutData
  *            the layout data
  */
 private void createToolBar(final Shell shell, Object layoutData) {
   toolBar = new ToolBar(shell, SWT.NULL);
   toolBar.setLayoutData(layoutData);
   ToolItem item = new ToolItem(toolBar, SWT.SEPARATOR);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdParent]);
   item.setToolTipText(getResourceString("tool.Parent.tiptext"));
   item.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       doParent();
     }
   });
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdRefresh]);
   item.setToolTipText(getResourceString("tool.Refresh.tiptext"));
   item.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       doRefresh();
     }
   });
   SelectionAdapter unimplementedListener = new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       MessageBox box = new MessageBox(shell, SWT.ICON_INFORMATION
           | SWT.OK);
       box.setText(getResourceString("dialog.NotImplemented.title"));
       box
           .setMessage(getResourceString("dialog.ActionNotImplemented.description"));
       box.open();
     }
   };
   item = new ToolItem(toolBar, SWT.SEPARATOR);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdCut]);
   item.setToolTipText(getResourceString("tool.Cut.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdCopy]);
   item.setToolTipText(getResourceString("tool.Copy.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdPaste]);
   item.setToolTipText(getResourceString("tool.Paste.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.SEPARATOR);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdDelete]);
   item.setToolTipText(getResourceString("tool.Delete.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdRename]);
   item.setToolTipText(getResourceString("tool.Rename.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.SEPARATOR);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdSearch]);
   item.setToolTipText(getResourceString("tool.Search.tiptext"));
   item.addSelectionListener(unimplementedListener);
   item = new ToolItem(toolBar, SWT.PUSH);
   item.setImage(iconCache.stockImages[iconCache.cmdPrint]);
   item.setToolTipText(getResourceString("tool.Print.tiptext"));
   item.addSelectionListener(unimplementedListener);
 }
 /**
  * Creates the combo box view.
  * 
  * @param parent
  *            the parent control
  */
 private void createComboView(Composite parent, Object layoutData) {
   combo = new Combo(parent, SWT.NONE);
   combo.setLayoutData(layoutData);
   combo.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent e) {
       final File[] roots = (File[]) combo.getData(COMBODATA_ROOTS);
       if (roots == null)
         return;
       int selection = combo.getSelectionIndex();
       if (selection >= 0 && selection < roots.length) {
         notifySelectedDirectory(roots[selection]);
       }
     }
     public void widgetDefaultSelected(SelectionEvent e) {
       final String lastText = (String) combo
           .getData(COMBODATA_LASTTEXT);
       String text = combo.getText();
       if (text == null)
         return;
       if (lastText != null && lastText.equals(text))
         return;
       combo.setData(COMBODATA_LASTTEXT, text);
       notifySelectedDirectory(new File(text));
     }
   });
 }
 /**
  * Creates the file tree view.
  * 
  * @param parent
  *            the parent control
  */
 private void createTreeView(Composite parent) {
   Composite composite = new Composite(parent, SWT.NONE);
   GridLayout gridLayout = new GridLayout();
   gridLayout.numColumns = 1;
   gridLayout.marginHeight = gridLayout.marginWidth = 2;
   gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
   composite.setLayout(gridLayout);
   treeScopeLabel = new Label(composite, SWT.BORDER);
   treeScopeLabel.setText(SWTFileViewerDemo
       .getResourceString("details.AllFolders.text"));
   treeScopeLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
       | GridData.VERTICAL_ALIGN_FILL));
   tree = new Tree(composite, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
       | SWT.SINGLE);
   tree.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
       | GridData.FILL_VERTICAL));
   tree.addSelectionListener(new SelectionListener() {
     public void widgetSelected(SelectionEvent event) {
       final TreeItem[] selection = tree.getSelection();
       if (selection != null && selection.length != 0) {
         TreeItem item = selection[0];
         File file = (File) item.getData(TREEITEMDATA_FILE);
         notifySelectedDirectory(file);
       }
     }
     public void widgetDefaultSelected(SelectionEvent event) {
       final TreeItem[] selection = tree.getSelection();
       if (selection != null && selection.length != 0) {
         TreeItem item = selection[0];
         item.setExpanded(true);
         treeExpandItem(item);
       }
     }
   });
   tree.addTreeListener(new TreeAdapter() {
     public void treeExpanded(TreeEvent event) {
       final TreeItem item = (TreeItem) event.item;
       final Image image = (Image) item
           .getData(TREEITEMDATA_IMAGEEXPANDED);
       if (image != null)
         item.setImage(image);
       treeExpandItem(item);
     }
     public void treeCollapsed(TreeEvent event) {
       final TreeItem item = (TreeItem) event.item;
       final Image image = (Image) item
           .getData(TREEITEMDATA_IMAGECOLLAPSED);
       if (image != null)
         item.setImage(image);
     }
   });
   createTreeDragSource(tree);
   createTreeDropTarget(tree);
 }
 /**
  * Creates the Drag & Drop DragSource for items being dragged from the tree.
  * 
  * @return the DragSource for the tree
  */
 private DragSource createTreeDragSource(final Tree tree) {
   DragSource dragSource = new DragSource(tree, DND.DROP_MOVE
       | DND.DROP_COPY);
   dragSource.setTransfer(new Transfer[] { FileTransfer.getInstance() });
   dragSource.addDragListener(new DragSourceListener() {
     TreeItem[] dndSelection = null;
     String[] sourceNames = null;
     public void dragStart(DragSourceEvent event) {
       dndSelection = tree.getSelection();
       sourceNames = null;
       event.doit = dndSelection.length > 0;
       isDragging = true;
       processedDropFiles = null;
     }
     public void dragFinished(DragSourceEvent event) {
       dragSourceHandleDragFinished(event, sourceNames);
       dndSelection = null;
       sourceNames = null;
       isDragging = false;
       processedDropFiles = null;
       handleDeferredRefresh();
     }
     public void dragSetData(DragSourceEvent event) {
       if (dndSelection == null || dndSelection.length == 0)
         return;
       if (!FileTransfer.getInstance().isSupportedType(event.dataType))
         return;
       sourceNames = new String[dndSelection.length];
       for (int i = 0; i < dndSelection.length; i++) {
         File file = (File) dndSelection[i]
             .getData(TREEITEMDATA_FILE);
         sourceNames[i] = file.getAbsolutePath();
       }
       event.data = sourceNames;
     }
   });
   return dragSource;
 }
 /**
  * Creates the Drag & Drop DropTarget for items being dropped onto the tree.
  * 
  * @return the DropTarget for the tree
  */
 private DropTarget createTreeDropTarget(final Tree tree) {
   DropTarget dropTarget = new DropTarget(tree, DND.DROP_MOVE
       | DND.DROP_COPY);
   dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
   dropTarget.addDropListener(new DropTargetAdapter() {
     public void dragEnter(DropTargetEvent event) {
       isDropping = true;
     }
     public void dragLeave(DropTargetEvent event) {
       isDropping = false;
       handleDeferredRefresh();
     }
     public void dragOver(DropTargetEvent event) {
       dropTargetValidate(event, getTargetFile(event));
       event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
     }
     public void drop(DropTargetEvent event) {
       File targetFile = getTargetFile(event);
       if (dropTargetValidate(event, targetFile))
         dropTargetHandleDrop(event, targetFile);
     }
     private File getTargetFile(DropTargetEvent event) {
       // Determine the target File for the drop
       TreeItem item = tree.getItem(tree.toControl(new Point(event.x,
           event.y)));
       File targetFile = null;
       if (item != null) {
         // We are over a particular item in the tree, use the item"s
         // file
         targetFile = (File) item.getData(TREEITEMDATA_FILE);
       }
       return targetFile;
     }
   });
   return dropTarget;
 }
 /**
  * Handles expand events on a tree item.
  * 
  * @param item
  *            the TreeItem to fill in
  */
 private void treeExpandItem(TreeItem item) {
   shell.setCursor(iconCache.stockCursors[iconCache.cursorWait]);
   final Object stub = item.getData(TREEITEMDATA_STUB);
   if (stub == null)
     treeRefreshItem(item, true);
   shell.setCursor(iconCache.stockCursors[iconCache.cursorDefault]);
 }
 /**
  * Traverse the entire tree and update only what has changed.
  * 
  * @param roots
  *            the root directory listing
  */
 private void treeRefresh(File[] masterFiles) {
   TreeItem[] items = tree.getItems();
   int masterIndex = 0;
   int itemIndex = 0;
   for (int i = 0; i < items.length; ++i) {
     final TreeItem item = items[i];
     final File itemFile = (File) item.getData(TREEITEMDATA_FILE);
     if ((itemFile == null) || (masterIndex == masterFiles.length)) {
       // remove bad item or placeholder
       item.dispose();
       continue;
     }
     final File masterFile = masterFiles[masterIndex];
     int compare = compareFiles(masterFile, itemFile);
     if (compare == 0) {
       // same file, update it
       treeRefreshItem(item, false);
       ++itemIndex;
       ++masterIndex;
     } else if (compare < 0) {
       // should appear before file, insert it
       TreeItem newItem = new TreeItem(tree, SWT.NULL, itemIndex);
       treeInitVolume(newItem, masterFile);
       new TreeItem(newItem, SWT.NULL); // placeholder child item to
                         // get "expand" button
       ++itemIndex;
       ++masterIndex;
       --i;
     } else {
       // should appear after file, delete stale item
       item.dispose();
     }
   }
   for (; masterIndex < masterFiles.length; ++masterIndex) {
     final File masterFile = masterFiles[masterIndex];
     TreeItem newItem = new TreeItem(tree, SWT.NULL);
     treeInitVolume(newItem, masterFile);
     new TreeItem(newItem, SWT.NULL); // placeholder child item to get
                       // "expand" button
   }
 }
 /**
  * Traverse an item in the tree and update only what has changed.
  * 
  * @param dirItem
  *            the tree item of the directory
  * @param forcePopulate
  *            true iff we should populate non-expanded items as well
  */
 private void treeRefreshItem(TreeItem dirItem, boolean forcePopulate) {
   final File dir = (File) dirItem.getData(TREEITEMDATA_FILE);
   if (!forcePopulate && !dirItem.getExpanded()) {
     // Refresh non-expanded item
     if (dirItem.getData(TREEITEMDATA_STUB) != null) {
       treeItemRemoveAll(dirItem);
       new TreeItem(dirItem, SWT.NULL); // placeholder child item to
                         // get "expand" button
       dirItem.setData(TREEITEMDATA_STUB, null);
     }
     return;
   }
   // Refresh expanded item
   dirItem.setData(TREEITEMDATA_STUB, this); // clear stub flag
   /* Get directory listing */
   File[] subFiles = (dir != null) ? SWTFileViewerDemo.getDirectoryList(dir)
       : null;
   if (subFiles == null || subFiles.length == 0) {
     /* Error or no contents */
     treeItemRemoveAll(dirItem);
     dirItem.setExpanded(false);
     return;
   }
   /* Refresh sub-items */
   TreeItem[] items = dirItem.getItems();
   final File[] masterFiles = subFiles;
   int masterIndex = 0;
   int itemIndex = 0;
   File masterFile = null;
   for (int i = 0; i < items.length; ++i) {
     while ((masterFile == null) && (masterIndex < masterFiles.length)) {
       masterFile = masterFiles[masterIndex++];
       if (!masterFile.isDirectory())
         masterFile = null;
     }
     final TreeItem item = items[i];
     final File itemFile = (File) item.getData(TREEITEMDATA_FILE);
     if ((itemFile == null) || (masterFile == null)) {
       // remove bad item or placeholder
       item.dispose();
       continue;
     }
     int compare = compareFiles(masterFile, itemFile);
     if (compare == 0) {
       // same file, update it
       treeRefreshItem(item, false);
       masterFile = null;
       ++itemIndex;
     } else if (compare < 0) {
       // should appear before file, insert it
       TreeItem newItem = new TreeItem(dirItem, SWT.NULL, itemIndex);
       treeInitFolder(newItem, masterFile);
       new TreeItem(newItem, SWT.NULL); // add a placeholder child
                         // item so we get the
                         // "expand" button
       masterFile = null;
       ++itemIndex;
       --i;
     } else {
       // should appear after file, delete stale item
       item.dispose();
     }
   }
   while ((masterFile != null) || (masterIndex < masterFiles.length)) {
     if (masterFile != null) {
       TreeItem newItem = new TreeItem(dirItem, SWT.NULL);
       treeInitFolder(newItem, masterFile);
       new TreeItem(newItem, SWT.NULL); // add a placeholder child
                         // item so we get the
                         // "expand" button
       if (masterIndex == masterFiles.length)
         break;
     }
     masterFile = masterFiles[masterIndex++];
     if (!masterFile.isDirectory())
       masterFile = null;
   }
 }
 /**
  * Foreign method: removes all children of a TreeItem.
  * 
  * @param treeItem
  *            the TreeItem
  */
 private static void treeItemRemoveAll(TreeItem treeItem) {
   final TreeItem[] children = treeItem.getItems();
   for (int i = 0; i < children.length; ++i) {
     children[i].dispose();
   }
 }
 /**
  * Initializes a folder item.
  * 
  * @param item
  *            the TreeItem to initialize
  * @param folder
  *            the File associated with this TreeItem
  */
 private void treeInitFolder(TreeItem item, File folder) {
   item.setText(folder.getName());
   item.setImage(iconCache.stockImages[iconCache.iconClosedFolder]);
   item.setData(TREEITEMDATA_FILE, folder);
   item.setData(TREEITEMDATA_IMAGEEXPANDED,
       iconCache.stockImages[iconCache.iconOpenFolder]);
   item.setData(TREEITEMDATA_IMAGECOLLAPSED,
       iconCache.stockImages[iconCache.iconClosedFolder]);
 }
 /**
  * Initializes a volume item.
  * 
  * @param item
  *            the TreeItem to initialize
  * @param volume
  *            the File associated with this TreeItem
  */
 private void treeInitVolume(TreeItem item, File volume) {
   item.setText(volume.getPath());
   item.setImage(iconCache.stockImages[iconCache.iconClosedDrive]);
   item.setData(TREEITEMDATA_FILE, volume);
   item.setData(TREEITEMDATA_IMAGEEXPANDED,
       iconCache.stockImages[iconCache.iconOpenDrive]);
   item.setData(TREEITEMDATA_IMAGECOLLAPSED,
       iconCache.stockImages[iconCache.iconClosedDrive]);
 }
 /**
  * Creates the file details table.
  * 
  * @param parent
  *            the parent control
  */
 private void createTableView(Composite parent) {
   Composite composite = new Composite(parent, SWT.NONE);
   GridLayout gridLayout = new GridLayout();
   gridLayout.numColumns = 1;
   gridLayout.marginHeight = gridLayout.marginWidth = 2;
   gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
   composite.setLayout(gridLayout);
   tableContentsOfLabel = new Label(composite, SWT.BORDER);
   tableContentsOfLabel.setLayoutData(new GridData(
       GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL));
   table = new Table(composite, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL
       | SWT.MULTI | SWT.FULL_SELECTION);
   table.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
       | GridData.FILL_VERTICAL));
   for (int i = 0; i < tableTitles.length; ++i) {
     TableColumn column = new TableColumn(table, SWT.NONE);
     column.setText(tableTitles[i]);
     column.setWidth(tableWidths[i]);
   }
   table.setHeaderVisible(true);
   table.addSelectionListener(new SelectionAdapter() {
     public void widgetSelected(SelectionEvent event) {
       notifySelectedFiles(getSelectedFiles());
     }
     public void widgetDefaultSelected(SelectionEvent event) {
       doDefaultFileAction(getSelectedFiles());
     }
     private File[] getSelectedFiles() {
       final TableItem[] items = table.getSelection();
       final File[] files = new File[items.length];
       for (int i = 0; i < items.length; ++i) {
         files[i] = (File) items[i].getData(TABLEITEMDATA_FILE);
       }
       return files;
     }
   });
   createTableDragSource(table);
   createTableDropTarget(table);
 }
 /**
  * Creates the Drag & Drop DragSource for items being dragged from the
  * table.
  * 
  * @return the DragSource for the table
  */
 private DragSource createTableDragSource(final Table table) {
   DragSource dragSource = new DragSource(table, DND.DROP_MOVE
       | DND.DROP_COPY);
   dragSource.setTransfer(new Transfer[] { FileTransfer.getInstance() });
   dragSource.addDragListener(new DragSourceListener() {
     TableItem[] dndSelection = null;
     String[] sourceNames = null;
     public void dragStart(DragSourceEvent event) {
       dndSelection = table.getSelection();
       sourceNames = null;
       event.doit = dndSelection.length > 0;
       isDragging = true;
     }
     public void dragFinished(DragSourceEvent event) {
       dragSourceHandleDragFinished(event, sourceNames);
       dndSelection = null;
       sourceNames = null;
       isDragging = false;
       handleDeferredRefresh();
     }
     public void dragSetData(DragSourceEvent event) {
       if (dndSelection == null || dndSelection.length == 0)
         return;
       if (!FileTransfer.getInstance().isSupportedType(event.dataType))
         return;
       sourceNames = new String[dndSelection.length];
       for (int i = 0; i < dndSelection.length; i++) {
         File file = (File) dndSelection[i]
             .getData(TABLEITEMDATA_FILE);
         sourceNames[i] = file.getAbsolutePath();
       }
       event.data = sourceNames;
     }
   });
   return dragSource;
 }
 /**
  * Creates the Drag & Drop DropTarget for items being dropped onto the
  * table.
  * 
  * @return the DropTarget for the table
  */
 private DropTarget createTableDropTarget(final Table table) {
   DropTarget dropTarget = new DropTarget(table, DND.DROP_MOVE
       | DND.DROP_COPY);
   dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
   dropTarget.addDropListener(new DropTargetAdapter() {
     public void dragEnter(DropTargetEvent event) {
       isDropping = true;
     }
     public void dragLeave(DropTargetEvent event) {
       isDropping = false;
       handleDeferredRefresh();
     }
     public void dragOver(DropTargetEvent event) {
       dropTargetValidate(event, getTargetFile(event));
       event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
     }
     public void drop(DropTargetEvent event) {
       File targetFile = getTargetFile(event);
       if (dropTargetValidate(event, targetFile))
         dropTargetHandleDrop(event, targetFile);
     }
     private File getTargetFile(DropTargetEvent event) {
       // Determine the target File for the drop
       TableItem item = table.getItem(table.toControl(new Point(
           event.x, event.y)));
       File targetFile = null;
       if (item == null) {
         // We are over an unoccupied area of the table.
         // If it is a COPY, we can use the table"s root file.
         if (event.detail == DND.DROP_COPY) {
           targetFile = (File) table.getData(TABLEDATA_DIR);
         }
       } else {
         // We are over a particular item in the table, use the
         // item"s file
         targetFile = (File) item.getData(TABLEITEMDATA_FILE);
       }
       return targetFile;
     }
   });
   return dropTarget;
 }
 /**
  * Notifies the application components that a new current directory has been
  * selected
  * 
  * @param dir
  *            the directory that was selected, null is ignored
  */
 void notifySelectedDirectory(File dir) {
   if (dir == null)
     return;
   if (currentDirectory != null && dir.equals(currentDirectory))
     return;
   currentDirectory = dir;
   notifySelectedFiles(null);
   /*
    * Shell: Sets the title to indicate the selected directory
    */
   shell.setText(getResourceString("Title",
       new Object[] { currentDirectory.getPath() }));
   /*
    * Table view: Displays the contents of the selected directory.
    */
   workerUpdate(dir, false);
   /*
    * Combo view: Sets the combo box to point to the selected directory.
    */
   final File[] comboRoots = (File[]) combo.getData(COMBODATA_ROOTS);
   int comboEntry = -1;
   if (comboRoots != null) {
     for (int i = 0; i < comboRoots.length; ++i) {
       if (dir.equals(comboRoots[i])) {
         comboEntry = i;
         break;
       }
     }
   }
   if (comboEntry == -1)
     combo.setText(dir.getPath());
   else
     combo.select(comboEntry);
   /*
    * Tree view: If not already expanded, recursively expands the parents
    * of the specified directory until it is visible.
    */
   Vector /* of File */path = new Vector();
   // Build a stack of paths from the root of the tree
   while (dir != null) {
     path.add(dir);
     dir = dir.getParentFile();
   }
   // Recursively expand the tree to get to the specified directory
   TreeItem[] items = tree.getItems();
   TreeItem lastItem = null;
   for (int i = path.size() - 1; i >= 0; --i) {
     final File pathElement = (File) path.elementAt(i);
     // Search for a particular File in the array of tree items
     // No guarantee that the items are sorted in any recognizable
     // fashion, so we"ll
     // just sequential scan. There shouldn"t be more than a few thousand
     // entries.
     TreeItem item = null;
     for (int k = 0; k < items.length; ++k) {
       item = items[k];
       if (item.isDisposed())
         continue;
       final File itemFile = (File) item.getData(TREEITEMDATA_FILE);
       if (itemFile != null && itemFile.equals(pathElement))
         break;
     }
     if (item == null)
       break;
     lastItem = item;
     if (i != 0 && !item.getExpanded()) {
       treeExpandItem(item);
       item.setExpanded(true);
     }
     items = item.getItems();
   }
   tree.setSelection((lastItem != null) ? new TreeItem[] { lastItem }
       : new TreeItem[0]);
 }
 /**
  * Notifies the application components that files have been selected
  * 
  * @param files
  *            the files that were selected, null or empty array indicates no
  *            active selection
  */
 void notifySelectedFiles(File[] files) {
   /*
    * Details: Update the details that are visible on screen.
    */
   if ((files != null) && (files.length != 0)) {
     numObjectsLabel.setText(getResourceString(
         "details.NumberOfSelectedFiles.text",
         new Object[] { new Integer(files.length) }));
     long fileSize = 0L;
     for (int i = 0; i < files.length; ++i) {
       fileSize += files[i].length();
     }
     diskSpaceLabel.setText(getResourceString("details.FileSize.text",
         new Object[] { new Long(fileSize) }));
   } else {
     // No files selected
     diskSpaceLabel.setText("");
     if (currentDirectory != null) {
       int numObjects = getDirectoryList(currentDirectory).length;
       numObjectsLabel.setText(getResourceString(
           "details.DirNumberOfObjects.text",
           new Object[] { new Integer(numObjects) }));
     } else {
       numObjectsLabel.setText("");
     }
   }
 }
 /**
  * Notifies the application components that files must be refreshed
  * 
  * @param files
  *            the files that need refreshing, empty array is a no-op, null
  *            refreshes all
  */
 void notifyRefreshFiles(File[] files) {
   if (files != null && files.length == 0)
     return;
   if ((deferredRefreshRequested) && (deferredRefreshFiles != null)
       && (files != null)) {
     // merge requests
     File[] newRequest = new File[deferredRefreshFiles.length
         + files.length];
     System.arraycopy(deferredRefreshFiles, 0, newRequest, 0,
         deferredRefreshFiles.length);
     System.arraycopy(files, 0, newRequest, deferredRefreshFiles.length,
         files.length);
     deferredRefreshFiles = newRequest;
   } else {
     deferredRefreshFiles = files;
     deferredRefreshRequested = true;
   }
   handleDeferredRefresh();
 }
 /**
  * Handles deferred Refresh notifications (due to Drag & Drop)
  */
 void handleDeferredRefresh() {
   if (isDragging || isDropping || !deferredRefreshRequested)
     return;
   if (progressDialog != null) {
     progressDialog.close();
     progressDialog = null;
   }
   deferredRefreshRequested = false;
   File[] files = deferredRefreshFiles;
   deferredRefreshFiles = null;
   shell.setCursor(iconCache.stockCursors[iconCache.cursorWait]);
   /*
    * Table view: Refreshes information about any files in the list and
    * their children.
    */
   boolean refreshTable = false;
   if (files != null) {
     for (int i = 0; i < files.length; ++i) {
       final File file = files[i];
       if (file.equals(currentDirectory)) {
         refreshTable = true;
         break;
       }
       File parentFile = file.getParentFile();
       if ((parentFile != null)
           && (parentFile.equals(currentDirectory))) {
         refreshTable = true;
         break;
       }
     }
   } else
     refreshTable = true;
   if (refreshTable)
     workerUpdate(currentDirectory, true);
   /*
    * Combo view: Refreshes the list of roots
    */
   final File[] roots = getRoots();
   if (files == null) {
     boolean refreshCombo = false;
     final File[] comboRoots = (File[]) combo.getData(COMBODATA_ROOTS);
     if ((comboRoots != null) && (comboRoots.length == roots.length)) {
       for (int i = 0; i < roots.length; ++i) {
         if (!roots[i].equals(comboRoots[i])) {
           refreshCombo = true;
           break;
         }
       }
     } else
       refreshCombo = true;
     if (refreshCombo) {
       combo.removeAll();
       combo.setData(COMBODATA_ROOTS, roots);
       for (int i = 0; i < roots.length; ++i) {
         final File file = roots[i];
         combo.add(file.getPath());
       }
     }
   }
   /*
    * Tree view: Refreshes information about any files in the list and
    * their children.
    */
   treeRefresh(roots);
   // Remind everyone where we are in the filesystem
   final File dir = currentDirectory;
   currentDirectory = null;
   notifySelectedDirectory(dir);
   shell.setCursor(iconCache.stockCursors[iconCache.cursorDefault]);
 }
 /**
  * Performs the default action on a set of files.
  * 
  * @param files
  *            the array of files to process
  */
 void doDefaultFileAction(File[] files) {
   // only uses the 1st file (for now)
   if (files.length == 0)
     return;
   final File file = files[0];
   if (file.isDirectory()) {
     notifySelectedDirectory(file);
   } else {
     final String fileName = file.getAbsolutePath();
     if (!Program.launch(fileName)) {
       MessageBox dialog = new MessageBox(shell, SWT.ICON_ERROR
           | SWT.OK);
       dialog
           .setMessage(getResourceString(
               "error.FailedLaunch.message",
               new Object[] { fileName }));
       dialog.setText(shell.getText());
       dialog.open();
     }
   }
 }
 /**
  * Navigates to the parent directory
  */
 void doParent() {
   if (currentDirectory == null)
     return;
   File parentDirectory = currentDirectory.getParentFile();
   notifySelectedDirectory(parentDirectory);
 }
 /**
  * Performs a refresh
  */
 void doRefresh() {
   notifyRefreshFiles(null);
 }
 /**
  * Validates a drop target as a candidate for a drop operation.
*

* Used in dragOver() and dropAccept().
* Note event.detail is set to DND.DROP_NONE by this method if the target is * not valid. *

  * 
  * @param event
  *            the DropTargetEvent to validate
  * @param targetFile
  *            the File representing the drop target location under
  *            inspection, or null if none
  */
 private boolean dropTargetValidate(DropTargetEvent event, File targetFile) {
   if (targetFile != null && targetFile.isDirectory()) {
     if (event.detail != DND.DROP_COPY && event.detail != DND.DROP_MOVE) {
       event.detail = DND.DROP_MOVE;
     }
   } else {
     event.detail = DND.DROP_NONE;
   }
   return event.detail != DND.DROP_NONE;
 }
 /**
  * Handles a drop on a dropTarget.
*

* Used in drop().
* Note event.detail is modified by this method. *

  * 
  * @param event
  *            the DropTargetEvent passed as parameter to the drop() method
  * @param targetFile
  *            the File representing the drop target location under
  *            inspection, or null if none
  */
 private void dropTargetHandleDrop(DropTargetEvent event, File targetFile) {
   // Get dropped data (an array of filenames)
   if (!dropTargetValidate(event, targetFile))
     return;
   final String[] sourceNames = (String[]) event.data;
   if (sourceNames == null)
     event.detail = DND.DROP_NONE;
   if (event.detail == DND.DROP_NONE)
     return;
   // Open progress dialog
   progressDialog = new ProgressDialog(shell,
       (event.detail == DND.DROP_MOVE) ? ProgressDialog.MOVE
           : ProgressDialog.COPY);
   progressDialog.setTotalWorkUnits(sourceNames.length);
   progressDialog.open();
   // Copy each file
   Vector /* of File */processedFiles = new Vector();
   for (int i = 0; (i < sourceNames.length)
       && (!progressDialog.isCancelled()); i++) {
     final File source = new File(sourceNames[i]);
     final File dest = new File(targetFile, source.getName());
     if (source.equals(dest))
       continue; // ignore if in same location
     progressDialog.setDetailFile(source, ProgressDialog.COPY);
     while (!progressDialog.isCancelled()) {
       if (copyFileStructure(source, dest)) {
         processedFiles.add(source);
         break;
       } else if (!progressDialog.isCancelled()) {
         if (event.detail == DND.DROP_MOVE && (!isDragging)) {
           // It is not possible to notify an external drag source
           // that a drop
           // operation was only partially successful. This is
           // particularly a
           // problem for DROP_MOVE operations since unless the
           // source gets
           // DROP_NONE, it will delete the original data including
           // bits that
           // may not have been transferred successfully.
           MessageBox box = new MessageBox(shell, SWT.ICON_ERROR
               | SWT.RETRY | SWT.CANCEL);
           box
               .setText(getResourceString("dialog.FailedCopy.title"));
           box.setMessage(getResourceString(
               "dialog.FailedCopy.description", new Object[] {
                   source, dest }));
           int button = box.open();
           if (button == SWT.CANCEL) {
             i = sourceNames.length;
             event.detail = DND.DROP_NONE;
             break;
           }
         } else {
           // We can recover gracefully from errors if the drag
           // source belongs
           // to this application since it will look at
           // processedDropFiles.
           MessageBox box = new MessageBox(shell, SWT.ICON_ERROR
               | SWT.ABORT | SWT.RETRY | SWT.IGNORE);
           box
               .setText(getResourceString("dialog.FailedCopy.title"));
           box.setMessage(getResourceString(
               "dialog.FailedCopy.description", new Object[] {
                   source, dest }));
           int button = box.open();
           if (button == SWT.ABORT)
             i = sourceNames.length;
           if (button != SWT.RETRY)
             break;
         }
       }
       progressDialog.addProgress(1);
     }
   }
   if (isDragging) {
     // Remember exactly which files we processed
     processedDropFiles = ((File[]) processedFiles
         .toArray(new File[processedFiles.size()]));
   } else {
     progressDialog.close();
     progressDialog = null;
   }
   notifyRefreshFiles(new File[] { targetFile });
 }
 /**
  * Handles the completion of a drag on a dragSource.
*

* Used in dragFinished().
*

  * 
  * @param event
  *            the DragSourceEvent passed as parameter to the dragFinished()
  *            method
  * @param sourceNames
  *            the names of the files that were dragged (event.data is
  *            invalid)
  */
 private void dragSourceHandleDragFinished(DragSourceEvent event,
     String[] sourceNames) {
   if (sourceNames == null)
     return;
   if (event.detail != DND.DROP_MOVE)
     return;
   // Get array of files that were actually transferred
   final File[] sourceFiles;
   if (processedDropFiles != null) {
     sourceFiles = processedDropFiles;
   } else {
     sourceFiles = new File[sourceNames.length];
     for (int i = 0; i < sourceNames.length; ++i)
       sourceFiles[i] = new File(sourceNames[i]);
   }
   if (progressDialog == null)
     progressDialog = new ProgressDialog(shell, ProgressDialog.MOVE);
   progressDialog.setTotalWorkUnits(sourceFiles.length);
   progressDialog.setProgress(0);
   progressDialog.open();
   // Delete each file
   for (int i = 0; (i < sourceFiles.length)
       && (!progressDialog.isCancelled()); i++) {
     final File source = sourceFiles[i];
     progressDialog.setDetailFile(source, ProgressDialog.DELETE);
     while (!progressDialog.isCancelled()) {
       if (deleteFileStructure(source)) {
         break;
       } else if (!progressDialog.isCancelled()) {
         MessageBox box = new MessageBox(shell, SWT.ICON_ERROR
             | SWT.ABORT | SWT.RETRY | SWT.IGNORE);
         box.setText(getResourceString("dialog.FailedDelete.title"));
         box.setMessage(getResourceString(
             "dialog.FailedDelete.description",
             new Object[] { source }));
         int button = box.open();
         if (button == SWT.ABORT)
           i = sourceNames.length;
         if (button == SWT.RETRY)
           break;
       }
     }
     progressDialog.addProgress(1);
   }
   notifyRefreshFiles(sourceFiles);
   progressDialog.close();
   progressDialog = null;
 }
 /**
  * Gets filesystem root entries
  * 
  * @return an array of Files corresponding to the root directories on the
  *         platform, may be empty but not null
  */
 File[] getRoots() {
   /*
    * On JDK 1.22 only...
    */
   // return File.listRoots();
   /*
    * On JDK 1.1.7 and beyond... -- PORTABILITY ISSUES HERE --
    */
   if (System.getProperty("os.name").indexOf("Windows") != -1) {
     Vector /* of File */list = new Vector();
     list.add(new File(DRIVE_A));
     list.add(new File(DRIVE_B));
     for (char i = "c"; i <= "z"; ++i) {
       File drive = new File(i + ":" + File.separator);
       if (drive.isDirectory() && drive.exists()) {
         list.add(drive);
         if (initial && i == "c") {
           currentDirectory = drive;
           initial = false;
         }
       }
     }
     File[] roots = (File[]) list.toArray(new File[list.size()]);
     sortFiles(roots);
     return roots;
   } else {
     File root = new File(File.separator);
     if (initial) {
       currentDirectory = root;
       initial = false;
     }
     return new File[] { root };
   }
 }
 /**
  * Gets a directory listing
  * 
  * @param file
  *            the directory to be listed
  * @return an array of files this directory contains, may be empty but not
  *         null
  */
 static File[] getDirectoryList(File file) {
   File[] list = file.listFiles();
   if (list == null)
     return new File[0];
   sortFiles(list);
   return list;
 }
 /**
  * Copies a file or entire directory structure.
  * 
  * @param oldFile
  *            the location of the old file or directory
  * @param newFile
  *            the location of the new file or directory
  * @return true iff the operation succeeds without errors
  */
 boolean copyFileStructure(File oldFile, File newFile) {
   if (oldFile == null || newFile == null)
     return false;
   // ensure that newFile is not a child of oldFile or a dupe
   File searchFile = newFile;
   do {
     if (oldFile.equals(searchFile))
       return false;
     searchFile = searchFile.getParentFile();
   } while (searchFile != null);
   if (oldFile.isDirectory()) {
     /*
      * Copy a directory
      */
     if (progressDialog != null) {
       progressDialog.setDetailFile(oldFile, ProgressDialog.COPY);
     }
     if (simulateOnly) {
       // System.out.println(getResourceString("simulate.DirectoriesCreated.text",
       // new Object[] { newFile.getPath() }));
     } else {
       if (!newFile.mkdirs())
         return false;
     }
     File[] subFiles = oldFile.listFiles();
     if (subFiles != null) {
       if (progressDialog != null) {
         progressDialog.addWorkUnits(subFiles.length);
       }
       for (int i = 0; i < subFiles.length; i++) {
         File oldSubFile = subFiles[i];
         File newSubFile = new File(newFile, oldSubFile.getName());
         if (!copyFileStructure(oldSubFile, newSubFile))
           return false;
         if (progressDialog != null) {
           progressDialog.addProgress(1);
           if (progressDialog.isCancelled())
             return false;
         }
       }
     }
   } else {
     /*
      * Copy a file
      */
     if (simulateOnly) {
       // System.out.println(getResourceString("simulate.CopyFromTo.text",
       // new Object[] { oldFile.getPath(), newFile.getPath() }));
     } else {
       FileReader in = null;
       FileWriter out = null;
       try {
         in = new FileReader(oldFile);
         out = new FileWriter(newFile);
         int count;
         while ((count = in.read()) != -1)
           out.write(count);
       } catch (FileNotFoundException e) {
         return false;
       } catch (IOException e) {
         return false;
       } finally {
         try {
           if (in != null)
             in.close();
           if (out != null)
             out.close();
         } catch (IOException e) {
           return false;
         }
       }
     }
   }
   return true;
 }
 /**
  * Deletes a file or entire directory structure.
  * 
  * @param oldFile
  *            the location of the old file or directory
  * @return true iff the operation succeeds without errors
  */
 boolean deleteFileStructure(File oldFile) {
   if (oldFile == null)
     return false;
   if (oldFile.isDirectory()) {
     /*
      * Delete a directory
      */
     if (progressDialog != null) {
       progressDialog.setDetailFile(oldFile, ProgressDialog.DELETE);
     }
     File[] subFiles = oldFile.listFiles();
     if (subFiles != null) {
       if (progressDialog != null) {
         progressDialog.addWorkUnits(subFiles.length);
       }
       for (int i = 0; i < subFiles.length; i++) {
         File oldSubFile = subFiles[i];
         if (!deleteFileStructure(oldSubFile))
           return false;
         if (progressDialog != null) {
           progressDialog.addProgress(1);
           if (progressDialog.isCancelled())
             return false;
         }
       }
     }
   }
   if (simulateOnly) {
     // System.out.println(getResourceString("simulate.Delete.text",
     // new Object[] { oldFile.getPath(), oldFile.getPath() }));
     return true;
   } else {
     return oldFile.delete();
   }
 }
 /**
  * Sorts files lexicographically by name.
  * 
  * @param files
  *            the array of Files to be sorted
  */
 static void sortFiles(File[] files) {
   /* Very lazy merge sort algorithm */
   sortBlock(files, 0, files.length - 1, new File[files.length]);
 }
 private static void sortBlock(File[] files, int start, int end,
     File[] mergeTemp) {
   final int length = end - start + 1;
   if (length < 8) {
     for (int i = end; i > start; --i) {
       for (int j = end; j > start; --j) {
         if (compareFiles(files[j - 1], files[j]) > 0) {
           final File temp = files[j];
           files[j] = files[j - 1];
           files[j - 1] = temp;
         }
       }
     }
     return;
   }
   final int mid = (start + end) / 2;
   sortBlock(files, start, mid, mergeTemp);
   sortBlock(files, mid + 1, end, mergeTemp);
   int x = start;
   int y = mid + 1;
   for (int i = 0; i < length; ++i) {
     if ((x > mid)
         || ((y <= end) && compareFiles(files[x], files[y]) > 0)) {
       mergeTemp[i] = files[y++];
     } else {
       mergeTemp[i] = files[x++];
     }
   }
   for (int i = 0; i < length; ++i)
     files[i + start] = mergeTemp[i];
 }
 private static int compareFiles(File a, File b) {
   // boolean aIsDir = a.isDirectory();
   // boolean bIsDir = b.isDirectory();
   // if (aIsDir && ! bIsDir) return -1;
   // if (bIsDir && ! aIsDir) return 1;
   // sort case-sensitive files in a case-insensitive manner
   int compare = a.getName().rupareToIgnoreCase(b.getName());
   if (compare == 0)
     compare = a.getName().rupareTo(b.getName());
   return compare;
 }
 /*
  * This worker updates the table with file information in the background.
*

Implementation notes:

  • It is designed such that it can be * interrupted cleanly.
  • It uses asyncExec() in some places to ensure * that SWT Widgets are manipulated in the right thread. Exclusive use of * syncExec() would be inappropriate as it would require a pair of context * switches between each table update operation.

  */
 /**
  * Stops the worker and waits for it to terminate.
  */
 void workerStop() {
   if (workerThread == null)
     return;
   synchronized (workerLock) {
     workerCancelled = true;
     workerStopped = true;
     workerLock.notifyAll();
   }
   while (workerThread != null) {
     if (!display.readAndDispatch())
       display.sleep();
   }
 }
 /**
  * Notifies the worker that it should update itself with new data. Cancels
  * any previous operation and begins a new one.
  * 
  * @param dir
  *            the new base directory for the table, null is ignored
  * @param force
  *            if true causes a refresh even if the data is the same
  */
 void workerUpdate(File dir, boolean force) {
   if (dir == null)
     return;
   if ((!force) && (workerNextDir != null) && (workerNextDir.equals(dir)))
     return;
   synchronized (workerLock) {
     workerNextDir = dir;
     workerStopped = false;
     workerCancelled = true;
     workerLock.notifyAll();
   }
   if (workerThread == null) {
     workerThread = new Thread(workerRunnable);
     workerThread.start();
   }
 }
 /**
  * Manages the worker"s thread
  */
 private final Runnable workerRunnable = new Runnable() {
   public void run() {
     while (!workerStopped) {
       synchronized (workerLock) {
         workerCancelled = false;
         workerStateDir = workerNextDir;
       }
       workerExecute();
       synchronized (workerLock) {
         try {
           if ((!workerCancelled)
               && (workerStateDir == workerNextDir))
             workerLock.wait();
         } catch (InterruptedException e) {
         }
       }
     }
     workerThread = null;
     // wake up UI thread in case it is in a modal loop awaiting thread
     // termination
     // (see workerStop())
     display.wake();
   }
 };
 /**
  * Updates the table"s contents
  */
 private void workerExecute() {
   File[] dirList;
   // Clear existing information
   display.syncExec(new Runnable() {
     public void run() {
       tableContentsOfLabel.setText(SWTFileViewerDemo.getResourceString(
           "details.ContentsOf.text",
           new Object[] { workerStateDir.getPath() }));
       table.removeAll();
       table.setData(TABLEDATA_DIR, workerStateDir);
     }
   });
   dirList = getDirectoryList(workerStateDir);
   for (int i = 0; (!workerCancelled) && (i < dirList.length); i++) {
     workerAddFileDetails(dirList[i]);
   }
 }
 /**
  * Adds a file"s detail information to the directory list
  */
 private void workerAddFileDetails(final File file) {
   final String nameString = file.getName();
   final String dateString = dateFormat.format(new Date(file
       .lastModified()));
   final String sizeString;
   final String typeString;
   final Image iconImage;
   if (file.isDirectory()) {
     typeString = getResourceString("filetype.Folder");
     sizeString = "";
     iconImage = iconCache.stockImages[iconCache.iconClosedFolder];
   } else {
     sizeString = getResourceString("filesize.KB",
         new Object[] { new Long((file.length() + 512) / 1024) });
     int dot = nameString.lastIndexOf(".");
     if (dot != -1) {
       String extension = nameString.substring(dot);
       Program program = Program.findProgram(extension);
       if (program != null) {
         typeString = program.getName();
         iconImage = iconCache.getIconFromProgram(program);
       } else {
         typeString = getResourceString("filetype.Unknown",
             new Object[] { extension.toUpperCase() });
         iconImage = iconCache.stockImages[iconCache.iconFile];
       }
     } else {
       typeString = getResourceString("filetype.None");
       iconImage = iconCache.stockImages[iconCache.iconFile];
     }
   }
   final String[] strings = new String[] { nameString, sizeString,
       typeString, dateString };
   display.syncExec(new Runnable() {
     public void run() {
       // guard against the shell being closed before this runs
       if (shell.isDisposed())
         return;
       TableItem tableItem = new TableItem(table, 0);
       tableItem.setText(strings);
       tableItem.setImage(iconImage);
       tableItem.setData(TABLEITEMDATA_FILE, file);
     }
   });
 }
 /**
  * Instances of this class manage a progress dialog for file operations.
  */
 class ProgressDialog {
   public final static int COPY = 0;
   public final static int DELETE = 1;
   public final static int MOVE = 2;
   Shell shell;
   Label messageLabel, detailLabel;
   ProgressBar progressBar;
   Button cancelButton;
   boolean isCancelled = false;
   final String operationKeyName[] = { "Copy", "Delete", "Move" };
   /**
    * Creates a progress dialog but does not open it immediately.
    * 
    * @param parent
    *            the parent Shell
    * @param style
    *            one of COPY, MOVE
    */
   public ProgressDialog(Shell parent, int style) {
     shell = new Shell(parent, SWT.BORDER | SWT.TITLE
         | SWT.APPLICATION_MODAL);
     GridLayout gridLayout = new GridLayout();
     shell.setLayout(gridLayout);
     shell.setText(getResourceString("progressDialog."
         + operationKeyName[style] + ".title"));
     shell.addShellListener(new ShellAdapter() {
       public void shellClosed(ShellEvent e) {
         isCancelled = true;
       }
     });
     messageLabel = new Label(shell, SWT.HORIZONTAL);
     messageLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
         | GridData.VERTICAL_ALIGN_FILL));
     messageLabel.setText(getResourceString("progressDialog."
         + operationKeyName[style] + ".description"));
     progressBar = new ProgressBar(shell, SWT.HORIZONTAL | SWT.WRAP);
     progressBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL
         | GridData.VERTICAL_ALIGN_FILL));
     progressBar.setMinimum(0);
     progressBar.setMaximum(0);
     detailLabel = new Label(shell, SWT.HORIZONTAL);
     GridData gridData = new GridData(GridData.FILL_HORIZONTAL
         | GridData.VERTICAL_ALIGN_BEGINNING);
     gridData.widthHint = 400;
     detailLabel.setLayoutData(gridData);
     cancelButton = new Button(shell, SWT.PUSH);
     cancelButton.setLayoutData(new GridData(
         GridData.HORIZONTAL_ALIGN_END
             | GridData.VERTICAL_ALIGN_FILL));
     cancelButton
         .setText(getResourceString("progressDialog.cancelButton.text"));
     cancelButton.addSelectionListener(new SelectionAdapter() {
       public void widgetSelected(SelectionEvent e) {
         isCancelled = true;
         cancelButton.setEnabled(false);
       }
     });
   }
   /**
    * Sets the detail text to show the filename along with a string
    * representing the operation being performed on that file.
    * 
    * @param file
    *            the file to be detailed
    * @param operation
    *            one of COPY, DELETE
    */
   public void setDetailFile(File file, int operation) {
     detailLabel.setText(getResourceString("progressDialog."
         + operationKeyName[operation] + ".operation",
         new Object[] { file }));
   }
   /**
    * Returns true if the Cancel button was been clicked.
    * 
    * @return true if the Cancel button was clicked.
    */
   public boolean isCancelled() {
     return isCancelled;
   }
   /**
    * Sets the total number of work units to be performed.
    * 
    * @param work
    *            the total number of work units
    */
   public void setTotalWorkUnits(int work) {
     progressBar.setMaximum(work);
   }
   /**
    * Adds to the total number of work units to be performed.
    * 
    * @param work
    *            the number of work units to add
    */
   public void addWorkUnits(int work) {
     setTotalWorkUnits(progressBar.getMaximum() + work);
   }
   /**
    * Sets the progress of completion of the total work units.
    * 
    * @param work
    *            the total number of work units completed
    */
   public void setProgress(int work) {
     progressBar.setSelection(work);
     while (display.readAndDispatch()) {
     } // enable event processing
   }
   /**
    * Adds to the progress of completion of the total work units.
    * 
    * @param work
    *            the number of work units completed to add
    */
   public void addProgress(int work) {
     setProgress(progressBar.getSelection() + work);
   }
   /**
    * Opens the dialog.
    */
   public void open() {
     shell.pack();
     final Shell parentShell = (Shell) shell.getParent();
     Rectangle rect = parentShell.getBounds();
     Rectangle bounds = shell.getBounds();
     bounds.x = rect.x + (rect.width - bounds.width) / 2;
     bounds.y = rect.y + (rect.height - bounds.height) / 2;
     shell.setBounds(bounds);
     shell.open();
   }
   /**
    * Closes the dialog and disposes its resources.
    */
   public void close() {
     shell.close();
     shell.dispose();
     shell = null;
     messageLabel = null;
     detailLabel = null;
     progressBar = null;
     cancelButton = null;
   }
 }

} /*******************************************************************************

* Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
* 
* Contributors: IBM Corporation - initial API and implementation
******************************************************************************/

/**

* Manages icons for the application. This is necessary as we could easily end
* up creating thousands of icons bearing the same image.
*/

class IconCache {

 // Stock images
 public final int shellIcon = 0, iconClosedDrive = 1, iconClosedFolder = 2,
     iconFile = 3, iconOpenDrive = 4, iconOpenFolder = 5, cmdCopy = 6,
     cmdCut = 7, cmdDelete = 8, cmdParent = 9, cmdPaste = 10,
     cmdPrint = 11, cmdRefresh = 12, cmdRename = 13, cmdSearch = 14;
 public final String[] stockImageLocations = { "generic_example.gif",
     "icon_ClosedDrive.gif", "icon_ClosedFolder.gif", "icon_File.gif",
     "icon_OpenDrive.gif", "icon_OpenFolder.gif", "cmd_Copy.gif",
     "cmd_Cut.gif", "cmd_Delete.gif", "cmd_Parent.gif", "cmd_Paste.gif",
     "cmd_Print.gif", "cmd_Refresh.gif", "cmd_Rename.gif",
     "cmd_Search.gif" };
 public Image stockImages[];
 // Stock cursors
 public final int cursorDefault = 0, cursorWait = 1;
 public Cursor stockCursors[];
 // Cached icons
 private Hashtable iconCache; /* map Program to Image */
 public IconCache() {
 }
 /**
  * Loads the resources
  * 
  * @param display
  *            the display
  */
 public void initResources(Display display) {
   if (stockImages == null) {
     stockImages = new Image[stockImageLocations.length];
     for (int i = 0; i < stockImageLocations.length; ++i) {
       Image image = createStockImage(display, stockImageLocations[i]);
       if (image == null) {
         freeResources();
         throw new IllegalStateException(SWTFileViewerDemo
             .getResourceString("error.CouldNotLoadResources"));
       }
       stockImages[i] = image;
     }
   }
   if (stockCursors == null) {
     stockCursors = new Cursor[] { null,
         new Cursor(display, SWT.CURSOR_WAIT) };
   }
   iconCache = new Hashtable();
 }
 /**
  * Frees the resources
  */
 public void freeResources() {
   if (stockImages != null) {
     for (int i = 0; i < stockImages.length; ++i) {
       final Image image = stockImages[i];
       if (image != null)
         image.dispose();
     }
     stockImages = null;
   }
   if (iconCache != null) {
     for (Enumeration it = iconCache.elements(); it.hasMoreElements();) {
       Image image = (Image) it.nextElement();
       image.dispose();
     }
   }
   if (stockCursors != null) {
     for (int i = 0; i < stockCursors.length; ++i) {
       final Cursor cursor = stockCursors[i];
       if (cursor != null)
         cursor.dispose();
     }
     stockCursors = null;
   }
 }
 /**
  * Creates a stock image
  * 
  * @param display
  *            the display
  * @param path
  *            the relative path to the icon
  */
 private Image createStockImage(Display display, String path) {
   InputStream stream = IconCache.class.getResourceAsStream(path);
   ImageData imageData = new ImageData(stream);
   ImageData mask = imageData.getTransparencyMask();
   Image result = new Image(display, imageData, mask);
   try {
     stream.close();
   } catch (IOException e) {
     e.printStackTrace();
   }
   return result;
 }
 /**
  * Gets an image for a file associated with a given program
  * 
  * @param program
  *            the Program
  */
 public Image getIconFromProgram(Program program) {
   Image image = (Image) iconCache.get(program);
   if (image == null) {
     ImageData imageData = program.getImageData();
     if (imageData != null) {
       image = new Image(null, imageData, imageData
           .getTransparencyMask());
       iconCache.put(program, image);
     } else {
       image = stockImages[iconFile];
     }
   }
   return image;
 }

}


      </source>
   
  
 
  



SWT File Browser

   <source lang="java">

/* SWT/JFace in Action GUI Design with Eclipse 3.0 Matthew Scarpino, Stephen Holder, Stanford Ng, and Laurent Mihalkovic ISBN: 1932394273 Publisher: Manning

  • /

import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.ListViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.ruposite;

public class Ch12FileBrowserComposite extends Composite {

 private FileBrowser browser;
 public Ch12FileBrowserComposite(Composite parent) {
   super(parent, SWT.NONE);
   RowLayout layout = new RowLayout(SWT.HORIZONTAL);
   setLayout(layout);
   Button copyButton = new Button(this, SWT.PUSH);
   copyButton.setText("Copy");
   copyButton.addSelectionListener(new SelectionListener() {
     public void widgetSelected(SelectionEvent e) {
       Clipboard clipboard = new Clipboard(getDisplay());
       FileTransfer transfer = FileTransfer.getInstance();
       clipboard.setContents(
           new Object[] { browser.getSelectedFiles() },
           new Transfer[] { transfer });
       clipboard.dispose();
     }
     public void widgetDefaultSelected(SelectionEvent e) {
     }
   });
   Button pasteButton = new Button(this, SWT.PUSH);
   pasteButton.setText("Paste");
   pasteButton.addSelectionListener(new SelectionListener() {
     public void widgetSelected(SelectionEvent e) {
       Clipboard clipboard = new Clipboard(getDisplay());
       FileTransfer transfer = FileTransfer.getInstance();
       Object data = clipboard.getContents(transfer);
       if (data != null) {
         browser.copyFiles((String[]) data);
       }
       clipboard.dispose();
     }
     public void widgetDefaultSelected(SelectionEvent e) {
     }
   });
   browser = new FileBrowser(this);
   new FileBrowser(this);
 }

} class FileBrowser {

 private ListViewer viewer;
 private File currentDirectory;
 public FileBrowser(Composite parent) {
   super();
   buildListViewer(parent);
   Transfer[] types = new Transfer[] { FileTransfer.getInstance() };
   viewer.addDropSupport(DND.DROP_COPY, types, new FileDropListener(this));
   viewer.addDragSupport(DND.DROP_COPY, types, new FileDragListener(this));
 }
 private void buildListViewer(Composite parent) {
   viewer = new ListViewer(parent);
   viewer.setLabelProvider(new LabelProvider() {
     public String getText(Object element) {
       File file = (File) element;
       String name = file.getName();
       return file.isDirectory() ? "<Dir> " + name : name;
     }
   });
   viewer.setContentProvider(new IStructuredContentProvider() {
     public Object[] getElements(Object inputElement) {
       File file = (File) inputElement;
       if (file.isDirectory()) {
         return file.listFiles();
       } else {
         return new Object[] { file.getName() };
       }
     }
     public void dispose() {
     }
     public void inputChanged(Viewer viewer, Object oldInput,
         Object newInput) {
     }
   });
   viewer.setSorter(new ViewerSorter() {
     public int category(Object element) {
       return ((File) element).isDirectory() ? 0 : 1;
     }
     public int compare(Viewer viewer, Object e1, Object e2) {
       int cat1 = category(e1);
       int cat2 = category(e2);
       if (cat1 != cat2)
         return cat1 - cat2;
       return ((File) e1).getName().rupareTo(((File) e2).getName());
     }
   });
   viewer.addDoubleClickListener(new IDoubleClickListener() {
     public void doubleClick(DoubleClickEvent event) {
       IStructuredSelection selection = (IStructuredSelection) event
           .getSelection();
       setCurrentDirectory((File) selection.getFirstElement());
     }
   });
   setCurrentDirectory(File.listRoots()[0]);
 }
 private void setCurrentDirectory(File directory) {
   if (!directory.isDirectory())
     throw new RuntimeException(directory + " is not a directory!");
   currentDirectory = directory;
   viewer.setInput(directory);
 }
 String[] getSelectedFiles() {
   IStructuredSelection selection = (IStructuredSelection) viewer
       .getSelection();
   List fileNameList = new LinkedList();
   Iterator iterator = selection.iterator();
   while (iterator.hasNext()) {
     File file = (File) iterator.next();
     fileNameList.add(file.getAbsoluteFile().toString());
   }
   return (String[]) fileNameList.toArray(new String[fileNameList.size()]);
 }
 void copyFiles(String[] sourceFileList) {
   for (int i = 0; i < sourceFileList.length; i++) {
     File sourceFile = new File(sourceFileList[i]);
     if (sourceFile.canRead() && currentDirectory.canWrite()) {
       File destFile = new File(currentDirectory, sourceFile.getName());
       if (!destFile.exists()) {
         FileOutputStream out;
         FileInputStream in;
         try {
           out = new FileOutputStream(destFile);
           in = new FileInputStream(sourceFile);
           byte[] buffer = new byte[1024];
           while ((in.read(buffer)) != -1) {
             out.write(buffer);
           }
           out.flush();
           out.close();
           in.close();
           viewer.refresh();
         } catch (FileNotFoundException e) {
           e.printStackTrace();
         } catch (IOException e) {
           e.printStackTrace();
         }
       } else {
         System.out.println(destFile
             + " already exists, refusing to clobber");
       }
     } else {
       System.out
           .println("Sorry, either your source file is not readable "
               + "or the target directory is not writable");
     }
   }
 }

} final class FileDropListener implements DropTargetListener {

 private final FileBrowser browser;
 FileDropListener(FileBrowser browser) {
   this.browser = browser;
 }
 public void dragEnter(DropTargetEvent event) {
 }
 public void dragLeave(DropTargetEvent event) {
 }
 public void dragOperationChanged(DropTargetEvent event) {
 }
 public void dragOver(DropTargetEvent event) {
 }
 public void dropAccept(DropTargetEvent event) {
 }
 public void drop(DropTargetEvent event) {
   String[] sourceFileList = (String[]) event.data;
   browser.copyFiles(sourceFileList);
 }

} class FileDragListener implements DragSourceListener {

 private FileBrowser browser;
 public FileDragListener(FileBrowser browser) {
   this.browser = browser;
 }
 public void dragStart(DragSourceEvent event) {
   event.doit = true;
 }
 public void dragSetData(DragSourceEvent event) {
   event.data = browser.getSelectedFiles();
 }
 public void dragFinished(DragSourceEvent event) {
 }

}

      </source>