blob: 0f8d54e70e65caaadd71adf6e624e9a0339fc319 [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
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contribution for Bug 465293 - External annotation path per container and project
*******************************************************************************/
package org.eclipse.jdt.internal.ui.wizards.buildpaths;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
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.IWorkspaceRunnable;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IImportWizard;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ResourceTransfer;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.launching.AbstractVMInstall;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.JarImportWizardAction;
import org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter;
import org.eclipse.jdt.internal.ui.jarimport.JarImportWizard;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.RootCPListElement.RootNodeChange;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.TreeListDialogField;
public class LibrariesWorkbookPage extends BuildPathBasePage {
private final ListDialogField<CPListElement> fClassPathList;
private IJavaProject fCurrJProject;
private final TreeListDialogField<CPListElement> fLibrariesList;
private Control fSWTControl;
private final IWorkbenchPreferenceContainer fPageContainer;
private final int IDX_ADDJAR= 0;
private final int IDX_ADDEXT= 1;
private final int IDX_ADDVAR= 2;
private final int IDX_ADDLIB= 3;
private final int IDX_ADDFOL= 4;
private final int IDX_ADDEXTFOL= 5;
private final int IDX_EDIT= 7;
private final int IDX_REMOVE= 8;
private final int IDX_REPLACE= 10;
private boolean dragDropEnabled = false;
private Object draggedItemsLibrary = null;
public LibrariesWorkbookPage(CheckedListDialogField<CPListElement> classPathList, IWorkbenchPreferenceContainer pageContainer) {
fClassPathList= classPathList;
fPageContainer= pageContainer;
fSWTControl= null;
String[] buttonLabels= new String[] {
NewWizardMessages.LibrariesWorkbookPage_libraries_addjar_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_addextjar_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_addvariable_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_addlibrary_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_addclassfolder_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_addextfolder_button,
/* */ null,
NewWizardMessages.LibrariesWorkbookPage_libraries_edit_button,
NewWizardMessages.LibrariesWorkbookPage_libraries_remove_button,
/* */ null,
NewWizardMessages.LibrariesWorkbookPage_libraries_replace_button
};
LibrariesAdapter adapter= new LibrariesAdapter();
fLibrariesList= new TreeListDialogField<>(adapter, buttonLabels, new CPListLabelProvider());
fLibrariesList.setDialogFieldListener(adapter);
fLibrariesList.setLabelText(NewWizardMessages.LibrariesWorkbookPage_libraries_label);
fLibrariesList.enableButton(IDX_REMOVE, false);
fLibrariesList.enableButton(IDX_EDIT, false);
fLibrariesList.enableButton(IDX_REPLACE, false);
fLibrariesList.setViewerComparator(new CPListElementSorter());
}
@Override
public void init(IJavaProject jproject) {
fCurrJProject= jproject;
if (Display.getCurrent() != null) {
updateLibrariesList();
} else {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
updateLibrariesList();
}
});
}
}
private void updateLibrariesList() {
if(JavaModelUtil.is9OrHigher(fCurrJProject)) {
updateLibrariesListWithRootNode();
return;
}
List<CPListElement> cpelements= fClassPathList.getElements();
List<CPListElement> libelements= new ArrayList<>(cpelements.size());
int nElements= cpelements.size();
for (int i= 0; i < nElements; i++) {
CPListElement cpe= cpelements.get(i);
if (isEntryKind(cpe.getEntryKind())) {
libelements.add(cpe);
}
}
fLibrariesList.setElements(libelements);
}
private void updateLibrariesListWithRootNode() {
RootCPListElement rootClasspath= new RootCPListElement(fCurrJProject, NewWizardMessages.PathRootWorkbookPage_classpath,false);
RootCPListElement rootModulepath= new RootCPListElement(fCurrJProject,NewWizardMessages.PathRootWorkbookPage_modulepath,true);
List<CPListElement> cpelements= fClassPathList.getElements();
List<CPListElement> libelements= new ArrayList<>(cpelements.size());
int nElements= cpelements.size();
for (int i= 0; i < nElements; i++) {
CPListElement cpe= cpelements.get(i);
if (isEntryKind(cpe.getEntryKind())) {
Object mod= cpe.getAttribute(CPListElement.MODULE);
if(mod == null) {
rootClasspath.addCPListElement(cpe);
} else {
rootModulepath.addCPListElement(cpe);
}
}
}
libelements.add(rootModulepath);
libelements.add(rootClasspath);
fLibrariesList.setElements(libelements);
fLibrariesList.enableButton(IDX_ADDEXT, false);
fLibrariesList.enableButton(IDX_ADDFOL, false);
fLibrariesList.enableButton(IDX_ADDEXTFOL, false);
fLibrariesList.enableButton(IDX_ADDJAR, false);
fLibrariesList.enableButton(IDX_ADDLIB, false);
fLibrariesList.enableButton(IDX_ADDVAR, false);
if(dragDropEnabled == false) {
enableDragDropSupport();
}
}
private void enableDragDropSupport() {
dragDropEnabled= true;
int ops= DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_DEFAULT;
Transfer[] transfers= new Transfer[] { ResourceTransfer.getInstance(), FileTransfer.getInstance() };
fLibrariesList.getTreeViewer().addDragSupport(DND.DROP_MOVE | DND.DROP_COPY, transfers, new DragSourceListener() {
@Override
public void dragStart(DragSourceEvent event) {
IStructuredSelection ssel= (IStructuredSelection) fLibrariesList.getTreeViewer().getSelection();
if (ssel == null || ssel.isEmpty()) {
event.doit= false;
}
if (ssel != null) {
Object[] ele= ssel.toArray();
for (Object element : ele) {
// dont start drag on root nodes
if (element instanceof RootCPListElement) {
event.doit= false;
break;
}
}
}
}
@Override
public void dragSetData(DragSourceEvent event) {
IStructuredSelection ssel= (IStructuredSelection) fLibrariesList.getTreeViewer().getSelection();
event.data= ssel.toArray();
draggedItemsLibrary= ssel.toArray();
}
@Override
public void dragFinished(DragSourceEvent event) {
draggedItemsLibrary= null;
}
});
fLibrariesList.getTreeViewer().addDropSupport(ops, transfers, new ViewerDropAdapter(fLibrariesList.getTreeViewer()) {
@Override
public void dragEnter(DropTargetEvent event) {
Object target= determineTarget(event);
if (target == null && event.detail == DND.DROP_COPY) {
event.detail= DND.DROP_MOVE;
}
super.dragEnter(event);
}
@Override
public void dragOperationChanged(DropTargetEvent event) {
Object target= determineTarget(event);
if (target == null && event.detail == DND.DROP_COPY) {
event.detail= DND.DROP_MOVE;
}
super.dragOperationChanged(event);
}
@Override
public void dragOver(DropTargetEvent event) {
Object target= determineTarget(event);
if (target == null && event.detail == DND.DROP_COPY) {
event.detail= DND.DROP_MOVE;
}
super.dragOver(event);
}
@Override
protected int determineLocation(DropTargetEvent event) {
if (!(event.item instanceof Item)) {
return LOCATION_NONE;
}
Item item= (Item) event.item;
Point coordinates= new Point(event.x, event.y);
coordinates= getViewer().getControl().toControl(coordinates);
if (item != null) {
Rectangle bounds= getBounds(item);
if (bounds == null) {
return LOCATION_NONE;
}
}
return LOCATION_ON;
}
@Override
public boolean performDrop(Object data) {
Object[] objects= (data == null) ? (Object[]) draggedItemsLibrary : (Object[]) data;
if (objects == null)
return false;
Object target= getCurrentTarget();
if (target instanceof RootCPListElement) {
for (Object object : objects) {
if (!(object instanceof CPListElement))
return false;
if(object instanceof RootCPListElement)
return false;
boolean contains= ((RootCPListElement) target).getChildren().contains(object);
if (contains == true)
return false;
RootCPListElement rootNode= (RootCPListElement) target;
boolean isModular= rootNode.isModulePathRootNode();
RootNodeChange direction= RootNodeChange.fromOldAndNew(!isModular, isModular);
if (direction != RootNodeChange.NoChange) {
moveCPElementAcrossNode(fLibrariesList, (CPListElement) object, direction);
}
((CPListElement) object).setAttribute(IClasspathAttribute.MODULE, isModular ? new ModuleEncapsulationDetail[0] : null);
}
return true;
}
return false;
}
@Override
public boolean validateDrop(Object target, int operation, TransferData transferType) {
return (target instanceof RootCPListElement);
}
});
}
boolean hasRootNodes(){
if (fLibrariesList == null)
return false;
if(fLibrariesList.getSize()==0)
return false;
if(fLibrariesList.getElement(0).isRootNodeForPath())
return true;
return false;
}
// -------- UI creation
@Override
public Control getControl(Composite parent) {
PixelConverter converter= new PixelConverter(parent);
Composite composite= new Composite(parent, SWT.NONE);
LayoutUtil.doDefaultLayout(composite, new DialogField[] { fLibrariesList }, true, SWT.DEFAULT, SWT.DEFAULT);
LayoutUtil.setHorizontalGrabbing(fLibrariesList.getTreeControl(null));
int buttonBarWidth= converter.convertWidthInCharsToPixels(24);
fLibrariesList.setButtonsMinWidth(buttonBarWidth);
fLibrariesList.setViewerComparator(new CPListElementSorter());
fSWTControl= composite;
return composite;
}
private Shell getShell() {
if (fSWTControl != null) {
return fSWTControl.getShell();
}
return JavaPlugin.getActiveWorkbenchShell();
}
private class LibrariesAdapter extends CPListAdapter {
// -------- IListAdapter --------
@Override
public void customButtonPressed(TreeListDialogField<CPListElement> field, int index) {
libaryPageCustomButtonPressed(field, index);
}
@Override
public void selectionChanged(TreeListDialogField<CPListElement> field) {
libaryPageSelectionChanged(field);
}
@Override
public void doubleClicked(TreeListDialogField<CPListElement> field) {
libaryPageDoubleClicked(field);
}
@Override
public void keyPressed(TreeListDialogField<CPListElement> field, KeyEvent event) {
libaryPageKeyPressed(field, event);
}
@Override
public Object[] getChildren(TreeListDialogField<CPListElement> field, Object element) {
if (element instanceof CPListElementAttribute) {
CPListElementAttribute attribute= (CPListElementAttribute) element;
if (CPListElement.ACCESSRULES.equals(attribute.getKey())) {
return (IAccessRule[]) attribute.getValue();
}
}
return super.getChildren(field, element);
}
// ---------- IDialogFieldListener --------
@Override
public void dialogFieldChanged(DialogField field) {
libaryPageDialogFieldChanged(field);
}
}
/**
* A button has been pressed.
*
* @param field the dialog field containing the button
* @param index the index of the button
*/
private void libaryPageCustomButtonPressed(DialogField field, int index) {
CPListElement[] libentries= null;
switch (index) {
case IDX_ADDJAR: /* add jar */
libentries= openJarFileDialog(null);
break;
case IDX_ADDEXT: /* add external jar */
libentries= openExtJarFileDialog(null);
break;
case IDX_ADDVAR: /* add variable */
libentries= openVariableSelectionDialog(null);
break;
case IDX_ADDLIB: /* add library */
libentries= openContainerSelectionDialog(null);
break;
case IDX_ADDFOL: /* add folder */
libentries= openClassFolderDialog(null);
break;
case IDX_ADDEXTFOL: /* add external folder */
libentries= openExternalClassFolderDialog(null);
break;
case IDX_EDIT: /* edit */
editEntry();
return;
case IDX_REMOVE: /* remove */
removeEntry();
return;
case IDX_REPLACE: /* replace */
replaceJarFile();
return;
}
if (libentries != null) {
int nElementsChosen= libentries.length;
// remove duplicates
List<CPListElement> cplist= fLibrariesList.getElements();
List<CPListElement> elementsToAdd= new ArrayList<>(nElementsChosen);
for (int i= 0; i < nElementsChosen; i++) {
CPListElement curr= libentries[i];
boolean contains= cplist.contains(curr);
if(hasRootNodes()) {
contains= hasCurrentElement(cplist,curr);
}
if (!contains && !elementsToAdd.contains(curr)) {
elementsToAdd.add(curr);
curr.setAttribute(CPListElement.SOURCEATTACHMENT, BuildPathSupport.guessSourceAttachment(curr));
curr.setAttribute(CPListElement.JAVADOC, BuildPathSupport.guessJavadocLocation(curr));
}
}
if (!elementsToAdd.isEmpty() && (index == IDX_ADDFOL)) {
askForAddingExclusionPatternsDialog(elementsToAdd);
}
if(!hasRootNodes()) {
fLibrariesList.addElements(elementsToAdd);
} else {
// on root nodes, only additions allowed, rest disabled
List<Object> selectedElements= fLibrariesList.getSelectedElements();
List<CPListElement> elements= fLibrariesList.getElements();
// sanity check, button should only be enabled if exactly one root node is selected
if(selectedElements.size() != 1) {
return;
}
fLibrariesList.removeAllElements();
RootCPListElement selectedCPElement= (RootCPListElement) selectedElements.get(0);
if(selectedCPElement.isClassPathRootNode()) {
for (CPListElement cpListElement : elementsToAdd) {
cpListElement.setAttribute(IClasspathAttribute.MODULE, null);
}
} else if(selectedCPElement.isModulePathRootNode()) {
for (CPListElement cpListElement : elementsToAdd) {
Object attribute= cpListElement.getAttribute(IClasspathAttribute.MODULE);
if(attribute == null) {
cpListElement.setAttribute(IClasspathAttribute.MODULE, new ModuleEncapsulationDetail[0]);
}
}
}
selectedCPElement.addCPListElement(elementsToAdd);
fLibrariesList.setElements(elements);
fLibrariesList.refresh();
fLibrariesList.getTreeViewer().expandToLevel(2);
}
if (index == IDX_ADDLIB || index == IDX_ADDVAR) {
fLibrariesList.refresh();
}
fLibrariesList.postSetSelection(new StructuredSelection(libentries));
}
}
private boolean hasCurrentElement(List<CPListElement> cplist, CPListElement curr) {
//note that the same cpelement with different attribute can be added
for (CPListElement cpListElement : cplist) {
if(cpListElement.isRootNodeForPath()) {
boolean cont= ( (RootCPListElement)cpListElement).getChildren().contains(curr);
if(cont == true) {
return true;
}
}
}
return false;
}
@Override
public void addElement(CPListElement element) {
fLibrariesList.addElement(element);
fLibrariesList.postSetSelection(new StructuredSelection(element));
}
private void askForAddingExclusionPatternsDialog(List<CPListElement> newEntries) {
HashSet<CPListElement> modified= new HashSet<>();
List<CPListElement> existing= fClassPathList.getElements();
fixNestingConflicts(newEntries.toArray(new CPListElement[newEntries.size()]), existing.toArray(new CPListElement[existing.size()]), modified);
if (!modified.isEmpty()) {
String title= NewWizardMessages.LibrariesWorkbookPage_exclusion_added_title;
String message= NewWizardMessages.LibrariesWorkbookPage_exclusion_added_message;
MessageDialog.openInformation(getShell(), title, message);
}
}
protected void libaryPageDoubleClicked(TreeListDialogField<CPListElement> field) {
List<?> selection= field.getSelectedElements();
if (canEdit(selection)) {
editEntry();
}
}
protected void libaryPageKeyPressed(TreeListDialogField<CPListElement> field, KeyEvent event) {
if (field == fLibrariesList) {
if (event.character == SWT.DEL && event.stateMask == 0) {
List<?> selection= field.getSelectedElements();
if (canRemove(selection)) {
removeEntry();
}
}
}
}
private void replaceJarFile() {
final IPackageFragmentRoot root= getSelectedPackageFragmentRoot();
if (root != null) {
final IImportWizard wizard= new JarImportWizard(false);
wizard.init(PlatformUI.getWorkbench(), new StructuredSelection(root));
final WizardDialog dialog= new WizardDialog(getShell(), wizard);
dialog.create();
dialog.getShell().setSize(Math.max(JarImportWizardAction.SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x), JarImportWizardAction.SIZING_WIZARD_HEIGHT);
PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(), IJavaHelpContextIds.JARIMPORT_WIZARD_PAGE);
dialog.open();
}
}
private IPackageFragmentRoot getSelectedPackageFragmentRoot() {
final List<Object> elements= fLibrariesList.getSelectedElements();
if (elements.size() == 1) {
final Object object= elements.get(0);
if (object instanceof CPListElement) {
final CPListElement element= (CPListElement) object;
final IClasspathEntry entry= element.getClasspathEntry();
if (JarImportWizard.isValidClassPathEntry(entry)) {
final IJavaProject project= element.getJavaProject();
if (project != null) {
try {
final IPackageFragmentRoot[] roots= project.getPackageFragmentRoots();
for (int index= 0; index < roots.length; index++) {
if (entry.equals(roots[index].getRawClasspathEntry()))
return roots[index];
}
} catch (JavaModelException exception) {
JavaPlugin.log(exception);
}
}
}
}
}
return null;
}
private void removeEntry() {
List<Object> selElements= fLibrariesList.getSelectedElements();
HashMap<CPListElement, HashSet<String>> containerEntriesToUpdate= new HashMap<>();
for (int i= selElements.size() - 1; i >= 0 ; i--) {
Object elem= selElements.get(i);
if (elem instanceof CPListElementAttribute) {
CPListElementAttribute attrib= (CPListElementAttribute) elem;
String key= attrib.getKey();
if (attrib.isBuiltIn()) {
Object value= null;
if (key.equals(CPListElement.ACCESSRULES)) {
value= new IAccessRule[0];
}
attrib.setValue(value);
} else {
removeCustomAttribute(attrib);
}
selElements.remove(i);
if (attrib.getParent().getParentContainer() instanceof CPListElement) { // inside a container: apply changes right away
CPListElement containerEntry= attrib.getParent();
HashSet<String> changedAttributes= containerEntriesToUpdate.get(containerEntry);
if (changedAttributes == null) {
changedAttributes= new HashSet<>();
containerEntriesToUpdate.put(containerEntry, changedAttributes);
}
changedAttributes.add(key); // collect the changed attributes
}
} else if (elem instanceof ModuleEncapsulationDetail) {
removeEncapsulationDetail((ModuleEncapsulationDetail) elem);
}
}
if (selElements.isEmpty()) {
fLibrariesList.refresh();
fClassPathList.dialogFieldChanged(); // validate
} else {
if(hasRootNodes()) {
List<CPListElement> elements= fLibrariesList.getElements();
for (CPListElement cpListElement : elements) {
((RootCPListElement)cpListElement).getChildren().removeAll(selElements);
}
fLibrariesList.getTreeViewer().remove(selElements.toArray());
fLibrariesList.dialogFieldChanged();
}
else {
fLibrariesList.removeElements(selElements);
}
}
for (Iterator<Map.Entry<CPListElement, HashSet<String>>> iter= containerEntriesToUpdate.entrySet().iterator(); iter.hasNext();) {
Map.Entry<CPListElement, HashSet<String>> entry= iter.next();
CPListElement curr= entry.getKey();
HashSet<String> attribs= entry.getValue();
String[] changedAttributes= attribs.toArray(new String[attribs.size()]);
IClasspathEntry changedEntry= curr.getClasspathEntry();
updateContainerEntry(changedEntry, changedAttributes, fCurrJProject, ((CPListElement) curr.getParentContainer()).getPath());
}
}
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 CPListElementAttribute) {
CPListElementAttribute attrib= (CPListElementAttribute) elem;
if (IClasspathAttribute.MODULE.equals(attrib.getKey())) {
return false;
}
if (attrib.isNonModifiable()) {
return false;
}
if (attrib.isBuiltIn()) {
if (attrib.getParent().isInContainer(JavaRuntime.JRE_CONTAINER) && CPListElement.ACCESSRULES.equals(attrib.getKey())) {
return false; // workaround for 166519 until we have full story
}
if (attrib.getKey().equals(CPListElement.ACCESSRULES)) {
return ((IAccessRule[]) attrib.getValue()).length > 0;
}
if (attrib.getValue() == null) {
return false;
}
} else {
if (!canRemoveCustomAttribute(attrib)) {
return false;
}
}
} else if (elem instanceof CPListElement) {
CPListElement curr= (CPListElement) elem;
if(curr.isRootNodeForPath()) {
return false;
}
if (curr.getParentContainer() != null) {
return false;
}
} else if (elem instanceof ModuleEncapsulationDetail) {
return true;
} else { // unknown element
return false;
}
}
return true;
}
/**
* Method editEntry.
*/
private void editEntry() {
List<?> selElements= fLibrariesList.getSelectedElements();
if (selElements.size() != 1) {
return;
}
Object elem= selElements.get(0);
boolean canEdit= false;
if(hasRootNodes()) {
canEdit= ((RootCPListElement)fLibrariesList.getElement(0)).getChildren().indexOf(elem) != -1 ||
((RootCPListElement)fLibrariesList.getElement(1)).getChildren().indexOf(elem) != -1 ;
}
if (canEdit || fLibrariesList.getIndexOfElement(elem) != -1 ) {
editElementEntry((CPListElement) elem);
} else if (elem instanceof CPListElementAttribute) {
editAttributeEntry((CPListElementAttribute) elem);
}
}
private void editAttributeEntry(CPListElementAttribute elem) {
String key= elem.getKey();
CPListElement selElement= elem.getParent();
CPListElementAttribute[] allAttributes= selElement.getAllAttributes();
boolean canEditEncoding= false;
for (int i= 0; i < allAttributes.length; i++) {
if (CPListElement.SOURCE_ATTACHMENT_ENCODING.equals(allAttributes[i].getKey())) {
canEditEncoding= !(allAttributes[i].isNonModifiable() || allAttributes[i].isNotSupported());
}
}
if (key.equals(CPListElement.SOURCEATTACHMENT)) {
IClasspathEntry result= BuildPathDialogAccess.configureSourceAttachment(getShell(), selElement.getClasspathEntry(), canEditEncoding);
if (result != null) {
selElement.setAttribute(CPListElement.SOURCEATTACHMENT, result.getSourceAttachmentPath());
selElement.setAttribute(CPListElement.SOURCE_ATTACHMENT_ENCODING, SourceAttachmentBlock.getSourceAttachmentEncoding(result));
String[] changedAttributes= { CPListElement.SOURCEATTACHMENT, CPListElement.SOURCE_ATTACHMENT_ENCODING };
attributeUpdated(selElement, changedAttributes);
fLibrariesList.refresh(elem);
fLibrariesList.update(selElement); // image
fClassPathList.refresh(); // images
updateEnabledState();
}
} else if (key.equals(CPListElement.ACCESSRULES)) {
AccessRulesDialog dialog= new AccessRulesDialog(getShell(), selElement, fCurrJProject, fPageContainer != null);
int res= dialog.open();
if (res == Window.OK || res == AccessRulesDialog.SWITCH_PAGE) {
selElement.setAttribute(CPListElement.ACCESSRULES, dialog.getAccessRules());
String[] changedAttributes= { CPListElement.ACCESSRULES };
attributeUpdated(selElement, changedAttributes);
fLibrariesList.refresh(elem);
fClassPathList.dialogFieldChanged(); // validate
updateEnabledState();
if (res == AccessRulesDialog.SWITCH_PAGE) { // switch after updates and validation
dialog.performPageSwitch(fPageContainer);
}
}
} else if (key.equals(CPListElement.MODULE)) {
boolean wasModular= selElement.getAttribute(CPListElement.MODULE) != null;
if (showModuleDialog(getShell(), elem)) {
String[] changedAttributes= { CPListElement.MODULE };
attributeUpdated(selElement, changedAttributes);
if (hasRootNodes()) {
boolean isModular= selElement.getAttribute(CPListElement.MODULE) != null;
RootNodeChange direction= RootNodeChange.fromOldAndNew(wasModular, isModular);
if (direction != RootNodeChange.NoChange) {
moveCPElementAcrossNode(fLibrariesList, selElement, direction);
}
}
fLibrariesList.refresh(elem);
fClassPathList.dialogFieldChanged(); // validate
updateEnabledState();
}
} else {
if (editCustomAttribute(getShell(), elem)) {
String[] changedAttributes= { key };
attributeUpdated(selElement, changedAttributes);
fLibrariesList.refresh(elem);
fClassPathList.dialogFieldChanged(); // validate
updateEnabledState();
if (key.equals(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH)) {
if (fCurrJProject.getOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, true).equals(JavaCore.DISABLED)) {
MessageDialog messageDialog= new MessageDialog(getShell(),
NewWizardMessages.LibrariesWorkbookPage_externalAnnotationNeedsNullAnnotationEnabled_title,
null,
NewWizardMessages.LibrariesWorkbookPage_externalAnnotationNeedsNullAnnotationEnabled_message,
MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL },
0);
messageDialog.open();
}
}
}
}
}
private void attributeUpdated(CPListElement selElement, String[] changedAttributes) {
Object parentContainer= selElement.getParentContainer();
if (parentContainer instanceof CPListElement) { // inside a container: apply changes right away
IClasspathEntry updatedEntry= selElement.getClasspathEntry();
updateContainerEntry(updatedEntry, changedAttributes, fCurrJProject, ((CPListElement) parentContainer).getPath());
}
}
private void updateContainerEntry(final IClasspathEntry newEntry, final String[] changedAttributes, final IJavaProject jproject, final IPath containerPath) {
try {
IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
BuildPathSupport.modifyClasspathEntry(null, newEntry, changedAttributes, jproject, containerPath, false, monitor);
}
};
PlatformUI.getWorkbench().getProgressService().run(true, true, new WorkbenchRunnableAdapter(runnable));
} catch (InvocationTargetException e) {
String title= NewWizardMessages.LibrariesWorkbookPage_configurecontainer_error_title;
String message= NewWizardMessages.LibrariesWorkbookPage_configurecontainer_error_message;
ExceptionHandler.handle(e, getShell(), title, message);
} catch (InterruptedException e) {
//
}
}
private void editElementEntry(CPListElement elem) {
CPListElement[] res= null;
switch (elem.getEntryKind()) {
case IClasspathEntry.CPE_CONTAINER:
res= openContainerSelectionDialog(elem);
break;
case IClasspathEntry.CPE_LIBRARY:
IResource resource= elem.getResource();
if (resource == null) {
File file= elem.getPath().toFile();
if (file.isDirectory()) {
res= openExternalClassFolderDialog(elem);
} else {
res= openExtJarFileDialog(elem);
}
} else if (resource.getType() == IResource.FOLDER) {
if (resource.exists()) {
res= openClassFolderDialog(elem);
} else {
res= openNewClassFolderDialog(elem);
}
} else if (resource.getType() == IResource.FILE) {
res= openJarFileDialog(elem);
}
break;
case IClasspathEntry.CPE_VARIABLE:
res= openVariableSelectionDialog(elem);
break;
}
if (res != null && res.length > 0) {
CPListElement curr= res[0];
curr.setExported(elem.isExported());
curr.setAttributesFromExisting(elem);
if (hasRootNodes()) {
for (int i= 0; i < fLibrariesList.getElements().size(); i++) {
CPListElement cpe= fLibrariesList.getElement(i);
if (cpe.isRootNodeForPath()) {
if ((((RootCPListElement)cpe).getChildren().contains(elem))) {
for (int j= 0; j < ((RootCPListElement)cpe).getChildren().size(); j++) {
// find index
Object obj= ((RootCPListElement) cpe).getChildren().get(j);
if (obj.equals(elem)) {
((RootCPListElement) cpe).getChildren().set(j, curr);
RootNodeChange changeNodeDirection= doesElementNeedNodeChange(elem, curr);
if (changeNodeDirection != RootNodeChange.NoChange) {
moveCPElementAcrossNode(fLibrariesList, curr, changeNodeDirection);
CPListElementAttribute moduleAttr= curr.findAttributeElement(CPListElement.MODULE);
Object value= (changeNodeDirection == RootNodeChange.ToModulepath) ? new ModuleEncapsulationDetail[0] : null;
if (moduleAttr != null) {
moduleAttr.setValue(value);
} else {
curr.setAttribute(CPListElement.MODULE, value);
}
}
fLibrariesList.dialogFieldChanged();
fLibrariesList.refresh();
break;
}
}
}
}
}
} else {
fLibrariesList.replaceElement(elem, curr);
}
if (elem.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
fLibrariesList.refresh();
}
}
}
/**
* @param elem is former cpelement
* @param curr is new cpelement
* @return 0 is no change is required, -1 if modular element is removed, +1 if non-modular element
* is removed.
*/
private RootNodeChange doesElementNeedNodeChange(CPListElement elem, CPListElement curr) {
if (elem.getClasspathEntry().getEntryKind() != IClasspathEntry.CPE_CONTAINER)
return RootNodeChange.NoChange;
if (curr.getClasspathEntry().getEntryKind() != IClasspathEntry.CPE_CONTAINER)
return RootNodeChange.NoChange;
String v1= null;
String v2= null;
IVMInstall vm1= JavaRuntime.getVMInstall(elem.getPath());
if (vm1 instanceof AbstractVMInstall) {
v1= ((AbstractVMInstall) vm1).getJavaVersion();
}
IVMInstall vm2= JavaRuntime.getVMInstall(curr.getPath());
if (vm2 instanceof AbstractVMInstall) {
v2= ((AbstractVMInstall) vm2).getJavaVersion();
}
if (v1 != null && v2 != null) {
boolean mod1= JavaModelUtil.is9OrHigher(v1);
boolean mod2= JavaModelUtil.is9OrHigher(v2);
if (mod1 == true && mod2 == true)
return RootNodeChange.NoChange;
if (mod1 == false && mod2 == false)
return RootNodeChange.NoChange;
if (mod1 == true && mod2 == false) {
// removed module
return RootNodeChange.ToClasspath;
}
if (mod1 == false && mod2 == true) {
//added module
return RootNodeChange.ToModulepath;
}
}
return RootNodeChange.NoChange;
}
/**
* @param field the dilaog field
*/
private void libaryPageSelectionChanged(DialogField field) {
updateEnabledState();
}
private void updateEnabledState() {
List<?> selElements= fLibrariesList.getSelectedElements();
fLibrariesList.enableButton(IDX_EDIT, canEdit(selElements));
fLibrariesList.enableButton(IDX_REMOVE, canRemove(selElements));
fLibrariesList.enableButton(IDX_REPLACE, getSelectedPackageFragmentRoot() != null);
boolean addEnabled= containsOnlyTopLevelEntries(selElements);
fLibrariesList.enableButton(IDX_ADDEXT, addEnabled);
fLibrariesList.enableButton(IDX_ADDFOL, addEnabled);
fLibrariesList.enableButton(IDX_ADDEXTFOL, addEnabled);
fLibrariesList.enableButton(IDX_ADDJAR, addEnabled);
fLibrariesList.enableButton(IDX_ADDLIB, addEnabled);
fLibrariesList.enableButton(IDX_ADDVAR, addEnabled);
}
@Override
protected boolean containsOnlyTopLevelEntries(List<?> selElements) {
if(hasRootNodes()==false) {
return super.containsOnlyTopLevelEntries(selElements);
}
if (selElements.size() == 0 || selElements.size() > 1) {
return false;
}
for (int i= 0; i < selElements.size(); i++) {
Object elem= selElements.get(i);
if (elem instanceof CPListElement) {
if (!((CPListElement) elem).isRootNodeForPath()) {
return false;
}
} else {
return false;
}
}
return true;
}
private boolean canEdit(List<?> selElements) {
if (selElements.size() != 1) {
return false;
}
Object elem= selElements.get(0);
if (elem instanceof CPListElement) {
CPListElement curr= (CPListElement) elem;
if(((CPListElement) elem).isRootNodeForPath()) {
return false;
}
return !(curr.getResource() instanceof IFolder) && curr.getParentContainer() == null;
}
if (elem instanceof CPListElementAttribute) {
CPListElementAttribute attrib= (CPListElementAttribute) elem;
if (attrib.isNonModifiable()) {
return false;
}
if (!attrib.isBuiltIn()) {
return canEditCustomAttribute(attrib);
}
if (hasRootNodes() && attrib.getKey().equals(IClasspathAttribute.MODULE)) {
//module attribute should always be enabled
return true;
}
return true;
}
return false;
}
/**
* @param field the dialog field
*/
private void libaryPageDialogFieldChanged(DialogField field) {
if (fCurrJProject != null) {
// already initialized
updateClasspathList();
}
}
private void updateClasspathList() {
List<CPListElement> projelements= fLibrariesList.getElements();
List<CPListElement> flattenedProjElements= new ArrayList<>();
for ( int i =0; i < projelements.size(); i++ ) {
CPListElement ele= projelements.get(i);
// if root node, collect the CPList elements
if(ele.isRootNodeForPath()) {
ArrayList<Object> children= ((RootCPListElement)ele).getChildren();
for (Iterator<?> iterator= children.iterator(); iterator.hasNext();) {
Object object= iterator.next();
if(object instanceof CPListElement) {
flattenedProjElements.add((CPListElement) object);
}
}
}
else {
flattenedProjElements.add(ele);
}
}
List<CPListElement> cpelements= fClassPathList.getElements();
int nEntries= cpelements.size();
// backwards, as entries will be deleted
int lastRemovePos= nEntries;
for (int i= nEntries - 1; i >= 0; i--) {
CPListElement cpe= cpelements.get(i);
int kind= cpe.getEntryKind();
if (isEntryKind(kind)) {
if (!flattenedProjElements.remove(cpe)) {
cpelements.remove(i);
lastRemovePos= i;
}
}
}
cpelements.addAll(lastRemovePos, flattenedProjElements);
if (lastRemovePos != nEntries || !flattenedProjElements.isEmpty()) {
fClassPathList.setElements(cpelements);
}
}
private CPListElement[] openNewClassFolderDialog(CPListElement existing) {
String title= (existing == null) ? NewWizardMessages.LibrariesWorkbookPage_NewClassFolderDialog_new_title : NewWizardMessages.LibrariesWorkbookPage_NewClassFolderDialog_edit_title;
IProject currProject= fCurrJProject.getProject();
NewContainerDialog dialog= new NewContainerDialog(getShell(), title, currProject, getUsedContainers(existing), existing);
IPath projpath= currProject.getFullPath();
dialog.setMessage(Messages.format(NewWizardMessages.LibrariesWorkbookPage_NewClassFolderDialog_description, BasicElementLabels.getPathLabel(projpath, false)));
if (dialog.open() == Window.OK) {
IFolder folder= dialog.getFolder();
return new CPListElement[] { newCPLibraryElement(folder) };
}
return null;
}
private CPListElement[] openClassFolderDialog(CPListElement existing) {
if (existing == null) {
IPath[] selected= BuildPathDialogAccess.chooseClassFolderEntries(getShell(), fCurrJProject.getPath(), getUsedContainers(existing));
if (selected != null) {
IWorkspaceRoot root= fCurrJProject.getProject().getWorkspace().getRoot();
ArrayList<CPListElement> res= new ArrayList<>();
for (int i= 0; i < selected.length; i++) {
IPath curr= selected[i];
IResource resource= root.findMember(curr);
if (resource instanceof IContainer) {
CPListElement newCPLibraryElement= newCPLibraryElement(resource);
newCPLibraryElement.setModuleAttributeIf9OrHigher(fCurrJProject);
res.add(newCPLibraryElement);
}
}
return res.toArray(new CPListElement[res.size()]);
}
} else {
// disabled
}
return null;
}
private CPListElement[] openJarFileDialog(CPListElement existing) {
IWorkspaceRoot root= fCurrJProject.getProject().getWorkspace().getRoot();
if (existing == null) {
IPath[] selected= BuildPathDialogAccess.chooseJAREntries(getShell(), fCurrJProject.getPath(), getUsedJARFiles(existing));
if (selected != null) {
ArrayList<CPListElement> res= new ArrayList<>();
for (int i= 0; i < selected.length; i++) {
IPath curr= selected[i];
IResource resource= root.findMember(curr);
if (resource instanceof IFile) {
CPListElement newCPLibraryElement= newCPLibraryElement(resource);
newCPLibraryElement.setModuleAttributeIf9OrHigher(fCurrJProject);
res.add(newCPLibraryElement);
}
}
return res.toArray(new CPListElement[res.size()]);
}
} else {
IPath configured= BuildPathDialogAccess.configureJAREntry(getShell(), existing.getPath(), getUsedJARFiles(existing));
if (configured != null) {
IResource resource= root.findMember(configured);
if (resource instanceof IFile) {
return new CPListElement[] { newCPLibraryElement(resource) };
}
}
}
return null;
}
private IPath[] getUsedContainers(CPListElement existing) {
ArrayList<IPath> res= new ArrayList<>();
if (fCurrJProject.exists()) {
try {
IPath outputLocation= fCurrJProject.getOutputLocation();
if (outputLocation != null && outputLocation.segmentCount() > 1) { // != Project
res.add(outputLocation);
}
} catch (JavaModelException e) {
// ignore it here, just log
JavaPlugin.log(e.getStatus());
}
}
List<CPListElement> cplist= fLibrariesList.getElements();
for (int i= 0; i < cplist.size(); i++) {
CPListElement elem= cplist.get(i);
if (elem.getEntryKind() == IClasspathEntry.CPE_LIBRARY && (elem != existing)) {
IResource resource= elem.getResource();
if (resource instanceof IContainer) {
res.add(resource.getFullPath());
}
}
}
return res.toArray(new IPath[res.size()]);
}
private IPath[] getUsedJARFiles(CPListElement existing) {
List<IPath> res= new ArrayList<>();
List<CPListElement> cplist= fLibrariesList.getElements();
for (int i= 0; i < cplist.size(); i++) {
CPListElement elem= cplist.get(i);
if (elem.getEntryKind() == IClasspathEntry.CPE_LIBRARY && (elem != existing)) {
IResource resource= elem.getResource();
if (resource instanceof IFile) {
res.add(resource.getFullPath());
}
}
}
return res.toArray(new IPath[res.size()]);
}
private CPListElement newCPLibraryElement(IResource res) {
return new CPListElement(fCurrJProject, IClasspathEntry.CPE_LIBRARY, res.getFullPath(), res);
}
private CPListElement[] openExtJarFileDialog(CPListElement existing) {
if (existing == null) {
IPath[] selected= BuildPathDialogAccess.chooseExternalJAREntries(getShell());
if (selected != null) {
ArrayList<CPListElement> res= new ArrayList<>();
for (int i= 0; i < selected.length; i++) {
CPListElement cpListElement= new CPListElement(fCurrJProject, IClasspathEntry.CPE_LIBRARY, selected[i], null);
cpListElement.setModuleAttributeIf9OrHigher(fCurrJProject);
res.add(cpListElement);
}
return res.toArray(new CPListElement[res.size()]);
}
} else {
IPath path;
IPackageFragmentRoot[] roots= existing.getJavaProject().findPackageFragmentRoots(existing.getClasspathEntry());
if (roots.length == 1)
path= roots[0].getPath();
else
path= existing.getPath();
IPath configured= BuildPathDialogAccess.configureExternalJAREntry(getShell(), path);
if (configured != null) {
return new CPListElement[] { new CPListElement(fCurrJProject, IClasspathEntry.CPE_LIBRARY, configured, null) };
}
}
return null;
}
private CPListElement[] openExternalClassFolderDialog(CPListElement existing) {
if (existing == null) {
IPath[] selected= BuildPathDialogAccess.chooseExternalClassFolderEntries(getShell());
if (selected != null) {
ArrayList<CPListElement> res= new ArrayList<>();
for (int i= 0; i < selected.length; i++) {
CPListElement cpListElement= new CPListElement(fCurrJProject, IClasspathEntry.CPE_LIBRARY, selected[i], null);
cpListElement.setModuleAttributeIf9OrHigher(fCurrJProject);
res.add(cpListElement);
}
return res.toArray(new CPListElement[res.size()]);
}
} else {
IPath configured= BuildPathDialogAccess.configureExternalClassFolderEntries(getShell(), existing.getPath());
if (configured != null) {
return new CPListElement[] { new CPListElement(fCurrJProject, IClasspathEntry.CPE_LIBRARY, configured, null) };
}
}
return null;
}
private CPListElement[] openVariableSelectionDialog(CPListElement existing) {
List<CPListElement> existingElements= fLibrariesList.getElements();
ArrayList<IPath> existingPaths= new ArrayList<>(existingElements.size());
for (int i= 0; i < existingElements.size(); i++) {
CPListElement elem= existingElements.get(i);
if (elem.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
existingPaths.add(elem.getPath());
}
}
IPath[] existingPathsArray= existingPaths.toArray(new IPath[existingPaths.size()]);
if (existing == null) {
IPath[] paths= BuildPathDialogAccess.chooseVariableEntries(getShell(), existingPathsArray);
if (paths != null) {
ArrayList<CPListElement> result= new ArrayList<>();
for (int i= 0; i < paths.length; i++) {
IPath path= paths[i];
CPListElement elem= createCPVariableElement(path);
if (!existingElements.contains(elem)) {
elem.setModuleAttributeIf9OrHigher(fCurrJProject);
result.add(elem);
}
}
return result.toArray(new CPListElement[result.size()]);
}
} else {
IPath path= BuildPathDialogAccess.configureVariableEntry(getShell(), existing.getPath(), existingPathsArray);
if (path != null) {
return new CPListElement[] { createCPVariableElement(path) };
}
}
return null;
}
private CPListElement createCPVariableElement(IPath path) {
CPListElement elem= new CPListElement(fCurrJProject, IClasspathEntry.CPE_VARIABLE, path, null);
IPath resolvedPath= JavaCore.getResolvedVariablePath(path);
elem.setIsMissing((resolvedPath == null) || !resolvedPath.toFile().exists());
return elem;
}
private CPListElement[] openContainerSelectionDialog(CPListElement existing) {
boolean shouldAddModule= false;
if (this.getSelection().size() == 1) {
Object obj= this.getSelection().get(0);
if (obj instanceof RootCPListElement) {
shouldAddModule= ((RootCPListElement) obj).isModulePathRootNode();
}
}
if (existing == null) {
IClasspathEntry[] created= BuildPathDialogAccess.chooseContainerEntries(getShell(), fCurrJProject, getRawClasspath());
if (created != null) {
CPListElement[] res= new CPListElement[created.length];
for (int i= 0; i < res.length; i++) {
res[i]= CPListElement.create(created[i], true, fCurrJProject);
if(shouldAddModule && res[i].getClasspathEntry().getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
res[i].updateExtraAttributeOfClasspathEntry();
}
}
return res;
}
} else {
IClasspathEntry existingEntry= existing.getClasspathEntry();
IClasspathEntry created= BuildPathDialogAccess.configureContainerEntry(getShell(), existingEntry, fCurrJProject, getRawClasspath());
if (created != null) {
CPListElement elem= new CPListElement(null, fCurrJProject, created, IClasspathEntry.CPE_CONTAINER, created.getPath(), null, ! created.equals(existingEntry), null, null);
return new CPListElement[] { elem };
}
}
return null;
}
private IClasspathEntry[] getRawClasspath() {
IClasspathEntry[] currEntries= new IClasspathEntry[fClassPathList.getSize()];
for (int i= 0; i < currEntries.length; i++) {
CPListElement curr= fClassPathList.getElement(i);
currEntries[i]= curr.getClasspathEntry();
}
return currEntries;
}
@Override
public boolean isEntryKind(int kind) {
return kind == IClasspathEntry.CPE_LIBRARY || kind == IClasspathEntry.CPE_VARIABLE || kind == IClasspathEntry.CPE_CONTAINER;
}
/*
* @see BuildPathBasePage#getSelection
*/
@Override
public List<?> getSelection() {
return fLibrariesList.getSelectedElements();
}
/*
* @see BuildPathBasePage#setSelection
*/
@Override
public void setSelection(List<?> selElements, boolean expand) {
fLibrariesList.selectElements(new StructuredSelection(selElements));
if (expand) {
for (int i= 0; i < selElements.size(); i++) {
fLibrariesList.expandElement(selElements.get(i), 1);
}
}
}
@Override
public void setFocus() {
fLibrariesList.setFocus();
}
}