/*******************************************************************************
* Copyright (c) 2000, 2005 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
*******************************************************************************/
package org.cfeclipse.cfml.views.explorer.vfs.view;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.program.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.part.ViewPart;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.text.*;
import java.util.*;
import org.apache.commons.vfs.FileName;
import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.FileSystemManager;
import org.apache.commons.vfs.FileSystemOptions;
import org.apache.commons.vfs.VFS;
import org.apache.commons.vfs.auth.StaticUserAuthenticator;
import org.apache.commons.vfs.impl.DefaultFileSystemConfigBuilder;
import org.apache.commons.vfs.provider.ftp.FtpFileSystemConfigBuilder;
import org.apache.commons.vfs.provider.sftp.SftpFileSystemConfigBuilder;
import org.apache.commons.vfs.util.Os;
import org.cfeclipse.cfml.editors.CFJavaFileEditorInput;
import org.cfeclipse.cfml.editors.CFMLEditor;
import org.cfeclipse.cfml.images.ColumnViewerToolTipSupport;
import org.cfeclipse.cfml.images.ToolTip;
import org.cfeclipse.cfml.net.FTPConnectionProperties;
import org.cfeclipse.cfml.net.RemoteFile;
import org.cfeclipse.cfml.net.RemoteFileEditorInput;
import org.cfeclipse.cfml.preferences.FtpConnectionDialog;
import org.cfeclipse.cfml.util.CFPluginImages;
import org.cfeclipse.cfml.views.explorer.FileExplorerView;
import org.cfeclipse.cfml.views.explorer.vfs.FileOperation;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.EditMenu;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.FileMenu;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.EditMenu.CopyAction;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.EditMenu.PasteAction;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.FileMenu.ConnectionAction;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.FileMenu.DeleteAction;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.FileMenu.NewFileAction;
import org.cfeclipse.cfml.views.explorer.vfs.view.menus.FileMenu.NewFolderAction;
/**
* File Viewer example
*/
public class VFSView extends ViewPart implements IShowInTarget
{
public static final String ID_FILEEXPLORER = "org.cfeclipse.cfml.views.explorer.vfs.view.VFSView";
private static final String RESOURCE_BUNDLE= VFSView.class.getName();
private static ResourceBundle resourceBundle= ResourceBundle.getBundle(RESOURCE_BUNDLE);
private final static String DRIVE_A = "a:" + FileName.SEPARATOR;
// private final static String DRIVE_B = "b:" + FileName.SEPARATOR;
private static boolean initial = true;
/* UI elements */
private Display display;
private Shell shell;
// private ToolBar toolBar;
private Label numObjectsLabel;
private Label diskSpaceLabel;
/* currently selected directory */
private FileObject currentDirectory = null;
/* Drag and drop optimizations */
private boolean isDragging = false; // if this app is dragging
private boolean isDropping = false; // if this app is dropping
// private FileObject[] processedDropFiles = null; // so Drag only deletes what it needs to
private FileObject[] deferredRefreshFiles = null; // to defer notifyRefreshFiles while we do DND
private boolean deferredRefreshRequested = false; // to defer notifyRefreshFiles while we do DND
/* 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 static final String COMBODATA_LASTCONNECTIONID = "Combo.lastConnectionId";
// String: Previous connectionid
private Combo combo;
/* Tree view */
static public ImageRegistry iconCache = CFPluginImages.getImageRegistry();
public static final String TREEITEMDATA_FILE = "TreeItem.file";
// File: File associated with tree item
public static final String TREEITEMDATA_IMAGEEXPANDED = "TreeItem.imageExpanded";
// Image: shown when item is expanded
public 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
public static final String TREEITEMDATA_URI = "TreeItem.uri";
// VFS URI associated with table row
public static final String TREEITEMDATA_CONNECTIONID = "TableItem.connectionId";
// connection id
private static Tree tree;
private Label treeScopeLabel;
/* Table view */
protected static final DateFormat dateFormat = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM, DateFormat.MEDIUM);
public static final String TABLEITEMDATA_FILE = "TableItem.file";
// File: File associated with table row
public static final String TABLEDATA_DIR = "Table.dir";
// File: Currently visible directory
private static final int[] tableWidths = new int[] {150, 60, 75, 150};
public static final String TABLEITEMDATA_CONNECTIONID = "Table.connectionId";
protected static final String TABLEDATA_CONNECTIONID = "TableItem.connectionId";
private final String[] tableTitles = new String [] {
VFSView.getResourceString("table.Name.title"),
VFSView.getResourceString("table.Size.title"),
VFSView.getResourceString("table.Type.title"),
VFSView.getResourceString("table.Modified.title")
};
private Table table;
/* File Items Tabs */
private TabItem tabFileItems;
// private TabItem tabTrasnferItems;
/* 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 FileObject workerStateDir = null;
// State information to use for the next cycle
private volatile FileObject workerNextDir = null;
// Comnnons VFS Manager
private FileSystemManager fsManager = null;
public TreeMap<String, FTPConnectionProperties> fConnections;
private String currentConnectionId;
private String workerNextConnectionId;
protected String workerStateConnectionId;
public Object fSourceConnectionId;
private ConnectionAction connectionAction;
private DeleteAction deleteAction;
private CopyAction copyAction;
private PasteAction pasteAction;
private NewFolderAction newFolderAction;
private NewFileAction newFileAction;
//private static boolean VFS_DEBUG = System.getProperty("org.cfeclipse.cfml.views.explorer.vfs.debug") != null;
private static boolean VFS_DEBUG = true;
public static void error (String s) {
if ( VFS_DEBUG )
System.err.println(s);
}
public static void debug (Exception e) {
if ( VFS_DEBUG )
e.printStackTrace();
}
public Tree getTree () {
return tree;
}
public Table getTable () {
return table;
}
/**
* Returns the Commons VFS File System Manager
*/
public FileSystemManager getFileSystemManager ()
{
return fsManager;
}
/**
* Closes the main program.
*/
public void dispose() {
workerStop();
//return super.close();
}
/**
* Returns a string from the resource bundle.
* We don't want to crash because of a missing String.
* Returns the key if not found.
*/
public static String getResourceString(String key) {
try {
return resourceBundle.getString(key);
} catch (MissingResourceException e) {
return key;
} catch (NullPointerException e) {
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.
*/
public static String getResourceString(String key, Object[] args) {
try {
return MessageFormat.format(getResourceString(key), args);
} catch (MissingResourceException e) {
return key;
} catch (NullPointerException e) {
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.
*/
public static String getResourceString(String key, Object arg) {
try {
return MessageFormat.format(getResourceString(key), new Object []{arg});
} catch (MissingResourceException e) {
return key;
} catch (NullPointerException e) {
return "!" + key + "!";
}
}
/**
* Returns a new menu manager for the window
*/
protected MenuManager createMenuManager()
{
MenuManager menuManager = (MenuManager) getViewSite().getActionBars().getMenuManager();
// File
MenuManager fileMenu =new MenuManager(getResourceString("menu.File.text"));
connectionAction = new FileMenu.ConnectionAction(this
, getResourceString("menu.File.New.text")
, getResourceString("menu.File.New.text") );
fileMenu.add(connectionAction);
deleteAction = new FileMenu.DeleteAction(this
, getResourceString("menu.Connection.Delete.text")
, getResourceString("menu.Connection.Delete.text") );
fileMenu.add(deleteAction);
newFolderAction = new FileMenu.NewFolderAction(this
, getResourceString("menu.File.NewFolder.text")
, getResourceString("menu.File.NewFolder.text"));
fileMenu.add(newFolderAction);
newFileAction = new FileMenu.NewFileAction(this
, getResourceString("menu.File.NewFile.text")
, getResourceString("menu.File.NewFile.text"));
fileMenu.add(newFileAction);
// Edit
MenuManager editMenu =new MenuManager(getResourceString("menu.Edit.text"));
copyAction = new EditMenu.CopyAction(this
, getResourceString("menu.Edit.copy.text")
, getResourceString("menu.Edit.copy.text") );
editMenu.add(copyAction);
pasteAction = new EditMenu.PasteAction(this
, getResourceString("menu.Edit.paste.text")
, getResourceString("menu.Edit.paste.text"));
editMenu.add(pasteAction);
menuManager.add(fileMenu);
menuManager.add(editMenu);
// hook the tree context menu
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
VFSView.this.fillContextMenu(manager,new Action[]{connectionAction,deleteAction,copyAction,pasteAction,newFolderAction,newFileAction});
}
});
Menu menu = menuMgr.createContextMenu(tree);
tree.setMenu(menu);
// hook the table context menu
MenuManager tabMenuMgr = new MenuManager("#PopupMenu");
tabMenuMgr.setRemoveAllWhenShown(true);
tabMenuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
VFSView.this.fillContextMenu(manager,new Action[]{copyAction,pasteAction,newFolderAction,newFileAction});
}
});
Menu tabMenu = tabMenuMgr.createContextMenu(table);
table.setMenu(tabMenu);
return menuManager;
}
private void fillContextMenu(IMenuManager manager,Action[] actions) {
//Somehow we have to know what this item is
for(Action action:actions) {
manager.add(action);
}
}
/**
* Helper method to calculate the size of the cool item
*
* @param item the cool item
*/
private void calcSize(CoolItem item) {
Control control = item.getControl();
Point pt = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
pt = item.computeSize(pt.x, pt.y);
item.setSize(pt);
}
/**
* Construct the UI
*
* @param container the ShellContainer managing the Shell we are rendering inside
*/
public void createPartControl(Composite parent)
{
display = parent.getDisplay();
shell = getSite().getShell();
fConnections = VFSUtil.loadFileSystems();
try {
fsManager = VFS.getManager();
} catch (FileSystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Composite container = new Composite(parent, SWT.NONE);
container.setLayout(new GridLayout(1, true));
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
// gridData.horizontalSpan = 3;
gridData.grabExcessHorizontalSpace = true;
// createComboView(parent, gridData); // shell, gridData);
CoolBar coolbar = new CoolBar(container, SWT.NONE);
coolbar.setLayoutData(gridData);
// Create a toolbar coolitem
final CoolItem item1 = new CoolItem(coolbar, SWT.NONE);
item1.setControl(createToolBar(coolbar));
calcSize(item1);
// Create a combo coolitem
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.widthHint = 185;
final CoolItem item2 = new CoolItem(coolbar, SWT.NONE);
item2.setControl(createComboView(coolbar, gridData));
calcSize(item2);
SashForm sashForm = new SashForm(container, SWT.NONE);
sashForm.setOrientation(SWT.VERTICAL);
gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
sashForm.setLayoutData(gridData);
createTreeView(sashForm);
createTableView(sashForm);
sashForm.setWeights(new int[] { 2, 5 });
Composite container1 = new Composite(container, SWT.NONE);
container1.setLayout(new GridLayout(2, true));
container1.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false));
numObjectsLabel = new Label(container1, SWT.BORDER);
numObjectsLabel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));// gridData);
diskSpaceLabel = new Label(container1, SWT.BORDER);
diskSpaceLabel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true)); //gridData);
createMenuManager();
try {
notifyRefreshFiles(null);
} catch (Exception e) {
debug (e);
}
//return container;
}
/**
* Creates the toolbar
*
* @param shell the shell on which to attach the toolbar
* @param layoutData the layout data
*/
private Control createToolBar(final Composite shell) { //, Object layoutData) {
final ToolBar toolBar = new ToolBar(shell, SWT.FLAT);
// toolBar.setLayoutData(layoutData);
// New VFS
ToolItem item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(iconCache.get(CFPluginImages.ICON_DRIVE_FTP));//.iconFile]);
//item.setText(getResourceString("tool.New.vfs.text"));
item.setToolTipText(getResourceString("tool.New.vfs.tip"));
item.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e)
{
connectionAction.run();
}
});
// Home
item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(iconCache.get(CFPluginImages.ICON_HOME));
//item.setText(getResourceString("tool.home.text"));
item.setToolTipText(getResourceString("tool.home.tip"));
item.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e)
{
try {
// Jump the file system home directory, some FS don't have homes
String homeDir = getCurrentDirectory().getName().getScheme().equals("file")
? VFSUtil.USER_HOME
: (String)getCurrentDirectory().getFileSystem().getAttribute("HOME_DIRECTORY");
// Build a URI from the home dir
String uri = Os.isFamily(Os.OS_FAMILY_UNIX)
? getCurrentDirectory().getName().getRootURI() + homeDir
: getCurrentDirectory().getName().getScheme() + ":///" + homeDir.replace('\\','/');
FileObject fo = resolveURI(uri,getCurrentConnectionId());
if ( fo.exists() )
notifySelectedDirectory(fo, getCurrentConnectionId());
else
VFSUtil.MessageBoxInfo(getResourceString("error.jump.home", new Object[] {homeDir} ));
} catch (FileSystemException ex) {
FileObject fo;
try {
fo = resolveURI(fConnections.get(getCurrentConnectionId()).getURI().toString(),getCurrentConnectionId());
if ( fo.exists() )
notifySelectedDirectory(fo, getCurrentConnectionId());
else
VFSUtil.MessageBoxInfo(getResourceString("error.jump.home", new Object[] {fo.getURL().toString()} ));
} catch (FileSystemException e1) {
VFSUtil.MessageBoxInfo(ex.getMessage());
}
}
}
});
// New folder
item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(iconCache.get(CFPluginImages.ICON_FOLDER_NEW));
//item.setText(getResourceString("tool.New.folder.text"));
item.setToolTipText(getResourceString("tool.New.folder.tip"));
item.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e)
{
VFSUtil.newFolder(getCurrentDirectory());
}
});
item = new ToolItem(toolBar, SWT.SEPARATOR);
// Parent
item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(iconCache.get(CFPluginImages.ICON_FOLDER_PARENT));
//item.setText(getResourceString("tool.Parent.tiptext"));
item.setToolTipText(getResourceString("tool.Parent.tiptext"));
item.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) {
doParent();
}
});
// Refresh
item = new ToolItem(toolBar, SWT.PUSH);
item.setImage(iconCache.get(CFPluginImages.ICON_REFRESH));
//item.setText(getResourceString("tool.Refresh.tiptext"));
item.setToolTipText(getResourceString("tool.Refresh.tiptext"));
item.addSelectionListener(new SelectionAdapter () {
public void widgetSelected(SelectionEvent e) {
doRefresh();
}
});
return toolBar;
}
/**
* Creates the combo box view.
*
* @param parent the parent control
*/
private Control createComboView(Composite parent, Object layoutData)
{
combo = new Combo(parent, SWT.NONE);
combo.setLayoutData(layoutData);
combo.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e)
{
final FileObject[] roots = (FileObject[]) combo.getData(COMBODATA_ROOTS);
if (roots == null) return;
int selection = combo.getSelectionIndex();
if (selection >= 0 && selection < roots.length)
{
try {
System.out.println("combo.widgetSelected " + roots[selection]);
notifySelectedDirectory(roots[selection],roots[selection].getName().toString());
} catch (Exception ex) {
System.err.println("createComboView.widgetSelected: " + ex);
}
}
}
public void widgetDefaultSelected(SelectionEvent e) {
final String lastText = (String) combo.getData(COMBODATA_LASTTEXT);
final String lastConnectionId = (String) combo.getData(COMBODATA_LASTCONNECTIONID);
String text = combo.getText();
if (text == null) return;
if (lastText != null && lastText.equals(text)) return;
combo.setData(COMBODATA_LASTTEXT, text);
try {
FileObject file = resolveURI(text,lastConnectionId);
if ( file.exists() )
notifySelectedDirectory(file,lastConnectionId);
else {
VFSUtil.MessageBoxInfo(
getResourceString("file.not.found", new Object[] {file}) );
combo.setText(getCurrentDirectory().toString());
}
} catch (FileSystemException ex) {
System.err.println("createComboView::widgetDefaultSelected Error: " + ex);
}
}
});
return combo;
}
/**
* 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(VFSView.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];
try {
//FileObject file = (FileObject) item.getData(TREEITEMDATA_FILE);
String uri = (String) item.getData(TREEITEMDATA_URI);
String connectionId = (String) item.getData(TREEITEMDATA_CONNECTIONID);
shell.setText(getResourceString("Title.Resolving"
, new Object[] { uri } ));
notifySelectedDirectory(resolveURI(uri, connectionId),connectionId);
}
catch (FileSystemException e) {
debug(e); // "createTreeView.widgetSelected " +
VFSUtil.MessageBoxError( VFSUtil.getErrorMessageStack(e));
VFSUtil.setUiStateIdle(shell, getCurrentDirectory().getName().toString());
}
}
}
public void widgetDefaultSelected(SelectionEvent event) {
final TreeItem[] selection = tree.getSelection();
if (selection != null && selection.length != 0) {
TreeItem item = selection[0];
String imageName;
if(item.getExpanded()) {
imageName = TREEITEMDATA_IMAGECOLLAPSED;
} else {
imageName = TREEITEMDATA_IMAGEEXPANDED;
}
item.setExpanded(!item.getExpanded());
final Image image = (Image) item.getData(imageName);
if (image != null) item.setImage(image);
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);
}
});
// Listen for key presses
tree.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event)
{
if ( event.keyCode == 127 )
{
TreeItem item = tree.getSelection()[0];
String connectionId = (String)item.getData(TREEITEMDATA_CONNECTIONID);
// delete at the root level only
if ( ! (item.getParentItem() == null) ) return;
if ( connectionId.startsWith("file://"))
VFSUtil.MessageBoxInfo(getResourceString("remove.local.fs"));
else {
deleteAction.run(item);
}
}
}
});
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_COPY); // | DND.DROP_MOVE
// Transfer data type is text (file URI)
dragSource.setTransfer(new Transfer[] { FileTransfer.getInstance() });
//dragSource.setTransfer(new Transfer[] { RTFTransfer.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;
//TODO try {
// handleDeferredRefresh();
// } catch (Exception e) {
// debug ("createTreeDragSource.dragFinished " + e);
// }
}
public void dragSetData(DragSourceEvent event){
if (dndSelection == null || dndSelection.length == 0) return;
//if (! FileTransfer.getInstance().isSupportedType(event.dataType)) return;
if (! FileTransfer.getInstance().isSupportedType(event.dataType)) {
//debug("createTreeDragSource.dragSetData File transfer data type is required");
return;
}
sourceNames = new String[dndSelection.length];
FileObject file = null;
String uri = null;
String connectionId = null;
for (int i = 0; i < dndSelection.length; i++) {
uri = (String) dndSelection[i].getData(TREEITEMDATA_URI);
connectionId = (String) dndSelection[i].getData(TREEITEMDATA_CONNECTIONID);
try {
file = resolveURI(uri,connectionId);
} catch (FileSystemException e) {
debug(e); //"createTreeDragSource.dragSetData " +
continue;
}
/*
* In Order for FileTransfer to Work, the name must begin w/
* / in UNIX systems
*/
sourceNames[i] = Os.isFamily(Os.OS_FAMILY_UNIX)
? FileName.SEPARATOR + file.toString()
: file.toString();
System.out.println("createTreeDragSource.dragSetData file path=" + sourceNames[i]);
}
//sourceNames[0] = connectionId;
fSourceConnectionId = connectionId;
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_COPY); // | DND.DROP_MOVE
dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
// Transfer data type is text
//dropTarget.setTransfer(new Transfer[] { RTFTransfer.getInstance()} );
System.out.println("createTreeDropTarget");
dropTarget.addDropListener(new DropTargetAdapter() {
public void dragEnter(DropTargetEvent event) {
isDropping = true;
}
public void dragLeave(DropTargetEvent event) {
isDropping = false;
//TODO try {
// handleDeferredRefresh();
// } catch (Exception e) {
// debug("createTreeDropTarget.dragLeave " + e);
// }
}
public void dragOver(DropTargetEvent event) {
dropTargetValidate(event, getTargetFile(event));
event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
}
public void drop(DropTargetEvent event) {
FileAndConnectionId targetFile = getTargetFile(event);
try {
System.out.println("createTreeDropTarget.drop targetFile=" + targetFile.file);
if (dropTargetValidate(event, targetFile))
dropTargetHandleDrop(event, targetFile);
}
catch (FileSystemException e) {
VFSUtil.MessageBoxError(e.getMessage());
}
catch (Exception e1) {
debug(e1); // "createTreeDropTarget.drop " +
}
}
private FileAndConnectionId getTargetFile(DropTargetEvent event) {
// Determine the target FileObject for the drop
TreeItem item = tree.getItem(tree.toControl(new Point(event.x, event.y)));
FileObject targetFile = null;
String connectionId = "";
if (item != null) {
// We are over a particular item in the tree, use the item's file
//targetFile = (FileObject) item.getData(TREEITEMDATA_FILE);
String uri = (String)item.getData(TREEITEMDATA_URI);
connectionId = (String)item.getData(TREEITEMDATA_CONNECTIONID);
try {
targetFile = resolveURI(uri,connectionId);
} catch (Exception e) {
debug(e); //"createTreeDropTarget.getTargetFile " +
}
}
return new FileAndConnectionId(targetFile,connectionId);
}
});
return dropTarget;
}
/**
* Handles expand events on a tree item.
*
* @param item the TreeItem to fill in
*/
private void treeExpandItem(TreeItem item)
{
shell.setCursor(CFPluginImages.cursors[CFPluginImages.cursorWait]);
final Object stub = item.getData(TREEITEMDATA_STUB);
if (stub == null) {
try {
treeRefreshItem(item, true);
} catch (Exception e) {
debug(e); // "treeExpandItem " +
}
}
shell.setCursor(CFPluginImages.cursors[CFPluginImages.cursorDefault]);
}
/**
* Add a file sytem node
* @param filesystem
*/
public void addFileSystem (String connectionId)
{
try {
TreeItem newItem = new TreeItem(tree, SWT.NULL);
treeInitVolume(newItem, connectionId) ;// masterFile);
// placeholder child item to get "expand" button
new TreeItem(newItem, SWT.NULL);
} catch (Exception e) {
VFSUtil.MessageBoxInfo(e.getMessage());
}
}
/**
* Traverse the entire tree and update only what has changed.
*
* @param roots the root directory listing
*/
private void treeRefresh(FileObject[] 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 String uri = (String)item.getData(TREEITEMDATA_URI);
final FileObject itemFile = null;
if ((itemFile == null) || (masterIndex == masterFiles.length)) {
// remove bad item or placeholder
item.dispose();
continue;
}
final FileObject masterFile = masterFiles[masterIndex];
int compare = VFSUtil.compareFiles(masterFile, itemFile);
if (compare == 0) {
// same file, update it
try {
treeRefreshItem(item, false);
} catch (Exception e) {
error("treeRefresh.treeRefreshItem " + e);
}
++itemIndex;
++masterIndex;
}
else if (compare < 0) {
// should appear before file, insert it
TreeItem newItem = new TreeItem(tree, SWT.NULL, itemIndex);
treeInitVolume(newItem, masterFile.getName().toString()) ;// 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 FileObject masterFile = masterFiles[masterIndex];
TreeItem newItem = new TreeItem(tree, SWT.NULL);
//System.out.println("treeRefresh file=" + masterFile.getName().getURI());
treeInitVolume(newItem, masterFile.getName().toString()) ;// masterFile);
new TreeItem(newItem, SWT.NULL); // placeholder child item to get "expand" button
}
}
/**
* Insert URIS from $HOME/.vfs into the Tree
*/
private void treeInsertRemoteURIs ()
{
// Add remote URI nodes to the tree
if ( fConnections != null ) {
Iterator it = fConnections.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
FTPConnectionProperties conProps = (FTPConnectionProperties) pairs.getValue();
if(!conProps.getURI().equals(conProps.getConnectionid())) {
VFSUtil.treeAddFsNode(tree, conProps);
}
}
}
}
public void treeRefreshRemoteURIs ()
{
fConnections = VFSUtil.loadFileSystems();
try {
treeRefresh(getRoots(fsManager));
} catch (FileSystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if ( fConnections != null ) {
Iterator it = fConnections.entrySet().iterator();
TreeItem[] items = tree.getItems();
int masterIndex = 0;
int itemIndex = 0;
while (it.hasNext()) {
boolean foundConnection = false;
Map.Entry pairs = (Map.Entry)it.next();
FTPConnectionProperties conProps = (FTPConnectionProperties) pairs.getValue();
for (int i = 0; i < items.length; ++i) {
final TreeItem item = items[i];
final String treeConnectionId = (String)item.getData(TREEITEMDATA_CONNECTIONID);
final String filePath = (String)item.getData(TREEITEMDATA_FILE);
if(treeConnectionId.equals(conProps.getConnectionid())){
foundConnection = true;
break;
} else {
if(fConnections.get(treeConnectionId) == null && filePath != treeConnectionId) {
item.dispose();
}
}
}
if(!foundConnection) {
VFSUtil.treeAddFsNode(tree, conProps);
}
}
}
}
/**
* 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)
throws FileSystemException
{
final String uri = (String) dirItem.getData(TREEITEMDATA_URI);
//System.out.println("treeRefreshItem uri=" + uri);
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 */
FileObject[] subFiles = (uri != null)
? getDirectoryList( resolveURI(uri,(String) dirItem.getData(TREEITEMDATA_CONNECTIONID)))
: 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 FileObject[] masterFiles = subFiles;
int masterIndex = 0;
int itemIndex = 0;
FileObject masterFile = null;
String folderBaseName = null;
for (int i = 0; i < items.length; ++i) {
while ((masterFile == null) && (masterIndex < masterFiles.length)) {
masterFile = masterFiles[masterIndex++];
//if (! masterFile.isDirectory()) masterFile = null;
if (! VFSUtil.isDirectory(masterFile)) masterFile = null;
}
final TreeItem item = items[i];
// final String itemUri = (String) item.getData(TREEITEMDATA_URI);
//System.out.println("itemUri=" + itemUri);
final String itemFile = (String) item.getData(TREEITEMDATA_URI);
//final FileObject itemFile = (FileObject) item.getData(TREEITEMDATA_FILE);
if ((itemFile == null) || (masterFile == null)) {
// remove bad item or placeholder
item.dispose();
continue;
}
int compare = VFSUtil.compareFiles(masterFile, resolveURI( itemFile, (String) item.getData(TREEITEMDATA_CONNECTIONID)) );
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);
folderBaseName = masterFile.getName().getBaseName();
//treeInitFolder(newItem, folderBaseName , uri + FileName.SEPARATOR + folderBaseName); //masterFile);
treeInitFolder(newItem, folderBaseName , masterFile.toString());
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);
folderBaseName = masterFile.getName().getBaseName();
//treeInitFolder(newItem, folderBaseName , uri + FileName.SEPARATOR + folderBaseName );
treeInitFolder(newItem, folderBaseName , masterFile.toString());
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 (! VFSUtil.isDirectory(masterFile) ) {
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 FileObject associated with this TreeItem
*/
private void treeInitFolder(TreeItem item, String folder, String uri) {
item.setText(folder);
item.setImage(iconCache.get(CFPluginImages.ICON_FOLDER));
item.setData(TREEITEMDATA_FILE, folder);
item.setData(TREEITEMDATA_URI, uri);
item.setData(TREEITEMDATA_CONNECTIONID, item.getParentItem().getData(TREEITEMDATA_CONNECTIONID));
item.setData(TREEITEMDATA_IMAGEEXPANDED, iconCache.get(CFPluginImages.ICON_FOLDER_OPEN));
item.setData(TREEITEMDATA_IMAGECOLLAPSED, iconCache.get(CFPluginImages.ICON_FOLDER));
}
/**
* Initializes a volume item.
*
* @param item the TreeItem to initialize
* @param volume the File associated with this TreeItem
*/
private void treeInitVolume(TreeItem item, String connectionId ) {//FileObject volume) {
FTPConnectionProperties connectionProperties = fConnections.get(connectionId);
if(connectionProperties == null) {
addLocalConnection(connectionId);
connectionProperties = fConnections.get(connectionId);
}
item.setText(connectionId);
item.setImage(iconCache.get(CFPluginImages.ICON_DRIVE));
item.setData(TREEITEMDATA_FILE, connectionProperties.getConnectionid());
item.setData(TREEITEMDATA_URI, connectionProperties.getURI());
item.setData(TREEITEMDATA_CONNECTIONID, connectionProperties.getConnectionid());
item.setData(TREEITEMDATA_IMAGEEXPANDED, iconCache.get(CFPluginImages.ICON_DRIVE_FTP));
item.setData(TREEITEMDATA_IMAGECOLLAPSED, iconCache.get(CFPluginImages.ICON_DRIVE));
}
/**
* Creates the file details table.
*
* @param parent the parent control
*/
private void createTableView(Composite parent)
{
//Composite composite = new Composite(parent, SWT.NONE);
TabFolder composite = new TabFolder(parent, SWT.NONE);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 1;
gridLayout.marginHeight = gridLayout.marginWidth = 2;
gridLayout.horizontalSpacing = gridLayout.verticalSpacing = 0;
composite.setLayout(gridLayout);
tabFileItems = new TabItem(composite, SWT.CLOSE);
// 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));
//ColumnViewerToolTipSupport.enableFor(table);
// Tooltips
// final ToolTipHandler tooltip = new ToolTipHandler(parent.getParent().getShell());
// tooltip.activateHoverHelp(table);
tabFileItems.setControl(table);
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);
// Listen for key presses
table.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
// Del key pressed
if ( event.keyCode == 127 )
{
FileObject[] files = getSelectedFiles();
int count = files.length;
// set a single delete or multiple delete text message
String message = (count == 1)
? getResourceString("msg.box.delete.uri", new Object[]{files[0]})
: getResourceString("msg.box.delete.resources", new Object[]{new Integer(count), getCurrentDirectory() }) ;
if ( VFSUtil.MessageBoxYesNo( message) )
{
deleteObjects(files);
// Refresh
doRefresh();
}
}
}
private FileObject[] getSelectedFiles() {
final TableItem[] items = table.getSelection();
final FileObject[] files = new FileObject[items.length];
for (int i = 0; i < items.length; ++i) {
files[i] = (FileObject) items[i].getData(TABLEITEMDATA_FILE);
}
return files;
}
});
// Listen for selections
table.addSelectionListener(new SelectionAdapter() {
// Fires when item is clicked
public void widgetSelected(SelectionEvent event) {
try {
notifySelectedFiles(getSelectedFiles());
} catch (Exception e) {
//debug ("createTableView.widgetSelected " + e);
}
}
// fires when list item is selected (double clicked)
public void widgetDefaultSelected(SelectionEvent event) {
doDefaultFileAction(getSelectedFiles());
}
private FileObject[] getSelectedFiles() {
final TableItem[] items = table.getSelection();
final FileObject[] files = new FileObject[items.length];
for (int i = 0; i < items.length; ++i) {
files[i] = (FileObject) 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_COPY); // | DND.DROP_MOVE
// transfer type is text data (file URI)
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;
//TODO try {
// handleDeferredRefresh();
// } catch (Exception e) {
// debug("createTableDragSource.dragFinished " + e);
// }
}
public void dragSetData(DragSourceEvent event) {
if (dndSelection == null || dndSelection.length == 0) return;
if (! FileTransfer.getInstance().isSupportedType(event.dataType)) {
error("createTableDragSource.dragSetData File Transfer data type text is required.");
return;
}
// Cannot put Objects in the transfer event data field, they must be path
// and begin with / in UNIX
sourceNames = new String[dndSelection.length+1];
String connectionId = "";
for (int i = 1; i < dndSelection.length; i++) {
FileObject file = (FileObject) dndSelection[i].getData(TABLEITEMDATA_FILE);
connectionId = (String) dndSelection[i].getData(TABLEITEMDATA_CONNECTIONID);
/*
* In Order for FileTransfer to Work, the name must begin w/
* / in UNIX systems
*/
sourceNames[i] = Os.isFamily(Os.OS_FAMILY_UNIX)
? FileName.SEPARATOR + file.toString()
: file.toString();
System.out.println("createTableDragSource::dragSetData: sourceNames ["
+ i + "] path= " + sourceNames[i] );
}
sourceNames[0] = connectionId;
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_COPY); // | DND.DROP_MOVE
dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
//dropTarget.setTransfer(new Transfer[] { RTFTransfer.getInstance() });
dropTarget.addDropListener(new DropTargetAdapter() {
public void dragEnter(DropTargetEvent event) {
isDropping = true;
}
public void dragLeave(DropTargetEvent event) {
isDropping = false;
// TODO try {
// handleDeferredRefresh();
// } catch (Exception e) {
// debug("createTableDropTarget.dragLeave " + e);
// }
}
public void dragOver(DropTargetEvent event) {
dropTargetValidate(event, getTargetFile(event));
event.feedback |= DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
}
public void drop(DropTargetEvent event) {
FileAndConnectionId targetFile = getTargetFile(event);
try {
if (dropTargetValidate(event, targetFile))
dropTargetHandleDrop(event, targetFile);
} catch (Exception e) {
debug(e); // "createTableDropTarget.drop " +
}
}
private FileAndConnectionId getTargetFile(DropTargetEvent event) {
// Determine the target FileObject for the drop
TableItem item = table.getItem(table.toControl(new Point(event.x, event.y)));
FileObject targetFile = null;
String connectionId = "";
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 = (FileObject) table.getData(TABLEDATA_DIR);
connectionId = (String) table.getData(TABLEDATA_CONNECTIONID);
}
} else {
// We are over a particular item in the table, use the item's file
targetFile = (FileObject) item.getData(TABLEITEMDATA_FILE);
connectionId = (String) table.getData(TABLEITEMDATA_CONNECTIONID);
}
return new FileAndConnectionId(targetFile,connectionId);
}
});
return dropTarget;
}
/**
* Notifies the application components that a new current directory has been selected
*
* @param dir the directory that was selected, null is ignored
*/
public void notifySelectedDirectory(FileObject dir, String connectionId)
throws FileSystemException
{
if (dir == null || connectionId == null) return;
if (getCurrentDirectory() != null && dir.equals(getCurrentDirectory())) return;
setCurrentDirectory(dir);
setCurrentConnectionId(connectionId);
//System.err.println("notifySelectedDirectory currentDirectory:"
// + currentDirectory + " notify dir:" + dir );
// Processing...
VFSUtil.setUiStateListContents(shell, getCurrentDirectory().getName().toString());
notifySelectedFiles(null);
/* Table view:
* Displays the contents of the selected directory.
*/
workerUpdate(dir, connectionId, false);
/* Combo view:
* Sets the combo box to point to the selected directory.
*/
final FileObject[] comboRoots = (FileObject[]) 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.getName().toString());
else combo.select(comboEntry);
/* Tree view:
* If not already expanded, recursively expands the parents of the specified
* directory until it is visible.
*/
Vector /* of FileObject */ path = new Vector();
// Build a stack of paths from the root of the tree
while (dir != null) {
path.add(dir);
//dir = dir.getParentFile();
try {
dir = dir.getParent();
} catch (Exception e) {
System.err.println("notifySelectedDirectory:" + e);
}
}
//System.out.println("notifySelectedDirectory currentDirectory:"
// + currentDirectory + " dir:" + dir + " tree path:" + path);
// Recursively expand the tree to get to the specified directory
TreeItem[] items = tree.getItems();
TreeItem lastItem = null;
String destConnectionId = null;
TreeItem item = null;
// filter by connection first
for (int k = 0; k < items.length; ++k) {
item = items[k];
destConnectionId = (String)item.getData(TREEITEMDATA_CONNECTIONID);
if(connectionId.equals(connectionId)){
items = items[k].getItems();
}
}
for (int i = path.size() - 1; i >= 0; --i)
{
final FileObject pathElement = (FileObject) path.elementAt(i);
// Search for a particular FileObject 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.
item = null;
for (int k = 0; k < items.length; ++k) {
item = items[k];
if (item.isDisposed()) continue;
final String fileURI = ((String)item.getData(TREEITEMDATA_URI));
destConnectionId = (String)item.getData(TREEITEMDATA_CONNECTIONID);
// Resolving the children will attempt a server connection. This will hang the UI if the server is down
// Thus perform a comparison by Host/Scheme/Path only
// Cannot just compare the URI strings cuz FileObject hides the port number
if (connectionId.equals(destConnectionId) && VFSUtil.compareURIs(fileURI, pathElement.toString()) )
break;
}
if (item == null) break;
lastItem = item;
if (i != 0 && !item.getExpanded()) {
treeExpandItem(item);
item.setExpanded(true);
}
items = item.getItems();
}
if(connectionId.equals(destConnectionId)) {
tree.setSelection((lastItem != null) ? new TreeItem[] { lastItem } : new TreeItem[0]);
}
/* Shell:
* Sets the title to indicate the selected directory
*/
VFSUtil.setUiStateIdle(shell, VFSUtil.stripUserTokens(getCurrentDirectory().toString()));
}
/**
* 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(FileObject[] files) throws FileSystemException {
/* 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();
fileSize += files[i].getContent().getSize();
}
diskSpaceLabel.setText(getResourceString("details.FileSize.text",
new Object[] { new Long(fileSize) }));
} else {
// No files selected
diskSpaceLabel.setText("");
if (getCurrentDirectory() != null)
{
int numObjects = getDirectoryList( getCurrentDirectory()).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
*/
public void notifyRefreshFiles(FileObject[] files) throws FileSystemException {
if (files != null && files.length == 0) return;
if ((deferredRefreshRequested) && (deferredRefreshFiles != null) && (files != null)) {
// merge requests
FileObject[] newRequest = new FileObject[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() throws FileSystemException
{
//System.out.println("handleDeferredRefresh");
if (isDragging || isDropping || ! deferredRefreshRequested) return;
deferredRefreshRequested = false;
FileObject[] files = deferredRefreshFiles;
deferredRefreshFiles = null;
shell.setCursor(CFPluginImages.cursors[CFPluginImages.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 FileObject file = files[i];
if (file.equals(getCurrentDirectory())) {
refreshTable = true;
break;
}
FileObject parentFile = file.getParent();
if ((parentFile != null) && (parentFile.equals(getCurrentDirectory()))) {
refreshTable = true;
break;
}
}
}
else
refreshTable = true;
if (refreshTable)
workerUpdate(getCurrentDirectory(), getCurrentConnectionId(), true);
/* Combo view:
* Refreshes the list of roots
*/
final FileObject[] roots = getRoots(fsManager);
if (files == null) {
boolean refreshCombo = false;
final FileObject[] comboRoots = (FileObject[]) 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 FileObject file = roots[i];
combo.add(file.getName().toString() );
}
}
}
/* Tree view:
* Refreshes information about any files in the list and their children.
*/
treeRefresh(roots);
treeInsertRemoteURIs();
// Remind everyone where we are in the filesystem
final FileObject dir = getCurrentDirectory();
setCurrentDirectory(null);
final String con = getCurrentConnectionId();
setCurrentConnectionId(null);
notifySelectedDirectory(dir,con);
shell.setCursor(CFPluginImages.cursors[CFPluginImages.cursorDefault]);
}
/**
* Performs the default action on a set of files.
*
* @param files the array of files to process
*/
void doDefaultFileAction(FileObject[] files) {
// only uses the 1st file (for now)
if (files.length == 0) return;
final FileObject file = files[0];
if (VFSUtil.isDirectory(file)) {
try {
notifySelectedDirectory(file,getCurrentConnectionId());
} catch (Exception e) {
debug(e); // "FileViewer.doDefaultFileAction " +
}
}
else {
//final String fileName = file.getAbsolutePath();
RemoteFileEditorInput input = new RemoteFileEditorInput(file);
try {
IEditorDescriptor desc = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(file.getName().getBaseName());
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getActivePage();
//page.openEditor(input, desc.getId());
page.openEditor(input, CFMLEditor.ID);
// wonder how this could work?
// IFileStore fileStore;
// fileStore = EFS.getFileSystem(file.getName().getScheme()).getStore(file.getURL().toURI());
// IDE.openEditorOnFileStore( page, fileStore );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 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 (getCurrentDirectory() == null) return;
//FileObject parentDirectory = currentDirectory.getParentFile();
try {
FileObject parentDirectory = getCurrentDirectory().getParent();
notifySelectedDirectory(parentDirectory,getCurrentConnectionId());
} catch (Exception e) {
System.err.println("FileViewer::doParent " + e);
}
}
/**
* Performs a refresh
*/
void doRefresh() {
try {
notifyRefreshFiles(null);
} catch (Exception e) {
debug (e); // "FileViewer.doRefresh " +
}
}
/**
* Validates a drop target as a candidate for a drop operation.
* <p>
* Used in dragOver() and dropAccept().<br>
* Note event.detail is set to DND.DROP_NONE by this method if the target is not valid.
* </p>
* @param event the DropTargetEvent to validate
* @param fileAndConnectionId the FileObject representing the drop target location
* under inspection, or null if none
*/
private boolean dropTargetValidate(DropTargetEvent event, FileAndConnectionId fileAndConnectionId)
{
//if (targetFile != null && targetFile.isDirectory()) {
if (fileAndConnectionId.file != null && VFSUtil.isDirectory(fileAndConnectionId.file) ) {
if (event.detail != DND.DROP_COPY && event.detail != DND.DROP_MOVE) {
event.detail = DND.DROP_COPY; // DND.DROP_MOVE;
}
} else {
event.detail = DND.DROP_NONE;
}
return event.detail != DND.DROP_NONE;
}
/**
* Handles a drop on a dropTarget.
* <p>
* Used in drop().<br>
* Note event.detail is modified by this method.
* </p>
* @param event the DropTargetEvent passed as parameter to the drop() method
* @param targetFile the FileObject representing the drop target location
* under inspection, or null if none
*/
private void dropTargetHandleDrop(DropTargetEvent event, FileAndConnectionId fileAndConnectionId)
throws IOException
{
// 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;
VFSUtil.copyFiles(fsManager, sourceNames, fConnections.get(fSourceConnectionId), fileAndConnectionId.file, fConnections.get(fileAndConnectionId.connectionId));
//VFSUtil.copyFiles(fsManager, sourceNames, fileAndConnectionId.file);
// refresh
notifyRefreshFiles(new FileObject[] { fileAndConnectionId.file });
}
/**
* Handles the completion of a drag on a dragSource.
* <p>
* Used in dragFinished().<br>
* </p>
* @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)
* @param sourceConnectionId
*/
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
// Do nothing w/ source files
}
/**
* Gets filesystem root entries
* @param fsManager
* @return an array of Files corresponding to the root directories on the platform,
* may be empty but not null
*/
FileObject[] getRoots( FileSystemManager fsManager)
throws FileSystemException
{
/*
* On JDK 1.22 only...
*/
// return File.listRoots();
FileObject[] roots = null;
// FileObject[] newRequest = null;
/*
* On JDK 1.1.7 and beyond...
* -- PORTABILITY ISSUES HERE --
*/
if (System.getProperty ("os.name").indexOf ("Windows") != -1) {
Vector /* of FileObject */ list = new Vector();
list.add(fsManager.resolveFile(DRIVE_A));
for (char i = 'c'; i <= 'z'; ++i)
{
//FileObject drive = new FileObject(i + ":" + FileName.SEPARATOR);
FileObject drive = fsManager.resolveFile(i + ":" + FileName.SEPARATOR);
if (VFSUtil.isDirectory(drive) && drive.exists()) {
list.add(drive);
if (initial && i == 'c') {
setCurrentDirectory(drive);
setCurrentConnectionId(drive.getName().toString());
initial = false;
}
}
}
roots = (FileObject[]) list.toArray(new FileObject[list.size()]);
VFSUtil.sortFiles(roots);
//return roots;
}
else {
FileObject root = fsManager.resolveFile (FileName.SEPARATOR);
if (initial) {
setCurrentDirectory(root);
setCurrentConnectionId(root.getName().toString());
initial = false;
}
roots = new FileObject[] { root };
}
return roots; //newRequest;
}
private void addLocalConnection(String connectionId) {
FTPConnectionProperties newConProps = new FTPConnectionProperties(connectionId);
newConProps.setURI(connectionId);
fConnections.put(connectionId, newConProps);
}
/*
* This worker updates the table with file information in the background.
* <p>
* Implementation notes:
* <ul>
* <li> It is designed such that it can be interrupted cleanly.
* <li> 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.
* </ul>
* </p>
*/
/**
* 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 currentConnectionId
* @param force if true causes a refresh even if the data is the same
*/
void workerUpdate(FileObject dir, String connectionId, boolean force) {
if (dir == null) return;
if ((!force) && (workerNextDir != null) && (workerNextDir.equals(dir))) return;
synchronized(workerLock) {
workerNextDir = dir;
workerNextConnectionId = connectionId;
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;
workerStateConnectionId = workerNextConnectionId;
}
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() {
FileObject[] dirList;
// Clear existing information
display.syncExec(new Runnable() {
public void run()
{
tabFileItems.setText(VFSView.getResourceString("details.ContentsOf.text",
new Object[] { VFSUtil.stripUserTokens(workerStateDir.toString()) }));
table.removeAll();
table.setData(TABLEDATA_DIR, workerStateDir);
table.setData(TABLEDATA_CONNECTIONID,workerStateConnectionId);
}
});
try {
dirList = getDirectoryList( workerStateDir);
for (int i = 0; (! workerCancelled) && (i < dirList.length); i++) {
workerAddFileDetails(dirList[i],workerStateConnectionId);
}
} catch (FileSystemException e) {
VFSUtil.MessageBoxError( e.getMessage());
}
}
/**
* Adds a file's detail information to the directory list
*/
private void workerAddFileDetails(final FileObject file, final String connectionId)
{
long date = 0;
try {
date = file.getContent().getLastModifiedTime();
} catch (Exception e) {}
final String nameString = file.getName().getBaseName();
final String dateString = dateFormat.format(new Date(date));
final String sizeString;
final String typeString;
final Image iconImage;
// If directory
if (VFSUtil.isDirectory(file))
{
typeString = getResourceString("filetype.Folder");
sizeString = "";
iconImage = iconCache.get(CFPluginImages.ICON_FOLDER);
}
else {
long size = 0;
try {
size = file.getContent().getSize();
} catch (Exception e) {}
// It is a file, get size
sizeString = getResourceString("filesize.KB",
new Object[] { new Long((size + 512) / 1024) });
int dot = nameString.lastIndexOf('.');
if (dot != -1)
{
String extension = nameString.substring(dot);
Program program = Program.findProgram(extension);
// get icon based on extension
if (program != null)
{
typeString = program.getName();
iconImage = CFPluginImages.getIconFromProgram(program);
}
else {
typeString = getResourceString("filetype.Unknown", new Object[] { extension.toUpperCase() });
iconImage = iconCache.get(CFPluginImages.ICON_FILE);
}
}
else {
typeString = getResourceString("filetype.None");
iconImage = iconCache.get(CFPluginImages.ICON_FILE);
}
}
// Table values: Name, Size, Type, Date
final String[] strings = new String[] { nameString, sizeString, typeString, dateString };
display.syncExec(new Runnable() {
public void run () {
String attrs = VFSUtil.getFileAttributes(file);
// 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);
tableItem.setData(TABLEITEMDATA_CONNECTIONID, connectionId);
if ( attrs.length() > 0 )
tableItem.setData ("TIP_TEXT", attrs);
}
});
}
/**
* Resolve a FileSystem Uri seting progress UI messages
*/
public FileObject resolveURI (String Uri, String connectionId) throws FileSystemException
{
shell.setCursor(CFPluginImages.cursors[CFPluginImages.cursorWait]);
shell.setText(getResourceString("Title.Resolving"
, new Object[] { Uri }));
FTPConnectionProperties connectionProperties = fConnections.get(connectionId);
FileObject fo = fsManager.resolveFile(Uri,connectionProperties.getFileSystemOptions());
shell.setCursor(CFPluginImages.cursors[CFPluginImages.cursorDefault]);
shell.setText(getResourceString("Title"
, new Object[] { Uri }));
return fo;
}
/**
* 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
*/
private FileObject[] getDirectoryList(FileObject file)
throws FileSystemException
{
FileObject[] list = file.getChildren();
if (list == null) {
return new FileObject[0];
}
VFSUtil.sortFiles(list);
return list;
}
/**
* Delete selected files
* @param files
*/
private void deleteObjects (FileObject[] files)
{
// run a delete operation
try {
FileOperation delOperation = new FileOperation(fsManager, FileOperation.DELETE, true);
delOperation.setDeleteArgs(files);
new ProgressMonitorDialog(shell).run(true, true, delOperation);
}
catch (InvocationTargetException e)
{
VFSUtil.MessageBoxError(e.getMessage());
} catch (InterruptedException e)
{
VFSUtil.MessageBoxInfo(e.getMessage());
}
// Refresh
doRefresh();
}
@Override
public void setFocus() {
// TODO Auto-generated method stub
}
public boolean show(ShowInContext context) {
String filePath;
if (table == null || context == null)
return false;
ISelection sel = context.getSelection();
Object input = context.getInput();
if (input instanceof CFJavaFileEditorInput) {
filePath = ((CFJavaFileEditorInput)input).getPath(input).toString();
}
else {
filePath = ((FileEditorInput)input).getFile().getRawLocation().toString();
}
//showFile(filePath);
return false;
}
/**
* @param currentConnectionId the currentConnectionId to set
*/
public void setCurrentConnectionId(String currentConnectionId) {
this.currentConnectionId = currentConnectionId;
}
/**
* @return the currentConnectionId
*/
public String getCurrentConnectionId() {
return currentConnectionId;
}
/**
* @param currentDirectory the currentDirectory to set
*/
public void setCurrentDirectory(FileObject currentDirectory) {
this.currentDirectory = currentDirectory;
}
/**
* @return the currentDirectory
*/
public FileObject getCurrentDirectory() {
return currentDirectory;
}
public class FileAndConnectionId {
public FileObject file = null;
public String connectionId = "";
public FileAndConnectionId(FileObject file, String connectionId) {
super();
this.file = file;
this.connectionId = connectionId;
}
}
}