| /******************************************************************************* |
| * Copyright (c) 2000, 2006 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.eclipse.ui.internal.ide.dialogs; |
| |
| import java.net.URI; |
| |
| import org.eclipse.core.filesystem.IFileInfo; |
| import org.eclipse.core.filesystem.IFileStore; |
| import org.eclipse.core.resources.IPathVariableManager; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.fieldassist.FieldAssistColors; |
| 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.SelectionListener; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontMetrics; |
| import org.eclipse.swt.graphics.GC; |
| 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.Control; |
| import org.eclipse.swt.widgets.DirectoryDialog; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Listener; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.ide.dialogs.PathVariableSelectionDialog; |
| import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; |
| import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; |
| import org.eclipse.ui.internal.ide.filesystem.FileSystemConfiguration; |
| import org.eclipse.ui.internal.ide.filesystem.FileSystemSupportRegistry; |
| |
| /** |
| * Widget group for specifying a linked file or folder target. |
| * |
| * @since 2.1 |
| */ |
| public class CreateLinkedResourceGroup { |
| private Listener listener; |
| |
| private String linkTarget = ""; //$NON-NLS-1$ |
| |
| private int type; |
| |
| private boolean createLink = false; |
| |
| // used to compute layout sizes |
| private FontMetrics fontMetrics; |
| |
| // widgets |
| private Composite groupComposite; |
| |
| private Text linkTargetField; |
| |
| private Button browseButton; |
| |
| private Button variablesButton; |
| |
| private Label resolvedPathLabelText; |
| |
| private Label resolvedPathLabelData; |
| |
| private final IStringValue updatableResourceName; |
| |
| /** |
| * Helper interface intended for updating a string value based on the |
| * currently selected link target. |
| * |
| * @since 3.2 |
| */ |
| public static interface IStringValue { |
| /** |
| * Sets the String value. |
| * |
| * @param string |
| * a non-null String |
| */ |
| void setValue(String string); |
| |
| /** |
| * Gets the String value. |
| * |
| * @return the current value, or <code>null</code> |
| */ |
| String getValue(); |
| } |
| |
| private String lastUpdatedValue; |
| |
| private FileSystemSelectionArea fileSystemSelectionArea; |
| |
| /** |
| * Creates a link target group |
| * |
| * @param type |
| * specifies the type of resource to link to. |
| * <code>IResource.FILE</code> or <code>IResource.FOLDER</code> |
| * @param listener |
| * listener to notify when one of the widgets' value is changed. |
| * @param updatableResourceName |
| * an updatable string value that will be updated to reflect the |
| * link target's last segment, or <code>null</code>. Updating |
| * will only happen if the current value of that string is null |
| * or the empty string, or if it has not been changed since the |
| * last time it was updated. |
| */ |
| public CreateLinkedResourceGroup(int type, Listener listener, |
| IStringValue updatableResourceName) { |
| this.type = type; |
| this.listener = listener; |
| this.updatableResourceName = updatableResourceName; |
| if (updatableResourceName != null) { |
| lastUpdatedValue = updatableResourceName.getValue(); |
| } |
| } |
| |
| /** |
| * Creates the widgets |
| * |
| * @param parent |
| * parent composite of the widget group |
| * @return the widget group |
| */ |
| public Composite createContents(Composite parent) { |
| Font font = parent.getFont(); |
| initializeDialogUnits(parent); |
| // top level group |
| groupComposite = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| groupComposite.setLayout(layout); |
| groupComposite.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL |
| | GridData.FILL_HORIZONTAL)); |
| groupComposite.setFont(font); |
| |
| final Button createLinkButton = new Button(groupComposite, SWT.CHECK); |
| if (type == IResource.FILE) { |
| createLinkButton |
| .setText(IDEWorkbenchMessages.CreateLinkedResourceGroup_linkFileButton); |
| } else { |
| createLinkButton |
| .setText(IDEWorkbenchMessages.CreateLinkedResourceGroup_linkFolderButton); |
| } |
| createLinkButton.setSelection(createLink); |
| createLinkButton.setFont(font); |
| SelectionListener selectionListener = new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent e) { |
| createLink = createLinkButton.getSelection(); |
| browseButton.setEnabled(createLink); |
| variablesButton.setEnabled(createLink); |
| // Set the required field color if the field is enabled |
| if (createLink) { |
| linkTargetField.setBackground(FieldAssistColors |
| .getRequiredFieldBackgroundColor(linkTargetField)); |
| } else { |
| linkTargetField.setBackground(null); |
| } |
| linkTargetField.setEnabled(createLink); |
| if (fileSystemSelectionArea != null) |
| fileSystemSelectionArea.setEnabled(createLink); |
| |
| if (listener != null) { |
| listener.handleEvent(new Event()); |
| } |
| } |
| }; |
| createLinkButton.addSelectionListener(selectionListener); |
| |
| createLinkLocationGroup(groupComposite, createLink); |
| return groupComposite; |
| } |
| |
| /** |
| * Creates the link target location widgets. |
| * |
| * @param locationGroup |
| * the parent composite |
| * @param enabled |
| * sets the initial enabled state of the widgets |
| */ |
| private void createLinkLocationGroup(Composite locationGroup, |
| boolean enabled) { |
| Button button = new Button(locationGroup, SWT.CHECK); |
| int indent = button.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; |
| |
| button.dispose(); |
| |
| // linkTargetGroup is necessary to decouple layout from |
| // resolvedPathGroup layout |
| Composite linkTargetGroup = new Composite(locationGroup, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.numColumns = 4; |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| linkTargetGroup.setLayout(layout); |
| GridData data = new GridData(GridData.FILL_HORIZONTAL); |
| data.horizontalIndent = indent; |
| linkTargetGroup.setLayoutData(data); |
| |
| // link target location entry field |
| linkTargetField = new Text(linkTargetGroup, SWT.BORDER); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; |
| data.horizontalSpan = 2; |
| linkTargetField.setLayoutData(data); |
| linkTargetField.setEnabled(enabled); |
| if (enabled) { |
| linkTargetField.setBackground(FieldAssistColors |
| .getRequiredFieldBackgroundColor(linkTargetField)); |
| } |
| linkTargetField.addModifyListener(new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| linkTarget = linkTargetField.getText(); |
| resolveVariable(); |
| if (updatableResourceName != null) { |
| String value = updatableResourceName.getValue(); |
| if (value == null |
| || value.equals("") || value.equals(lastUpdatedValue)) { //$NON-NLS-1$ |
| IPath linkTargetPath = new Path(linkTarget); |
| String lastSegment = linkTargetPath.lastSegment(); |
| if (lastSegment != null) { |
| lastUpdatedValue = lastSegment; |
| updatableResourceName.setValue(lastSegment); |
| } |
| } |
| } |
| if (listener != null) { |
| listener.handleEvent(new Event()); |
| } |
| } |
| }); |
| |
| // browse button |
| browseButton = new Button(linkTargetGroup, SWT.PUSH); |
| browseButton |
| .setText(IDEWorkbenchMessages.CreateLinkedResourceGroup_browseButton); |
| browseButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| handleLinkTargetBrowseButtonPressed(); |
| } |
| }); |
| browseButton.setEnabled(enabled); |
| setButtonLayoutData(browseButton); |
| |
| // variables button |
| variablesButton = new Button(linkTargetGroup, SWT.PUSH); |
| variablesButton |
| .setText(IDEWorkbenchMessages.CreateLinkedResourceGroup_variablesButton); |
| variablesButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(SelectionEvent event) { |
| handleVariablesButtonPressed(); |
| } |
| }); |
| variablesButton.setEnabled(enabled); |
| setButtonLayoutData(variablesButton); |
| |
| createFileSystemSelection(linkTargetGroup, enabled); |
| |
| createResolvedPathGroup(locationGroup, indent); |
| |
| if (linkTarget != null) { |
| linkTargetField.setText(linkTarget); |
| } |
| } |
| |
| /** |
| * Create the file system selection area. |
| * |
| * @param composite |
| * @param enabled |
| * the initial enablement state. |
| */ |
| private void createFileSystemSelection(Composite composite, boolean enabled) { |
| |
| // Always use the default if that is all there is. |
| if (FileSystemSupportRegistry.getInstance().hasOneFileSystem()) { |
| return; |
| } |
| |
| fileSystemSelectionArea = new FileSystemSelectionArea(); |
| fileSystemSelectionArea.createContents(composite); |
| fileSystemSelectionArea.setEnabled(enabled); |
| } |
| |
| /** |
| * Create the composite for the resolved path. |
| * |
| * @param locationGroup |
| * @param indent |
| */ |
| private void createResolvedPathGroup(Composite locationGroup, int indent) { |
| GridLayout layout; |
| GridData data; |
| Composite resolvedPathGroup = new Composite(locationGroup, SWT.NONE); |
| layout = new GridLayout(); |
| layout.numColumns = 2; |
| layout.marginHeight = 0; |
| layout.marginWidth = 0; |
| resolvedPathGroup.setLayout(layout); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| data.horizontalIndent = indent; |
| resolvedPathGroup.setLayoutData(data); |
| |
| resolvedPathLabelText = new Label(resolvedPathGroup, SWT.SINGLE); |
| resolvedPathLabelText |
| .setText(IDEWorkbenchMessages.CreateLinkedResourceGroup_resolvedPathLabel); |
| resolvedPathLabelText.setVisible(false); |
| |
| resolvedPathLabelData = new Label(resolvedPathGroup, SWT.SINGLE); |
| data = new GridData(GridData.FILL_HORIZONTAL); |
| resolvedPathLabelData.setLayoutData(data); |
| resolvedPathLabelData.setVisible(false); |
| } |
| |
| /** |
| * Returns a new status object with the given severity and message. |
| * |
| * @return a new status object with the given severity and message. |
| */ |
| private IStatus createStatus(int severity, String message) { |
| return new Status(severity, IDEWorkbenchPlugin.getDefault().getBundle() |
| .getSymbolicName(), severity, message, null); |
| } |
| |
| /** |
| * Disposes the group's widgets. |
| */ |
| public void dispose() { |
| if (groupComposite != null && groupComposite.isDisposed() == false) { |
| groupComposite.dispose(); |
| } |
| } |
| |
| /** |
| * Returns the link target location entered by the user. |
| * |
| * @return the link target location entered by the user. null if the user |
| * chose not to create a link. |
| */ |
| public String getLinkTarget() { |
| if (createLink) { |
| return linkTarget; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Opens a file or directory browser depending on the link type. |
| */ |
| private void handleLinkTargetBrowseButtonPressed() { |
| IFileStore store = null; |
| String selection = null; |
| FileSystemConfiguration config = getSelectedConfiguration(); |
| boolean isDefault = config == null |
| || (FileSystemSupportRegistry.getInstance() |
| .getDefaultConfiguration()).equals(config); |
| |
| if (linkTarget.length() > 0) { |
| store = IDEResourceInfoUtils.getFileStore(linkTarget); |
| if (!store.fetchInfo().exists()) { |
| store = null; |
| } |
| } |
| if (type == IResource.FILE) { |
| if (isDefault) { |
| FileDialog dialog = new FileDialog(linkTargetField.getShell()); |
| if (store != null) { |
| if (store.fetchInfo().isDirectory()) { |
| dialog.setFilterPath(linkTarget); |
| } else { |
| dialog.setFileName(linkTarget); |
| } |
| } |
| selection = dialog.open(); |
| } else { |
| URI uri = config.getContributor().browseFileSystem(linkTarget, |
| linkTargetField.getShell()); |
| if (uri != null) |
| selection = uri.toString(); |
| } |
| } else { |
| String filterPath = null; |
| if (store != null) { |
| IFileStore path = store; |
| if (!store.fetchInfo().isDirectory()) { |
| path = store.getParent(); |
| } |
| if (path != null) { |
| filterPath = store.toString(); |
| } |
| } |
| |
| if (isDefault) { |
| DirectoryDialog dialog = new DirectoryDialog(linkTargetField |
| .getShell()); |
| dialog |
| .setMessage(IDEWorkbenchMessages.CreateLinkedResourceGroup_targetSelectionLabel); |
| if (filterPath != null) |
| dialog.setFilterPath(filterPath); |
| selection = dialog.open(); |
| } else { |
| String initialPath = IDEResourceInfoUtils.EMPTY_STRING; |
| if (filterPath != null) |
| initialPath = filterPath; |
| URI uri = config.getContributor().browseFileSystem(initialPath, |
| linkTargetField.getShell()); |
| if (uri != null) |
| selection = uri.toString(); |
| } |
| } |
| if (selection != null) { |
| linkTargetField.setText(selection); |
| } |
| } |
| |
| /** |
| * Return the selected configuration or <code>null</code> |
| * if there is not one selected. |
| * @return FileSystemConfiguration or <code>null</code> |
| */ |
| private FileSystemConfiguration getSelectedConfiguration() { |
| if(fileSystemSelectionArea == null) |
| return null; |
| return fileSystemSelectionArea.getSelectedConfiguration(); |
| } |
| |
| /** |
| * Opens a path variable selection dialog |
| */ |
| private void handleVariablesButtonPressed() { |
| int variableTypes = IResource.FOLDER; |
| |
| // allow selecting file and folder variables when creating a |
| // linked file |
| if (type == IResource.FILE) { |
| variableTypes |= IResource.FILE; |
| } |
| |
| PathVariableSelectionDialog dialog = new PathVariableSelectionDialog( |
| linkTargetField.getShell(), variableTypes); |
| if (dialog.open() == IDialogConstants.OK_ID) { |
| String[] variableNames = (String[]) dialog.getResult(); |
| if (variableNames != null && variableNames.length == 1) { |
| linkTargetField.setText(variableNames[0]); |
| } |
| } |
| } |
| |
| /** |
| * Initializes the computation of horizontal and vertical dialog units based |
| * on the size of current font. |
| * <p> |
| * This method must be called before <code>setButtonLayoutData</code> is |
| * called. |
| * </p> |
| * |
| * @param control |
| * a control from which to obtain the current font |
| */ |
| protected void initializeDialogUnits(Control control) { |
| // Compute and store a font metric |
| GC gc = new GC(control); |
| gc.setFont(control.getFont()); |
| fontMetrics = gc.getFontMetrics(); |
| gc.dispose(); |
| } |
| |
| /** |
| * Tries to resolve the value entered in the link target field as a |
| * variable, if the value is a relative path. Displays the resolved value if |
| * the entered value is a variable. |
| */ |
| private void resolveVariable() { |
| IPathVariableManager pathVariableManager = ResourcesPlugin |
| .getWorkspace().getPathVariableManager(); |
| IPath path = new Path(linkTarget); |
| IPath resolvedPath = pathVariableManager.resolvePath(path); |
| |
| if (path.equals(resolvedPath)) { |
| resolvedPathLabelText.setVisible(false); |
| resolvedPathLabelData.setVisible(false); |
| } else { |
| resolvedPathLabelText.setVisible(true); |
| resolvedPathLabelData.setVisible(true); |
| } |
| resolvedPathLabelData.setText(resolvedPath.toOSString()); |
| } |
| |
| /** |
| * Sets the <code>GridData</code> on the specified button to be one that |
| * is spaced for the current dialog page units. The method |
| * <code>initializeDialogUnits</code> must be called once before calling |
| * this method for the first time. |
| * |
| * @param button |
| * the button to set the <code>GridData</code> |
| * @return the <code>GridData</code> set on the specified button |
| */ |
| private GridData setButtonLayoutData(Button button) { |
| GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| int widthHint = Dialog.convertHorizontalDLUsToPixels(fontMetrics, |
| IDialogConstants.BUTTON_WIDTH); |
| data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, |
| SWT.DEFAULT, true).x); |
| button.setLayoutData(data); |
| return data; |
| } |
| |
| /** |
| * Sets the value of the link target field |
| * |
| * @param target |
| * the value of the link target field |
| */ |
| public void setLinkTarget(String target) { |
| linkTarget = target; |
| if (linkTargetField != null && linkTargetField.isDisposed() == false) { |
| linkTargetField.setText(target); |
| } |
| } |
| |
| /** |
| * Validates the type of the given file against the link type specified in |
| * the constructor. |
| * |
| * @param linkTargetFile |
| * file to validate |
| * @return IStatus indicating the validation result. IStatus.OK if the given |
| * file is valid. |
| */ |
| private IStatus validateFileType(IFileInfo linkTargetFile) { |
| if (type == IResource.FILE && linkTargetFile.isDirectory()) { |
| return createStatus( |
| IStatus.ERROR, |
| IDEWorkbenchMessages.CreateLinkedResourceGroup_linkTargetNotFile); |
| } else if (type == IResource.FOLDER && !linkTargetFile.isDirectory()) { |
| return createStatus( |
| IStatus.ERROR, |
| IDEWorkbenchMessages.CreateLinkedResourceGroup_linkTargetNotFolder); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| /** |
| * Validates this page's controls. |
| * |
| * @param linkHandle |
| * The target to check |
| * |
| * @return IStatus indicating the validation result. IStatus.OK if the |
| * specified link target is valid given the linkHandle. |
| */ |
| public IStatus validateLinkLocation(IResource linkHandle) { |
| if (linkTargetField == null || linkTargetField.isDisposed()) { |
| return createStatus(IStatus.OK, ""); //$NON-NLS-1$ |
| } |
| |
| IWorkspace workspace = IDEWorkbenchPlugin.getPluginWorkspace(); |
| IPath path = new Path(linkTarget); |
| |
| if (createLink == false) { |
| return createStatus(IStatus.OK, ""); //$NON-NLS-1$ |
| } |
| |
| if (path.isUNC()) { |
| // print that path is not valid, but don't do core validation. See |
| // bug 90825. |
| return createStatus( |
| IStatus.WARNING, |
| IDEWorkbenchMessages.CreateLinkedResourceGroup_unableToValidateLinkTarget); |
| } |
| |
| IStatus locationStatus = workspace.validateLinkLocation(linkHandle, |
| path); |
| if (locationStatus.getSeverity() == IStatus.ERROR) { |
| return locationStatus; |
| } |
| |
| // use the resolved link target name |
| String resolvedLinkTarget = resolvedPathLabelData.getText(); |
| path = new Path(resolvedLinkTarget); |
| IFileInfo linkTargetFile = IDEResourceInfoUtils |
| .getFileInfo(resolvedLinkTarget); |
| if (linkTargetFile != null && linkTargetFile.exists()) { |
| IStatus fileTypeStatus = validateFileType(linkTargetFile); |
| if (fileTypeStatus.isOK() == false) { |
| return fileTypeStatus; |
| } |
| } else if (locationStatus.getSeverity() == IStatus.OK) { |
| // locationStatus takes precedence over missing location warning. |
| return createStatus( |
| IStatus.WARNING, |
| IDEWorkbenchMessages.CreateLinkedResourceGroup_linkTargetNonExistent); |
| } |
| return locationStatus; |
| } |
| } |