blob: b5443c65265010cdc707c0fe7d43ddc6d5faf9cb [file] [log] [blame]
/*******************************************************************************
* 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
* Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
* font should be activated and used by other components.
*******************************************************************************/
package org.eclipse.ui.dialogs;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectNatureDescriptor;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
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.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
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.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.ide.dialogs.CreateLinkedResourceGroup;
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
/**
* The NewFolderDialog is used to create a new folder.
* The folder can optionally be linked to a file system folder.
* <p>
* NOTE:
* A linked folder can only be created at the project
* level. The widgets used to specify a link target are disabled
* if the supplied container is not a project.
* </p>
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*/
public class NewFolderDialog extends SelectionStatusDialog {
// widgets
private Text folderNameField;
private Button advancedButton;
private CreateLinkedResourceGroup linkedResourceGroup;
private IContainer container;
private boolean firstLinkCheck = true;
/**
* Parent composite of the advanced widget group for creating
* linked resources.
*/
private Composite linkedResourceParent;
/**
* Linked resources widget group. Null if advanced section is not visible.
*/
private Composite linkedResourceComposite;
/**
* Height of the dialog without the "advanced" linked resource group.
* Set when the advanced group is first made visible.
*/
private int basicShellHeight = -1;
/**
* Creates a NewFolderDialog
*
* @param parentShell parent of the new dialog
* @param container parent of the new folder
*/
public NewFolderDialog(Shell parentShell, IContainer container) {
super(parentShell);
this.container = container;
setTitle(IDEWorkbenchMessages.NewFolderDialog_title);
setShellStyle(getShellStyle() | SWT.RESIZE);
setStatusLineAboveButtons(true);
}
/**
* Creates the folder using the name and link target entered
* by the user.
* Sets the dialog result to the created folder.
*/
protected void computeResult() {
//Do nothing here as we
//need to know the result
}
/* (non-Javadoc)
* Method declared in Window.
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
PlatformUI.getWorkbench().getHelpSystem().setHelp(shell,
IIDEHelpContextIds.NEW_FOLDER_DIALOG);
}
/**
* @see org.eclipse.jface.window.Window#create()
*/
public void create() {
super.create();
// initially disable the ok button since we don't preset the
// folder name field
getButton(IDialogConstants.OK_ID).setEnabled(false);
}
/**
* Creates the widget for advanced options.
*
* @param parent the parent composite
*/
protected void createAdvancedControls(Composite parent) {
Preferences preferences = ResourcesPlugin.getPlugin()
.getPluginPreferences();
if (preferences.getBoolean(ResourcesPlugin.PREF_DISABLE_LINKING) == false
&& isValidContainer()) {
linkedResourceParent = new Composite(parent, SWT.NONE);
linkedResourceParent.setFont(parent.getFont());
linkedResourceParent.setLayoutData(new GridData(
GridData.FILL_HORIZONTAL));
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
linkedResourceParent.setLayout(layout);
advancedButton = new Button(linkedResourceParent, SWT.PUSH);
advancedButton.setFont(linkedResourceParent.getFont());
advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
setButtonLayoutData(advancedButton);
GridData data = (GridData) advancedButton.getLayoutData();
data.horizontalAlignment = GridData.BEGINNING;
advancedButton.setLayoutData(data);
advancedButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
handleAdvancedButtonSelect();
}
});
}
linkedResourceGroup = new CreateLinkedResourceGroup(IResource.FOLDER,
new Listener() {
public void handleEvent(Event e) {
validateLinkedResource();
firstLinkCheck = false;
}
},
new CreateLinkedResourceGroup.IStringValue(){
public void setValue(String string) {
folderNameField.setText(string);
}
public String getValue() {
return folderNameField.getText();
}
});
}
/* (non-Javadoc)
* Method declared on Dialog.
*/
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
createFolderNameGroup(composite);
createAdvancedControls(composite);
return composite;
}
/**
* Creates the folder name specification controls.
*
* @param parent the parent composite
*/
private void createFolderNameGroup(Composite parent) {
Font font = parent.getFont();
// project specification group
Composite folderGroup = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
folderGroup.setLayout(layout);
folderGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// new project label
Label folderLabel = new Label(folderGroup, SWT.NONE);
folderLabel.setFont(font);
folderLabel.setText(IDEWorkbenchMessages.NewFolderDialog_nameLabel);
// new project name entry field
folderNameField = new Text(folderGroup, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH;
folderNameField.setLayoutData(data);
folderNameField.setFont(font);
folderNameField.addListener(SWT.Modify, new Listener() {
public void handleEvent(Event event) {
validateLinkedResource();
}
});
}
/**
* Creates a folder resource handle for the folder with the given name.
* The folder handle is created relative to the container specified during
* object creation.
*
* @param folderName the name of the folder resource to create a handle for
* @return the new folder resource handle
*/
private IFolder createFolderHandle(String folderName) {
IWorkspaceRoot workspaceRoot = container.getWorkspace().getRoot();
IPath folderPath = container.getFullPath().append(folderName);
IFolder folderHandle = workspaceRoot.getFolder(folderPath);
return folderHandle;
}
/**
* Creates a new folder with the given name and optionally linking to
* the specified link target.
*
* @param folderName name of the new folder
* @param linkTargetName name of the link target folder. may be null.
* @return IFolder the new folder
*/
private IFolder createNewFolder(String folderName,
final String linkTargetName) {
final IFolder folderHandle = createFolderHandle(folderName);
WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {
public void execute(IProgressMonitor monitor) throws CoreException {
try {
monitor.beginTask(IDEWorkbenchMessages.NewFolderDialog_progress, 2000);
if (monitor.isCanceled())
throw new OperationCanceledException();
if (linkTargetName == null)
folderHandle.create(false, true, monitor);
else
folderHandle.createLink(new Path(linkTargetName),
IResource.ALLOW_MISSING_LOCAL, monitor);
if (monitor.isCanceled())
throw new OperationCanceledException();
} finally {
monitor.done();
}
}
};
try {
new ProgressMonitorJobsDialog(getShell())
.run(true, true, operation);
} catch (InterruptedException exception) {
return null;
} catch (InvocationTargetException exception) {
if (exception.getTargetException() instanceof CoreException) {
ErrorDialog.openError(getShell(), IDEWorkbenchMessages.NewFolderDialog_errorTitle,
null, // no special message
((CoreException) exception.getTargetException())
.getStatus());
} else {
// CoreExceptions are handled above, but unexpected runtime exceptions and errors may still occur.
IDEWorkbenchPlugin.log(getClass(),
"createNewFolder", exception.getTargetException()); //$NON-NLS-1$
MessageDialog.openError(getShell(), IDEWorkbenchMessages.NewFolderDialog_errorTitle,
NLS.bind(IDEWorkbenchMessages.NewFolderDialog_internalError, exception.getTargetException().getMessage()));
}
return null;
}
return folderHandle;
}
/**
* Shows/hides the advanced option widgets.
*/
protected void handleAdvancedButtonSelect() {
Shell shell = getShell();
Point shellSize = shell.getSize();
Composite composite = (Composite) getDialogArea();
if (linkedResourceComposite != null) {
linkedResourceComposite.dispose();
linkedResourceComposite = null;
composite.layout();
shell.setSize(shellSize.x, basicShellHeight);
advancedButton.setText(IDEWorkbenchMessages.showAdvanced);
} else {
if (basicShellHeight == -1) {
basicShellHeight = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT,
true).y;
}
linkedResourceComposite = linkedResourceGroup
.createContents(linkedResourceParent);
shellSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
shell.setSize(shellSize);
composite.layout();
advancedButton.setText(IDEWorkbenchMessages.hideAdvanced);
}
}
/**
* Returns whether the container specified in the constructor is
* a valid parent for creating linked resources.
*
* @return boolean <code>true</code> if the container specified in
* the constructor is a valid parent for creating linked resources.
* <code>false</code> if no linked resources may be created with the
* specified container as a parent.
*/
private boolean isValidContainer() {
if (container.getType() != IResource.PROJECT)
return false;
try {
IWorkspace workspace = IDEWorkbenchPlugin.getPluginWorkspace();
IProject project = (IProject) container;
String[] natureIds = project.getDescription().getNatureIds();
for (int i = 0; i < natureIds.length; i++) {
IProjectNatureDescriptor descriptor = workspace
.getNatureDescriptor(natureIds[i]);
if (descriptor != null
&& descriptor.isLinkingAllowed() == false)
return false;
}
} catch (CoreException exception) {
// project does not exist or is closed
return false;
}
return true;
}
/**
* Update the dialog's status line to reflect the given status. It is safe to call
* this method before the dialog has been opened.
*/
protected void updateStatus(IStatus status) {
if (firstLinkCheck && status != null) {
// don't show the first validation result as an error.
// fixes bug 29659
Status newStatus = new Status(IStatus.OK, status.getPlugin(),
status.getCode(), status.getMessage(), status
.getException());
super.updateStatus(newStatus);
} else {
super.updateStatus(status);
}
}
/**
* Update the dialog's status line to reflect the given status. It is safe to call
* this method before the dialog has been opened.
* @param severity
* @param message
*/
private void updateStatus(int severity, String message) {
updateStatus(new Status(severity, IDEWorkbenchPlugin.IDE_WORKBENCH, severity, message, null));
}
/**
* Checks whether the folder name and link location are valid.
* Disable the OK button if the folder name and link location are valid.
* a message that indicates the problem otherwise.
*/
private void validateLinkedResource() {
boolean valid = validateFolderName();
if (valid) {
IFolder linkHandle = createFolderHandle(folderNameField.getText());
IStatus status = linkedResourceGroup
.validateLinkLocation(linkHandle);
if (status.getSeverity() != IStatus.ERROR)
getOkButton().setEnabled(true);
else
getOkButton().setEnabled(false);
if (status.isOK() == false)
updateStatus(status);
} else
getOkButton().setEnabled(false);
}
/**
* Checks if the folder name is valid.
*
* @return null if the new folder name is valid.
* a message that indicates the problem otherwise.
*/
private boolean validateFolderName() {
String name = folderNameField.getText();
IWorkspace workspace = container.getWorkspace();
IStatus nameStatus = workspace.validateName(name, IResource.FOLDER);
if ("".equals(name)) { //$NON-NLS-1$
updateStatus(IStatus.ERROR, IDEWorkbenchMessages.NewFolderDialog_folderNameEmpty);
return false;
}
if (nameStatus.isOK() == false) {
updateStatus(nameStatus);
return false;
}
IPath path = new Path(name);
if (container.getFolder(path).exists()
|| container.getFile(path).exists()) {
updateStatus(IStatus.ERROR, NLS.bind(IDEWorkbenchMessages.NewFolderDialog_alreadyExists, name));
return false;
}
updateStatus(IStatus.OK, ""); //$NON-NLS-1$
return true;
}
/* (non-Javadoc)
* @see org.eclipse.ui.dialogs.SelectionStatusDialog#okPressed()
*/
protected void okPressed() {
String linkTarget = linkedResourceGroup.getLinkTarget();
IFolder folder = createNewFolder(folderNameField.getText(), linkTarget);
if (folder == null)
return;
setSelectionResult(new IFolder[] { folder });
super.okPressed();
}
}