blob: 4a01a2ae8eb8a6f66c003ae800f65f9bb74e3d2c [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2007 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 - Initial API and implementation
*
* </copyright>
*
* $Id$
*/
package org.eclipse.gmf.runtime.emf.ui.preferences;
import java.io.File;
import org.eclipse.core.resources.IPathVariableManager;
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.emf.common.util.URI;
import org.eclipse.gmf.runtime.emf.core.internal.resources.PathmapManager;
import org.eclipse.gmf.runtime.emf.ui.internal.MslUIPlugin;
import org.eclipse.gmf.runtime.emf.ui.internal.l10n.EMFUIMessages;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
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.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.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* Modal dialog for manipulation of path variables for modeling pathmaps. This
* dialog supports both creation of new path variables, using the
* {@link #openNew(Shell)} method, and editing of existing path variables, using
* the {@link #openEdit(Shell, String, String)} method. In either case, if the
* user successfully closes the dialog (i.e., hits the OK button), then the name
* and location of the variable are accessed via the {@link #getVariableName()}
* and {@link #getVariableLocation()} methods, respectively.
* <p>
* Note that this dialog intentionally differs from that utilized by the Linked
* Resources preference page because GMF's pathmaps apply more constraints to
* path variables, in particular that:
* </p>
* <ul>
* <li>a pathmap variable name must be a valid URI segment, because it is used
* as is in <tt>pathmap://</tt> URIs</li>
* <li>a pathmap variable must reference a folder, not a file</li>
* </ul>
*
* @author Christian W. Damus (cdamus)
*/
class NewPathVariableDialog
extends TitleAreaDialog {
private String variableName;
private IPath variableLocation;
private Text nameText;
private Text locationText;
private String initialName;
private String initialLocation;
private final IPathVariableManager pathMgr;
private final String plainMsg;
private final PathmapsPreferencePage page;
/**
* Not instantiable by clients.
*
* @param page
* the path maps preference page that I serve
* @param name
* the current name of the variable to be edited, or
* <code>null</code> if creating a new path variable
* @param location
* the current location of the variable to be edited, or
* <code>null</code> if creating a new path variable
*/
private NewPathVariableDialog(PathmapsPreferencePage page, String name,
String location) {
super(page.getShell());
this.page = page;
this.initialName = name;
this.initialLocation = location;
if (name != null) {
// edit mode
plainMsg = EMFUIMessages.PathVariableDialog_editMessage;
} else {
// new mode
plainMsg = EMFUIMessages.PathVariableDialog_newMessage;
}
pathMgr = ResourcesPlugin.getWorkspace().getPathVariableManager();
}
/**
* Opens the path-variable editing dialog in creation mode, to create a new
* path variable.
*
* @param page
* the path maps preference page that the dialog serves
* @return the dialog instance, from which the path variable data can be
* extracted, if the user closed it with the "OK" button;
* <code>null</code>, otherwise (i.e., if the user canceled)
*/
public static NewPathVariableDialog openNew(PathmapsPreferencePage page) {
NewPathVariableDialog dlg = new NewPathVariableDialog(page, null, null);
return (dlg.open() == IDialogConstants.OK_ID) ? dlg
: null;
}
/**
* Opens the path-variable editing dialog in edit mode, to modify an
* existing path variable. Clients must account for the possibility that the
* returned variable name may differ from the specified <code>name</code>,
* because users may rename variables.
*
* @param page
* the path maps preference page that the dialog serves
* @return the dialog instance, from which the path variable data can be
* extracted, if the user closed it with the "OK" button;
* <code>null</code>, otherwise (i.e., if the user canceled)
*/
public static NewPathVariableDialog openEdit(PathmapsPreferencePage page,
String name, String location) {
NewPathVariableDialog dlg = new NewPathVariableDialog(page, name,
location);
return (dlg.open() == IDialogConstants.OK_ID) ? dlg
: null;
}
/**
* Sets the dialog's window title according to whether it is in creation or
* edit mode.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
if (initialName != null) {
// edit mode
newShell.setText(EMFUIMessages.PathVariableDialog_editTitle);
} else {
// new mode
newShell.setText(EMFUIMessages.PathVariableDialog_newTitle);
}
}
protected Control createDialogArea(Composite parent) {
Composite result = (Composite) super.createDialogArea(parent);
initializeDialogUnits(result);
Composite composite = new Composite(result, SWT.NONE);
composite.setLayout(new GridLayout(3, false));
GridData data = null;
data = new GridData(GridData.FILL_BOTH);
data.grabExcessHorizontalSpace = true;
data.grabExcessHorizontalSpace = true;
data.horizontalIndent = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
data.verticalIndent = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
composite.setLayoutData(data);
Label label = new Label(composite, SWT.LEFT);
label.setText(EMFUIMessages.PathVariableDialog_nameLabel);
data = new GridData(SWT.BEGINNING);
label.setLayoutData(data);
nameText = new Text(composite, SWT.BORDER);
data = new GridData(GridData.FILL_HORIZONTAL);
data.grabExcessHorizontalSpace = true;
nameText.setLayoutData(data);
if (initialName != null) {
nameText.setText(initialName);
}
// blank to occupy the upper-right corner
new Label(composite, SWT.None);
label = new Label(composite, SWT.NONE);
label.setText(EMFUIMessages.PathVariableDialog_locationLabel);
data = new GridData(SWT.BEGINNING);
label.setLayoutData(data);
// force left-to-right orientation because file paths are always LTR
locationText = new Text(composite, SWT.BORDER | SWT.LEFT_TO_RIGHT);
data = new GridData(GridData.FILL_HORIZONTAL);
data.grabExcessHorizontalSpace = true;
locationText.setLayoutData(data);
if (initialLocation != null) {
locationText.setText(initialLocation);
}
Button browseButton = new Button(composite, SWT.PUSH);
browseButton.setText(EMFUIMessages.PathVariableDialog_browseButton);
setButtonLayoutData(browseButton);
browseButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
DirectoryDialog dlg = new DirectoryDialog(getShell());
dlg.setText(EMFUIMessages.PathVariableDialog_browseDialogTitle);
dlg
.setMessage(EMFUIMessages.PathVariableDialog_browseDialogMessage);
String folder = dlg.open();
if (folder != null) {
locationText.setText(folder);
}
}
});
ModifyListener l = new ModifyListener() {
public void modifyText(ModifyEvent e) {
validateInputs();
}
};
nameText.addModifyListener(l);
locationText.addModifyListener(l);
if (initialName != null) {
// edit mode
setTitle(EMFUIMessages.PathVariableDialog_editTitle);
// select the location field text and set focus to it
locationText.setSelection(0, locationText.getText().length());
locationText.setFocus();
} else {
// new mode
setTitle(EMFUIMessages.PathVariableDialog_newTitle);
}
setMessage(plainMsg);
return result;
}
/**
* Initially disables the OK button, because in either creation or edit
* mode, the user will have to input some data before it can hit OK.
*/
protected void createButtonsForButtonBar(Composite parent) {
super.createButtonsForButtonBar(parent);
// initially, the OK button is disabled because we haven't yet any input
getButton(IDialogConstants.OK_ID).setEnabled(false);
}
/**
* Validates the current values of the variable name and location entry
* fields. A warning or error message is shown in the title area, if
* appropriate, and the OK button is disabled if any input is invalid.
* Moreover, in edit mode, the OK button is disabled if the user hasn't
* changed either the variable name or the location.
*/
private void validateInputs() {
IStatus status = Status.OK_STATUS;
boolean isError = false;
String name = nameText.getText();
String location = locationText.getText();
boolean hasName = name.length() > 0;
boolean hasLocation = location.length() > 0;
if (hasName && !name.equals(initialName)) {
status = validateName(name);
}
if (!status.isOK()) {
isError = true;
setMessage(status.getMessage(), IMessageProvider.ERROR);
} else if (hasLocation && !location.equals(initialLocation)) {
status = validateLocation(new Path(location));
if (!status.isOK()) {
isError = status.getSeverity() >= IStatus.ERROR;
setMessage(status.getMessage(),
isError ? IMessageProvider.ERROR
: IMessageProvider.WARNING);
}
}
if (status.isOK()) {
setMessage(plainMsg);
}
if (initialName != null) {
// edit mode. Check that either the name or the location is changed
if (name.equals(initialName) && location.equals(initialLocation)) {
// force OK button to be disabled
hasName = false;
}
}
// dialog not complete if error or missing an input
getButton(IDialogConstants.OK_ID).setEnabled(
!isError && hasName && hasLocation);
}
/**
* Validates the specified variable <code>name</code>.
*
* @param name
* the variable name to validate
* @return the result of validation, which may be OK or may contain a
* warning or error message to display in the title area
*/
private IStatus validateName(String name) {
IStatus result;
if (pathMgr.isDefined(name) && !page.isRemoved(name)
|| PathmapManager.isRegisteredPathVariable(name)
|| page.isAdded(name)) {
result = new Status(IStatus.ERROR, MslUIPlugin.getPluginId(),
EMFUIMessages.PathVariableDialog_alreadyDefined_ERROR_);
} else if (!URI.validSegment(name)) {
result = new Status(IStatus.ERROR, MslUIPlugin.getPluginId(),
EMFUIMessages.PathVariableDialog_invalidSegment_ERROR_);
} else {
result = pathMgr.validateName(name);
}
return result;
}
/**
* Validates the specified variable <code>location</code>.
*
* @param location
* the variable location to validate
* @return the result of validation, which may be OK or may contain a
* warning or error message to display in the title area
*/
private IStatus validateLocation(IPath location) {
IStatus result;
File file = location.toFile();
if (file.exists() && !file.isDirectory()) {
result = new Status(IStatus.ERROR, MslUIPlugin.getPluginId(),
EMFUIMessages.PathVariableDialog_notFolder_ERROR_);
} else if (!file.exists()) {
result = new Status(IStatus.ERROR, MslUIPlugin.getPluginId(),
EMFUIMessages.PathVariableDialog_noSuchFolder_ERROR_);
} else {
result = pathMgr.validateValue(location);
}
if (result.isOK()) {
if (page.isLocationDefined(location)) {
result = new Status(IStatus.WARNING, MslUIPlugin
.getPluginId(),
EMFUIMessages.PathVariableDialog_sameLocation_WARN_);
}
}
return result;
}
/**
* Stores the variable name and location for retrieval by the client when
* the user succeeds in closing the dialog by pressing the OK button.
*
* @see #getVariableName()
* @see #getVariableLocation()
*/
protected void okPressed() {
variableName = nameText.getText();
variableLocation = new Path(locationText.getText());
super.okPressed();
}
/**
* Obtains the path variable name entered by the user.
*
* @return the path variable name
*/
String getVariableName() {
return variableName;
}
/**
* Obtains the path variable location entered by the user.
*
* @return the path variable location
*/
IPath getVariableLocation() {
return variableLocation;
}
}