blob: 67a7d04026442603f5dcd6836ce91d941b2bc449 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 GK Software SE, and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.wizards.buildpaths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.Function;
import com.ibm.icu.text.MessageFormat;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.viewsupport.ImageDescriptorRegistry;
import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleDependenciesList.ModuleKind;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleDependenciesPage.DecoratedImageDescriptor;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExpose;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddOpens;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddReads;
import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModulePatch;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.ITreeListAdapter;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.TreeListDialogField;
/**
* Implementation of the right-hand pane of the {@link ModuleDependenciesPage}.
*/
class ModuleDependenciesAdapter implements IDialogFieldListener, ITreeListAdapter<Object> {
private static final int IDX_REMOVE= 0;
private static final int IDX_READ_MODULE= 2;
private static final int IDX_EXPOSE_PACKAGE= 3;
private static final int IDX_PATCH= 5;
private static final int IDX_EDIT= 7;
abstract static class Details {
/** the module selected in the LHS pane, for which details are being shown / edited in this RHS pane. */
protected final IModuleDescription fFocusModule;
/** the classpath element by which the current project refers to the focus module. */
protected final CPListElement fElem;
public Details(IModuleDescription focusModule, CPListElement elem) {
fFocusModule= focusModule;
fElem= elem;
}
/**
* Answer the module of the current IJavaProject for which the build path is being configured.
* @return the module of the current project, or {@code null}.
*/
protected IModuleDescription getContextModule() {
try {
IModuleDescription moduleDescription= fElem.getJavaProject().getModuleDescription();
if (moduleDescription != null) {
return moduleDescription;
}
} catch (JavaModelException jme) {
JavaPlugin.log(jme.getStatus());
}
return null;
}
protected String getContextModuleName() {
try {
IModuleDescription moduleDescription= fElem.getJavaProject().getModuleDescription();
if (moduleDescription != null) {
return moduleDescription.getElementName();
}
} catch (JavaModelException jme) {
JavaPlugin.log(jme.getStatus());
}
return ""; //$NON-NLS-1$
}
protected IJavaProject getContextProject() {
return fElem.getJavaProject();
}
}
/** Synthetic tree node as a parent for details that are declared by the focus module (in its module-info) */
static class DeclaredDetails extends Details {
public DeclaredDetails(IModuleDescription mod, CPListElement elem) {
super(mod, elem);
}
/**
* Answer all packages accessible to the context module (exports/opens)
* @return accessible packages represented by {@link AccessiblePackage}.
*/
public Object[] getPackages() {
try {
if (fFocusModule != null && !fFocusModule.isAutoModule()) {
IModuleDescription contextModule= getContextModule();
String[] exported= fFocusModule.getExportedPackageNames(contextModule);
List<AccessiblePackage> result= new ArrayList<>();
for (String export : exported) {
result.add(new AccessiblePackage(export, AccessiblePackage.Kind.Exports, this));
}
String[] opened= fFocusModule.getOpenedPackageNames(contextModule);
for (String open : opened) {
result.add(new AccessiblePackage(open, AccessiblePackage.Kind.Opens, this));
}
return result.toArray();
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
return new Object[0];
}
}
/** Synthetic tree node. */
static class ConfiguredDetails extends Details {
private ModuleKind fKind;
public ConfiguredDetails(IModuleDescription focusModule, CPListElement elem, ModuleKind moduleKind) {
super(focusModule, elem);
fKind= moduleKind;
}
public Object[] getChildren() {
if (fKind == ModuleKind.System) {
// aggregate attribute is in the parent (corresponding to the JRE)
Object parent= fElem.getParentContainer();
if (parent instanceof CPListElement) {
Object attribute= ((CPListElement) parent).getAttribute(CPListElement.MODULE);
if (attribute instanceof ModuleEncapsulationDetail[]) {
return convertEncapsulationDetails((ModuleEncapsulationDetail[]) attribute, fFocusModule.getElementName());
}
}
}
Object attribute= fElem.getAttribute(CPListElement.MODULE);
if (attribute instanceof ModuleEncapsulationDetail[]) {
return convertEncapsulationDetails((ModuleEncapsulationDetail[]) attribute, null);
}
return fElem.getChildren(true);
}
private DetailNode<?>[] convertEncapsulationDetails(ModuleEncapsulationDetail[] attribute, String filterModule) {
List<DetailNode<?>> filteredDetails= new ArrayList<>();
for (ModuleEncapsulationDetail detail : attribute) {
if (detail instanceof ModuleAddExpose) {
ModuleAddExpose moduleAddExpose= (ModuleAddExpose) detail;
if (filterModule == null || filterModule.equals(moduleAddExpose.fSourceModule)) {
AccessiblePackage.Kind kind= moduleAddExpose instanceof ModuleAddExport ? AccessiblePackage.Kind.Exports : AccessiblePackage.Kind.Opens;
filteredDetails.add(new AccessiblePackage(moduleAddExpose.fPackage, kind, this));
}
} else if (detail instanceof ModuleAddReads) {
ModuleAddReads moduleAddReads= (ModuleAddReads) detail;
if (filterModule == null || filterModule.equals(moduleAddReads.fSourceModule)) {
filteredDetails.add(new ReadModule(moduleAddReads.fTargetModule, this));
}
} else if (detail instanceof ModulePatch) {
ModulePatch modulePatch= (ModulePatch) detail;
if (filterModule == null || filterModule.equals(modulePatch.fModule)) {
try {
if (modulePatch.fPaths != null) {
IPath path= new Path(modulePatch.fPaths);
IFolder folder= ResourcesPlugin.getWorkspace().getRoot().getFolder(path);
IJavaElement elem= JavaCore.create(folder.getProject()).getPackageFragmentRoot(folder);
if (elem instanceof IPackageFragmentRoot) {
filteredDetails.add(new PatchModule((IPackageFragmentRoot) elem, this));
}
} else {
for (IClasspathEntry entry : fElem.getJavaProject().getRawClasspath()) {
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
for (IPackageFragmentRoot root : fElem.getJavaProject().findPackageFragmentRoots(entry)) {
if (root.getKind() == IPackageFragmentRoot.K_SOURCE)
filteredDetails.add(new PatchModule(root, this));
}
}
}
}
} catch (JavaModelException e) {
JavaPlugin.log(e);
}
}
}
}
return filteredDetails.toArray(new DetailNode<?>[filteredDetails.size()]);
}
public void removeAll() {
if (fKind == ModuleKind.System) {
// aggregate attribute is in the parent (corresponding to the JRE)
Object parent= fElem.getParentContainer();
if (parent instanceof CPListElement) {
CPListElement jreElement= (CPListElement) parent;
Object attribute= jreElement.getAttribute(CPListElement.MODULE);
if (attribute instanceof ModuleEncapsulationDetail[]) {
// need to filter so we remove only affected details:
ModuleEncapsulationDetail[] filtered= Arrays.stream((ModuleEncapsulationDetail[]) attribute)
.filter(d -> !d.affects(fFocusModule.getElementName()))
.toArray(ModuleEncapsulationDetail[]::new);
jreElement.setAttribute(CPListElement.MODULE, filtered);
return;
}
}
}
Object attribute= fElem.getAttribute(CPListElement.MODULE);
if (attribute instanceof ModuleEncapsulationDetail[]) {
fElem.setAttribute(CPListElement.MODULE, new ModuleEncapsulationDetail[0]);
}
}
public boolean addOrEditAccessiblePackage(AccessiblePackage selectedPackage, Shell shell) {
Object container= fElem.getParentContainer();
CPListElement element= (container instanceof CPListElement) ? (CPListElement) container : fElem;
CPListElementAttribute moduleAttribute= element.findAttributeElement(CPListElement.MODULE);
IPackageFragmentRoot packRoot= (IPackageFragmentRoot) fFocusModule.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
String packageName= selectedPackage != null ? selectedPackage.getName() : ""; //$NON-NLS-1$
ModuleAddExpose initial= (selectedPackage != null)
? selectedPackage.convertToCP(moduleAttribute)
: new ModuleAddExport(fFocusModule.getElementName(), packageName, getContextModuleName(), moduleAttribute);
ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(shell, new IJavaElement[] { packRoot }, initial);
if (dialog.open() == Window.OK) {
ModuleAddExpose expose= dialog.getExport(moduleAttribute);
if (expose != null) {
Object attribute= moduleAttribute.getValue();
ModuleEncapsulationDetail[] arrayValue= null;
if (attribute instanceof ModuleEncapsulationDetail[]) {
arrayValue= (ModuleEncapsulationDetail[]) attribute;
if (selectedPackage != null) {
// editing: replace existing entry
for (int i= 0; i < arrayValue.length; i++) {
ModuleEncapsulationDetail detail= arrayValue[i];
if (detail.equals(initial)) {
arrayValue[i]= expose;
break;
}
}
} else {
arrayValue= Arrays.copyOf(arrayValue, arrayValue.length+1);
arrayValue[arrayValue.length-1]= expose;
}
} else {
arrayValue= new ModuleEncapsulationDetail[] { expose };
}
element.setAttribute(CPListElement.MODULE, arrayValue);
return true;
}
}
return false;
}
public void remove(List<Object> selectedElements) {
CPListElementAttribute moduleAttribute;
if (fKind == ModuleKind.System) {
moduleAttribute= ((CPListElement) fElem.getParentContainer()).findAttributeElement(CPListElement.MODULE);
} else {
moduleAttribute= fElem.findAttributeElement(CPListElement.MODULE);
}
if (moduleAttribute == null) {
// TODO report
return;
}
if (!(moduleAttribute.getValue() instanceof ModuleEncapsulationDetail[])) {
// TODO report
return;
}
List<ModuleEncapsulationDetail> details= new ArrayList<>(Arrays.asList((ModuleEncapsulationDetail[]) moduleAttribute.getValue()));
for (Object node : selectedElements) {
if (node instanceof DetailNode<?>) {
ModuleEncapsulationDetail med= ((DetailNode<?>) node).convertToCP(moduleAttribute);
if (med != null) {
details.remove(med);
}
} else if (node instanceof ConfiguredDetails) {
((ConfiguredDetails) node).removeAll();
return; // covers all details, changes in 'details' are irrelevant
}
}
moduleAttribute.setValue(details.toArray(new ModuleEncapsulationDetail[details.size()]));
}
public boolean addReads(Shell shell) {
Object container= fElem.getParentContainer();
CPListElement element= (container instanceof CPListElement) ? (CPListElement) container : fElem;
CPListElementAttribute moduleAttribute= element.findAttributeElement(CPListElement.MODULE);
if (moduleAttribute == null) {
return false; // TODO report
}
List<String> irrelevantModules;
try {
irrelevantModules= Arrays.asList(fFocusModule.getRequiredModuleNames());
} catch (JavaModelException e) {
JavaPlugin.log(e.getStatus());
irrelevantModules= Collections.emptyList();
}
irrelevantModules= new ArrayList<>(irrelevantModules);
irrelevantModules.add(fFocusModule.getElementName());
ModuleSelectionDialog dialog= new ModuleSelectionDialog(shell, fElem.getJavaProject(), null, irrelevantModules, HashSet::new);
if (dialog.open() != 0) {
return false;
}
List<IModuleDescription> result= dialog.getResult();
editModularityDetails(element, moduleAttribute, result,
null,
mod -> new ModuleAddReads(fFocusModule.getElementName(), mod.getElementName(), moduleAttribute));
return true;
}
public boolean addPatch(Shell shell, Map<String, String> patchMap) {
Object container= fElem.getParentContainer();
CPListElement element= (container instanceof CPListElement) ? (CPListElement) container : fElem;
CPListElementAttribute moduleAttribute= element.findAttributeElement(CPListElement.MODULE);
if (moduleAttribute == null) {
return false; // TODO report
}
IJavaProject contextProject= getContextProject();
ModulePatchSourceSelectionDialog dialog= new ModulePatchSourceSelectionDialog(shell, fFocusModule, contextProject);
if (dialog.open() != 0) {
return false;
}
List<IPackageFragmentRoot> result= dialog.getResult();
for (IPackageFragmentRoot root : result) {
String rootPath= root.getPath().toString();
if (patchMap.containsKey(rootPath)) {
if (!MessageDialog.openQuestion(shell, "Patch module conflict",
MessageFormat.format("The source folder {0} was declared to patch module {1}, change to replacing module {2} instead?",
root.getPath(), patchMap.get(rootPath), fFocusModule.getElementName()))) {
return false;
}
}
}
editModularityDetails(element, moduleAttribute, result,
(r,med) -> med instanceof ModulePatch && r.getPath().toString().equals(((ModulePatch)med).fPaths),
root -> new ModulePatch(fFocusModule.getElementName(), root.getPath().toString(), moduleAttribute));
return true;
}
private <T> void editModularityDetails(CPListElement element, CPListElementAttribute moduleAttribute, List<T> result,
BiPredicate<T,ModuleEncapsulationDetail> shouldReplace, Function<T,ModuleEncapsulationDetail> factory) {
ModuleEncapsulationDetail[] arrayValue= null;
int idx= 0;
Object attribute= moduleAttribute.getValue();
if (attribute instanceof ModuleEncapsulationDetail[]) {
List<T> remaining= new ArrayList<>();
arrayValue= (ModuleEncapsulationDetail[]) attribute;
if (shouldReplace != null) {
allResults:
for (T newValue : result) {
for (int i= 0; i < arrayValue.length; i++) {
if (shouldReplace.test(newValue, arrayValue[i])) {
arrayValue[i]= factory.apply(result.get(0));
continue allResults;
}
}
remaining.add(newValue);
}
if (remaining.isEmpty())
return;
result= remaining;
}
idx= arrayValue.length;
arrayValue= Arrays.copyOf(arrayValue, arrayValue.length+result.size());
} else {
arrayValue= new ModuleEncapsulationDetail[result.size()];
}
for (T detail : result) {
arrayValue[idx++]= factory.apply(detail);
}
element.setAttribute(CPListElement.MODULE, arrayValue);
}
}
abstract static class DetailNode<D extends ModuleEncapsulationDetail> {
protected String fName;
protected Details fParent;
protected DetailNode(Details parent) {
fParent= parent;
}
public String getName() {
return fName;
}
public boolean isIsConfigured() {
return fParent instanceof ConfiguredDetails;
}
public abstract D convertToCP(CPListElementAttribute attribElem);
}
/** Declare that the package denoted by {@link #fName} is accessible (exported/opened) to the current context module. */
static class AccessiblePackage extends DetailNode<ModuleAddExpose> {
enum Kind { Exports, Opens;
ImageDescriptor getDecoration() {
switch (this) {
case Exports: return JavaPluginImages.DESC_OVR_EXPORTS;
case Opens: return JavaPluginImages.DESC_OVR_OPENS;
default: return null;
}
}
}
private Kind fKind;
public AccessiblePackage(String name, Kind kind, Details parent) {
super(parent);
fName= name;
fKind= kind;
}
public Kind getKind() {
return fKind;
}
@Override
public ModuleAddExpose convertToCP(CPListElementAttribute attribElem) {
if (fParent instanceof ConfiguredDetails) {
String targetModule= fParent.getContextModuleName();
if (targetModule != null) {
switch (fKind) {
case Exports:
return new ModuleAddExport(fParent.fFocusModule.getElementName(), fName, targetModule, attribElem);
case Opens:
return new ModuleAddOpens(fParent.fFocusModule.getElementName(), fName, targetModule, attribElem);
default:
break;
}
}
}
return null; // TODO: report
}
}
/** Declare that the module given by {@link #fName} is read by the selected focus module. */
static class ReadModule extends DetailNode<ModuleAddReads> {
public ReadModule(String targetModule, Details parent) {
super(parent);
fName= targetModule;
}
@Override
public ModuleAddReads convertToCP(CPListElementAttribute attribElem) {
if (fParent instanceof ConfiguredDetails) {
return new ModuleAddReads(fParent.fFocusModule.getElementName(), fName, attribElem);
}
return null; // TODO: report
}
}
/** Declare that the selected focus module is patched by the content of the given package fragment root. */
static class PatchModule extends DetailNode<ModulePatch> {
private IPackageFragmentRoot fRoot;
public PatchModule(IPackageFragmentRoot root, Details parent) {
super(parent);
fRoot= root;
fName= root.getPath().makeRelative().toString();
}
@Override
public ModulePatch convertToCP(CPListElementAttribute attribElem) {
return new ModulePatch(fParent.fFocusModule.getElementName(), attribElem); // assumes root is "the source folder" of the current context project
}
}
static class ModularityDetailsLabelProvider extends CPListLabelProvider {
private ImageDescriptorRegistry fRegistry= JavaPlugin.getImageDescriptorRegistry();
private JavaElementImageProvider fImageLabelProvider= new JavaElementImageProvider();
@Override
public String getText(Object element) {
if (element instanceof DeclaredDetails) {
return NewWizardMessages.ModuleDependenciesAdapter_declared_node;
}
if (element instanceof ConfiguredDetails) {
return NewWizardMessages.ModuleDependenciesAdapter_configured_node;
}
if (element instanceof DetailNode) {
return ((DetailNode<?>) element).getName();
}
return super.getText(element);
}
@Override
public Image getImage(Object element) {
if (element instanceof CPListElement) {
return fRegistry.get(JavaPluginImages.DESC_OBJS_MODULE);
}
if (element instanceof AccessiblePackage) {
AccessiblePackage.Kind kind= ((AccessiblePackage) element).getKind();
ImageDescriptor imgDesc= new DecoratedImageDescriptor(JavaPluginImages.DESC_OBJS_PACKAGE, kind.getDecoration(), true);
return JavaPlugin.getImageDescriptorRegistry().get(imgDesc);
}
if (element instanceof ReadModule) {
ImageDescriptor imgDesc= new DecoratedImageDescriptor(JavaPluginImages.DESC_OBJS_MODULE,
JavaPluginImages.DESC_OVR_READS, true);
return JavaPlugin.getImageDescriptorRegistry().get(imgDesc);
}
if (element instanceof PatchModule) {
return fImageLabelProvider.getImageLabel(((PatchModule) element).fRoot, 0);
}
return super.getImage(element);
}
}
static class ElementSorter extends CPListElementSorter {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
// sorting for root nodes: CPListElement > DeclaredDetails > ConfiguredDetails
if (e1 instanceof DeclaredDetails) {
return e2 instanceof ConfiguredDetails ? -1 : 1;
}
if (e1 instanceof ConfiguredDetails) {
return e2 instanceof DeclaredDetails ? 1 : -1;
}
if (e2 instanceof DeclaredDetails || e2 instanceof ConfiguredDetails) {
return -1;
}
return super.compare(viewer, e1, e2);
}
}
public static void enableDefaultButtons(TreeListDialogField<?> list, boolean enable, boolean removeEnabled) {
list.enableButton(IDX_REMOVE, removeEnabled);
list.enableButton(IDX_EXPOSE_PACKAGE, enable);
list.enableButton(IDX_READ_MODULE, enable);
list.enableButton(IDX_PATCH, enable);
}
private final ModuleDependenciesPage fModuleDependenciesPage; // parent structure
private TreeListDialogField<Object> fDetailsList; // RHS widget managed by this class
public ModuleDependenciesAdapter(ModuleDependenciesPage moduleDependenciesPage) {
fModuleDependenciesPage= moduleDependenciesPage;
}
public void setList(TreeListDialogField<Object> detailsList) {
fDetailsList= detailsList;
fDetailsList.enableButton(IDX_REMOVE, false);
fDetailsList.enableButton(IDX_EXPOSE_PACKAGE, false);
fDetailsList.enableButton(IDX_READ_MODULE, false);
fDetailsList.enableButton(IDX_PATCH, false);
fDetailsList.enableButton(IDX_EDIT, false);
}
// -------- IListAdapter --------
@Override
public void customButtonPressed(TreeListDialogField<Object> field, int index) {
AccessiblePackage selectedPackage= null;
List<Object> selectedElements= field.getSelectedElements();
switch (index) {
case IDX_REMOVE:
if (selectedElements.size() == 0) {
// no detail selected, remove the module(s) (with question):
fModuleDependenciesPage.removeModules();
} else {
getConfiguredDetails().remove(selectedElements);
}
field.refresh();
break;
case IDX_EDIT:
if (selectedElements.size() == 1 && selectedElements.get(0) instanceof AccessiblePackage) {
selectedPackage= (AccessiblePackage) selectedElements.get(0);
}
// FIXME: can no longer use fallthrough, when editing other details
//$FALL-THROUGH$
case IDX_EXPOSE_PACKAGE:
if (getConfiguredDetails().addOrEditAccessiblePackage(selectedPackage, fModuleDependenciesPage.getShell())) {
field.refresh();
}
break;
case IDX_READ_MODULE:
if (getConfiguredDetails().addReads(fModuleDependenciesPage.getShell())) {
field.refresh();
}
break;
case IDX_PATCH:
if (getConfiguredDetails().addPatch(fModuleDependenciesPage.getShell(), fModuleDependenciesPage.fPatchMap)) {
field.refresh();
}
break;
default:
throw new IllegalArgumentException("Non-existent button index "+index); //$NON-NLS-1$
}
}
private ConfiguredDetails getConfiguredDetails() {
for (Object object : fDetailsList.getElements()) {
if (object instanceof ConfiguredDetails)
return (ConfiguredDetails) object;
}
throw new IllegalStateException("detail list has no ConfiguredDetails element"); //$NON-NLS-1$
}
@Override
public void selectionChanged(TreeListDialogField<Object> field) {
List<Object> selected= fDetailsList.getSelectedElements();
boolean enable= false;
if (selected.size() == 1) {
Object selectedNode= selected.get(0);
enable= isConfigurableNode(selectedNode);
fDetailsList.enableButton(IDX_EDIT, enable && selectedNode instanceof DetailNode<?>);
return;
} else {
enable= allAreConfigurable(selected);
fDetailsList.enableButton(IDX_EDIT, false);
}
fDetailsList.enableButton(IDX_EXPOSE_PACKAGE, enable);
fDetailsList.enableButton(IDX_READ_MODULE, enable);
fDetailsList.enableButton(IDX_PATCH, enable);
fDetailsList.enableButton(IDX_REMOVE, enable);
}
private boolean allAreConfigurable(List<Object> selected) {
for (Object node : selected) {
if (!isConfigurableNode(node))
return false;
}
return true;
}
private boolean isConfigurableNode(Object node) {
if (node instanceof ConfiguredDetails) {
return true;
}
if (node instanceof DeclaredDetails) {
return false;
}
if (node instanceof DetailNode) {
return ((DetailNode<?>) node).isIsConfigured();
}
return true;
}
@Override
public void doubleClicked(TreeListDialogField<Object> field) {
List<Object> selectedElements= fDetailsList.getSelectedElements();
if (selectedElements.size() == 1) {
Object selected= selectedElements.get(0);
if (selected instanceof ReadModule) {
String moduleName= ((ReadModule) selected).getName();
fModuleDependenciesPage.setSelectionToModule(moduleName);
} else {
TreeViewer treeViewer= fDetailsList.getTreeViewer();
boolean isExpanded= treeViewer.getExpandedState(selectedElements.get(0));
if (isExpanded) {
treeViewer.collapseToLevel(selectedElements.get(0), 1);
} else {
treeViewer.expandToLevel(selectedElements.get(0), 1);
}
}
}
}
@Override
public void keyPressed(TreeListDialogField<Object> field, KeyEvent event) {
// libaryPageKeyPressed(field, event);
}
@Override
public Object[] getChildren(TreeListDialogField<Object> field, Object element) {
if (element instanceof CPListElement) { // assumed to be root
// no direct children
} else if (element instanceof DeclaredDetails) {
return ((DeclaredDetails) element).getPackages();
} else if (element instanceof ConfiguredDetails) {
return ((ConfiguredDetails) element).getChildren();
}
return new Object[0];
}
@Override
public Object getParent(TreeListDialogField<Object> field, Object element) {
if (element instanceof CPListElementAttribute) {
return ((CPListElementAttribute) element).getParent();
}
// TODO
return null;
}
@Override
public boolean hasChildren(TreeListDialogField<Object> field, Object element) {
Object[] children= getChildren(field, element);
return children != null && children.length > 0;
}
// ---------- IDialogFieldListener --------
@Override
public void dialogFieldChanged(DialogField field) {
// libaryPageDialogFieldChanged(field);
}
}