/******************************************************************************* * Copyright (c) 2000, 2015 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 java.net.URI; 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.Path; import org.eclipse.core.runtime.Preferences; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; 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.Label; 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; /** * The NewFolderDialog is used to create a new folder. * The folder can optionally be linked to a file system folder. * <p> * This class may be instantiated; it is not intended to be subclassed. * </p> * @noextend This class is not intended to be subclassed by clients. */ 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); setStatusLineAboveButtons(true); } /** * Creates the folder using the name and link target entered * by the user. * Sets the dialog result to the created folder. */ @Override protected void computeResult() { //Do nothing here as we //need to know the result } @Override protected void configureShell(Shell shell) { super.configureShell(shell); PlatformUI.getWorkbench().getHelpSystem().setHelp(shell, IIDEHelpContextIds.NEW_FOLDER_DIALOG); } /** * @see org.eclipse.jface.window.Window#create() */ @Override 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() { @Override public void widgetSelected(SelectionEvent e) { handleAdvancedButtonSelect(); } }); } linkedResourceGroup = new CreateLinkedResourceGroup(IResource.FOLDER, e -> { validateLinkedResource(); firstLinkCheck = false; }, new CreateLinkedResourceGroup.IStringValue() { @Override public void setValue(String string) { folderNameField.setText(string); } @Override public String getValue() { return folderNameField.getText(); } @Override public IResource getResource() { return container; } }); } @Override 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 folder label Label folderLabel = new Label(folderGroup, SWT.NONE); folderLabel.setFont(font); folderLabel.setText(IDEWorkbenchMessages.NewFolderDialog_nameLabel); // new folder 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, 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 linkTarget name of the link target folder. may be null. * @return IFolder the new folder */ private IFolder createNewFolder(String folderName, final URI linkTarget) { final IFolder folderHandle = createFolderHandle(folderName); WorkspaceModifyOperation operation = new WorkspaceModifyOperation() { @Override public void execute(IProgressMonitor monitor) throws CoreException { SubMonitor subMonitor = SubMonitor.convert(monitor, IDEWorkbenchMessages.NewFolderDialog_progress, 1); if (linkTarget == null) { folderHandle.create(false, true, subMonitor.split(1)); } else { folderHandle.createLink(linkTarget, IResource.ALLOW_MISSING_LOCAL, subMonitor.split(1)); } } }; try { PlatformUI.getWorkbench().getProgressService().busyCursorWhile( 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 && container.getType() != IResource.FOLDER) { return false; } try { IWorkspace workspace = IDEWorkbenchPlugin.getPluginWorkspace(); IProject project = container.getProject(); String[] natureIds = project.getDescription().getNatureIds(); for (String natureId : natureIds) { IProjectNatureDescriptor descriptor = workspace .getNatureDescriptor(natureId); 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. */ @Override 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; } @Override protected void okPressed() { URI linkTarget = linkedResourceGroup.getLinkTargetURI(); IFolder folder = createNewFolder(folderNameField.getText(), linkTarget); if (folder == null) { return; } setSelectionResult(new IFolder[] { folder }); super.okPressed(); } }