| /******************************************************************************* |
| * Copyright (c) 2008, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| * Martin Oberhuber - [468889] Support Eclipse older than Mars |
| *******************************************************************************/ |
| package org.eclipse.remote.ui.widgets; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.filesystem.EFS; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.IInputValidator; |
| import org.eclipse.jface.dialogs.InputDialog; |
| import org.eclipse.jface.dialogs.ProgressMonitorDialog; |
| import org.eclipse.jface.operation.IRunnableContext; |
| import org.eclipse.jface.operation.IRunnableWithProgress; |
| import org.eclipse.jface.viewers.DoubleClickEvent; |
| import org.eclipse.jface.viewers.IDoubleClickListener; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.jface.viewers.TreeSelection; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.jface.viewers.ViewerFilter; |
| import org.eclipse.remote.core.IRemoteConnection; |
| import org.eclipse.remote.core.IRemoteFileService; |
| import org.eclipse.remote.core.IRemoteProcessService; |
| import org.eclipse.remote.core.RemoteServicesUtils; |
| import org.eclipse.remote.internal.ui.DeferredFileStore; |
| import org.eclipse.remote.internal.ui.DeferredFileStoreComparer; |
| import org.eclipse.remote.internal.ui.PendingUpdateAdapter; |
| import org.eclipse.remote.internal.ui.RemoteContentProvider; |
| import org.eclipse.remote.internal.ui.RemoteResourceComparator; |
| import org.eclipse.remote.internal.ui.RemoteTreeViewer; |
| import org.eclipse.remote.internal.ui.RemoteUIImages; |
| import org.eclipse.remote.internal.ui.RemoteUIPlugin; |
| import org.eclipse.remote.internal.ui.messages.Messages; |
| import org.eclipse.remote.ui.IRemoteUIConnectionService; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.TraverseEvent; |
| import org.eclipse.swt.events.TraverseListener; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.model.WorkbenchLabelProvider; |
| import org.eclipse.ui.progress.UIJob; |
| |
| /** |
| * Generic file/directory browser for remote resources. |
| * |
| * @author greg |
| * |
| */ |
| public class RemoteResourceBrowserWidget extends Composite { |
| /** |
| * Delayed input dialog uses {@link ValidateJob} to create an InputDialog that only validates it's text field after an |
| * appropriate timeout has occurred. This is to prevent excessive network traffic when checking the existence of a remote |
| * directory on a target system. |
| * |
| * Due to the timing of the validation, it is possible to close the dialog prior to the validation completing. However since the |
| * validation is only used to check for the existence of a remote file/directory, the worst that can happen is that the user |
| * will not be notified that the directory already exists. |
| * |
| */ |
| private class DelayedInputDialog extends InputDialog { |
| public DelayedInputDialog(Shell parentShell, String dialogTitle, String dialogMessage, String initialValue, |
| IInputValidator validator) { |
| super(parentShell, dialogTitle, dialogMessage, initialValue, validator); |
| } |
| |
| @Override |
| protected void buttonPressed(int buttonId) { |
| /* |
| * Cancel the job as soon as the dialog is closed to avoid SWTException |
| */ |
| fValidateJob.cancel(); |
| super.buttonPressed(buttonId); |
| } |
| |
| protected void doValidate() { |
| super.validateInput(); |
| } |
| |
| @Override |
| protected void validateInput() { |
| fValidateJob.cancel(); |
| if (!getText().getText().equals("")) { //$NON-NLS-1$ |
| fValidateJob.schedule(VALIDATE_DELAY); |
| } else { |
| super.validateInput(); |
| } |
| } |
| } |
| |
| /** |
| * Validation job that will call the {@link DelayedInputDialog#doValidate()} method when run. The job should be scheduled with a |
| * delay to limit the frequency of validation. |
| */ |
| private class ValidateJob extends UIJob { |
| private DelayedInputDialog fDialog; |
| |
| public ValidateJob() { |
| super(Messages.RemoteResourceBrowserWidget_0); |
| setSystem(true); |
| } |
| |
| @Override |
| public IStatus runInUIThread(IProgressMonitor monitor) { |
| fDialog.doValidate(); |
| return Status.OK_STATUS; |
| } |
| |
| public void setDialog(DelayedInputDialog dialog) { |
| fDialog = dialog; |
| } |
| } |
| |
| private static final int VALIDATE_DELAY = 100; |
| private final ValidateJob fValidateJob = new ValidateJob(); |
| |
| /** |
| * Browse for files |
| */ |
| public static final int FILE_BROWSER = 0x01; |
| /** |
| * Browse for directories (files are not shown) |
| */ |
| public static final int DIRECTORY_BROWSER = 0x02; |
| /** |
| * Show local selection button |
| */ |
| public static final int SHOW_LOCAL_SELECTION = 0x04; |
| /** |
| * Display checkbox to show/hide hidden files |
| */ |
| public static final int SHOW_HIDDEN_CHECKBOX = 0x10; |
| /** |
| * Display button to create new folders |
| */ |
| public static final int SHOW_NEW_FOLDER_BUTTON = 0x20; |
| /** |
| * Display widget to select a connection |
| */ |
| public static final int SHOW_CONNECTIONS = 0x40; |
| |
| @SuppressWarnings("unused") |
| private static final int minimumWidth = 200; |
| private static final int heightHint = 300; |
| |
| private RemoteTreeViewer fTreeViewer; |
| private Text fRemotePathText; |
| private Button fUpButton; |
| private Button fNewFolderButton; |
| private Button fShowHiddenButton; |
| private RemoteConnectionWidget fRemoteConnectionWidget; |
| |
| private String fDialogTitle; |
| private String fDialogLabel; |
| |
| private boolean fShowHidden; |
| private final List<IFileStore> fResources = new ArrayList<>(); |
| private String fResource; |
| private String fInitialPath; |
| private IPath fRootPath; |
| private IRemoteFileService fFileMgr; |
| private IRemoteConnection fConnection; |
| |
| private final ListenerList fSelectionListeners = new ListenerList(); |
| |
| private int fOptionFlags = FILE_BROWSER | SHOW_HIDDEN_CHECKBOX | SHOW_NEW_FOLDER_BUTTON; |
| |
| private IRunnableContext fRunnableContext; |
| |
| public RemoteResourceBrowserWidget(Composite parent, int style, int flags) { |
| super(parent, style); |
| setTitle(Messages.RemoteResourceBrowser_resourceTitle); |
| |
| if (flags != 0) { |
| fOptionFlags = flags; |
| } |
| |
| setType(); |
| |
| GridLayout layout = new GridLayout(1, false); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| setLayout(layout); |
| |
| final Composite mainComp = new Composite(this, SWT.NONE); |
| mainComp.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| mainComp.setLayout(new GridLayout(1, false)); |
| |
| if ((fOptionFlags & SHOW_CONNECTIONS) != 0) { |
| fRemoteConnectionWidget = new RemoteConnectionWidget(mainComp, SWT.NONE, "", //$NON-NLS-1$ |
| (fOptionFlags & SHOW_LOCAL_SELECTION) == 0 ? RemoteConnectionWidget.FLAG_NO_LOCAL_SELECTION : 0); |
| fRemoteConnectionWidget.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); |
| // Must happen before adding selection listener as this will trigger selection event |
| fRemoteConnectionWidget.filterConnections(IRemoteFileService.class); |
| fRemoteConnectionWidget.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent event) { |
| try { |
| connectionSelected(); |
| } catch (CoreException e) { |
| RemoteUIPlugin.log(e.getStatus()); |
| } |
| updateEnablement(); |
| notifySelectionChangedListeners(new SelectionChangedEvent(fTreeViewer, new ISelection() { |
| @Override |
| public boolean isEmpty() { |
| return true; |
| } |
| })); |
| } |
| }); |
| } |
| |
| Composite textComp = new Composite(mainComp, SWT.NONE); |
| layout = new GridLayout(4, false); |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| textComp.setLayout(layout); |
| textComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| |
| Label label = new Label(textComp, SWT.NONE); |
| label.setText(fDialogLabel); |
| label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); |
| |
| fRemotePathText = new Text(textComp, SWT.BORDER | SWT.SINGLE); |
| fRemotePathText.addTraverseListener(new TraverseListener() { |
| @Override |
| public void keyTraversed(TraverseEvent e) { |
| if (e.detail == SWT.TRAVERSE_RETURN) { |
| e.doit = false; |
| } |
| } |
| }); |
| fRemotePathText.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetDefaultSelected(SelectionEvent e) { |
| fRemotePathText.setSelection(fRemotePathText.getText().length()); |
| setRoot(fRemotePathText.getText()); |
| } |
| }); |
| fRemotePathText.addModifyListener(new ModifyListener() { |
| @Override |
| public void modifyText(ModifyEvent e) { |
| fResource = fRemotePathText.getText().trim(); |
| } |
| }); |
| GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); |
| // gd.minimumWidth = minimumWidth; |
| fRemotePathText.setLayoutData(gd); |
| |
| fUpButton = new Button(textComp, SWT.PUSH | SWT.FLAT); |
| fUpButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); |
| fUpButton.setImage(RemoteUIImages.get(RemoteUIImages.IMG_ELCL_UP_NAV)); |
| fUpButton.setToolTipText(Messages.RemoteResourceBrowser_UpOneLevel); |
| fUpButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (!fRootPath.isRoot()) { |
| setRoot(fRootPath.removeLastSegments(1).toString()); |
| } |
| } |
| }); |
| |
| if ((fOptionFlags & SHOW_NEW_FOLDER_BUTTON) != 0) { |
| // new folder: See Bug 396334 |
| fNewFolderButton = new Button(textComp, SWT.PUSH | SWT.FLAT); |
| fNewFolderButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); |
| fNewFolderButton.setImage(RemoteUIImages.get(RemoteUIImages.IMG_ELCL_NEW_FOLDER)); |
| fNewFolderButton.setToolTipText(Messages.RemoteResourceBrowser_NewFolder); |
| fNewFolderButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| ISelection selection = fTreeViewer.getSelection(); |
| if (!selection.isEmpty()) { |
| if (selection instanceof TreeSelection) { |
| TreePath[] treePaths = ((TreeSelection) selection).getPaths(); |
| /* |
| * There should only be one path |
| */ |
| if (treePaths.length > 0) { |
| TreePath treePath = treePaths[0]; |
| if (treePath.getLastSegment() instanceof DeferredFileStore) { |
| DeferredFileStore element = ((DeferredFileStore) treePath.getLastSegment()); |
| String path = toPath(element.getFileStore().toURI()); |
| String newPath = createNewFolder(path); |
| if (newPath != null) { |
| fTreeViewer.expandToLevel(element, 1); |
| fTreeViewer.refresh(element); |
| Object[] children = element.getChildren(null); |
| for (Object child : children) { |
| if (child instanceof DeferredFileStore && newPath |
| .equals(((DeferredFileStore) child).getFileStore().getName())) { |
| fTreeViewer.deferSelection(new StructuredSelection(child)); |
| } |
| } |
| } |
| } |
| } |
| } |
| } else { |
| DeferredFileStore root = (DeferredFileStore) fTreeViewer.getInput(); |
| String path = toPath(root.getFileStore().toURI()); |
| String newPath = createNewFolder(path); |
| if (newPath != null) { |
| fTreeViewer.refresh(); |
| fTreeViewer.getTree().setFocus(); |
| Object[] children = root.getChildren(null); |
| for (Object child : children) { |
| if (child instanceof DeferredFileStore |
| && newPath.equals(((DeferredFileStore) child).getFileStore().getName())) { |
| fTreeViewer.deferSelection(new StructuredSelection(child)); |
| } |
| } |
| } |
| } |
| } |
| }); |
| } else { |
| gd = new GridData(SWT.LEFT, SWT.CENTER, false, false); |
| gd.horizontalSpan = 2; |
| fUpButton.setLayoutData(gd); |
| } |
| |
| if ((style & SWT.MULTI) == SWT.MULTI) { |
| fTreeViewer = new RemoteTreeViewer(mainComp, SWT.MULTI | SWT.BORDER); |
| } else { |
| fTreeViewer = new RemoteTreeViewer(mainComp, SWT.SINGLE | SWT.BORDER); |
| } |
| gd = new GridData(SWT.FILL, SWT.FILL, true, true); |
| // see bug 158380 |
| gd.heightHint = Math.max(parent.getSize().y, heightHint); |
| fTreeViewer.getTree().setLayoutData(gd); |
| fTreeViewer.setUseHashlookup(true); |
| fTreeViewer.setComparer(new DeferredFileStoreComparer()); |
| fTreeViewer.setComparator(new RemoteResourceComparator()); |
| fTreeViewer.setContentProvider(new RemoteContentProvider()); |
| fTreeViewer.setLabelProvider(new WorkbenchLabelProvider()); |
| fTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { |
| @Override |
| public void selectionChanged(SelectionChangedEvent event) { |
| ISelection selection = event.getSelection(); |
| if (!selection.isEmpty() && selection instanceof IStructuredSelection) { |
| IStructuredSelection ss = (IStructuredSelection) selection; |
| fResources.clear(); |
| for (Object currentSelection : ss.toArray()) { |
| if (currentSelection instanceof DeferredFileStore) { |
| IFileStore store = ((DeferredFileStore) currentSelection).getFileStore(); |
| fResources.add(store); |
| } |
| } |
| if (fResources.size() > 0) { |
| fRemotePathText.setText(toPath(fResources.get(0).toURI())); |
| } |
| updateEnablement(); |
| notifySelectionChangedListeners(event); |
| } |
| } |
| }); |
| fTreeViewer.addDoubleClickListener(new IDoubleClickListener() { |
| @Override |
| public void doubleClick(DoubleClickEvent event) { |
| IStructuredSelection s = (IStructuredSelection) event.getSelection(); |
| Object o = s.getFirstElement(); |
| if (fTreeViewer.isExpandable(o)) { |
| fTreeViewer.setExpandedState(o, !fTreeViewer.getExpandedState(o)); |
| } |
| } |
| |
| }); |
| /* |
| * Only add filter if we are a directory browser. File and resource browsers show everything. |
| */ |
| int mask = FILE_BROWSER | DIRECTORY_BROWSER; |
| if ((fOptionFlags & mask) != mask // Avoid filter on resource browsers. |
| && (fOptionFlags & DIRECTORY_BROWSER) != 0) { |
| fTreeViewer.addFilter(new ViewerFilter() { |
| @Override |
| public boolean select(Viewer viewer, Object parentElement, Object element) { |
| if ((element instanceof DeferredFileStore)) { |
| return ((DeferredFileStore) element).isContainer(); |
| } |
| return element instanceof PendingUpdateAdapter; |
| } |
| }); |
| } |
| |
| if ((fOptionFlags & SHOW_HIDDEN_CHECKBOX) != 0) { |
| fShowHiddenButton = new Button(mainComp, SWT.CHECK); |
| fShowHiddenButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false)); |
| fShowHiddenButton.setText(Messages.RemoteResourceBrowser_Show_hidden_files); |
| fShowHiddenButton.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| fShowHidden = fShowHiddenButton.getSelection(); |
| setRoot(fRootPath.toString()); |
| } |
| }); |
| } |
| |
| updateEnablement(); |
| } |
| |
| private String toPath(URI uri) { |
| return getConnection().getService(IRemoteFileService.class).toPath(uri); |
| } |
| |
| /** |
| * Add a listener that will be notified when the selection is changed. |
| * |
| * @param listener |
| * listener to add |
| */ |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| fSelectionListeners.add(listener); |
| } |
| |
| /** |
| * Change the viewers input. Called when a new connection is selected. |
| * |
| * @param conn |
| * new connection |
| * @return true if input successfully changed |
| */ |
| private boolean changeInput(final IRemoteConnection conn) { |
| if (conn == null) { |
| setRoot(null); |
| return true; |
| } |
| IRemoteUIConnectionService uiMgr = conn.getConnectionType().getService(IRemoteUIConnectionService.class); |
| if (uiMgr != null) { |
| uiMgr.openConnectionWithProgress(getShell(), getRunnableContext(), conn); |
| } |
| if (!conn.isOpen()) { |
| return false; |
| } |
| |
| fFileMgr = conn.getService(IRemoteFileService.class); |
| if (fFileMgr != null) { |
| /* |
| * Note: the call to findInitialPath must happen before the |
| * fTreeViewer input is set or the fTreeViewer fails. No idea why this |
| * is. |
| */ |
| IRemoteProcessService processService = conn.getService(IRemoteProcessService.class); |
| if (processService != null) { |
| String cwd = processService.getWorkingDirectory(); |
| IPath initial = findInitialPath(cwd, fInitialPath); |
| |
| // TODO: not platform independent - needs IRemotePath |
| setRoot(initial.toString()); |
| } |
| |
| fConnection = conn; |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * When a new connection is selected, make sure it is open before using it. |
| * |
| * @throws CoreException |
| */ |
| private void connectionSelected() throws CoreException { |
| /* |
| * Make sure the connection is open before we try and read from the |
| * connection. |
| */ |
| final IRemoteConnection conn = fRemoteConnectionWidget.getConnection(); |
| if (!changeInput(conn)) { |
| /* |
| * Reset combo back to the previous selection |
| */ |
| fRemoteConnectionWidget.setConnection(fConnection); |
| } |
| } |
| |
| /** |
| * @return |
| */ |
| private String createNewFolder(final String parent) { |
| final String[] name = new String[1]; |
| name[0] = null; |
| try { |
| IRunnableWithProgress runnable = new IRunnableWithProgress() { |
| @Override |
| public void run(IProgressMonitor monitor) { |
| SubMonitor progress = SubMonitor.convert(monitor, 10); |
| String baseName = "newfolder"; //$NON-NLS-1$ |
| final IFileStore path = fConnection.getService(IRemoteFileService.class).getResource(parent); |
| IFileStore child = path.getChild(baseName); |
| int count = 1; |
| try { |
| while (!progress.isCanceled() && child.fetchInfo(EFS.NONE, progress.newChild(1)).exists()) { |
| progress.setWorkRemaining(10); |
| child = path.getChild(baseName + " (" + count++ + ")"); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| } catch (final CoreException e) { |
| Display.getDefault().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| ErrorDialog.openError(getShell(), Messages.RemoteResourceBrowserWidget_New_Folder, |
| Messages.RemoteResourceBrowserWidget_Unable_to_create_new_folder, |
| e.getStatus()); |
| } |
| }); |
| } |
| final IFileStore basePath = child; |
| final String[] userPath = new String[1]; |
| Display.getDefault().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| DelayedInputDialog dialog = new DelayedInputDialog(getShell(), |
| Messages.RemoteResourceBrowserWidget_1, Messages.RemoteResourceBrowserWidget_2, |
| basePath.getName(), new IInputValidator() { |
| @Override |
| public String isValid(String newText) { |
| if (!newText.equals("")) { //$NON-NLS-1$ |
| IFileStore newPath = path.getChild(newText); |
| if (newPath.fetchInfo().exists()) { |
| return Messages.RemoteResourceBrowserWidget_3; |
| } |
| } else { |
| return Messages.RemoteResourceBrowserWidget_4; |
| } |
| return null; |
| } |
| }); |
| fValidateJob.setDialog(dialog); |
| if (dialog.open() == Dialog.OK) { |
| userPath[0] = dialog.getValue(); |
| } |
| } |
| }); |
| if (userPath[0] != null) { |
| try { |
| IFileStore newPath = path.getChild(userPath[0]); |
| if (!progress.isCanceled()) { |
| newPath.mkdir(EFS.SHALLOW, progress.newChild(10)); |
| name[0] = newPath.getName(); |
| } |
| } catch (final CoreException e) { |
| Display.getDefault().syncExec(new Runnable() { |
| @Override |
| public void run() { |
| ErrorDialog.openError(getShell(), Messages.RemoteResourceBrowserWidget_New_Folder, |
| Messages.RemoteResourceBrowserWidget_Unable_to_create_new_folder, |
| e.getStatus()); |
| } |
| }); |
| } |
| } |
| } |
| }; |
| getRunnableContext().run(true, true, runnable); |
| } catch (InvocationTargetException e) { |
| // Ignore, return null |
| } catch (InterruptedException e) { |
| // Ignore, return null |
| } |
| return name[0]; |
| } |
| |
| /** |
| * Determine the initial path for the browser. If the initial path is not |
| * supplied or does not exist on the remote machine, then the initial path |
| * will be the cwd. |
| * |
| * @param cwd |
| * @param initialPath |
| * @return initial path |
| */ |
| private IPath findInitialPath(String cwd, String initialPath) { |
| if (initialPath != null) { |
| IPath path = RemoteServicesUtils.posixPath(initialPath); |
| if (!path.isAbsolute()) { |
| path = RemoteServicesUtils.posixPath(cwd).append(path); |
| } |
| if (fFileMgr.getResource(path.toString()).fetchInfo().exists()) { |
| return path; |
| } |
| } |
| return RemoteServicesUtils.posixPath(cwd); |
| } |
| |
| /** |
| * Get the connection that was selected |
| * |
| * @return selected connection |
| */ |
| public IRemoteConnection getConnection() { |
| return fConnection; |
| } |
| |
| /** |
| * Get a resource that corresponds to the text field |
| * |
| * @return resource corresponding to the text field |
| * @since 1.1 |
| */ |
| public IFileStore getResource() { |
| if (fResource != null) { |
| if (!fResource.equals("") && getConnection() != null) { //$NON-NLS-1$ |
| return getConnection().getService(IRemoteFileService.class).getResource(fResource); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get the resources that were selected. |
| * |
| * @return selected resources |
| */ |
| public List<IFileStore> getResources() { |
| return fResources; |
| } |
| |
| public IRunnableContext getRunnableContext() { |
| if (fRunnableContext == null) { |
| return new ProgressMonitorDialog(getShell()); |
| } |
| return fRunnableContext; |
| } |
| |
| private void notifySelectionChangedListeners(SelectionChangedEvent e) { |
| for (Object listener : fSelectionListeners.getListeners()) { |
| ((ISelectionChangedListener) listener).selectionChanged(e); |
| } |
| } |
| |
| /** |
| * Remove a listener that will be notified when the selection is changed |
| * |
| * @param listener |
| * listener to remove |
| */ |
| public void removeSelectionChangedListener(ISelectionChangedListener listener) { |
| fSelectionListeners.remove(listener); |
| } |
| |
| /** |
| * Set the connection for the browser. The connection must support the IRemoteFileService service or this method will have no |
| * effect. |
| * |
| * @param connection |
| * connection that supports the IRemoteFileService service |
| */ |
| public void setConnection(IRemoteConnection connection) { |
| if (connection.hasService(IRemoteFileService.class)) { |
| changeInput(connection); |
| if (fRemoteConnectionWidget != null) { |
| fRemoteConnectionWidget.setConnection(connection); |
| } |
| updateEnablement(); |
| } |
| } |
| |
| /** |
| * Set the initial path to start browsing. This will be set in the browser |
| * text field, and in a future version should expand the browser to this |
| * location if it exists. |
| * |
| * NOTE: This must be called *before* {@link #setConnection(IRemoteConnection)} to have any effect. |
| * |
| * @param path |
| */ |
| public void setInitialPath(String path) { |
| fInitialPath = path; |
| updateEnablement(); |
| } |
| |
| /** |
| * Set the root directory for the browser. This will also update the text |
| * field with the path. If the path is null, the browser will be set to the initial state. |
| * |
| * @param path |
| * path of root directory or null |
| */ |
| private void setRoot(String path) { |
| fResources.clear(); |
| fRootPath = null; |
| if (path == null) { |
| fTreeViewer.setInput(null); |
| } else if (fFileMgr != null) { |
| IFileStore root = fFileMgr.getResource(path); |
| fTreeViewer.setInput(new DeferredFileStore(root, !fShowHidden)); |
| fRemotePathText.setText(path); |
| fRemotePathText.setSelection(fRemotePathText.getText().length()); |
| fResources.add(root); |
| fRootPath = RemoteServicesUtils.posixPath(path); |
| } |
| } |
| |
| public void setRunnableContext(IRunnableContext context) { |
| fRunnableContext = context; |
| } |
| |
| /** |
| * Set the fDialogTitle of the dialog. |
| * |
| * @param title |
| */ |
| public void setTitle(String title) { |
| fDialogTitle = title; |
| if (fDialogTitle == null) { |
| fDialogTitle = ""; //$NON-NLS-1$ |
| } |
| Shell shell = getShell(); |
| if ((shell != null) && !shell.isDisposed()) { |
| shell.setText(fDialogTitle); |
| } |
| } |
| |
| /** |
| * Set the type of browser. Can be either a file browser (allows selection |
| * of files only) or a directory browser (allows selection of directories only), or |
| * both files and directories. |
| */ |
| public void setType() { |
| if ((fOptionFlags & DIRECTORY_BROWSER) == 0) { |
| fDialogLabel = Messages.RemoteResourceBrowser_fileLabel; |
| setTitle(Messages.RemoteResourceBrowser_fileTitle); |
| } else if ((fOptionFlags & FILE_BROWSER) == 0) { |
| fDialogLabel = Messages.RemoteResourceBrowser_directoryLabel; |
| setTitle(Messages.RemoteResourceBrowser_directoryTitle); |
| } else { |
| fDialogLabel = Messages.RemoteResourceBrowser_resourceLabel; |
| setTitle(Messages.RemoteResourceBrowser_resourceTitle); |
| } |
| } |
| |
| private void updateEnablement() { |
| boolean upEnabled = false; |
| boolean newFolderEnabled = false; |
| boolean connectionOpen = fConnection != null && fConnection.isOpen(); |
| |
| if (connectionOpen) { |
| if (fResources.size() == 1) { |
| IFileStore store = fResources.get(0); |
| /* |
| * Assume that we have already called fetchInfo() on the file store, so this should |
| * effectively be a noop. |
| */ |
| if (store.fetchInfo().isDirectory()) { |
| newFolderEnabled = true; |
| } |
| if (store.getParent() != null) { |
| upEnabled = true; |
| } |
| } |
| } |
| |
| if (fUpButton != null) { |
| fUpButton.setEnabled(upEnabled); |
| } |
| if (fNewFolderButton != null) { |
| fNewFolderButton.setEnabled(newFolderEnabled); |
| } |
| if (fRemotePathText != null) { |
| fRemotePathText.setEnabled(connectionOpen); |
| } |
| if (fTreeViewer != null) { |
| fTreeViewer.getTree().setEnabled(connectionOpen); |
| } |
| if (fShowHiddenButton != null) { |
| fShowHiddenButton.setEnabled(connectionOpen); |
| } |
| } |
| } |