blob: f127100a5de8aef6aeffcad5d0e1ae3508846a35 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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
*
*******************************************************************************/
package org.eclipse.dltk.internal.ui.wizards.buildpath;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.core.IBuildpathEntry;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.internal.core.util.Util;
import org.eclipse.dltk.internal.corext.buildpath.BuildpathModifier;
import org.eclipse.dltk.internal.ui.wizards.NewWizardMessages;
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.ITreeListAdapter;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.LayoutUtil;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.ListDialogField;
import org.eclipse.dltk.internal.ui.wizards.dialogfields.TreeListDialogField;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.actions.AbstractOpenWizardAction;
import org.eclipse.dltk.ui.util.PixelConverter;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.INewWizard;
public class SourceContainerWorkbookPage extends BuildPathBasePage {
public class OpenBuildPathWizardAction extends AbstractOpenWizardAction
implements IPropertyChangeListener {
private final BuildPathWizard fWizard;
private final List fSelectedElements;
public OpenBuildPathWizardAction(BuildPathWizard wizard) {
setShell(SourceContainerWorkbookPage.this.getShell());
fWizard = wizard;
addPropertyChangeListener(this);
fSelectedElements = fFoldersList.getSelectedElements();
}
@Override
protected INewWizard createWizard() throws CoreException {
return fWizard;
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(IAction.RESULT)) {
if (event.getNewValue().equals(Boolean.TRUE)) {
finishWizard();
} else {
fWizard.cancel();
}
}
}
protected void finishWizard() {
List insertedElements = fWizard.getInsertedElements();
refresh(insertedElements, fWizard.getRemovedElements(),
fWizard.getModifiedElements());
if (insertedElements.isEmpty()) {
fFoldersList.postSetSelection(
new StructuredSelection(fSelectedElements));
}
}
}
protected static AddSourceFolderWizard newSourceFolderWizard(
BPListElement element, List<BPListElement> existingElements,
boolean newFolder) {
BPListElement[] existing = existingElements
.toArray(new BPListElement[existingElements.size()]);
AddSourceFolderWizard wizard = new AddSourceFolderWizard(existing,
element, false, newFolder, newFolder,
newFolder ? BPListElement.isProjectSourceFolder(existing,
element.getScriptProject()) : false,
newFolder);
wizard.setDoFlushChange(false);
return wizard;
}
private static AddSourceFolderWizard newLinkedSourceFolderWizard(
BPListElement element, List<BPListElement> existingElements,
boolean newFolder) {
BPListElement[] existing = existingElements
.toArray(new BPListElement[existingElements.size()]);
AddSourceFolderWizard wizard = new AddSourceFolderWizard(existing,
element, true, newFolder, newFolder,
newFolder ? BPListElement.isProjectSourceFolder(existing,
element.getScriptProject()) : false,
newFolder);
wizard.setDoFlushChange(false);
return wizard;
}
private static EditFilterWizard newEditFilterWizard(BPListElement element,
List<BPListElement> existingElements) {
BPListElement[] existing = existingElements
.toArray(new BPListElement[existingElements.size()]);
EditFilterWizard result = new EditFilterWizard(existing, element);
result.setDoFlushChange(false);
return result;
}
private ListDialogField fBuildpathList;
protected IScriptProject fCurrJProject;
private Control fSWTControl;
protected TreeListDialogField fFoldersList;
private final int IDX_ADD = 0;
private final int IDX_ADD_LINK = 1;
private final int IDX_EDIT = 3;
private final int IDX_REMOVE = 4;
protected int getIDX_ADD() {
return IDX_ADD;
}
protected int getIDX_ADD_LINK() {
return IDX_ADD_LINK;
}
protected int getIDX_EDIT() {
return IDX_EDIT;
}
protected int getIDX_REMOVE() {
return IDX_REMOVE;
}
public SourceContainerWorkbookPage(ListDialogField buildpathList) {
fBuildpathList = buildpathList;
fSWTControl = null;
}
/**
* Initialize container elements. This code should not be in the constructor
* in order to enable extensibility
*/
protected void initContainerElements() {
SourceContainerAdapter adapter = new SourceContainerAdapter();
String[] buttonLabels;
buttonLabels = new String[] {
NewWizardMessages.SourceContainerWorkbookPage_folders_add_button,
NewWizardMessages.SourceContainerWorkbookPage_folders_link_source_button,
/* 1 */null,
NewWizardMessages.SourceContainerWorkbookPage_folders_edit_button,
NewWizardMessages.SourceContainerWorkbookPage_folders_remove_button };
fFoldersList = new TreeListDialogField(adapter, buttonLabels,
new BPListLabelProvider());
fFoldersList.setDialogFieldListener(adapter);
fFoldersList.setLabelText(
NewWizardMessages.SourceContainerWorkbookPage_folders_label);
fFoldersList.setViewerComparator(new BPListElementSorter());
fFoldersList.enableButton(getIDX_EDIT(), false);
}
@Override
public void setTitle(String title) {
fFoldersList.setLabelText(title);
}
@Override
public void init(IScriptProject jproject) {
fCurrJProject = jproject;
if (Display.getCurrent() != null) {
updateFoldersList();
} else {
Display.getDefault().asyncExec(() -> updateFoldersList());
}
}
protected void updateFoldersList() {
ArrayList<BPListElement> folders = new ArrayList<BPListElement>();
List<?> cpelements = fBuildpathList.getElements();
for (int i = 0; i < cpelements.size(); i++) {
BPListElement cpe = (BPListElement) cpelements.get(i);
if (cpe.getEntryKind() == IBuildpathEntry.BPE_SOURCE) {
folders.add(cpe);
}
}
fFoldersList.setElements(folders);
for (int i = 0; i < folders.size(); i++) {
BPListElement cpe = folders.get(i);
IPath[] ePatterns = (IPath[]) cpe
.getAttribute(BPListElement.EXCLUSION);
IPath[] iPatterns = (IPath[]) cpe
.getAttribute(BPListElement.INCLUSION);
if (ePatterns.length > 0 || iPatterns.length > 0) {
fFoldersList.expandElement(cpe, 3);
}
}
}
@Override
public Control getControl(Composite parent) {
initContainerElements();
PixelConverter converter = new PixelConverter(parent);
Composite composite = new Composite(parent, SWT.NONE);
LayoutUtil.doDefaultLayout(composite,
new DialogField[] { fFoldersList }, true, SWT.DEFAULT,
SWT.DEFAULT);
LayoutUtil.setHorizontalGrabbing(fFoldersList.getTreeControl(null));
int buttonBarWidth = converter.convertWidthInCharsToPixels(24);
fFoldersList.setButtonsMinWidth(buttonBarWidth);
fSWTControl = composite;
// expand
List elements = fFoldersList.getElements();
for (int i = 0; i < elements.size(); i++) {
BPListElement elem = (BPListElement) elements.get(i);
IPath[] exclusionPatterns = (IPath[]) elem
.getAttribute(BPListElement.EXCLUSION);
IPath[] inclusionPatterns = (IPath[]) elem
.getAttribute(BPListElement.INCLUSION);
if (exclusionPatterns.length > 0 || inclusionPatterns.length > 0) {
fFoldersList.expandElement(elem, 3);
}
}
return composite;
}
protected Shell getShell() {
if (fSWTControl != null) {
return fSWTControl.getShell();
}
return DLTKUIPlugin.getActiveWorkbenchShell();
}
public class SourceContainerAdapter
implements ITreeListAdapter, IDialogFieldListener {
private final Object[] EMPTY_ARR = new Object[0];
// -------- IListAdapter --------
@Override
public void customButtonPressed(TreeListDialogField field, int index) {
sourcePageCustomButtonPressed(field, index);
}
@Override
public void selectionChanged(TreeListDialogField field) {
sourcePageSelectionChanged(field);
}
@Override
public void doubleClicked(TreeListDialogField field) {
sourcePageDoubleClicked(field);
}
@Override
public void keyPressed(TreeListDialogField field, KeyEvent event) {
sourcePageKeyPressed(field, event);
}
@Override
public Object[] getChildren(TreeListDialogField field, Object element) {
if (element instanceof BPListElement) {
return ((BPListElement) element).getChildren();
}
return EMPTY_ARR;
}
@Override
public Object getParent(TreeListDialogField field, Object element) {
if (element instanceof BPListElementAttribute) {
return ((BPListElementAttribute) element).getParent();
}
return null;
}
@Override
public boolean hasChildren(TreeListDialogField field, Object element) {
return (element instanceof BPListElement);
}
// ---------- IDialogFieldListener --------
@Override
public void dialogFieldChanged(DialogField field) {
sourcePageDialogFieldChanged(field);
}
}
protected void sourcePageKeyPressed(TreeListDialogField field,
KeyEvent event) {
if (field == fFoldersList) {
if (event.character == SWT.DEL && event.stateMask == 0) {
List selection = field.getSelectedElements();
if (canRemove(selection)) {
removeEntry();
}
}
}
}
protected void sourcePageDoubleClicked(TreeListDialogField field) {
if (field == fFoldersList) {
List selection = field.getSelectedElements();
if (canEdit(selection)) {
editEntry();
}
}
}
protected void sourcePageCustomButtonPressed(DialogField field, int index) {
if (field == fFoldersList) {
if (index == getIDX_ADD()) {
IProject project = fCurrJProject.getProject();
if (project.isAccessible() && hasFolders(project)) {
List existingElements = fFoldersList.getElements();
BPListElement[] existing = (BPListElement[]) existingElements
.toArray(
new BPListElement[existingElements.size()]);
CreateMultipleSourceFoldersDialog dialog = new CreateMultipleSourceFoldersDialog(
fCurrJProject, existing, getShell());
if (dialog.open() == Window.OK) {
refresh(dialog.getInsertedElements(),
dialog.getRemovedElements(),
dialog.getModifiedElements());
}
} else {
BPListElement newElement = new BPListElement(fCurrJProject,
IBuildpathEntry.BPE_SOURCE, false);
AddSourceFolderWizard wizard = newSourceFolderWizard(
newElement, fFoldersList.getElements(), true);
OpenBuildPathWizardAction action = new OpenBuildPathWizardAction(
wizard);
action.run();
}
} else if (index == getIDX_ADD_LINK()) {
BPListElement newElement = new BPListElement(fCurrJProject,
IBuildpathEntry.BPE_SOURCE, false);
AddSourceFolderWizard wizard = newLinkedSourceFolderWizard(
newElement, fFoldersList.getElements(), true);
OpenBuildPathWizardAction action = new OpenBuildPathWizardAction(
wizard);
action.run();
} else if (index == getIDX_EDIT()) {
editEntry();
} else if (index == getIDX_REMOVE()) {
removeEntry();
}
}
}
protected boolean hasFolders(IContainer container) {
try {
IResource[] members = container.members();
for (int i = 0; i < members.length; i++) {
if (members[i] instanceof IContainer
&& Util.isValidFolderNameForPackage(container,
members[i].getName())) {
return true;
}
}
} catch (CoreException e) {
// ignore
}
List elements = fFoldersList.getElements();
if (elements.size() > 1)
return true;
if (elements.size() == 0)
return false;
BPListElement single = (BPListElement) elements.get(0);
if (single.getPath().equals(fCurrJProject.getPath()))
return false;
return true;
}
private void editEntry() {
List selElements = fFoldersList.getSelectedElements();
if (selElements.size() != 1) {
return;
}
Object elem = selElements.get(0);
if (fFoldersList.getIndexOfElement(elem) != -1) {
editElementEntry((BPListElement) elem);
} else if (elem instanceof BPListElementAttribute) {
editAttributeEntry((BPListElementAttribute) elem);
}
}
private void editElementEntry(BPListElement elem) {
if (elem.getLinkTarget() != null) {
AddSourceFolderWizard wizard = newLinkedSourceFolderWizard(elem,
fFoldersList.getElements(), false);
OpenBuildPathWizardAction action = new OpenBuildPathWizardAction(
wizard);
action.run();
} else {
AddSourceFolderWizard wizard = newSourceFolderWizard(elem,
fFoldersList.getElements(), false);
OpenBuildPathWizardAction action = new OpenBuildPathWizardAction(
wizard);
action.run();
}
}
private void editAttributeEntry(BPListElementAttribute elem) {
String key = elem.getKey();
if (key.equals(BPListElement.EXCLUSION)
|| key.equals(BPListElement.INCLUSION)) {
EditFilterWizard wizard = newEditFilterWizard(elem.getParent(),
fFoldersList.getElements());
OpenBuildPathWizardAction action = new OpenBuildPathWizardAction(
wizard);
action.run();
fFoldersList.refresh();
fBuildpathList.dialogFieldChanged();
}
// else if (key.equals(BPListElement.NATIVE_LIB_PATH)) {
// BPListElement selElement= elem.getParent();
// NativeLibrariesDialog dialog= new NativeLibrariesDialog(getShell(),
// selElement);
// if (dialog.open() == Window.OK) {
// selElement.setAttribute(BPListElement.NATIVE_LIB_PATH,
// dialog.getNativeLibraryPath());
// fFoldersList.refresh();
// fClassPathList.dialogFieldChanged(); // validate
// }
// }
}
protected void sourcePageSelectionChanged(DialogField field) {
List selected = fFoldersList.getSelectedElements();
fFoldersList.enableButton(getIDX_EDIT(), canEdit(selected));
fFoldersList.enableButton(getIDX_REMOVE(), canRemove(selected));
boolean noAttributes = containsOnlyTopLevelEntries(selected);
fFoldersList.enableButton(getIDX_ADD(), noAttributes);
}
private void removeEntry() {
List selElements = fFoldersList.getSelectedElements();
for (int i = selElements.size() - 1; i >= 0; i--) {
Object elem = selElements.get(i);
if (elem instanceof BPListElementAttribute) {
BPListElementAttribute attrib = (BPListElementAttribute) elem;
String key = attrib.getKey();
Object value = null;
if (key.equals(BPListElement.EXCLUSION)
|| key.equals(BPListElement.INCLUSION)) {
value = new Path[0];
}
attrib.getParent().setAttribute(key, value);
selElements.remove(i);
}
}
if (selElements.isEmpty()) {
fFoldersList.refresh();
fBuildpathList.dialogFieldChanged(); // validate
} else {
for (Iterator iter = selElements.iterator(); iter.hasNext();) {
BPListElement element = (BPListElement) iter.next();
if (element.getEntryKind() == IBuildpathEntry.BPE_SOURCE) {
List list = BuildpathModifier.removeFilters(
element.getPath(), fCurrJProject,
fFoldersList.getElements());
for (Iterator iterator = list.iterator(); iterator
.hasNext();) {
BPListElement modified = (BPListElement) iterator
.next();
fFoldersList.refresh(modified);
fFoldersList.expandElement(modified, 3);
}
}
}
fFoldersList.removeElements(selElements);
}
}
private boolean canRemove(List selElements) {
if (selElements.size() == 0) {
return false;
}
for (int i = 0; i < selElements.size(); i++) {
Object elem = selElements.get(i);
if (elem instanceof BPListElementAttribute) {
BPListElementAttribute attrib = (BPListElementAttribute) elem;
String key = attrib.getKey();
if (BPListElement.INCLUSION.equals(key)) {
if (((IPath[]) attrib.getValue()).length == 0) {
return false;
}
} else if (BPListElement.EXCLUSION.equals(key)) {
if (((IPath[]) attrib.getValue()).length == 0) {
return false;
}
} else if (attrib.getValue() == null) {
return false;
}
} else if (elem instanceof BPListElement) {
BPListElement curr = (BPListElement) elem;
if (curr.getParentContainer() != null) {
return false;
}
}
}
return true;
}
private boolean canEdit(List selElements) {
if (selElements.size() != 1) {
return false;
}
Object elem = selElements.get(0);
if (elem instanceof BPListElement) {
BPListElement cp = ((BPListElement) elem);
if (cp.getPath().equals(cp.getScriptProject().getPath()))
return false;
return true;
}
if (elem instanceof BPListElementAttribute) {
return true;
}
return false;
}
private void sourcePageDialogFieldChanged(DialogField field) {
if (fCurrJProject == null) {
// not initialized
return;
}
if (field == fFoldersList) {
updateBuildpathList();
}
}
private void updateBuildpathList() {
List srcelements = fFoldersList.getElements();
List cpelements = fBuildpathList.getElements();
int nEntries = cpelements.size();
// backwards, as entries will be deleted
int lastRemovePos = nEntries;
int afterLastSourcePos = 0;
for (int i = nEntries - 1; i >= 0; i--) {
BPListElement cpe = (BPListElement) cpelements.get(i);
int kind = cpe.getEntryKind();
if (isEntryKind(kind)) {
if (!srcelements.remove(cpe)) {
cpelements.remove(i);
lastRemovePos = i;
} else if (lastRemovePos == nEntries) {
afterLastSourcePos = i + 1;
}
}
}
if (!srcelements.isEmpty()) {
int insertPos = Math.min(afterLastSourcePos, lastRemovePos);
cpelements.addAll(insertPos, srcelements);
}
if (lastRemovePos != nEntries || !srcelements.isEmpty()) {
fBuildpathList.setElements(cpelements);
}
}
@Override
public List getSelection() {
return fFoldersList.getSelectedElements();
}
@Override
public void setSelection(List selElements, boolean expand) {
fFoldersList.selectElements(new StructuredSelection(selElements));
if (expand) {
for (int i = 0; i < selElements.size(); i++) {
fFoldersList.expandElement(selElements.get(i), 1);
}
}
}
@Override
public boolean isEntryKind(int kind) {
return kind == IBuildpathEntry.BPE_SOURCE;
}
protected void refresh(List insertedElements, List removedElements,
List modifiedElements) {
fFoldersList.addElements(insertedElements);
for (Iterator iter = insertedElements.iterator(); iter.hasNext();) {
BPListElement element = (BPListElement) iter.next();
fFoldersList.expandElement(element, 3);
}
fFoldersList.removeElements(removedElements);
for (Iterator iter = modifiedElements.iterator(); iter.hasNext();) {
BPListElement element = (BPListElement) iter.next();
fFoldersList.refresh(element);
fFoldersList.expandElement(element, 3);
}
fFoldersList.refresh(); // does enforce the order of the entries.
if (!insertedElements.isEmpty()) {
fFoldersList.postSetSelection(
new StructuredSelection(insertedElements));
}
}
}