blob: 1418e5b461e3265c378da74d4db900f6b2ac2625 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.ui.wizards;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
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.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelStatus;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.ScriptModelUtil;
import org.eclipse.dltk.internal.core.BuildpathEntry;
import org.eclipse.dltk.internal.corext.util.Messages;
import org.eclipse.dltk.internal.ui.editor.EditorUtility;
import org.eclipse.dltk.internal.ui.util.CoreUtility;
import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages;
import org.eclipse.dltk.internal.ui.wizards.TypedElementSelectionValidator;
import org.eclipse.dltk.internal.ui.wizards.TypedViewerFilter;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.DialogField;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.IDialogFieldListener;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.IStringButtonAdapter;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.LayoutUtil;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.StringButtonDialogField;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.ModelElementLabelProvider;
import org.eclipse.dltk.ui.dialogs.StatusInfo;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
import org.eclipse.ui.dialogs.ISelectionStatusValidator;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator;
public class NewSourceFolderWizardPage extends NewElementWizardPage {
private static final String PAGE_NAME = "NewSourceFolderWizardPage"; //$NON-NLS-1$
private StringButtonDialogField fProjectField;
private StatusInfo fProjectStatus;
private StringButtonDialogField fRootDialogField;
private StatusInfo fRootStatus;
private SelectionButtonDialogField fExcludeInOthersFields;
private IWorkspaceRoot fWorkspaceRoot;
private IScriptProject fCurrJProject;
private IBuildpathEntry[] fEntries;
private IBuildpathEntry[] fNewEntries;
private boolean fIsProjectAsSourceFolder;
private IProjectFragment fCreatedRoot;
public NewSourceFolderWizardPage() {
super(PAGE_NAME);
setTitle(NewWizardMessages.NewSourceFolderWizardPage_title);
setDescription(NewWizardMessages.NewSourceFolderWizardPage_description);
fWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
RootFieldAdapter adapter = new RootFieldAdapter();
fProjectField = new StringButtonDialogField(adapter);
fProjectField.setDialogFieldListener(adapter);
fProjectField.setLabelText(
NewWizardMessages.NewSourceFolderWizardPage_project_label);
fProjectField.setButtonLabel(
NewWizardMessages.NewSourceFolderWizardPage_project_button);
fRootDialogField = new StringButtonDialogField(adapter);
fRootDialogField.setDialogFieldListener(adapter);
fRootDialogField.setLabelText(
NewWizardMessages.NewSourceFolderWizardPage_root_label);
fRootDialogField.setButtonLabel(
NewWizardMessages.NewSourceFolderWizardPage_root_button);
fExcludeInOthersFields = new SelectionButtonDialogField(SWT.CHECK);
fExcludeInOthersFields.setDialogFieldListener(adapter);
fExcludeInOthersFields.setLabelText(
NewWizardMessages.NewSourceFolderWizardPage_exclude_label);
fExcludeInOthersFields.setEnabled(DLTKCore.ENABLED.equals(DLTKCore
.getOption(DLTKCore.CORE_ENABLE_BUILDPATH_EXCLUSION_PATTERNS)));
fRootStatus = new StatusInfo();
fProjectStatus = new StatusInfo();
}
// -------- Initialization ---------
public void init(IStructuredSelection selection) {
if (selection == null || selection.isEmpty()) {
setDefaultAttributes();
return;
}
Object selectedElement = selection.getFirstElement();
if (selectedElement == null) {
selectedElement = EditorUtility.getActiveEditorModelInput();
}
String projPath = null;
if (selectedElement instanceof IResource) {
IProject proj = ((IResource) selectedElement).getProject();
if (proj != null) {
projPath = proj.getFullPath().makeRelative().toString();
}
} else if (selectedElement instanceof IModelElement) {
IScriptProject jproject = ((IModelElement) selectedElement)
.getScriptProject();
if (jproject != null) {
projPath = jproject.getProject().getFullPath().makeRelative()
.toString();
}
}
if (projPath != null) {
fProjectField.setText(projPath);
fRootDialogField.setText(""); //$NON-NLS-1$
} else {
setDefaultAttributes();
}
}
private void setDefaultAttributes() {
String projPath = ""; //$NON-NLS-1$
// find the first script project
IProject[] projects = fWorkspaceRoot.getProjects();
for (int i = 0; i < projects.length; i++) {
IProject proj = projects[i];
if (DLTKLanguageManager.hasScriptNature(proj)) {
projPath = proj.getFullPath().makeRelative().toString();
break;
}
}
fProjectField.setText(projPath);
fRootDialogField.setText(""); //$NON-NLS-1$
}
// -------- UI Creation ---------
/*
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.
* widgets .Composite)
*/
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 3;
composite.setLayout(layout);
fProjectField.doFillIntoGrid(composite, 3);
fRootDialogField.doFillIntoGrid(composite, 3);
fExcludeInOthersFields.doFillIntoGrid(composite, 3);
int maxFieldWidth = convertWidthInCharsToPixels(40);
LayoutUtil.setWidthHint(fProjectField.getTextControl(null),
maxFieldWidth);
LayoutUtil.setHorizontalGrabbing(fProjectField.getTextControl(null));
LayoutUtil.setWidthHint(fRootDialogField.getTextControl(null),
maxFieldWidth);
setControl(composite);
Dialog.applyDialogFont(composite);
if (DLTKCore.DEBUG) {
System.err.println("Add help support here..."); //$NON-NLS-1$
}
// PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
// IScriptHelpContextIds.NEW_PACKAGEROOT_WIZARD_PAGE);
}
/*
* @see org.eclipse.jface.dialogs.IDialogPage#setVisible(boolean)
*/
@Override
public void setVisible(boolean visible) {
super.setVisible(visible);
if (visible) {
fRootDialogField.setFocus();
}
}
// -------- ContainerFieldAdapter --------
private class RootFieldAdapter
implements IStringButtonAdapter, IDialogFieldListener {
// -------- IStringButtonAdapter
@Override
public void changeControlPressed(DialogField field) {
packRootChangeControlPressed(field);
}
// -------- IDialogFieldListener
@Override
public void dialogFieldChanged(DialogField field) {
packRootDialogFieldChanged(field);
}
}
protected void packRootChangeControlPressed(DialogField field) {
if (field == fRootDialogField) {
IPath initialPath = new Path(fRootDialogField.getText());
String title = NewWizardMessages.NewSourceFolderWizardPage_ChooseExistingRootDialog_title;
String message = NewWizardMessages.NewSourceFolderWizardPage_ChooseExistingRootDialog_description;
IFolder folder = chooseFolder(title, message, initialPath);
if (folder != null) {
IPath path = folder.getFullPath().removeFirstSegments(1);
fRootDialogField.setText(path.toString());
}
} else if (field == fProjectField) {
IScriptProject jproject = chooseProject();
if (jproject != null) {
IPath path = jproject.getProject().getFullPath().makeRelative();
fProjectField.setText(path.toString());
}
}
}
protected void packRootDialogFieldChanged(DialogField field) {
if (field == fRootDialogField) {
updateRootStatus();
} else if (field == fProjectField) {
updateProjectStatus();
updateRootStatus();
} else if (field == fExcludeInOthersFields) {
updateRootStatus();
}
updateStatus(new IStatus[] { fProjectStatus, fRootStatus });
}
private void updateProjectStatus() {
fCurrJProject = null;
fIsProjectAsSourceFolder = false;
String str = fProjectField.getText();
if (str.length() == 0) {
fProjectStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_EnterProjectName);
return;
}
IPath path = new Path(str);
if (path.segmentCount() != 1) {
fProjectStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_InvalidProjectPath);
return;
}
IProject project = fWorkspaceRoot.getProject(path.toString());
if (!project.exists()) {
fProjectStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_ProjectNotExists);
return;
}
try {
if (DLTKLanguageManager.hasScriptNature(project)) {
fCurrJProject = DLTKCore.create(project);
fEntries = fCurrJProject.getRawBuildpath();
fProjectStatus.setOK();
return;
}
} catch (CoreException e) {
DLTKUIPlugin.log(e);
fCurrJProject = null;
}
fProjectStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_NotAScriptProject);
}
private void updateRootStatus() {
fRootDialogField.enableButton(fCurrJProject != null);
fIsProjectAsSourceFolder = false;
if (fCurrJProject == null) {
return;
}
fRootStatus.setOK();
IPath projPath = fCurrJProject.getProject().getFullPath();
String str = fRootDialogField.getText();
if (str.length() == 0) {
fRootStatus.setError(Messages.format(
NewWizardMessages.NewSourceFolderWizardPage_error_EnterRootName,
fCurrJProject.getProject().getFullPath().toString()));
} else {
IPath path = projPath.append(str);
IStatus validate = fWorkspaceRoot.getWorkspace()
.validatePath(path.toString(), IResource.FOLDER);
if (validate.matches(IStatus.ERROR)) {
fRootStatus.setError(Messages.format(
NewWizardMessages.NewSourceFolderWizardPage_error_InvalidRootName,
validate.getMessage()));
} else {
IResource res = fWorkspaceRoot.findMember(path);
if (res != null) {
if (res.getType() != IResource.FOLDER) {
fRootStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_NotAFolder);
return;
}
} else {
URI projLocation = fCurrJProject.getProject()
.getLocationURI();
if (projLocation != null) {
try {
IFileStore store = EFS.getStore(projLocation)
.getChild(str);
if (store.fetchInfo().exists()) {
fRootStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExistingDifferentCase);
return;
}
} catch (CoreException e) {
// we couldn't create the file store. Ignore the
// exception
// since we can't check if the file exist. Pretend
// that it
// doesn't.
}
}
}
List<IBuildpathEntry> newEntries = new ArrayList<>(
fEntries.length + 1);
int projectEntryIndex = -1;
for (int i = 0; i < fEntries.length; i++) {
IBuildpathEntry curr = fEntries[i];
if (curr.getEntryKind() == IBuildpathEntry.BPE_SOURCE) {
if (path.equals(curr.getPath())) {
fRootStatus.setError(
NewWizardMessages.NewSourceFolderWizardPage_error_AlreadyExisting);
return;
}
if (projPath.equals(curr.getPath())) {
projectEntryIndex = i;
}
}
newEntries.add(curr);
}
IBuildpathEntry newEntry = DLTKCore.newSourceEntry(path);
Set<IBuildpathEntry> modified = new HashSet<>();
if (fExcludeInOthersFields.isSelected()) {
addExclusionPatterns(newEntry, newEntries, modified);
IBuildpathEntry entry = DLTKCore.newSourceEntry(path);
insertAtEndOfCategory(entry, newEntries);
} else {
if (projectEntryIndex != -1) {
fIsProjectAsSourceFolder = true;
newEntries.set(projectEntryIndex, newEntry);
} else {
IBuildpathEntry entry = DLTKCore.newSourceEntry(path);
insertAtEndOfCategory(entry, newEntries);
}
}
fNewEntries = newEntries
.toArray(new IBuildpathEntry[newEntries.size()]);
IModelStatus status = BuildpathEntry
.validateBuildpath(fCurrJProject, fNewEntries);
if (!status.isOK()) {
fRootStatus.setError(status.getMessage());
return;
} else if (fIsProjectAsSourceFolder) {
fRootStatus.setInfo(
NewWizardMessages.NewSourceFolderWizardPage_warning_ReplaceSF);
return;
}
if (!modified.isEmpty()) {
fRootStatus.setInfo(Messages.format(
NewWizardMessages.NewSourceFolderWizardPage_warning_AddedExclusions,
String.valueOf(modified.size())));
return;
}
}
}
}
private void insertAtEndOfCategory(IBuildpathEntry entry,
List<IBuildpathEntry> entries) {
int length = entries.size();
IBuildpathEntry[] elements = entries
.toArray(new IBuildpathEntry[length]);
int i = 0;
while (i < length
&& elements[i].getEntryKind() != entry.getEntryKind()) {
i++;
}
if (i < length) {
i++;
while (i < length
&& elements[i].getEntryKind() == entry.getEntryKind()) {
i++;
}
entries.add(i, entry);
return;
}
switch (entry.getEntryKind()) {
case IBuildpathEntry.BPE_SOURCE:
entries.add(0, entry);
break;
case IBuildpathEntry.BPE_CONTAINER:
case IBuildpathEntry.BPE_LIBRARY:
case IBuildpathEntry.BPE_PROJECT:
default:
entries.add(entry);
break;
}
}
private void addExclusionPatterns(IBuildpathEntry newEntry,
List<IBuildpathEntry> existing,
Set<IBuildpathEntry> modifiedEntries) {
IPath entryPath = newEntry.getPath();
for (int i = 0; i < existing.size(); i++) {
IBuildpathEntry curr = existing.get(i);
IPath currPath = curr.getPath();
if (curr.getEntryKind() == IBuildpathEntry.BPE_SOURCE
&& currPath.isPrefixOf(entryPath)) {
IPath[] exclusionFilters = curr.getExclusionPatterns();
if (!ScriptModelUtil.isExcludedPath(entryPath,
exclusionFilters)) {
IPath pathToExclude = entryPath
.removeFirstSegments(currPath.segmentCount())
.addTrailingSeparator();
IPath[] newExclusionFilters = new IPath[exclusionFilters.length
+ 1];
System.arraycopy(exclusionFilters, 0, newExclusionFilters,
0, exclusionFilters.length);
newExclusionFilters[exclusionFilters.length] = pathToExclude;
IBuildpathEntry updated = DLTKCore.newSourceEntry(currPath,
newExclusionFilters);
existing.set(i, updated);
modifiedEntries.add(updated);
}
}
}
}
// ---- creation ----------------
public IProjectFragment getNewProjectFragment() {
return fCreatedRoot;
}
public IResource getCorrespondingResource() {
return fCurrJProject.getProject().getFolder(fRootDialogField.getText());
}
public void createProjectFragment(IProgressMonitor monitor)
throws CoreException, InterruptedException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(NewWizardMessages.NewSourceFolderWizardPage_operation,
3);
try {
// IPath projPath= fCurrJProject.getProject().getFullPath();
String relPath = fRootDialogField.getText();
IFolder folder = fCurrJProject.getProject().getFolder(relPath);
if (!folder.exists()) {
CoreUtility.createFolder(folder, true, true,
new SubProgressMonitor(monitor, 1));
}
if (monitor.isCanceled()) {
throw new InterruptedException();
}
fCurrJProject.setRawBuildpath(fNewEntries,
new SubProgressMonitor(monitor, 2));
fCreatedRoot = fCurrJProject.getProjectFragment(folder);
} finally {
monitor.done();
}
}
// ------------- choose dialogs
private IFolder chooseFolder(String title, String message,
IPath initialPath) {
Class<?>[] acceptedClasses = new Class[] { IFolder.class };
ISelectionStatusValidator validator = new TypedElementSelectionValidator(
acceptedClasses, false);
ViewerFilter filter = new TypedViewerFilter(acceptedClasses, null);
ILabelProvider lp = new WorkbenchLabelProvider();
ITreeContentProvider cp = new WorkbenchContentProvider();
IProject currProject = fCurrJProject.getProject();
ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(
getShell(), lp, cp);
dialog.setValidator(validator);
dialog.setTitle(title);
dialog.setMessage(message);
dialog.addFilter(filter);
dialog.setInput(currProject);
dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
IResource res = currProject.findMember(initialPath);
if (res != null) {
dialog.setInitialSelection(res);
}
if (dialog.open() == Window.OK) {
return (IFolder) dialog.getFirstResult();
}
return null;
}
private IScriptProject chooseProject() {
IScriptProject[] projects;
try {
projects = DLTKCore.create(fWorkspaceRoot).getScriptProjects();
} catch (ModelException e) {
DLTKUIPlugin.log(e);
projects = new IScriptProject[0];
}
ILabelProvider labelProvider = new ModelElementLabelProvider(
ModelElementLabelProvider.SHOW_DEFAULT);
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
getShell(), labelProvider);
dialog.setTitle(
NewWizardMessages.NewSourceFolderWizardPage_ChooseProjectDialog_title);
dialog.setMessage(
NewWizardMessages.NewSourceFolderWizardPage_ChooseProjectDialog_description);
dialog.setElements(projects);
dialog.setInitialSelections(new Object[] { fCurrJProject });
dialog.setHelpAvailable(false);
if (dialog.open() == Window.OK) {
return (IScriptProject) dialog.getFirstResult();
}
return null;
}
}