diff options
| author | Stephan Herrmann | 2017-09-03 18:50:39 +0000 |
|---|---|---|
| committer | Stephan Herrmann | 2017-09-16 12:16:02 +0000 |
| commit | 8362220c2bf1e277c0bf682fdd1d0d3624bb63ec (patch) | |
| tree | 179300a98ed6292d57ea0a157cb945fe72470188 | |
| parent | ef015e1292f9fe5a9d40590896d5c2c8a0c88b02 (diff) | |
| download | eclipse.jdt.ui-8362220c2bf1e277c0bf682fdd1d0d3624bb63ec.tar.gz eclipse.jdt.ui-8362220c2bf1e277c0bf682fdd1d0d3624bb63ec.tar.xz eclipse.jdt.ui-8362220c2bf1e277c0bf682fdd1d0d3624bb63ec.zip | |
support in IDE
Change-Id: Idd4455da9cca89cc8050c78e3460f9d21492e65b
23 files changed, 1534 insertions, 494 deletions
diff --git a/org.eclipse.jdt.ui/icons/full/etool16/move_up.png b/org.eclipse.jdt.ui/icons/full/etool16/move_up.png Binary files differnew file mode 100644 index 0000000000..7eaaff9798 --- /dev/null +++ b/org.eclipse.jdt.ui/icons/full/etool16/move_up.png diff --git a/org.eclipse.jdt.ui/icons/full/etool16/move_up@2x.png b/org.eclipse.jdt.ui/icons/full/etool16/move_up@2x.png Binary files differnew file mode 100644 index 0000000000..0b95e38b51 --- /dev/null +++ b/org.eclipse.jdt.ui/icons/full/etool16/move_up@2x.png diff --git a/org.eclipse.jdt.ui/icons/full/obj16/export_package.png b/org.eclipse.jdt.ui/icons/full/obj16/export_package.png Binary files differdeleted file mode 100644 index f45bdbd75c..0000000000 --- a/org.eclipse.jdt.ui/icons/full/obj16/export_package.png +++ /dev/null diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml index 468f4d8aba..491001473e 100644 --- a/org.eclipse.jdt.ui/plugin.xml +++ b/org.eclipse.jdt.ui/plugin.xml @@ -185,10 +185,6 @@ attributeName="module" class="org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleAttributeConfiguration"> </classpathAttributeConfiguration> - <classpathAttributeConfiguration - attributeName="add-exports" - class="org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleAddExportsAttributeConfiguration"> - </classpathAttributeConfiguration> </extension> <!-- Not used to create markers but to allow registering a --> diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java index df2cfe27cf..923821d651 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaPluginImages.java @@ -148,7 +148,6 @@ public class JavaPluginImages { public static final String IMG_OBJS_JAVADOCTAG= NAME_PREFIX + "jdoc_tag_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_EXTERNAL_ANNOTATIONS = NAME_PREFIX + "external_annotation_location_attrib.gif"; //$NON-NLS-1$ - public static final String IMG_OBJS_ADD_EXPORTS = NAME_PREFIX + "export_package.png"; //$NON-NLS-1$ public static final String IMG_OBJS_HTMLTAG= NAME_PREFIX + "html_tag_obj.gif"; //$NON-NLS-1$ public static final String IMG_OBJS_TEMPLATE= NAME_PREFIX + "template_obj.gif"; //$NON-NLS-1$ @@ -215,6 +214,8 @@ public class JavaPluginImages { public static final ImageDescriptor DESC_MENU_SHIFT_LEFT= createUnManaged(T_ETOOL, "shift_l_edit.png"); //$NON-NLS-1$ public static final ImageDescriptor DESC_CLASSPATH_ROOT= createUnManaged(T_ETOOL, "classpath_obj.png"); //$NON-NLS-1$ + public static final ImageDescriptor DESC_BUTTON_MOVE_UP= createUnManaged(T_ETOOL, "move_up.png"); //$NON-NLS-1$ + public static final ImageDescriptor DESC_OBJS_GHOST= createManagedFromKey(T_OBJ, IMG_OBJS_GHOST); public static final ImageDescriptor DESC_OBJS_PACKDECL= createManagedFromKey(T_OBJ, IMG_OBJS_PACKDECL); public static final ImageDescriptor DESC_OBJS_IMPDECL= createManagedFromKey(T_OBJ, IMG_OBJS_IMPDECL); @@ -312,8 +313,6 @@ public class JavaPluginImages { public static final ImageDescriptor DESC_OBJS_EXTERNAL_ANNOTATION_LOCATION_ATTRIB= createManagedFromKey(T_OBJ, IMG_OBJS_EXTERNAL_ANNOTATIONS); - public static final ImageDescriptor DESC_OBJS_ADD_EXPORTS_ATTRIB= createManagedFromKey(T_OBJ, IMG_OBJS_ADD_EXPORTS); - public static final ImageDescriptor DESC_OBJS_ACCESSRULES_ATTRIB= createManagedFromKey(T_OBJ, IMG_OBJS_ACCESSRULES_ATTRIB); public static final ImageDescriptor DESC_OBJS_NATIVE_LIB_PATH_ATTRIB= createUnManaged(T_OBJ, "native_lib_path_attrib.png"); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/UserLibraryPreferencePage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/UserLibraryPreferencePage.java index a5a473237c..d719f1e86e 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/UserLibraryPreferencePage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/UserLibraryPreferencePage.java @@ -126,7 +126,7 @@ import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElementSorter; import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListLabelProvider; import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPUserLibraryElement; import org.eclipse.jdt.internal.ui.wizards.buildpaths.ClasspathAttributeConfigurationDescriptors; -import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleAddExport; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail; import org.eclipse.jdt.internal.ui.wizards.buildpaths.SourceAttachmentBlock; import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField; import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; @@ -1519,7 +1519,7 @@ public class UserLibraryPreferencePage extends PreferencePage implements IWorkbe return (IAccessRule[]) attribute.getValue(); } if (CPListElement.MODULE.equals(attribute.getKey())) { - return (ModuleAddExport[]) attribute.getValue(); + return (ModuleEncapsulationDetail[]) attribute.getValue(); } } return EMPTY; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.java index 46326a4868..76cb370797 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.java @@ -451,27 +451,58 @@ public final class NewWizardMessages extends NLS { public static String ModuleDialog_container_description; public static String ModuleDialog_project_description; public static String ModuleDialog_defines_modules_label; - public static String ModuleDialog_duplicatePackage_error; + public static String ModuleDialog_errorOnContentsTab_error; + public static String ModuleDialog_errorOnDetailsTab_error; + + public static String ModuleDialog_contents_tab; + public static String ModuleDialog_availableModules_list; + public static String ModuleDialog_availableModules_tooltip; + public static String ModuleDialog_explicitlyIncludedModules_list; + public static String ModuleDialog_explicitlyIncludedModules_tooltip; + public static String ModuleDialog_implicitelyIncludedModules_list; + public static String ModuleDialog_implicitlyIncludedModule_tooltip; + public static String ModuleDialog_addToIncluded_tooltip; + public static String ModuleDialog_removeFromIncluded_tooltip; + public static String ModuleDialog_addToExplicitlyIncluded_tooltip; + public static String ModuleDialog_cannotLimitSingle_error; + + public static String ModuleDialog_details_tab; + public static String ModuleDialog_patches_module_label; + public static String ModuleDialog_patched_module_label; + public static String ModuleDialog_patchedModuleExcluded_error; public static String ModuleDialog_source_module_header; public static String ModuleDialog_package_header; - public static String ModuleDialog_target_modules_header; + public static String ModuleDialog_target_module_header; public static String ModuleDialog_exports_label; - public static String ModuleDialog_exports_add; - public static String ModuleDialog_exports_edit; - public static String ModuleDialog_exports_remove; + public static String ModuleDialog_exportSourceModuleExcluded_error; + public static String ModuleDialog_reads_label; + public static String ModuleDialog_readsSourceModuleExcluded_error; + public static String ModuleDialog_detail_add; + public static String ModuleDialog_detail_edit; + public static String ModuleDialog_detail_remove; + public static String ModuleDialog_duplicatePackage_error; + public static String ModuleDialog_duplicateReads_error; + public static String ModuleDialog_missingPatch_error; + public static String ModuleDialog_wrongPatch_error; + public static String ModuleDialog_mustIncludeModule_error; public static String ModuleAddExportsBlock_packageEmpty_error; public static String ModuleAddExportsBlock_sourceModuleEmpty_error; public static String ModuleAddExportsBlock_wrongPackage_error; public static String ModuleAddExportsBlock_wrongSourceModule_error; - public static String AddExportsDialog_notPersisted_warning; + public static String AddModuleDetailsDialog_notPersisted_warning; public static String AddExportsDialog_title; public static String AddExportsBlock_message; public static String AddExportsBlock_sourceModule_label; public static String AddExportsBlock_package_label; public static String AddExportsBlock_targetModules_label; + + public static String AddReadsDialog_title; + public static String AddReadsBlock_message; + public static String AddReadsBlock_sourceModule_label; + public static String AddReadsBlock_targetModule_label; // public static String EditVariableEntryDialog_title; @@ -649,10 +680,15 @@ public final class NewWizardMessages extends NLS { public static String CPListLabelProvider_module_no; public static String CPListLabelProvider_modular_modifiesEncapsulation_label; public static String CPListLabelProvider_modular_label; + public static String CPListLabelProvider_modular_limitsAndModifies_label; + public static String CPListLabelProvider_modular_limitsModules_label; public static String CPListLabelProvider_not_modular_label; public static String CPListLabelProvider_add_exports_name_label; + public static String CPListLabelProvider_patch_module_full_label; public static String CPListLabelProvider_add_exports_full_label; + public static String CPListLabelProvider_add_reads_full_label; + public static String CPListLabelProvider_limitModules_full_label; public static String NewSourceFolderDialog_useproject_button; public static String NewSourceFolderDialog_usefolder_button; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.properties index ef3957f0eb..50c34a829f 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.properties +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/NewWizardMessages.properties @@ -488,14 +488,40 @@ ModuleDialog_description=Module related details for ''{0}''. ModuleDialog_container_description=Module related details for the library ''{0}''. ModuleDialog_project_description=Module related details for the project ''{0}''. ModuleDialog_defines_modules_label=&Defines one or more modules -ModuleDialog_duplicatePackage_error=Duplicate package {0} -ModuleDialog_exports_label=Added exports: -ModuleDialog_target_modules_header=Target module +ModuleDialog_errorOnContentsTab_error=Error exists on Contents tab +ModuleDialog_errorOnDetailsTab_error=Error exists on Details tab + +ModuleDialog_contents_tab=Contents +ModuleDialog_availableModules_list=Available modules: +ModuleDialog_availableModules_tooltip=Modules that are available in the current classpath entry, but not included in the module path +ModuleDialog_explicitlyIncludedModules_list=Explicitly included modules: +ModuleDialog_explicitlyIncludedModules_tooltip=Modules that are explicitly included in the module path +ModuleDialog_implicitelyIncludedModules_list=Implicitly included modules: +ModuleDialog_implicitlyIncludedModule_tooltip=Modules that are implicitly included in the module path, because they are required by explicitly included modules +ModuleDialog_addToIncluded_tooltip=Add selected to included modules +ModuleDialog_removeFromIncluded_tooltip=Remove selected from included modules +ModuleDialog_addToExplicitlyIncluded_tooltip=Add selected to explicitly included modules +ModuleDialog_cannotLimitSingle_error=Cannot limit a single-module entry + +ModuleDialog_details_tab=Details +ModuleDialog_patches_module_label=Patches an existing module +ModuleDialog_patched_module_label=Patched module: +ModuleDialog_patchedModuleExcluded_error=Patched module {0} is excluded on the Contents tab +ModuleDialog_exports_label=Added &exports: +ModuleDialog_exportSourceModuleExcluded_error=Cannot export package {0}, because declaring module {1} is excluded +ModuleDialog_reads_label=Added &read modules: +ModuleDialog_readsSourceModuleExcluded_error=Cannot add 'reads' to module {0}, which is excluded on the Contents tab +ModuleDialog_target_module_header=Target module ModuleDialog_package_header=Package ModuleDialog_source_module_header=Source module -ModuleDialog_exports_add=&Add... -ModuleDialog_exports_edit=Edi&t... -ModuleDialog_exports_remove=Rem&ove +ModuleDialog_detail_add=Add... +ModuleDialog_detail_edit=Edit... +ModuleDialog_detail_remove=Remove +ModuleDialog_duplicatePackage_error=Duplicate package {0} +ModuleDialog_duplicateReads_error=Duplicate reads ''{0}'' +ModuleDialog_missingPatch_error=Must specify the module to be patched +ModuleDialog_wrongPatch_error=Module {0} is not provided by this build path entry +ModuleDialog_mustIncludeModule_error=Must include at least one module ModuleAddExportsBlock_packageEmpty_error=Package is empty ModuleAddExportsBlock_sourceModuleEmpty_error=Source module is empty @@ -503,13 +529,19 @@ ModuleAddExportsBlock_wrongPackage_error=Package {0} is not provided by module { ModuleAddExportsBlock_wrongSourceModule_error=Module {0} is not provided by this build path entry # ------- ModuleAddExportsDialog --------- -AddExportsDialog_notPersisted_warning=Build path entry has not yet been persisted; content assist is not available. +AddModuleDetailsDialog_notPersisted_warning=Build path entry has not yet been persisted; content assist is not available. AddExportsDialog_title=Add-exports configuration AddExportsBlock_message=Enter the details of the export to add AddExportsBlock_sourceModule_label=Source module AddExportsBlock_package_label=Package AddExportsBlock_targetModules_label=Target module +# ------- ModuleAddReadsDialog --------- +AddReadsDialog_title=Add-reads configuration +AddReadsBlock_message=Enter the details of the reads edge to add +AddReadsBlock_sourceModule_label=Source module +AddReadsBlock_targetModule_label=Target module + # ------- EditVariableEntryDialog ------- EditVariableEntryDialog_title=Edit Variable Entry @@ -746,10 +778,15 @@ CPListLabelProvider_module_yes=Yes CPListLabelProvider_module_no=No CPListLabelProvider_modular_modifiesEncapsulation_label=Is modular (modifies encapsulation) CPListLabelProvider_modular_label=Is modular +CPListLabelProvider_modular_limitsAndModifies_label=Is modular (limits modules and modifies encapsulation) +CPListLabelProvider_modular_limitsModules_label=Is modular (limits modules) CPListLabelProvider_not_modular_label=Is not modular CPListLabelProvider_add_exports_name_label=add-exports +CPListLabelProvider_patch_module_full_label=Patch-module: {0} CPListLabelProvider_add_exports_full_label=Add-exports: {0} +CPListLabelProvider_add_reads_full_label=Add-reads: {0} +CPListLabelProvider_limitModules_full_label=Limit-modules: {0} CPListLabelProvider_ignore_optional_problems_label=Ignore optional compile problems: {0} CPListLabelProvider_ignore_optional_problems_yes=Yes diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java index e2cc6b1839..5cd1228be1 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java @@ -75,10 +75,10 @@ public abstract class BuildPathBasePage { return false; } - protected boolean showAddExportDialog(Shell shell, CPListElementAttribute elem) { + protected boolean showModuleDialog(Shell shell, CPListElementAttribute elem) { CPListElement selElement= elem.getParent(); // the element targeted by the CP entry will be the source module from which packages are exported: - IJavaElement[] selectedJavaElements= ModuleAddExport.getTargetJavaElements(selElement.getJavaProject(), selElement.getPath()); + IJavaElement[] selectedJavaElements= ModuleEncapsulationDetail.getTargetJavaElements(selElement.getJavaProject(), selElement.getPath()); if (selectedJavaElements == null) { MessageDialog dialog= new MessageDialog(shell, NewWizardMessages.BuildPathBasePage_notAddedQuestion_title, null, Messages.format(NewWizardMessages.BuildPathBasePage_notAddedQuestion_description, selElement.getPath().toString()), @@ -110,8 +110,8 @@ public abstract class BuildPathBasePage { ModuleDialog dialog= new ModuleDialog(shell, selElement, selectedJavaElements); int res= dialog.open(); if (res == Window.OK) { - ModuleAddExport[] newExports= dialog.getAddExports(); - elem.setValue(newExports); + ModuleEncapsulationDetail[] newDetails= dialog.getAllDetails(); + elem.setValue(newDetails); return true; } return false; @@ -133,7 +133,7 @@ public abstract class BuildPathBasePage { } }; PlatformUI.getWorkbench().getProgressService().run(true, true, new WorkbenchRunnableAdapter(runnable)); - selectedJavaElements= ModuleAddExport.getTargetJavaElements(element.getJavaProject(), element.getPath()); + selectedJavaElements= ModuleEncapsulationDetail.getTargetJavaElements(element.getJavaProject(), element.getPath()); return selectedJavaElements; } @@ -149,22 +149,22 @@ public abstract class BuildPathBasePage { return false; } - protected void removeAddExport(ModuleAddExport export) { - CPListElementAttribute parent= export.getParent(); + protected void removeEncapsulationDetail(ModuleEncapsulationDetail detail) { + CPListElementAttribute parent= detail.getParent(); if (parent != null) { Object value= parent.getValue(); - if (value instanceof ModuleAddExport[]) { - ModuleAddExport[] existingExports= (ModuleAddExport[]) value; + if (value instanceof ModuleEncapsulationDetail[]) { + ModuleEncapsulationDetail[] existingDetails= (ModuleEncapsulationDetail[]) value; int count= 0; - for (int j= 0; j < existingExports.length; j++) { - ModuleAddExport anExport= existingExports[j]; - if (anExport != export) - existingExports[count++]= anExport; + for (int j= 0; j < existingDetails.length; j++) { + ModuleEncapsulationDetail aDetail= existingDetails[j]; + if (aDetail != detail) + existingDetails[count++]= aDetail; } - if (count < existingExports.length) { - ModuleAddExport[] newExports= new ModuleAddExport[count]; - System.arraycopy(existingExports, 0, newExports, 0, count); - parent.setValue(newExports); + if (count < existingDetails.length) { + ModuleEncapsulationDetail[] newDetails= new ModuleEncapsulationDetail[count]; + System.arraycopy(existingDetails, 0, newDetails, 0, count); + parent.setValue(newDetails); parent.getParent().attributeChanged(CPListElement.MODULE); } } @@ -292,7 +292,7 @@ public abstract class BuildPathBasePage { } else if (element instanceof CPListElementAttribute) { CPListElementAttribute attribute= (CPListElementAttribute) element; if (CPListElement.MODULE.equals(attribute.getKey())) { - return (ModuleAddExport[]) attribute.getValue(); + return (ModuleEncapsulationDetail[]) attribute.getValue(); } } return EMPTY_ARR; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java index 2ffe715d98..64123e36d5 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java @@ -18,8 +18,10 @@ package org.eclipse.jdt.internal.ui.wizards.buildpaths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.stream.Stream; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; @@ -42,7 +44,12 @@ import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; + import org.eclipse.jdt.internal.corext.util.JavaModelUtil; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.LimitModules; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddReads; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModulePatch; import org.eclipse.jdt.launching.JavaRuntime; @@ -138,7 +145,7 @@ public class CPListElement { createAttributeElement(SOURCEATTACHMENT, null, true); createAttributeElement(JAVADOC, null, false); createAttributeElement(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH, null, false); - createAttributeElement(MODULE, (module != null ? new ModuleAddExport[0] : null), true); + createAttributeElement(MODULE, (module != null ? new ModuleEncapsulationDetail[0] : null), true); createAttributeElement(SOURCE_ATTACHMENT_ENCODING, null, false); createAttributeElement(NATIVE_LIB_PATH, null, false); createAttributeElement(ACCESSRULES, new IAccessRule[0], true); @@ -163,7 +170,7 @@ public class CPListElement { int beforeModules= fChildren.size(); boolean modulesAdded= addModuleNodes(entry, entries[0]); if (modulesAdded) { - fChildren.add(beforeModules, new CPListElementAttribute(this, MODULE, new ModuleAddExport[0], true)); + fChildren.add(beforeModules, new CPListElementAttribute(this, MODULE, new ModuleEncapsulationDetail[0], true)); return; } } @@ -208,6 +215,14 @@ public class CPListElement { return modulesAdded; } + private boolean hasLimitModules(IClasspathEntry entry) { + for (IClasspathAttribute attribute : entry.getExtraAttributes()) { + if (IClasspathAttribute.LIMIT_MODULES.equals(attribute.getName())) + return true; + } + return false; + } + public IClasspathEntry getClasspathEntry() { if (fCachedEntry == null) { fCachedEntry= newClasspathEntry(); @@ -226,12 +241,26 @@ public class CPListElement { if (elem.getValue() != null) { res.add(elem.getClasspathAttribute()); } - } else if (elem.getValue() instanceof ModuleAddExport[]) { + } else if (elem.getValue() instanceof ModuleEncapsulationDetail[]) { res.add(JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true")); //$NON-NLS-1$ - String encodedExports= ModuleAddExport.encode((ModuleAddExport[]) elem.getValue()); + + ModuleEncapsulationDetail[] detailValue= (ModuleEncapsulationDetail[]) elem.getValue(); + String encodedPatch= ModuleEncapsulationDetail.encodeFiltered(detailValue, ModulePatch.class); + if (!encodedPatch.isEmpty()) { + res.add(JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, encodedPatch)); + } + String encodedExports= ModuleEncapsulationDetail.encodeFiltered(detailValue, ModuleAddExport.class); if (!encodedExports.isEmpty()) { res.add(JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, encodedExports)); } + String encodedReads= ModuleEncapsulationDetail.encodeFiltered(detailValue, ModuleAddReads.class); + if (!encodedReads.isEmpty()) { + res.add(JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_READS, encodedReads)); + } + String encodedLimits= ModuleEncapsulationDetail.encodeFiltered(detailValue, LimitModules.class); + if (!encodedLimits.isEmpty()) { + res.add(JavaCore.newClasspathAttribute(IClasspathAttribute.LIMIT_MODULES, encodedLimits)); + } } } } @@ -411,6 +440,20 @@ public class CPListElement { return res.toArray(new CPListElementAttribute[res.size()]); } + public <T extends ModuleEncapsulationDetail> List<T> getModuleEncapsulationDetails(Class<T> clazz) { + Object moduleDetails= getAttribute(CPListElement.MODULE); + if (moduleDetails instanceof ModuleEncapsulationDetail[]) { + ModuleEncapsulationDetail[] details= (ModuleEncapsulationDetail[]) moduleDetails; + List<T> elements= new ArrayList<>(details.length); + for (int i= 0; i < details.length; i++) { + if (clazz.isInstance(details[i])) + elements.add(clazz.cast(details[i])); + } + return elements; + } else { + return Collections.emptyList(); + } + } private void createAttributeElement(String key, Object value, boolean builtIn) { fChildren.add(new CPListElementAttribute(this, key, value, builtIn)); @@ -722,21 +765,27 @@ public class CPListElement { IClasspathAttribute attrib= extraAttributes[i]; CPListElementAttribute attribElem= elem.findAttributeElement(attrib.getName()); if (attribElem == null) { - if (!IClasspathAttribute.ADD_EXPORTS.equals(attrib.getName()) && !IClasspathAttribute.MODULE.equals(attrib.getName())) { + if (!isModuleAttribute(attrib.getName())) { elem.createAttributeElement(attrib.getName(), attrib.getValue(), false); } } else { Object value= attrib.getValue(); if (attrib.getName().equals(MODULE)) { if (ModuleAttributeConfiguration.TRUE.equals(attrib.getValue())) { - List<ModuleAddExport> exports = new ArrayList<>(); + List<ModuleEncapsulationDetail> details= new ArrayList<>(); for (int j= 0; j < extraAttributes.length; j++) { IClasspathAttribute otherAttrib= extraAttributes[j]; - if (IClasspathAttribute.ADD_EXPORTS.equals(otherAttrib.getName())) { - exports.addAll(ModuleAddExport.fromMultiString(attribElem, otherAttrib.getValue())); + if (IClasspathAttribute.PATCH_MODULE.equals(otherAttrib.getName())) { + details.add(ModulePatch.fromString(attribElem, otherAttrib.getValue())); + } else if (IClasspathAttribute.ADD_EXPORTS.equals(otherAttrib.getName())) { + details.addAll(ModuleAddExport.fromMultiString(attribElem, otherAttrib.getValue())); + } else if (IClasspathAttribute.ADD_READS.equals(otherAttrib.getName())) { + details.addAll(ModuleAddReads.fromMultiString(attribElem, otherAttrib.getValue())); + } else if (IClasspathAttribute.LIMIT_MODULES.equals(otherAttrib.getName())) { + details.add(LimitModules.fromString(attribElem, otherAttrib.getValue())); } } - value= exports.toArray(new ModuleAddExport[exports.size()]); + value= details.toArray(new ModuleEncapsulationDetail[details.size()]); } else { value= null; } @@ -749,6 +798,12 @@ public class CPListElement { return elem; } + private static boolean isModuleAttribute(String attributeName) { + return Stream.of(IClasspathAttribute.MODULE, IClasspathAttribute.LIMIT_MODULES, + IClasspathAttribute.PATCH_MODULE, IClasspathAttribute.ADD_EXPORTS, IClasspathAttribute.ADD_READS) + .anyMatch(attributeName::equals); + } + public static StringBuffer appendEncodePath(IPath path, StringBuffer buf) { if (path != null) { String str= path.toString(); @@ -819,10 +874,18 @@ public class CPListElement { buf.append(((Boolean) elem.getValue()).booleanValue()).append(';'); } else if (MODULE.equals(key)) { Object value= elem.getValue(); - if (value instanceof ModuleAddExport[]) { + if (value instanceof ModuleEncapsulationDetail[]) { buf.append(MODULE+"=true;"); //$NON-NLS-1$ - for (ModuleAddExport export : ((ModuleAddExport[]) value)) - buf.append(IClasspathAttribute.ADD_EXPORTS+':'+export.toString()).append(';'); + for (ModuleEncapsulationDetail detail : ((ModuleEncapsulationDetail[]) value)) { + if (detail instanceof ModulePatch) + buf.append(IClasspathAttribute.PATCH_MODULE+':'+detail.toString()).append(';'); + if (detail instanceof ModuleAddExport) + buf.append(IClasspathAttribute.ADD_EXPORTS+':'+detail.toString()).append(';'); + if (detail instanceof ModuleAddReads) + buf.append(IClasspathAttribute.ADD_READS+':'+detail.toString()).append(';'); + if (detail instanceof LimitModules) + buf.append(IClasspathAttribute.LIMIT_MODULES+':'+detail.toString()).append(';'); + } } else { buf.append(MODULE+"=false;"); //$NON-NLS-1$ } @@ -966,9 +1029,9 @@ public class CPListElement { } CPListElementAttribute moduleAttribute= findAttributeElement(MODULE); if (moduleAttribute == null) { - createAttributeElement(MODULE, new ModuleAddExport[0], false); + createAttributeElement(MODULE, new ModuleEncapsulationDetail[0], true); } else { - moduleAttribute.setValue(new ModuleAddExport[0]); + moduleAttribute.setValue(new ModuleEncapsulationDetail[0]); } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListLabelProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListLabelProvider.java index f7f9258030..60ef841688 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListLabelProvider.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListLabelProvider.java @@ -53,6 +53,10 @@ import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; 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.ModuleEncapsulationDetail.LimitModules; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModulePatch; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddReads; public class CPListLabelProvider extends LabelProvider { @@ -100,8 +104,14 @@ public class CPListLabelProvider extends LabelProvider { } else if (element instanceof IAccessRule) { IAccessRule rule= (IAccessRule) element; return Messages.format(NewWizardMessages.CPListLabelProvider_access_rules_label, new String[] { AccessRulesLabelProvider.getResolutionLabel(rule.getKind()), BasicElementLabels.getPathLabel(rule.getPattern(), false)}); + } else if (element instanceof ModulePatch) { + return Messages.format(NewWizardMessages.CPListLabelProvider_patch_module_full_label, new String[] { element.toString() }); } else if (element instanceof ModuleAddExport) { return Messages.format(NewWizardMessages.CPListLabelProvider_add_exports_full_label, new String[] { element.toString() }); + } else if (element instanceof ModuleAddReads) { + return Messages.format(NewWizardMessages.CPListLabelProvider_add_reads_full_label, new String[] { element.toString() }); + } else if (element instanceof LimitModules) { + return Messages.format(NewWizardMessages.CPListLabelProvider_limitModules_full_label, new String[] { element.toString() }); } return super.getText(element); } @@ -240,12 +250,24 @@ public class CPListLabelProvider extends LabelProvider { return Messages.format(NewWizardMessages.CPListLabelProvider_ignore_optional_problems_label, arg); } else if (key.equals(CPListElement.MODULE)) { Object value= attrib.getValue(); - if (value instanceof ModuleAddExport[]) { - int nExports= ((ModuleAddExport[]) value).length; - if (nExports > 0) + if (value instanceof ModuleEncapsulationDetail[]) { + boolean limitModules= false; + boolean modifiesEncaps= false; + for (ModuleEncapsulationDetail detail : (ModuleEncapsulationDetail[]) value) { + if (detail instanceof LimitModules) { + limitModules= true; + } else { + modifiesEncaps= true; + } + } + if (modifiesEncaps) { + if (limitModules) + return NewWizardMessages.CPListLabelProvider_modular_limitsAndModifies_label; return NewWizardMessages.CPListLabelProvider_modular_modifiesEncapsulation_label; - else - return NewWizardMessages.CPListLabelProvider_modular_label; + } else if (limitModules) { + return NewWizardMessages.CPListLabelProvider_modular_limitsModules_label; + } + return NewWizardMessages.CPListLabelProvider_modular_label; } else { return NewWizardMessages.CPListLabelProvider_not_modular_label; } @@ -478,8 +500,14 @@ public class CPListLabelProvider extends LabelProvider { } else if (element instanceof IAccessRule) { IAccessRule rule= (IAccessRule) element; return AccessRulesLabelProvider.getResolutionImage(rule.getKind()); + } else if (element instanceof ModulePatch) { + return fRegistry.get(JavaPluginImages.DESC_OBJS_MODULE_ATTRIB); } else if (element instanceof ModuleAddExport) { - return fSharedImages.getImage(ISharedImages.IMG_OBJS_ADD_EXPORTS); + return fRegistry.get(JavaPluginImages.DESC_OBJS_MODULE_ATTRIB); + } else if (element instanceof ModuleAddReads) { + return fRegistry.get(JavaPluginImages.DESC_OBJS_MODULE_ATTRIB); + } else if (element instanceof LimitModules) { + return fRegistry.get(JavaPluginImages.DESC_OBJS_MODULE_ATTRIB); } return null; } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/LibrariesWorkbookPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/LibrariesWorkbookPage.java index 4c4a287f8a..4f8b52d7e6 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/LibrariesWorkbookPage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/LibrariesWorkbookPage.java @@ -182,7 +182,6 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { for (int i= 0; i < nElements; i++) { CPListElement cpe= cpelements.get(i); if (isEntryKind(cpe.getEntryKind())) { - boolean isModular = false; Object mod = cpe.getAttribute(CPListElement.MODULE); if(mod==null) { rootClasspath.addCPListElement(cpe); @@ -366,8 +365,7 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { for (CPListElement cpListElement : elementsToAdd) { Object attribute= cpListElement.getAttribute(IClasspathAttribute.MODULE); if(attribute == null) { - cpListElement.setAttribute(IClasspathAttribute.MODULE, new ModuleAddExport[0]); - + cpListElement.setAttribute(IClasspathAttribute.MODULE, new ModuleEncapsulationDetail[0]); } } } @@ -500,8 +498,8 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { } changedAttributes.add(key); // collect the changed attributes } - } else if (elem instanceof ModuleAddExport) { - removeAddExport((ModuleAddExport) elem); + } else if (elem instanceof ModuleEncapsulationDetail) { + removeEncapsulationDetail((ModuleEncapsulationDetail) elem); } } if (selElements.isEmpty()) { @@ -571,7 +569,7 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { if (curr.getParentContainer() != null) { return false; } - } else if (elem instanceof ModuleAddExport) { + } else if (elem instanceof ModuleEncapsulationDetail) { return true; } else { // unknown element return false; @@ -643,7 +641,7 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { } } } else if (key.equals(CPListElement.MODULE)) { - if (showAddExportDialog(getShell(), elem)) { + if (showModuleDialog(getShell(), elem)) { String[] changedAttributes= { CPListElement.MODULE }; attributeUpdated(selElement, changedAttributes); @@ -835,13 +833,13 @@ public class LibrariesWorkbookPage extends BuildPathBasePage { private void updateClasspathList() { List<CPListElement> projelements= fLibrariesList.getElements(); - List<CPListElement> flattenedProjElements = new ArrayList<CPListElement>(); + 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= ele.getChildren(); - for (Iterator iterator= children.iterator(); iterator.hasNext();) { + for (Iterator<?> iterator= children.iterator(); iterator.hasNext();) { Object object= iterator.next(); if(object instanceof CPListElement) { flattenedProjElements.add((CPListElement) object); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExport.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExport.java deleted file mode 100644 index fb56f87816..0000000000 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExport.java +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 GK Software AG, 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 - * - * This is an implementation of an early-draft specification developed under the Java - * Community Process (JCP) and is made available for testing and evaluation purposes - * only. The code is not compatible with any specification of the JCP. - * - * Contributors: - * Stephan Herrmann - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.ui.wizards.buildpaths; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.eclipse.core.runtime.IPath; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; - -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaElement; -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.ui.JavaPlugin; - -/** - * Node in the tree of CPListElement et al, representing an add-exports module directive. - */ -public class ModuleAddExport { - - public static ModuleAddExport fromString(CPListElementAttribute attribElem, String value) { - int slash = value.indexOf('/'); - int equals = value.indexOf('='); - if (slash != -1 && equals != -1 && equals > slash) { - return new ModuleAddExport(value.substring(0, slash), - value.substring(slash+1, equals), - value.substring(equals+1), - attribElem); - } - return null; - } - - public static Collection<ModuleAddExport> fromMultiString(CPListElementAttribute attribElem, String values) { - List<ModuleAddExport> exports= new ArrayList<>(); - for (String value : values.split(":")) { //$NON-NLS-1$ - ModuleAddExport export= fromString(attribElem, value); - if (export != null) - exports.add(export); - } - return exports; - } - - public static String encode(ModuleAddExport[] exports) { - StringBuilder buf= new StringBuilder(); - for (ModuleAddExport export : exports) { - if (buf.length() > 0) - buf.append(':'); - buf.append(export.toString()); - } - return buf.toString(); - } - - public final String fSourceModule; - public final String fPackage; - public final String fTargetModules; - - private CPListElementAttribute fAttribElem; - - public ModuleAddExport(String sourceModule, String aPackage, String targetModules, CPListElementAttribute attribElem) { - fSourceModule= sourceModule; - fPackage= aPackage; - fTargetModules= targetModules; - fAttribElem= attribElem; - } - - @Override - public String toString() { - return fSourceModule+'/'+fPackage+'='+fTargetModules; - } - - public CPListElementAttribute getParent() { - return fAttribElem; - } - - /** - * Retrieve the java element(s) targeted by a given classpath entry. - * @param currentProject the Java project holding the classpath entry - * @param path the path value of the classpath entry - * @return either an array of {@link IPackageFragmentRoot} or a singleton array of {@link IJavaProject} - * targeted by the given classpath entry, or {@code null} if no not found - */ - public static IJavaElement[] getTargetJavaElements(IJavaProject currentProject, IPath path) { - IResource member= ResourcesPlugin.getWorkspace().getRoot().findMember(path); - if (member != null) { - IJavaElement element= JavaCore.create(member); - if (element != null) - return new IJavaElement[] {element}; - } else if (path != null && path.isAbsolute()) { - try { - for (IClasspathEntry classpathEntry : currentProject.getRawClasspath()) { - if (classpathEntry.getPath().equals(path)) { - switch (classpathEntry.getEntryKind()) { - case IClasspathEntry.CPE_LIBRARY: - return new IJavaElement[] {currentProject.getPackageFragmentRoot(path.toString())}; - default: - // keep looking - } - } - } - } catch (JavaModelException e) { - JavaPlugin.log(e); - } - } else { - try { - for (IClasspathEntry classpathEntry : currentProject.getRawClasspath()) { - if (classpathEntry.getPath().equals(path)) { - return currentProject.findPackageFragmentRoots(classpathEntry); - } - } - } catch (JavaModelException e) { - JavaPlugin.log(e); - } - } - return null; - } -} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsAttributeConfiguration.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsAttributeConfiguration.java deleted file mode 100644 index dcf52b7d59..0000000000 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsAttributeConfiguration.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017 GK Software AG, 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 - * - * This is an implementation of an early-draft specification developed under the Java - * Community Process (JCP) and is made available for testing and evaluation purposes - * only. The code is not compatible with any specification of the JCP. - * - * Contributors: - * Stephan Herrmann - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.ui.wizards.buildpaths; - -import org.eclipse.swt.widgets.Shell; - -import org.eclipse.core.runtime.IPath; - -import org.eclipse.jface.resource.ImageDescriptor; - -import org.eclipse.jdt.core.IClasspathAttribute; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.JavaCore; - -import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess; -import org.eclipse.jdt.ui.wizards.ClasspathAttributeConfiguration; - -import org.eclipse.jdt.internal.ui.JavaPluginImages; -import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; - -public class ModuleAddExportsAttributeConfiguration extends ClasspathAttributeConfiguration { - - public ModuleAddExportsAttributeConfiguration() { - } - - @Override - public ImageDescriptor getImageDescriptor(ClasspathAttributeAccess attribute) { - return JavaPluginImages.DESC_OBJS_ADD_EXPORTS_ATTRIB; - } - - @Override - public String getNameLabel(ClasspathAttributeAccess attribute) { - return NewWizardMessages.CPListLabelProvider_add_exports_full_label; - } - - @Override - public String getValueLabel(ClasspathAttributeAccess access) { - return access.getClasspathAttribute().getValue(); - } - - @Override - public boolean canEdit(ClasspathAttributeAccess attribute) { - return true; - } - - @Override - public boolean canRemove(ClasspathAttributeAccess attribute) { - return attribute.getClasspathAttribute().getValue() != null; - } - - @Override - public IClasspathAttribute performEdit(Shell shell, ClasspathAttributeAccess attribute) { - String initialValue= attribute.getClasspathAttribute().getValue(); - IPath entryPath= attribute.getParentClasspassEntry().getPath(); - IJavaElement[] sourceElements= ModuleAddExport.getTargetJavaElements(attribute.getJavaProject(), entryPath); - String newValue= BuildPathDialogAccess.configureAddExports(shell, sourceElements, initialValue); - if(null == newValue) // Was the dialog cancelled? - return null; - return JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_READS, newValue); - } - - @Override - public IClasspathAttribute performRemove(ClasspathAttributeAccess attribute) { - return JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_READS, null); - } -} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsBlock.java index e92cf7fff7..46d0a0dbab 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsBlock.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsBlock.java @@ -24,7 +24,6 @@ import java.util.function.Predicate; import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory; import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; @@ -52,13 +51,12 @@ import org.eclipse.jdt.internal.corext.util.Messages; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; -import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper; import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaPackageCompletionProcessor; -import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaPrecomputedNamesAssistProcessor; import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport; 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.LayoutUtil; @@ -242,7 +240,9 @@ public class ModuleAddExportsBlock { LayoutUtil.setWidthHint(sourceModuleField, widthHint); LayoutUtil.setHorizontalGrabbing(sourceModuleField); BidiUtils.applyBidiProcessing(sourceModuleField, StructuredTextTypeHandlerFactory.JAVA); - configureModuleContentAssist(fSourceModule.getTextControl(composite)); + if (fSourceJavaElements != null) { + ModuleDialog.configureModuleContentAssist(fSourceModule.getTextControl(composite), moduleNames()); + } DialogField.createEmptySpace(composite, 2); @@ -270,18 +270,6 @@ public class ModuleAddExportsBlock { return composite; } - private void configureModuleContentAssist(Text textControl) { - if (fSourceJavaElements == null || fSourceJavaElements.length <= 1) { - return; - } - Set<String> moduleNames= moduleNames(); - if (!moduleNames.isEmpty()) { - Image image= JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_OBJS_MODULE); - JavaPrecomputedNamesAssistProcessor processor= new JavaPrecomputedNamesAssistProcessor(moduleNames, image); - ControlContentAssistHelper.createTextContentAssistant(textControl, processor); - } - } - private void configurePackageContentAssist(Text textControl) { if (fSourceJavaElements == null || fSourceJavaElements.length == 0) { return; @@ -421,7 +409,7 @@ public class ModuleAddExportsBlock { } if (status == null) { if (getPackageText().isEmpty()) { // not yet validated but empty? - status= ModuleAddExportsDialog.newSilentError(); + status= ModuleDialog.newSilentError(); } else { status= Status.OK_STATUS; } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsDialog.java index 93d63b98af..7683c81af4 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsDialog.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddExportsDialog.java @@ -23,7 +23,6 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.StatusDialog; -import org.eclipse.jface.util.Util; import org.eclipse.ui.PlatformUI; @@ -33,6 +32,7 @@ import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport; /** * A dialog to configure add-exports of a library. @@ -64,7 +64,7 @@ public class ModuleAddExportsDialog extends StatusDialog { setTitle(NewWizardMessages.AddExportsDialog_title); if (sourceJavaElements == null) updateStatus(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), - NewWizardMessages.AddExportsDialog_notPersisted_warning)); + NewWizardMessages.AddModuleDetailsDialog_notPersisted_warning)); } /* @@ -84,13 +84,9 @@ public class ModuleAddExportsDialog extends StatusDialog { @Override public void create() { super.create(); - updateButtonsEnableState(newSilentError()); // silently disable OK button until user input is given + updateButtonsEnableState(ModuleDialog.newSilentError()); // silently disable OK button until user input is given } - public static Status newSilentError() { - return new Status(IStatus.ERROR, JavaPlugin.getPluginId(), Util.ZERO_LENGTH_STRING); - } - @Override protected Control createDialogArea(Composite parent) { Composite composite= (Composite) super.createDialogArea(parent); diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsBlock.java new file mode 100644 index 0000000000..1378134427 --- /dev/null +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsBlock.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2017 GK Software AG, 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 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * Contributors: + * Stephan Herrmann - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.wizards.buildpaths; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.layout.PixelConverter; +import org.eclipse.jface.util.BidiUtils; + +import org.eclipse.ui.PlatformUI; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IModuleDescription; +import org.eclipse.jdt.core.IPackageFragmentRoot; + +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; +import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; +import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddReads; +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.LayoutUtil; +import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField; + + +/** + * UI to define one additional exports (add-reads). + */ +public class ModuleAddReadsBlock { + + private final IStatusChangeListener fContext; + + private StringDialogField fSourceModule; + private StringDialogField fTargetModule; + + private IStatus fSourceModuleStatus; + + private Control fSWTWidget; + + private final ModuleAddReads fInitialValue; + + private IJavaElement[] fSourceJavaElements; + + /** + * @param context listeners for status updates + * @param sourceJavaElements java element representing the source modules from where packages should be exported + * @param initialValue The value to edit + */ + public ModuleAddReadsBlock(IStatusChangeListener context, IJavaElement[] sourceJavaElements, ModuleAddReads initialValue) { + fContext= context; + fInitialValue= initialValue; + fSourceJavaElements= sourceJavaElements; + + fSourceModuleStatus= new StatusInfo(); + + IDialogFieldListener adapter= field -> addExportsDialogFieldChanged(field); + + // create the dialog fields (no widgets yet) + fSourceModule= new StringDialogField(); + fSourceModule.setDialogFieldListener(adapter); + fSourceModule.setLabelText(NewWizardMessages.AddReadsBlock_sourceModule_label); + + fTargetModule= new StringDialogField(); + fTargetModule.setDialogFieldListener(adapter); + fTargetModule.setLabelText(NewWizardMessages.AddReadsBlock_targetModule_label); + + setDefaults(); + } + + private void setDefaults() { + if (fInitialValue != null) { + fSourceModule.setText(fInitialValue.fSourceModule); + if (!fInitialValue.fSourceModule.isEmpty() && (fSourceJavaElements == null || fSourceJavaElements.length <= 1)) { + fSourceModule.setEnabled(false); + } + fTargetModule.setText(fInitialValue.fTargetModule); + fTargetModule.setEnabled(true); + } + } + + private Set<String> moduleNames() { + Set<String> moduleNames= new HashSet<>(); + if (fSourceJavaElements != null) { + for (int i= 0; i < fSourceJavaElements.length; i++) { + if (fSourceJavaElements[i] instanceof IPackageFragmentRoot) { + IModuleDescription module= ((IPackageFragmentRoot) fSourceJavaElements[i]).getModuleDescription(); + if (module != null) { + moduleNames.add(module.getElementName()); + } + } + } + } + return moduleNames; + } + + private String getSourceModuleText() { + return fSourceModule.getText().trim(); + } + + private String getTargetModulesText() { + return fTargetModule.getText().trim(); + } + + /** + * Gets the add-reads value entered by the user + * @return the add-reads value, or an empty string if any of the fields was left empty. + */ + public String getValue() { + String sourceModule= getSourceModuleText(); + String targetModules= getTargetModulesText(); + if (sourceModule.isEmpty() || targetModules.isEmpty()) + return ""; //$NON-NLS-1$ + return sourceModule+'='+targetModules; + } + + public ModuleAddReads getReads(CPListElementAttribute parentAttribute) { + String sourceModule= getSourceModuleText(); + String targetModules= getTargetModulesText(); + if (sourceModule.isEmpty() || targetModules.isEmpty()) + return null; + return new ModuleAddReads(sourceModule, targetModules, parentAttribute); + } + + /** + * Creates the control + * @param parent the parent + * @return the created control + */ + public Control createControl(Composite parent) { + PixelConverter converter= new PixelConverter(parent); + + fSWTWidget= parent; + + Composite composite= new Composite(parent, SWT.NONE); + + GridLayout layout= new GridLayout(); + layout.marginHeight= 0; + layout.marginWidth= 0; + layout.numColumns= 2; + composite.setLayout(layout); + + + int widthHint= converter.convertWidthInCharsToPixels(60); + + GridData gd= new GridData(GridData.FILL, GridData.BEGINNING, false, false, 2, 1); + gd.widthHint= converter.convertWidthInCharsToPixels(50); + + Label message= new Label(composite, SWT.LEFT + SWT.WRAP); + message.setLayoutData(gd); + message.setText(NewWizardMessages.AddReadsBlock_message); + + DialogField.createEmptySpace(composite, 2); + + fSourceModule.doFillIntoGrid(composite, 2); + Text sourceModuleField= fSourceModule.getTextControl(null); + LayoutUtil.setWidthHint(sourceModuleField, widthHint); + LayoutUtil.setHorizontalGrabbing(sourceModuleField); + BidiUtils.applyBidiProcessing(sourceModuleField, StructuredTextTypeHandlerFactory.JAVA); + if (fSourceJavaElements != null) { + ModuleDialog.configureModuleContentAssist(fSourceModule.getTextControl(composite), moduleNames()); + } + + DialogField.createEmptySpace(composite, 2); + + fTargetModule.doFillIntoGrid(composite, 2); + Text targetModulesField= fTargetModule.getTextControl(null); + LayoutUtil.setWidthHint(targetModulesField, widthHint); + LayoutUtil.setHorizontalGrabbing(targetModulesField); + BidiUtils.applyBidiProcessing(targetModulesField, StructuredTextTypeHandlerFactory.JAVA); + // TODO: content assist from all known modules? + + DialogField.createEmptySpace(composite, 2); + + Dialog.applyDialogFont(composite); + + PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, IJavaHelpContextIds.EXTERNAL_ANNOTATIONS_ATTACHMENT_DIALOG); // FIXME + return composite; + } + + // ---------- IDialogFieldListener -------- + + private void addExportsDialogFieldChanged(DialogField field) { + if (fSWTWidget != null) { + if (field == fSourceModule && fSourceModule.isEnabled()) { + updateModuleStatus(); + } + doStatusLineUpdate(); + } + } + + private void updateModuleStatus() { + fSourceModuleStatus= computeSourceModuleStatus(getSourceModuleText()); + } + + private IStatus computeSourceModuleStatus(String value) { + StatusInfo status= new StatusInfo(); + if (value.isEmpty()) { + status.setError(NewWizardMessages.ModuleAddExportsBlock_sourceModuleEmpty_error); + return status; + } + if (moduleNames().contains(value)) { + return status; + } + status.setError(Messages.format(NewWizardMessages.ModuleAddExportsBlock_wrongSourceModule_error, value)); + return status; + } + + private void doStatusLineUpdate() { + IStatus status= null; + if (!fSourceModuleStatus.isOK()) { + status= fSourceModuleStatus; // priority + } + // target module is not (yet) validated + if (status == null) { + status= Status.OK_STATUS; + } + fContext.statusChanged(status); + } +} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsDialog.java new file mode 100644 index 0000000000..94239b1bd9 --- /dev/null +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleAddReadsDialog.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2017 GK Software AG, 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 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * Contributors: + * Stephan Herrmann - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.wizards.buildpaths; + +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; + +import org.eclipse.jface.dialogs.StatusDialog; + +import org.eclipse.ui.PlatformUI; + +import org.eclipse.jdt.core.IJavaElement; + +import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; +import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddReads; + +/** + * A dialog to configure add-reads of a library. + * + */ +public class ModuleAddReadsDialog extends StatusDialog { + + private ModuleAddReadsBlock fAddReadsBlock; + + /** + * Creates an instance. After <code>open</code>, the edited export can be accessed using {@code #getResult()} + * or {@code #getReads()}. + * + * @param parent Parent shell for the dialog + * @param sourceJavaElements java elements representing the source modules for which more reads should be added + * @param value The value to edit. + */ + public ModuleAddReadsDialog(Shell parent, IJavaElement[] sourceJavaElements, ModuleAddReads value) { + super(parent); + + IStatusChangeListener listener= new IStatusChangeListener() { + @Override + public void statusChanged(IStatus status) { + updateStatus(status); + } + }; + fAddReadsBlock= new ModuleAddReadsBlock(listener, sourceJavaElements, value); + + setTitle(NewWizardMessages.AddReadsDialog_title); + if (sourceJavaElements == null) + updateStatus(new Status(IStatus.WARNING, JavaPlugin.getPluginId(), + NewWizardMessages.AddModuleDetailsDialog_notPersisted_warning)); + } + + /* + * @see org.eclipse.jface.dialogs.Dialog#isResizable() + */ + @Override + protected boolean isResizable() { + return true; + } + + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.EXTERNAL_ANNOTATIONS_ATTACHMENT_DIALOG); // FIXME + } + + @Override + public void create() { + super.create(); + updateButtonsEnableState(ModuleDialog.newSilentError()); // silently disable OK button until user input is given + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite composite= (Composite) super.createDialogArea(parent); + + Control inner= createAddReadsControls(composite); + inner.setLayoutData(new GridData(GridData.FILL_BOTH)); + applyDialogFont(composite); + return composite; + } + + /** + * Creates the controls for the add-exports configuration. + * + * @param composite the parent composite + * @return the control + */ + protected Control createAddReadsControls(Composite composite) { + return fAddReadsBlock.createControl(composite); + } + + /** + * Returns the configured export value. + * + * @return the configured export value, or an empty string if no export was configured. + */ + public String getResult() { + return fAddReadsBlock.getValue(); + } + + /** + * Returns the configured export value. + * @param parentAttribute the "module" attribute to which this export is associated + * + * @return the configured export value, or {@code null} if no export was configured. + */ + public ModuleAddReads getReads(CPListElementAttribute parentAttribute) { + return fAddReadsBlock.getReads(parentAttribute); + } +} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleDialog.java index ae658097a8..3a7f53489f 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleDialog.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleDialog.java @@ -14,26 +14,49 @@ *******************************************************************************/ package org.eclipse.jdt.internal.ui.wizards.buildpaths; +import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter; + import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; +import org.eclipse.equinox.bidi.StructuredTextTypeHandlerFactory; + import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Widget; + +import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.StatusDialog; +import org.eclipse.jface.layout.PixelConverter; +import org.eclipse.jface.util.BidiUtils; +import org.eclipse.jface.util.Util; import org.eclipse.jface.viewers.ColumnLayoutData; import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.window.Window; import org.eclipse.ui.PlatformUI; @@ -46,6 +69,7 @@ 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.core.provisional.JavaModelAccess; import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; @@ -55,20 +79,60 @@ import org.eclipse.jdt.ui.JavaElementLabels; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.jdt.internal.ui.refactoring.contentassist.ControlContentAssistHelper; +import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaPrecomputedNamesAssistProcessor; import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.LimitModules; +import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleEncapsulationDetail.ModuleAddExport; +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.IListAdapter; 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.SelectionButtonDialogField; +import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringDialogField; public class ModuleDialog extends StatusDialog { private static final String NO_NAME= ""; //$NON-NLS-1$ - public class AddExportsLabelProvider extends LabelProvider implements ITableLabelProvider { + static class ListContentProvider implements IStructuredContentProvider { + List<?> fContents; + + @Override + public Object[] getElements(Object input) { + if (fContents != null && fContents == input) + return fContents.toArray(); + return new Object[0]; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + if (newInput instanceof List<?>) + fContents= (List<?>)newInput; + else + fContents= null; + } + } + + static class ModulesLabelProvider extends LabelProvider implements ITableLabelProvider { + + @Override + public Image getColumnImage(Object element, int columnIndex) { + return JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_OBJS_MODULE); + } + + @Override + public String getColumnText(Object element, int columnIndex) { + return element.toString(); + } + + } + + public class AddDetailsLabelProvider extends LabelProvider implements ITableLabelProvider { @Override public Image getColumnImage(Object element, int columnIndex) { @@ -78,7 +142,7 @@ public class ModuleDialog extends StatusDialog { @Override public String getColumnText(Object element, int columnIndex) { if (element instanceof ModuleAddExport) { - ModuleAddExport export = (ModuleAddExport) element; + ModuleAddExport export= (ModuleAddExport) element; switch (columnIndex) { case 0: return export.fSourceModule; case 1: return export.fPackage; @@ -86,6 +150,14 @@ public class ModuleDialog extends StatusDialog { default: throw new IllegalArgumentException("Illegal column index "+columnIndex); //$NON-NLS-1$ } + } else if (element instanceof ModuleAddReads) { + ModuleAddReads reads= (ModuleAddReads) element; + switch (columnIndex) { + case 0: return reads.fSourceModule; + case 1: return reads.fTargetModule; + default: + throw new IllegalArgumentException("Illegal column index "+columnIndex); //$NON-NLS-1$ + } } return NO_NAME; } @@ -93,10 +165,36 @@ public class ModuleDialog extends StatusDialog { } private final SelectionButtonDialogField fIsModuleCheckbox; + + static class ModuleList { + TableViewer fViewer; + List<String> fNames; + public ModuleList(List<String> names) { + fNames= names; + } + } + private ModuleList[] fModuleLists= new ModuleList[3]; + private static final int IDX_AVAILABLE= 0; + private static final int IDX_INCLUDED= 1; + private static final int IDX_IMPLICITLY_INCLUDED= 2; + + private Button fAddIncludedButton; + private Button fRemoveIncludedButton; + private Button fPromoteIncludedButton; + + private final SelectionButtonDialogField fIsPatchCheckbox; + private final StringDialogField fPatchedModule; + private final ListDialogField<ModuleAddExport> fAddExportsList; + + private final ListDialogField<ModuleAddReads> fAddReadsList; + private final CPListElement fCurrCPElement; /** The element(s) targeted by the current CP entry, which will be the source module(s) of the added exports. */ private IJavaElement[] fJavaElements; + private Set<String> fModuleNames; + + private Map<String,List<String>> fModule2RequiredModules; private static final int IDX_ADD= 0; private static final int IDX_EDIT= 1; @@ -107,139 +205,94 @@ public class ModuleDialog extends StatusDialog { super(parent); fCurrCPElement= entryToEdit; + fJavaElements= selectedElements; setTitle(NewWizardMessages.ModuleDialog_title); fIsModuleCheckbox= new SelectionButtonDialogField(SWT.CHECK); fIsModuleCheckbox.setLabelText(NewWizardMessages.ModuleDialog_defines_modules_label); fIsModuleCheckbox.setSelection(entryToEdit.getAttribute(CPListElement.MODULE) != null); - fIsModuleCheckbox.setDialogFieldListener(new AddExportsAdapter()); + fIsModuleCheckbox.setDialogFieldListener(field -> doSelectionChangedAllLists()); - if (fCurrCPElement.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { - IPackageFragmentRoot[] roots= findRoots(fCurrCPElement); - if (roots.length > 1 && roots[0].getModuleDescription() != null) - fIsModuleCheckbox.setEnabled(false); // assume multi-module container is Java 9 JRE - } + // -- contents page initialized in createContentsTab() - fAddExportsList= createListContents(entryToEdit); - doSelectionChanged(fAddExportsList); + // -- details page: - fJavaElements= selectedElements; - } + fIsPatchCheckbox= new SelectionButtonDialogField(SWT.CHECK); + fIsPatchCheckbox.setLabelText(NewWizardMessages.ModuleDialog_patches_module_label); + fIsPatchCheckbox.setDialogFieldListener(field -> doPatchSelectionChanged(field)); - private IPackageFragmentRoot[] findRoots(CPListElement element) { - IClasspathEntry entry= element.getClasspathEntry(); - IPackageFragmentRoot[] roots= element.getJavaProject().findPackageFragmentRoots(entry); - if (roots.length == 0) { - // 2nd attempt in case "module=true" is not explicit on the real cp entry: - entry = copyCPEntryWithoutModuleAttribute(entry); - if (entry != null) - roots= element.getJavaProject().findPackageFragmentRoots(entry); - } - return roots; - } + fPatchedModule= new StringDialogField(); + fPatchedModule.setLabelText(NewWizardMessages.ModuleDialog_patched_module_label); + fPatchedModule.setDialogFieldListener(field -> validateDetails(field)); - private IClasspathEntry copyCPEntryWithoutModuleAttribute(IClasspathEntry entry) { - IClasspathAttribute[] oldAttributes= entry.getExtraAttributes(); - IClasspathAttribute[] newAttributes= new IClasspathAttribute[oldAttributes.length]; - int count= 0; - for (int i= 0; i < oldAttributes.length; i++) { - if (!oldAttributes[i].getName().equals(IClasspathAttribute.MODULE)) - newAttributes[count++]= oldAttributes[i]; - } - if (count == oldAttributes.length) - return null; - newAttributes= count == 0 ? new IClasspathAttribute[0] : Arrays.copyOf(newAttributes, count); - return JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), newAttributes, entry.isExported()); + fAddExportsList= createDetailListContents(entryToEdit, NewWizardMessages.ModuleDialog_exports_label, new AddExportsAdapter(), ModuleAddExport.class); + fAddReadsList= createDetailListContents(entryToEdit, NewWizardMessages.ModuleDialog_reads_label, new AddReadsAdapter(), ModuleAddReads.class); + + initializeValues(); + + doPatchSelectionChanged(fIsPatchCheckbox); + doSelectionChangedAllLists(); } - /* - * @see org.eclipse.jface.dialogs.Dialog#isResizable() - * @since 3.4 - */ @Override protected boolean isResizable() { return true; } - private ListDialogField<ModuleAddExport> createListContents(CPListElement entryToEdit) { - String label= NewWizardMessages.ModuleDialog_exports_label; + private <T extends ModuleEncapsulationDetail> ListDialogField<T> createDetailListContents(CPListElement entryToEdit, String label, ListAdapter<T> adapter, Class<T> clazz) { String[] buttonLabels= new String[] { - NewWizardMessages.ModuleDialog_exports_add, - NewWizardMessages.ModuleDialog_exports_edit, - NewWizardMessages.ModuleDialog_exports_remove + NewWizardMessages.ModuleDialog_detail_add, + NewWizardMessages.ModuleDialog_detail_edit, + NewWizardMessages.ModuleDialog_detail_remove }; - AddExportsAdapter adapter= new AddExportsAdapter(); - AddExportsLabelProvider labelProvider= new AddExportsLabelProvider(); + AddDetailsLabelProvider labelProvider= new AddDetailsLabelProvider(); - ListDialogField<ModuleAddExport> exportsList= new ListDialogField<>(adapter, buttonLabels, labelProvider); - exportsList.setDialogFieldListener(adapter); + ListDialogField<T> detailsList= new ListDialogField<>(adapter, buttonLabels, labelProvider); - exportsList.setLabelText(label); - exportsList.setRemoveButtonIndex(IDX_REMOVE); - exportsList.enableButton(IDX_EDIT, false); + detailsList.setLabelText(label); + detailsList.setRemoveButtonIndex(IDX_REMOVE); + detailsList.enableButton(IDX_EDIT, false); - ArrayList<ModuleAddExport> elements; - Object moduleDetails= entryToEdit.getAttribute(CPListElement.MODULE); - if (moduleDetails instanceof ModuleAddExport[]) { - ModuleAddExport[] exports= (ModuleAddExport[]) moduleDetails; - elements= new ArrayList<>(exports.length); - for (int i= 0; i < exports.length; i++) { - elements.add(exports[i]); - } - } else { - elements= new ArrayList<>(0); - } - exportsList.setElements(elements); - exportsList.selectFirstElement(); - return exportsList; + detailsList.setElements(entryToEdit.getModuleEncapsulationDetails(clazz)); + detailsList.selectFirstElement(); + return detailsList; } - @Override protected Control createDialogArea(Composite parent) { Composite composite= (Composite) super.createDialogArea(parent); + GridLayout layout= new GridLayout(1, true); + layout.marginBottom= 0; + composite.setLayout(layout); - Composite inner= new Composite(composite, SWT.NONE); - inner.setFont(composite.getFont()); - - GridLayout layout= new GridLayout(); - layout.marginHeight= 0; - layout.marginWidth= 0; - layout.numColumns= 2; - inner.setLayout(layout); - inner.setLayoutData(new GridData(GridData.FILL_BOTH)); - - Label description= new Label(inner, SWT.WRAP); + Label description= new Label(composite, SWT.WRAP); description.setText(getDescriptionString()); - GridData data= new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1); + GridData data= new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1); data.widthHint= convertWidthInCharsToPixels(100); description.setLayoutData(data); - fIsModuleCheckbox.doFillIntoGrid(inner, 2); + fIsModuleCheckbox.doFillIntoGrid(composite, 3); - ColumnLayoutData[] columnDta= { - new ColumnWeightData(2), - new ColumnWeightData(3), - new ColumnWeightData(2), - }; - String[] headers= { - NewWizardMessages.ModuleDialog_source_module_header, - NewWizardMessages.ModuleDialog_package_header, - NewWizardMessages.ModuleDialog_target_modules_header - }; - fAddExportsList.setTableColumns(new ListDialogField.ColumnsDescription(columnDta, headers, true)); - fAddExportsList.doFillIntoGrid(inner, 3); + TabFolder tabFolder= new TabFolder(composite, SWT.NONE); + tabFolder.setFont(composite.getFont()); + tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - LayoutUtil.setHorizontalSpan(fAddExportsList.getLabelControl(null), 2); + final TabItem tabItemContents= new TabItem(tabFolder, SWT.NONE); + tabItemContents.setText(NewWizardMessages.ModuleDialog_contents_tab); + tabItemContents.setImage(JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_OBJS_MODULE)); + tabItemContents.setControl(createContentsTab(tabFolder)); - data= (GridData) fAddExportsList.getListControl(null).getLayoutData(); - data.grabExcessHorizontalSpace= true; - data.heightHint= SWT.DEFAULT; + final TabItem tabItemDetails= new TabItem(tabFolder, SWT.NONE); + tabItemDetails.setText(NewWizardMessages.ModuleDialog_details_tab); + tabItemDetails.setImage(JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_OBJS_MODULE_ATTRIB)); + tabItemDetails.setControl(createDetailsTab(tabFolder)); + + tabFolder.addSelectionListener(widgetSelectedAdapter(e -> validateTab(e.widget, tabItemContents, tabItemDetails))); applyDialogFont(composite); return composite; @@ -267,69 +320,480 @@ public class ModuleDialog extends StatusDialog { return Messages.format(desc, name); } + Composite createContentsTab(Composite parent) { + Composite contentsPage= new Composite(parent, SWT.NONE); + contentsPage.setFont(parent.getFont()); + applyDialogFont(contentsPage); + + GridLayout layout= new GridLayout(); + layout.marginTop= 5; + layout.marginHeight= 0; + layout.marginWidth= 0; + layout.numColumns= 3; // list , buttons , list + contentsPage.setLayout(layout); + contentsPage.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // top + createContentListContents(contentsPage, + NewWizardMessages.ModuleDialog_availableModules_list, + NewWizardMessages.ModuleDialog_availableModules_tooltip, + IDX_AVAILABLE, IDX_INCLUDED); + createHorizontalButtons(contentsPage); + createContentListContents(contentsPage, + NewWizardMessages.ModuleDialog_explicitlyIncludedModules_list, + NewWizardMessages.ModuleDialog_explicitlyIncludedModules_tooltip, + IDX_INCLUDED, IDX_AVAILABLE); + + // bottom + Label spacer= new Label(contentsPage, SWT.NONE); + GridData gd= new GridData(); + gd.horizontalSpan= 2; + spacer.setLayoutData(gd); + + Composite lowerRight= new Composite(contentsPage, SWT.NONE); + lowerRight.setLayout(new GridLayout(1, true)); + gd= new GridData(SWT.FILL, SWT.FILL, true, true); + lowerRight.setLayoutData(gd); + + createVerticalButton(lowerRight); + createContentListContents(lowerRight, + NewWizardMessages.ModuleDialog_implicitelyIncludedModules_list, + NewWizardMessages.ModuleDialog_implicitlyIncludedModule_tooltip, + IDX_IMPLICITLY_INCLUDED, IDX_INCLUDED); + + validateContents(); + + return contentsPage; + } + + Composite createDetailsTab(Composite parent) { + Composite detailPage= new Composite(parent, SWT.NONE); + detailPage.setFont(parent.getFont()); + applyDialogFont(detailPage); - protected void doCustomButtonPressed(ListDialogField<ModuleAddExport> field, int index) { - if (index == IDX_ADD) { - addEntry(field); - } else if (index == IDX_EDIT) { - editEntry(field); + GridLayout layout= new GridLayout(); + layout.marginTop= 5; + layout.marginHeight= 0; + layout.marginWidth= 0; + layout.numColumns= 3; + detailPage.setLayout(layout); + detailPage.setLayoutData(new GridData(GridData.FILL_BOTH)); + + fIsPatchCheckbox.doFillIntoGrid(detailPage, 3); + fPatchedModule.doFillIntoGrid(detailPage, 2); + GridData data= (GridData) fPatchedModule.getLabelControl(null).getLayoutData(); + data.horizontalIndent= LayoutUtil.getIndent(); + + Text patchedModuleText= fPatchedModule.getTextControl(null); + BidiUtils.applyBidiProcessing(patchedModuleText, StructuredTextTypeHandlerFactory.JAVA); + if (fJavaElements != null) { + configureModuleContentAssist(patchedModuleText, moduleNames()); } + + ColumnLayoutData[] columnDta= { + new ColumnWeightData(2), + new ColumnWeightData(3), + new ColumnWeightData(2), + }; + String[] headers= { + NewWizardMessages.ModuleDialog_source_module_header, + NewWizardMessages.ModuleDialog_package_header, + NewWizardMessages.ModuleDialog_target_module_header + }; + fAddExportsList.setTableColumns(new ListDialogField.ColumnsDescription(columnDta, headers, true)); + + fAddExportsList.doFillIntoGrid(detailPage, 4); + + LayoutUtil.setHorizontalSpan(fAddExportsList.getLabelControl(null), 3); + + data= (GridData) fAddExportsList.getListControl(null).getLayoutData(); + data.grabExcessHorizontalSpace= true; + data.heightHint= SWT.DEFAULT; + + columnDta= new ColumnWeightData[] { + new ColumnWeightData(1), + new ColumnWeightData(1), + }; + headers= new String[] { + NewWizardMessages.ModuleDialog_source_module_header, + NewWizardMessages.ModuleDialog_target_module_header + }; + fAddReadsList.setTableColumns(new ListDialogField.ColumnsDescription(columnDta, headers, true)); + + fAddReadsList.doFillIntoGrid(detailPage, 4); + + LayoutUtil.setHorizontalSpan(fAddReadsList.getLabelControl(null), 3); + + data= (GridData) fAddReadsList.getListControl(null).getLayoutData(); + data.grabExcessHorizontalSpace= true; + data.heightHint= SWT.DEFAULT; + return detailPage; + } + + // ======== widgets for the Contents tab: ======== + + private void createContentListContents(Composite parent, String title, String tooltip, int idx, int targetIdx) { + Composite box= new Composite(parent, SWT.NONE); + GridLayout layout= new GridLayout(1, false); + layout.marginBottom= 0; + box.setLayout(layout); + GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true); + gd.minimumWidth= 0; + box.setLayoutData(gd); + + Label label= new Label(box, SWT.NONE); + label.setText(title); + label.setToolTipText(tooltip); + + TableViewer tableViewer= new TableViewer(box, SWT.MULTI | SWT.BORDER); + tableViewer.setContentProvider(new ListContentProvider()); + tableViewer.setLabelProvider(new ModulesLabelProvider()); + tableViewer.addDoubleClickListener(e -> moveModuleEntry(idx, targetIdx)); + tableViewer.setInput(fModuleLists[idx].fNames); + tableViewer.addSelectionChangedListener(e -> validateContents()); + tableViewer.setComparator(new ViewerComparator() { + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + return ((String)e1).compareTo((String)e2); + } + }); + + PixelConverter converter= new PixelConverter(parent); + gd= new GridData(SWT.FILL, SWT.FILL, true, true); + gd.widthHint= converter.convertWidthInCharsToPixels(30); + gd.heightHint= converter.convertHeightInCharsToPixels(6); + tableViewer.getControl().setLayoutData(gd); + + fModuleLists[idx].fViewer= tableViewer; } - protected void doDoubleClicked(ListDialogField<ModuleAddExport> field) { - editEntry(field); + private void createHorizontalButtons(Composite parent) { + org.eclipse.ui.ISharedImages sharedImages= JavaPlugin.getDefault().getWorkbench().getSharedImages(); + + Composite box= new Composite(parent, SWT.NONE); + box.setLayout(new GridLayout(1, true)); + + fAddIncludedButton= new Button(box, SWT.PUSH); + fAddIncludedButton.setImage(sharedImages.getImage(org.eclipse.ui.ISharedImages.IMG_TOOL_FORWARD)); + fAddIncludedButton.setToolTipText(NewWizardMessages.ModuleDialog_addToIncluded_tooltip); + fAddIncludedButton.addSelectionListener(widgetSelectedAdapter(e -> moveModuleEntry(IDX_AVAILABLE, IDX_INCLUDED))); + + fRemoveIncludedButton= new Button(box, SWT.PUSH); + fRemoveIncludedButton.setImage(sharedImages.getImage(org.eclipse.ui.ISharedImages.IMG_TOOL_BACK)); + fRemoveIncludedButton.setToolTipText(NewWizardMessages.ModuleDialog_removeFromIncluded_tooltip); + fRemoveIncludedButton.addSelectionListener(widgetSelectedAdapter(e -> moveModuleEntry(IDX_INCLUDED, IDX_AVAILABLE))); } - protected void doSelectionChanged(ListDialogField<ModuleAddExport> field) { + private void createVerticalButton(Composite parent) { + fPromoteIncludedButton= new Button(parent, SWT.PUSH); + fPromoteIncludedButton.setImage(JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_BUTTON_MOVE_UP)); + fPromoteIncludedButton.setToolTipText(NewWizardMessages.ModuleDialog_addToExplicitlyIncluded_tooltip); + fPromoteIncludedButton.addSelectionListener(widgetSelectedAdapter(e -> moveModuleEntry(IDX_IMPLICITLY_INCLUDED, IDX_INCLUDED))); + GridData gd= new GridData(); + gd.horizontalAlignment= SWT.CENTER; + fPromoteIncludedButton.setLayoutData(gd); + } + + private boolean canRemoveIncludedModules() { + if (fModuleLists[IDX_INCLUDED].fViewer.getSelection().isEmpty()) + return false; + return fModuleLists[IDX_INCLUDED].fNames.size() + fModuleLists[IDX_AVAILABLE].fNames.size() > 1; + } + + private void moveModuleEntry(int sourceIdx, int targetIdx) { + ISelection selection= fModuleLists[sourceIdx].fViewer.getSelection(); + if (selection instanceof IStructuredSelection) { + if (sourceIdx == IDX_INCLUDED && !canRemoveIncludedModules()) { + return; + } + List<String> sourceList= fModuleLists[sourceIdx].fNames; + List<String> targetList= fModuleLists[targetIdx].fNames; + for (Iterator<?> iter= ((IStructuredSelection) selection).iterator(); iter.hasNext();) { + Object selected= iter.next(); + if (selected instanceof String) { + sourceList.remove(selected); + targetList.add((String) selected); + } + } + updateImplicitlyIncluded(); + fModuleLists[IDX_AVAILABLE].fViewer.refresh(); + fModuleLists[IDX_INCLUDED].fViewer.refresh(); + fModuleLists[IDX_IMPLICITLY_INCLUDED].fViewer.refresh(); + validateContents(); + } + } + + public static void configureModuleContentAssist(Text textControl, Set<String> moduleNames) { + if (moduleNames.size() == 1) { + textControl.setText(moduleNames.iterator().next()); + } else if (!moduleNames.isEmpty()) { + Image image= JavaPlugin.getImageDescriptorRegistry().get(JavaPluginImages.DESC_OBJS_MODULE); + JavaPrecomputedNamesAssistProcessor processor= new JavaPrecomputedNamesAssistProcessor(moduleNames, image); + ControlContentAssistHelper.createTextContentAssistant(textControl, processor); + } + } + + // ======== updating & validation: ======== + + protected void doPatchSelectionChanged(DialogField field) { + fPatchedModule.setEnabled(fIsPatchCheckbox.isSelected() && moduleNames().size() != 1); + validateDetails(field); + } + + protected void doSelectionChangedAllLists() { + doSelectionChanged(fAddExportsList); + doSelectionChanged(fAddReadsList); + } + + protected void doSelectionChanged(ListDialogField<? extends ModuleEncapsulationDetail> field) { boolean isModular= fIsModuleCheckbox.isSelected(); - List<ModuleAddExport> selected= field.getSelectedElements(); + List<? extends ModuleEncapsulationDetail> selected= field.getSelectedElements(); field.enableButton(IDX_ADD, isModular); field.enableButton(IDX_EDIT, isModular && canEdit(selected)); field.enableButton(IDX_REMOVE, isModular && selected.size() > 0); - validate(); + validateDetails(field); } - private boolean canEdit(List<ModuleAddExport> selected) { + private boolean canEdit(List<? extends ModuleEncapsulationDetail> selected) { return selected.size() == 1; } - private void validate() { + private void validateTab(Widget widget, Widget contentItem, Widget detailsItem) { + if (widget instanceof TabFolder) { + TabItem[] selected= ((TabFolder) widget).getSelection(); + for (TabItem selectedItem : selected) { + if (selectedItem == contentItem) { + validateContents(); + return; + } else if (selectedItem == detailsItem) { + validateDetails(null); + return; + } + } + } + } + + private void validateContents() { + fAddIncludedButton.setEnabled(!fModuleLists[IDX_AVAILABLE].fViewer.getSelection().isEmpty()); + fRemoveIncludedButton.setEnabled(canRemoveIncludedModules()); + fPromoteIncludedButton.setEnabled(!fModuleLists[IDX_IMPLICITLY_INCLUDED].fViewer.getSelection().isEmpty()); + IStatus status= computeContentsStatus(); + updateStatus(status); + if (status.isOK()) { + status= computeDetailsStatus(null); + if (status.getSeverity() == IStatus.ERROR) { + updateStatus(new StatusInfo(IStatus.ERROR, NewWizardMessages.ModuleDialog_errorOnDetailsTab_error)); + } + } + } + + private IStatus computeContentsStatus() { + StatusInfo info= new StatusInfo(); + if (fModuleLists[IDX_INCLUDED].fNames.isEmpty()) { + info.setError(NewWizardMessages.ModuleDialog_mustIncludeModule_error); + } else if (fModuleLists[IDX_INCLUDED].fNames.size() + fModuleLists[IDX_AVAILABLE].fNames.size() == 1) { + info.setInfo(NewWizardMessages.ModuleDialog_cannotLimitSingle_error); + } + return info; + } + + private void validateDetails(DialogField field) { + IStatus status= computeDetailsStatus(field); + updateStatus(status); + if (status.isOK()) { + status= computeContentsStatus(); + if (status.getSeverity() == IStatus.ERROR) { + updateStatus(new StatusInfo(IStatus.ERROR, NewWizardMessages.ModuleDialog_errorOnContentsTab_error)); + } + } + } + + private StatusInfo computeDetailsStatus(DialogField field) { Set<String> packages= new HashSet<>(); StatusInfo status= new StatusInfo(); - for (ModuleAddExport export : fAddExportsList.getElements()) { - if (!packages.add(export.fPackage)) { - status.setError(Messages.format(NewWizardMessages.ModuleDialog_duplicatePackage_error, export.fPackage)); - break; + if (fIsPatchCheckbox.isSelected()) { + String patchedModule= fPatchedModule.getText().trim(); + if (patchedModule.isEmpty()) { + if (field == fIsPatchCheckbox) { + status= newSilentError(); // silently disable OK button until user input is given + } else { + status.setError(NewWizardMessages.ModuleDialog_missingPatch_error); + } + Shell shell= getShell(); + if (shell != null) { + fPatchedModule.getTextControl(shell).setFocus(); + } + } else if (!moduleNames().isEmpty() && !moduleNames().contains(patchedModule)) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_wrongPatch_error, patchedModule)); + } else if (isModuleExcluded(patchedModule)) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_patchedModuleExcluded_error, patchedModule)); } } - updateStatus(status); + if (status.isOK()) { + for (ModuleAddExport export : fAddExportsList.getElements()) { + if (!packages.add(export.fPackage)) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_duplicatePackage_error, export.fPackage)); + break; + } + if (isModuleExcluded(export.fSourceModule)) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_exportSourceModuleExcluded_error, + new String[]{ export.fPackage, export.fSourceModule })); + } + } + } + if (status.isOK()) { + Set<String> readModules= new HashSet<>(); + for (ModuleAddReads reads : fAddReadsList.getElements()) { + if (!readModules.add(reads.toString())) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_duplicateReads_error, reads.toString())); + break; + } + if (isModuleExcluded(reads.fSourceModule)) { + status.setError(Messages.format(NewWizardMessages.ModuleDialog_readsSourceModuleExcluded_error, + reads.fSourceModule)); + } + } + } + return status; + } + + private boolean isModuleExcluded(String moduleName) { + return fModuleLists[IDX_AVAILABLE].fNames.contains(moduleName); } - private void editEntry(ListDialogField<ModuleAddExport> field) { + // ======== operations on values, i.e., classpath entries, modules and packages: ======== - List<ModuleAddExport> selElements= field.getSelectedElements(); - if (selElements.size() != 1) { - return; + private void initializeValues() { + fModule2RequiredModules= new HashMap<>(); + + List<String> availableNames= new ArrayList<>(moduleNames()); + List<String> includedNames= new ArrayList<>(); + List<LimitModules> limits= fCurrCPElement.getModuleEncapsulationDetails(LimitModules.class); + if (!limits.isEmpty()) { + for (LimitModules limitModules : limits) { + includedNames.addAll(limitModules.fExplicitlyIncludedModules); + availableNames.removeAll(limitModules.fExplicitlyIncludedModules); + } + } else { + includedNames= availableNames; + availableNames= new ArrayList<>(); + } + fModuleLists[IDX_AVAILABLE]= new ModuleList(availableNames); + fModuleLists[IDX_INCLUDED]= new ModuleList(new ArrayList<>(includedNames)); + fModuleLists[IDX_IMPLICITLY_INCLUDED]= new ModuleList(new ArrayList<>()); + updateImplicitlyIncluded(); + + // access to widgets may trigger validation, which needs all values to be initialized (non-null): + + if (fCurrCPElement.getEntryKind() == IClasspathEntry.CPE_CONTAINER) { + IPackageFragmentRoot[] roots= findRoots(fCurrCPElement); + if (roots.length > 1 && roots[0].getModuleDescription() != null) + fIsModuleCheckbox.setEnabled(false); // assume multi-module container is Java 9 JRE } - ModuleAddExport export= selElements.get(0); - ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(getShell(), fJavaElements, export); - if (dialog.open() == Window.OK) { - ModuleAddExport newExport= dialog.getExport(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); - if (newExport != null) { - field.replaceElement(export, newExport); - } else { - field.removeElement(export); + + List<ModulePatch> patchedModules= fCurrCPElement.getModuleEncapsulationDetails(ModulePatch.class); + fIsPatchCheckbox.setSelection(!patchedModules.isEmpty()); + + if (patchedModules.size() == 1) + fPatchedModule.setText(patchedModules.iterator().next().fModule); + } + + private IPackageFragmentRoot[] findRoots(CPListElement element) { + IClasspathEntry entry= element.getClasspathEntry(); + IPackageFragmentRoot[] roots= element.getJavaProject().findPackageFragmentRoots(entry); + if (roots.length == 0) { + // 2nd attempt in case "module=true" is not explicit on the real cp entry: + entry= copyCPEntryWithoutModuleAttribute(entry); + if (entry != null) + roots= element.getJavaProject().findPackageFragmentRoots(entry); + } + return roots; + } + + private IClasspathEntry copyCPEntryWithoutModuleAttribute(IClasspathEntry entry) { + IClasspathAttribute[] oldAttributes= entry.getExtraAttributes(); + IClasspathAttribute[] newAttributes= new IClasspathAttribute[oldAttributes.length]; + int count= 0; + for (int i= 0; i < oldAttributes.length; i++) { + if (!oldAttributes[i].getName().equals(IClasspathAttribute.MODULE)) + newAttributes[count++]= oldAttributes[i]; + } + if (count == oldAttributes.length) + return null; + newAttributes= count == 0 ? new IClasspathAttribute[0] : Arrays.copyOf(newAttributes, count); + return JavaCore.newContainerEntry(entry.getPath(), entry.getAccessRules(), newAttributes, entry.isExported()); + } + + private Set<String> moduleNames() { + if (fModuleNames != null) + return fModuleNames; + Set<String> moduleNames= new HashSet<>(); + if (fJavaElements != null) { + for (int i= 0; i < fJavaElements.length; i++) { + if (fJavaElements[i] instanceof IPackageFragmentRoot) { + IModuleDescription module= ((IPackageFragmentRoot) fJavaElements[i]).getModuleDescription(); + if (module != null) { + recordModule(module, moduleNames); + } + } else if (fJavaElements[i] instanceof IJavaProject) { + try { + IModuleDescription module= ((IJavaProject) fJavaElements[i]).getModuleDescription(); + if (module != null) { + recordModule(module, moduleNames); + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } + } + } + } + return fModuleNames= moduleNames; + } + + private void recordModule(IModuleDescription module, Set<String> moduleNames) { + String moduleName= module.getElementName(); + if (moduleNames.add(moduleName)) { + try { + for (String required : JavaModelAccess.getRequiredModules(module)) { + List<String> requiredModules= fModule2RequiredModules.get(moduleName); + if (requiredModules == null) { + requiredModules= new ArrayList<>(); + fModule2RequiredModules.put(moduleName, requiredModules); + } + requiredModules.add(required); + } + } catch (JavaModelException e) { + JavaPlugin.log(e); } } } - private void addEntry(ListDialogField<ModuleAddExport> field) { - ModuleAddExport initialValue= new ModuleAddExport(getSourceModuleName(), NO_NAME, getCurrentModuleName(), null); - ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(getShell(), fJavaElements, initialValue); - if (dialog.open() == Window.OK) { - ModuleAddExport export= dialog.getExport(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); - if (export != null) - field.addElement(export); + private void updateImplicitlyIncluded() { + List<String> implicitNames= fModuleLists[IDX_IMPLICITLY_INCLUDED].fNames; + fModuleLists[IDX_AVAILABLE].fNames.addAll(implicitNames); + implicitNames.clear(); + for (String explicitName : fModuleLists[IDX_INCLUDED].fNames) { + if (!implicitNames.contains(explicitName)) { + collectRequired(explicitName); + } + } + } + + private void collectRequired(String explicitName) { + List<String> requireds= fModule2RequiredModules.get(explicitName); + if (requireds == null) { + return; + } + List<String> implicitNames= fModuleLists[IDX_IMPLICITLY_INCLUDED].fNames; + for (String required : requireds) { + if (!fModuleLists[IDX_INCLUDED].fNames.contains(required)) { + if (!implicitNames.contains(required)) { + if (fModuleLists[IDX_AVAILABLE].fNames.remove(required)) { + implicitNames.add(required); + collectRequired(required); + } + } + } } } @@ -367,46 +831,117 @@ public class ModuleDialog extends StatusDialog { // -------- TypeRestrictionAdapter -------- - private class AddExportsAdapter implements IListAdapter<ModuleAddExport>, IDialogFieldListener { + private abstract class ListAdapter<T extends ModuleEncapsulationDetail> implements IListAdapter<T> { /** * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#customButtonPressed(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField, int) */ @Override - public void customButtonPressed(ListDialogField<ModuleAddExport> field, int index) { - doCustomButtonPressed(field, index); + public void customButtonPressed(ListDialogField<T> field, int index) { + if (index == IDX_ADD) { + addEntry(field); + } else if (index == IDX_EDIT) { + doubleClicked(field); + } } /** * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#selectionChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField) */ @Override - public void selectionChanged(ListDialogField<ModuleAddExport> field) { + public void selectionChanged(ListDialogField<T> field) { doSelectionChanged(field); } /** * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#doubleClicked(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField) */ @Override - public void doubleClicked(ListDialogField<ModuleAddExport> field) { - doDoubleClicked(field); + public void doubleClicked(ListDialogField<T> field) { + List<T> selElements= field.getSelectedElements(); + if (selElements.size() != 1) { + return; + } + editEntry(field, selElements.get(0)); + } + + abstract void addEntry(ListDialogField<T> field); + + abstract void editEntry(ListDialogField<T> field, T detail); + } + + private class AddExportsAdapter extends ListAdapter<ModuleAddExport> { + + @Override + void addEntry(ListDialogField<ModuleAddExport> field) { + ModuleAddExport initialValue= new ModuleAddExport(getSourceModuleName(), NO_NAME, getCurrentModuleName(), null); + ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(getShell(), fJavaElements, initialValue); + if (dialog.open() == Window.OK) { + ModuleAddExport export= dialog.getExport(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); + if (export != null) + field.addElement(export); + } } - /** - * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener#dialogFieldChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField) - */ @Override - public void dialogFieldChanged(DialogField field) { - if (field == fIsModuleCheckbox) { - doSelectionChanged(fAddExportsList); + void editEntry(ListDialogField<ModuleAddExport> field, ModuleAddExport export) { + ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(getShell(), fJavaElements, export); + if (dialog.open() == Window.OK) { + ModuleAddExport newExport= dialog.getExport(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); + if (newExport != null) { + field.replaceElement(export, newExport); + } else { + field.removeElement(export); + } + } + } + } + + private class AddReadsAdapter extends ListAdapter<ModuleAddReads> { + + @Override + void addEntry(ListDialogField<ModuleAddReads> field) { + ModuleAddReads initialValue= new ModuleAddReads(getSourceModuleName(), NO_NAME, null); + ModuleAddReadsDialog dialog= new ModuleAddReadsDialog(getShell(), fJavaElements, initialValue); + if (dialog.open() == Window.OK) { + ModuleAddReads reads= dialog.getReads(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); + if (reads != null) + field.addElement(reads); + } + } + + @Override + void editEntry(ListDialogField<ModuleAddReads> field, ModuleAddReads reads) { + ModuleAddReadsDialog dialog= new ModuleAddReadsDialog(getShell(), fJavaElements, reads); + if (dialog.open() == Window.OK) { + ModuleAddReads newReads= dialog.getReads(fCurrCPElement.findAttributeElement(CPListElement.MODULE)); + if (newReads != null) { + field.replaceElement(reads, newReads); + } else { + field.removeElement(reads); + } } } } - public ModuleAddExport[] getAddExports() { + /** + * When the dialog is closed, this method provides the results. + * @return an array of ModuleEncapsulationDetail encoding the result of editing + */ + public ModuleEncapsulationDetail[] getAllDetails() { if (!fIsModuleCheckbox.isSelected()) return null; - List<ModuleAddExport> elements= fAddExportsList.getElements(); - return elements.toArray(new ModuleAddExport[elements.size()]); + CPListElementAttribute attribute= fCurrCPElement.findAttributeElement(CPListElement.MODULE); + List<ModuleEncapsulationDetail> allElements= new ArrayList<>(); + allElements.addAll(fAddExportsList.getElements()); + allElements.addAll(fAddReadsList.getElements()); + if (fIsPatchCheckbox.isSelected()) { + String patchedModule= fPatchedModule.getText().trim(); + if (!patchedModule.isEmpty()) + allElements.add(ModulePatch.fromString(attribute, patchedModule)); + } + if (!fModuleLists[IDX_AVAILABLE].fNames.isEmpty() || !fModuleLists[IDX_IMPLICITLY_INCLUDED].fNames.isEmpty()) { + allElements.add(new ModuleEncapsulationDetail.LimitModules(fModuleLists[IDX_INCLUDED].fNames, attribute)); + } + return allElements.toArray(new ModuleEncapsulationDetail[allElements.size()]); } /* @@ -422,4 +957,8 @@ public class ModuleDialog extends StatusDialog { helpContextId= IJavaHelpContextIds.ACCESS_RULES_DIALOG; // FIXME PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, helpContextId); } + + public static StatusInfo newSilentError() { + return new StatusInfo(IStatus.ERROR, Util.ZERO_LENGTH_STRING); + } } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleEncapsulationDetail.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleEncapsulationDetail.java new file mode 100644 index 0000000000..17df0239b5 --- /dev/null +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ModuleEncapsulationDetail.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2017 GK Software AG, 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 + * + * This is an implementation of an early-draft specification developed under the Java + * Community Process (JCP) and is made available for testing and evaluation purposes + * only. The code is not compatible with any specification of the JCP. + * + * 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.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.core.runtime.IPath; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; + +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaElement; +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.core.provisional.JavaModelAccess; + +import org.eclipse.jdt.internal.ui.JavaPlugin; + +/** + * Node in the tree of CPListElement et al, representing a module directive like add-exports ... + */ +public abstract class ModuleEncapsulationDetail { + + protected CPListElementAttribute fAttribElem; + + public CPListElementAttribute getParent() { + return fAttribElem; + } + + /** + * Retrieve the java element(s) targeted by a given classpath entry. + * @param currentProject the Java project holding the classpath entry + * @param path the path value of the classpath entry + * @return either an array of {@link IPackageFragmentRoot} or a singleton array of {@link IJavaProject} + * targeted by the given classpath entry, or {@code null} if no not found + */ + public static IJavaElement[] getTargetJavaElements(IJavaProject currentProject, IPath path) { + IResource member= ResourcesPlugin.getWorkspace().getRoot().findMember(path); + if (member != null) { + IJavaElement element= JavaCore.create(member); + if (element != null) + return new IJavaElement[] {element}; + } else if (path != null && path.isAbsolute()) { + try { + for (IClasspathEntry classpathEntry : currentProject.getRawClasspath()) { + if (classpathEntry.getPath().equals(path)) { + switch (classpathEntry.getEntryKind()) { + case IClasspathEntry.CPE_LIBRARY: + return new IJavaElement[] {currentProject.getPackageFragmentRoot(path.toString())}; + default: + // keep looking + } + } + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } + } else { + try { + for (IClasspathEntry classpathEntry : currentProject.getRawClasspath()) { + if (classpathEntry.getPath().equals(path)) { + return JavaModelAccess.getUnfilteredPackageFragmentRoots(currentProject, classpathEntry); + } + } + } catch (JavaModelException e) { + JavaPlugin.log(e); + } + } + return null; + } + + public static String encodeFiltered(ModuleEncapsulationDetail[] details, Class<?> detailClass) { + return Arrays.stream(details) + .filter(detailClass::isInstance) + .map(ModuleEncapsulationDetail::toString) + .collect(Collectors.joining(":")); //$NON-NLS-1$ + } + + /** + * Node in the tree of CPListElement et al, representing a patch-module directive. + */ + static class ModulePatch extends ModuleEncapsulationDetail { + + public static ModulePatch fromString(CPListElementAttribute attribElem, String value) { + return new ModulePatch(value, attribElem); + } + + public final String fModule; + + public ModulePatch(String module, CPListElementAttribute attribElem) { + fModule= module; + fAttribElem= attribElem; + } + + @Override + public String toString() { + return fModule; + } + } + + /** + * Node in the tree of CPListElement et al, representing an add-exports module directive. + */ + static class ModuleAddExport extends ModuleEncapsulationDetail { + + public static ModuleAddExport fromString(CPListElementAttribute attribElem, String value) { + int slash= value.indexOf('/'); + int equals= value.indexOf('='); + if (slash != -1 && equals != -1 && equals > slash) { + return new ModuleAddExport(value.substring(0, slash), + value.substring(slash+1, equals), + value.substring(equals+1), + attribElem); + } + return null; + } + + public static Collection<ModuleAddExport> fromMultiString(CPListElementAttribute attribElem, String values) { + List<ModuleAddExport> exports= new ArrayList<>(); + for (String value : values.split(":")) { //$NON-NLS-1$ + ModuleAddExport export= fromString(attribElem, value); + if (export != null) + exports.add(export); + } + return exports; + } + + public final String fSourceModule; + public final String fPackage; + public final String fTargetModules; + + public ModuleAddExport(String sourceModule, String aPackage, String targetModules, CPListElementAttribute attribElem) { + fSourceModule= sourceModule; + fPackage= aPackage; + fTargetModules= targetModules; + fAttribElem= attribElem; + } + + @Override + public String toString() { + return fSourceModule+'/'+fPackage+'='+fTargetModules; + } + } + + /** + * Node in the tree of CPListElement et al, representing an add-reads module directive. + */ + static class ModuleAddReads extends ModuleEncapsulationDetail { + + public static ModuleAddReads fromString(CPListElementAttribute attribElem, String value) { + int equals= value.indexOf('='); + if (equals != -1) { + return new ModuleAddReads(value.substring(0, equals), + value.substring(equals+1), + attribElem); + } + return null; + } + + public static Collection<ModuleAddReads> fromMultiString(CPListElementAttribute attribElem, String values) { + List<ModuleAddReads> readss= new ArrayList<>(); + for (String value : values.split(":")) { //$NON-NLS-1$ + ModuleAddReads reads= fromString(attribElem, value); + if (reads != null) + readss.add(reads); + } + return readss; + } + + public final String fSourceModule; + public final String fTargetModule; + + public ModuleAddReads(String sourceModule, String targetModule, CPListElementAttribute attribElem) { + fSourceModule= sourceModule; + fTargetModule= targetModule; + fAttribElem= attribElem; + } + + @Override + public String toString() { + return fSourceModule+'='+fTargetModule; + } + } + + /** + * Node in the tree of CPListElement et al, representing a limit-modules directive. + */ + static class LimitModules extends ModuleEncapsulationDetail { + + public static LimitModules fromString(CPListElementAttribute attribElem, String value) { + String[] modules= value.split(","); //$NON-NLS-1$ + for (int i= 0; i < modules.length; i++) { + modules[i]= modules[i].trim(); + } + return new LimitModules(Arrays.asList(modules), attribElem); + } + + public final List<String> fExplicitlyIncludedModules; + + public LimitModules(List<String> explicitlyIncludedModules, CPListElementAttribute attribElem) { + fExplicitlyIncludedModules= explicitlyIncludedModules; + fAttribElem= attribElem; + } + @Override + public String toString() { + return String.join(",", fExplicitlyIncludedModules); //$NON-NLS-1$ + } + } +} diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ProjectsWorkbookPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ProjectsWorkbookPage.java index 8fbe31617c..1e199d066e 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ProjectsWorkbookPage.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/ProjectsWorkbookPage.java @@ -189,13 +189,13 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { private void updateClasspathList() { List<CPListElement> projelements= fProjectsList.getElements(); - List<CPListElement> flattenedProjElements = new ArrayList<CPListElement>(); + 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= ele.getChildren(); - for (Iterator iterator= children.iterator(); iterator.hasNext();) { + for (Iterator<?> iterator= children.iterator(); iterator.hasNext();) { Object object= iterator.next(); if(object instanceof CPListElement) { flattenedProjElements.add((CPListElement) object); @@ -336,7 +336,7 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { for (CPListElement cpListElement : elementsToAdd) { Object attribute= cpListElement.getAttribute(IClasspathAttribute.MODULE); if(attribute == null) { - cpListElement.setAttribute(IClasspathAttribute.MODULE, new ModuleAddExport[0]); + cpListElement.setAttribute(IClasspathAttribute.MODULE, new ModuleEncapsulationDetail[0]); } } @@ -372,8 +372,8 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { removeCustomAttribute(attrib); } selElements.remove(i); - } else if (elem instanceof ModuleAddExport) { - removeAddExport((ModuleAddExport) elem); + } else if (elem instanceof ModuleEncapsulationDetail) { + removeEncapsulationDetail((ModuleEncapsulationDetail) elem); } } if (selElements.isEmpty()) { @@ -424,7 +424,7 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { return false; } } - } else if (elem instanceof ModuleAddExport) { + } else if (elem instanceof ModuleEncapsulationDetail) { return true; } else if (elem instanceof CPListElement) { if (((CPListElement)elem).isRootNodeForPath()) { @@ -488,7 +488,7 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { if (key.equals(CPListElement.ACCESSRULES)) { showAccessRestrictionDialog(elem.getParent()); } else if (key.equals(CPListElement.MODULE)) { - needRefresh= showAddExportDialog(getShell(), elem); + needRefresh= showModuleDialog(getShell(), elem); } else { needRefresh= editCustomAttribute(getShell(), elem); } @@ -558,7 +558,7 @@ public class ProjectsWorkbookPage extends BuildPathBasePage { CPListElement curr= elements.get(i); if (curr.isRootNodeForPath()) { ArrayList<Object> children= curr.getChildren(); - for (Iterator iterator= children.iterator(); iterator.hasNext();) { + for (Iterator<?> iterator= children.iterator(); iterator.hasNext();) { Object object= iterator.next(); if(object instanceof CPListElement) { CPListElement cpe = (CPListElement)object; diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ISharedImages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ISharedImages.java index a8d37a6826..bfe37848a5 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ISharedImages.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ISharedImages.java @@ -1,14 +1,10 @@ /******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. + * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * - * This is an implementation of an early-draft specification developed under the Java - * Community Process (JCP) and is made available for testing and evaluation purposes - * only. The code is not compatible with any specification of the JCP. - * * Contributors: * IBM Corporation - initial API and implementation * Frits Jalvingh - Contribution for Bug 459831 - [launching] Support attaching external annotations to a JRE container @@ -305,12 +301,6 @@ public interface ISharedImages { public static final String IMG_OBJS_EXTERNAL_ANNOTATIONS = JavaPluginImages.IMG_OBJS_EXTERNAL_ANNOTATIONS; /** - * Key to access the shared image or image descriptor for an add-exports module directive. - * @since 3.13 BETA_JAVA9 - */ - public static final String IMG_OBJS_ADD_EXPORTS = JavaPluginImages.IMG_OBJS_ADD_EXPORTS; - - /** * Returns the shared image managed under the given key. * <p> * Note that clients <b>must not</b> dispose the image returned by this method. diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/BuildPathDialogAccess.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/BuildPathDialogAccess.java index cc8a6cb2b4..bf209467b1 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/BuildPathDialogAccess.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/wizards/BuildPathDialogAccess.java @@ -43,7 +43,6 @@ import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.views.navigator.ResourceComparator; import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.internal.corext.javadoc.JavaDocLocations; @@ -63,8 +62,6 @@ import org.eclipse.jdt.internal.ui.wizards.buildpaths.ClasspathContainerWizard; import org.eclipse.jdt.internal.ui.wizards.buildpaths.EditVariableEntryDialog; import org.eclipse.jdt.internal.ui.wizards.buildpaths.ExternalAnnotationsAttachmentDialog; import org.eclipse.jdt.internal.ui.wizards.buildpaths.JavadocLocationDialog; -import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleAddExport; -import org.eclipse.jdt.internal.ui.wizards.buildpaths.ModuleAddExportsDialog; import org.eclipse.jdt.internal.ui.wizards.buildpaths.MultipleFolderSelectionDialog; import org.eclipse.jdt.internal.ui.wizards.buildpaths.NewVariableEntryDialog; import org.eclipse.jdt.internal.ui.wizards.buildpaths.SourceAttachmentDialog; @@ -167,25 +164,6 @@ public final class BuildPathDialogAccess { } /** - * Shows the UI for configuring an add-exports classpath attribute. <code>null</code> is - * returned when the user cancels the dialog. The dialog does not apply any changes. - * - * @param shell The parent shell for the dialog - * @param sourceElements the Java elements representing the source modules from which more packages should be exported - * @param initialValue The export value to edit; format: {@code <source-module>/<package>=<target-module>(,<target-module>)*}. - * @return Returns the entered value, possibly different from the initialValue, - * or <code>null</code> if the dialog has been cancelled. - * @since 3.13 BETA_JAVA9 - */ - public static String configureAddExports(Shell shell, IJavaElement[] sourceElements, String initialValue) { - ModuleAddExportsDialog dialog= new ModuleAddExportsDialog(shell, sourceElements, ModuleAddExport.fromString(null, initialValue)); - if (dialog.open() == Window.OK) { - return dialog.getResult(); - } - return null; - } - - /** * Shows the UI for configuring a javadoc location. <code>null</code> is returned * if the user cancels the dialog. If OK is pressed, an array of length 1 containing the configured URL is * returned. Note that the configured URL can be <code>null</code> when the user |
