Bug 102527 - A project preference page to configure natures
Change-Id: Ic75c1341c32f9fbfb022c27843d57bdb0028590e
Signed-off-by: Mickael Istria <mistria@redhat.com>
diff --git a/build/org.eclipse.e4.ui.update/category.xml b/build/org.eclipse.e4.ui.update/category.xml
index b9ab278..195c0c9 100644
--- a/build/org.eclipse.e4.ui.update/category.xml
+++ b/build/org.eclipse.e4.ui.update/category.xml
@@ -41,4 +41,9 @@
<bundle id="org.eclipse.e4.jdt.scope" version="0.0.1.qualifier">
<category name="JDT"/>
</bundle>
+
+ <category-def name="Misc" label="Misc"/>
+ <bundle id="org.eclipse.e4.ui.naturist" version="0.0.1.qualifier">
+ <category name="Misc"/>
+ </bundle>
</site>
diff --git a/bundles/org.eclipse.e4.ui.naturist/.classpath b/bundles/org.eclipse.e4.ui.naturist/.classpath
new file mode 100644
index 0000000..0b1bcf9
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src/"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/bundles/org.eclipse.e4.ui.naturist/.gitignore b/bundles/org.eclipse.e4.ui.naturist/.gitignore
new file mode 100644
index 0000000..06ba672
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target/
diff --git a/bundles/org.eclipse.e4.ui.naturist/.project b/bundles/org.eclipse.e4.ui.naturist/.project
new file mode 100644
index 0000000..93a6ccf
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclise.e4.ui.naturist</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..c537b63
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..58b4e45
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,60 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=false
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=false
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.m2e.core.prefs b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/bundles/org.eclipse.e4.ui.naturist/META-INF/MANIFEST.MF b/bundles/org.eclipse.e4.ui.naturist/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..2442fc4
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Project preference page to edit project natures
+Bundle-SymbolicName: org.eclipse.e4.ui.naturist;singleton:=true
+Bundle-Version: 0.0.1.qualifier
+Bundle-Vendor: Eclipse.org
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.ui.ide,
+ org.eclipse.e4.core.contexts
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.e4.ui.naturist/build.properties b/bundles/org.eclipse.e4.ui.naturist/build.properties
new file mode 100644
index 0000000..08bb920
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = target/classes
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties
diff --git a/bundles/org.eclipse.e4.ui.naturist/plugin.properties b/bundles/org.eclipse.e4.ui.naturist/plugin.properties
new file mode 100644
index 0000000..3b4d25f
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/plugin.properties
@@ -0,0 +1 @@
+PropertyPages.project.natures = Project Natures
\ No newline at end of file
diff --git a/bundles/org.eclipse.e4.ui.naturist/plugin.xml b/bundles/org.eclipse.e4.ui.naturist/plugin.xml
new file mode 100644
index 0000000..56ac4bb
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/plugin.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+ <extension point="org.eclipse.ui.propertyPages">
+ <page
+ class="org.eclipse.ui.resources.natures.ProjectNaturesPage"
+ id="org.eclipse.ui.propertypages.project.natures"
+ name="%PropertyPages.project.natures"
+ >
+ <filter
+ name="open"
+ value="true">
+ </filter>
+ <enabledWhen>
+ <adapt type="org.eclipse.core.resources.IProject"/>
+ </enabledWhen>
+ </page>
+ </extension>
+</plugin>
diff --git a/bundles/org.eclipse.e4.ui.naturist/pom.xml b/bundles/org.eclipse.e4.ui.naturist/pom.xml
new file mode 100644
index 0000000..611569e
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/pom.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.eclipse.e4.ui</groupId>
+ <artifactId>e4-ui-aggregator</artifactId>
+ <version>0.17.0-SNAPSHOT</version>
+ <relativePath>../../</relativePath>
+ </parent>
+
+ <artifactId>org.eclipse.e4.ui.naturist</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/Messages.java b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/Messages.java
new file mode 100644
index 0000000..cf5d1d7
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/Messages.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2016 Red Hat Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mickael Istria (Red Hat Inc) - [102527] initial implementation
+ ******************************************************************************/
+package org.eclipse.ui.resources.natures;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+ static {
+ NLS.initializeMessages(Messages.class.getPackage().getName().replace('.', '/') + "/messages", Messages.class);
+ }
+
+ public static String ProjectNaturesPage_label;
+ public static String ProjectNaturesPage_missingNatureText;
+ public static String ProjectNaturesPage_addNature;
+ public static String ProjectNaturesPage_removeNature;
+ public static String ProjectNaturesPage_selectNatureToAddMessage;
+ public static String ProjectNaturesPage_selectNatureToAddTitle;
+ public static String ProjectNaturesPage_changeWarningTitle;
+ public static String ProjectNaturesPage_warningMessage;
+ public static String ProjectNaturesPage_changeWarningQuestion;
+
+}
diff --git a/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/ProjectNaturesPage.java b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/ProjectNaturesPage.java
new file mode 100644
index 0000000..88b087e
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/ProjectNaturesPage.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2016 Gunnar Wagenknecht and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Gunnar Wagenknecht - initial API and implementation
+ * Mickael Istria (Red Hat Inc) - [102527] Reshaped UI, based on builders
+ ******************************************************************************/
+package org.eclipse.ui.resources.natures;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
+import org.eclipse.core.resources.IProjectNatureDescriptor;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.equinox.log.Logger;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+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.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+import org.eclipse.ui.dialogs.PropertyPage;
+import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
+import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
+import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * Project property page for viewing and modifying the project natures.
+ *
+ * @since 3.3
+ */
+public class ProjectNaturesPage extends PropertyPage {
+
+ private static final String PLUGIN_ID = "org.eclipse.e4.ui.naturist"; //$NON-NLS-1$
+ public static final String HELP_CONTEXT_ID = PLUGIN_ID + ".project_natures_property_page_context"; //$NON-NLS-1$
+
+ private IProject project;
+ private List<String> naturesIdsWorkingCopy;
+
+ // widgets
+ private TableViewer activeNaturesList;
+
+ private boolean warningAlreadyShown = false;
+ private Logger logger;
+
+ /**
+ * @see PreferencePage#createContents
+ */
+ @Override
+ protected Control createContents(final Composite parent) {
+ Bundle bundle = FrameworkUtil.getBundle(this.getClass());
+ BundleContext bundleContext = bundle.getBundleContext();
+ logger = bundleContext.getService(bundleContext.getServiceReference(Logger.class));
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), HELP_CONTEXT_ID);
+ Font font = parent.getFont();
+
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, false);
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ composite.setFont(font);
+
+ initialize();
+
+ Composite header = new Composite(composite, SWT.NONE);
+ header.setLayout(new GridLayout(2, false));
+ Label description = createDescriptionLabel(header);
+ description.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));
+ header.setLayout(new GridLayout(2, false));
+ Label warningImageLabel = new Label(header, SWT.NONE);
+ warningImageLabel.setImage(header.getDisplay().getSystemImage(SWT.ICON_WARNING));
+ Label warningLabel = new Label(header, SWT.WRAP);
+ warningLabel.setText(Messages.ProjectNaturesPage_warningMessage);
+ GridData warningMessageLayoutData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ warningMessageLayoutData.widthHint = 400;
+ warningMessageLayoutData.verticalIndent = 10;
+ warningLabel.setLayoutData(warningMessageLayoutData);
+
+ Composite naturesComposite = new Composite(composite, SWT.NONE);
+ naturesComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+ naturesComposite.setLayout(new GridLayout(2, false));
+ this.activeNaturesList = new TableViewer(naturesComposite);
+ this.activeNaturesList.getTable().setFont(font);
+ this.activeNaturesList.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ this.activeNaturesList.setLabelProvider(new NatureLabelProvider(this.project.getWorkspace()));
+ this.activeNaturesList.setContentProvider(new ArrayContentProvider());
+ try {
+ this.naturesIdsWorkingCopy = new ArrayList<String>();
+ this.naturesIdsWorkingCopy.addAll(Arrays.asList(project.getDescription().getNatureIds()));
+ } catch (CoreException ex) {
+ logger.log(IStatus.WARNING, "Error while loading project description for " + this.project.getName(), //$NON-NLS-1$
+ ex);
+ }
+ this.activeNaturesList.setInput(this.naturesIdsWorkingCopy);
+
+ Composite buttonComposite = new Composite(naturesComposite, SWT.NONE);
+ buttonComposite.setLayout(new GridLayout(1, false));
+ buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
+ Button addButton = new Button(buttonComposite, SWT.PUSH);
+ addButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ addButton.setText(Messages.ProjectNaturesPage_addNature);
+ addButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (!ProjectNaturesPage.this.warningAlreadyShown) {
+ if (!MessageDialog.openConfirm(getShell(), Messages.ProjectNaturesPage_changeWarningTitle,
+ Messages.ProjectNaturesPage_warningMessage + "\n\n" //$NON-NLS-1$
+ + Messages.ProjectNaturesPage_changeWarningQuestion)) {
+ return;
+ }
+ ProjectNaturesPage.this.warningAlreadyShown = true;
+ }
+ ElementListSelectionDialog naturesSelectionDialog = new ElementListSelectionDialog(parent.getShell(),
+ new NatureLabelProvider(project.getWorkspace()));
+ naturesSelectionDialog.setMessage(Messages.ProjectNaturesPage_selectNatureToAddMessage);
+ naturesSelectionDialog.setTitle(Messages.ProjectNaturesPage_selectNatureToAddTitle);
+ List<IProjectNatureDescriptor> natures = new ArrayList<IProjectNatureDescriptor>();
+ for (IProjectNatureDescriptor nature : project.getWorkspace().getNatureDescriptors()) {
+ if (!naturesIdsWorkingCopy.contains(nature.getNatureId())) {
+ natures.add(nature);
+ }
+ }
+ naturesSelectionDialog.setElements(natures.toArray(new IProjectNatureDescriptor[natures.size()]));
+ if (naturesSelectionDialog.open() == Window.OK) {
+ for (Object item : naturesSelectionDialog.getResult()) {
+ IProjectNatureDescriptor nature = (IProjectNatureDescriptor) item;
+ naturesIdsWorkingCopy.add(nature.getNatureId());
+ }
+ ProjectNaturesPage.this.activeNaturesList.refresh();
+ }
+ }
+ });
+ final Button removeButton = new Button(buttonComposite, SWT.PUSH);
+ removeButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
+ removeButton.setText(Messages.ProjectNaturesPage_removeNature);
+ removeButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (!ProjectNaturesPage.this.warningAlreadyShown) {
+ if (!MessageDialog.openConfirm(getShell(), Messages.ProjectNaturesPage_changeWarningTitle,
+ Messages.ProjectNaturesPage_warningMessage + "\n\n" //$NON-NLS-1$
+ + Messages.ProjectNaturesPage_changeWarningQuestion)) {
+ return;
+ }
+ ProjectNaturesPage.this.warningAlreadyShown = true;
+ }
+ IStructuredSelection selection = (IStructuredSelection) ProjectNaturesPage.this.activeNaturesList
+ .getSelection();
+ for (Object item : selection.toList()) {
+ String natureId = (String) item;
+ naturesIdsWorkingCopy.remove(natureId);
+ }
+ ProjectNaturesPage.this.activeNaturesList.refresh();
+ }
+ });
+ this.activeNaturesList.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ removeButton.setEnabled(!ProjectNaturesPage.this.activeNaturesList.getSelection().isEmpty());
+ }
+ });
+ this.activeNaturesList.setSelection(new StructuredSelection()); // Empty
+ // selection
+
+ return composite;
+ }
+
+ private static class NatureLabelProvider extends LabelProvider {
+ private IWorkspace workspace;
+ private Map<String, Image> natureImages;
+
+ public NatureLabelProvider(IWorkspace workspace) {
+ this.workspace = workspace;
+ this.natureImages = new HashMap<String, Image>(workspace.getNatureDescriptors().length);
+ }
+
+ @Override
+ public String getText(Object element) {
+ IProjectNatureDescriptor nature = null;
+ if (element instanceof IProjectNatureDescriptor) {
+ nature = (IProjectNatureDescriptor) element;
+ } else if (element instanceof String) {
+ String natureId = (String) element;
+ nature = this.workspace.getNatureDescriptor(natureId);
+ if (nature == null) {
+ return getMissingNatureLabel(natureId);
+ }
+ } else {
+ return "Not a valid nature input " + element.toString(); //$NON-NLS-1$
+ }
+ return getNatureDescriptorLabel(nature);
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ String natureId = null;
+ if (element instanceof IProjectNatureDescriptor) {
+ natureId = ((IProjectNatureDescriptor) element).getNatureId();
+ } else if (element instanceof String) {
+ natureId = (String) element;
+ } else {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
+ }
+ if (this.workspace.getNatureDescriptor(natureId) != null) {
+ if (!natureImages.containsKey(natureId)) {
+ ImageDescriptor image = IDEWorkbenchPlugin.getDefault().getProjectImageRegistry()
+ .getNatureImage(natureId);
+ if (image != null) {
+ this.natureImages.put(natureId, image.createImage());
+ } else {
+ // TODO a generic image?
+ }
+ }
+ return natureImages.get(natureId);
+ } else /* Unknown nature */ {
+ return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ }
+
+ }
+
+ protected String getMissingNatureLabel(String natureId) {
+ return NLS.bind(Messages.ProjectNaturesPage_missingNatureText, natureId);
+ }
+
+ protected String getNatureDescriptorLabel(IProjectNatureDescriptor natureDescriptor) {
+ String label = natureDescriptor.getLabel();
+ if (label.trim().length() == 0)
+ return natureDescriptor.getNatureId();
+ return label;
+ }
+
+ @Override
+ public void dispose() {
+ for (Image image : natureImages.values()) {
+ image.dispose();
+ }
+ super.dispose();
+ }
+
+ }
+
+ /**
+ * Handle the exception thrown when saving.
+ *
+ * @param e
+ * the exception
+ */
+ protected void handle(InvocationTargetException e) {
+ IStatus error;
+ Throwable target = e.getTargetException();
+ if (target instanceof CoreException) {
+ error = ((CoreException) target).getStatus();
+ } else {
+ String msg = target.getMessage();
+ if (msg == null) {
+ msg = IDEWorkbenchMessages.Internal_error;
+ }
+ error = new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, 1, msg, target);
+ }
+ ErrorDialog.openError(getControl().getShell(), null, null, error);
+ }
+
+ /**
+ * Initializes a ProjectReferencePage.
+ */
+ private void initialize() {
+ project = (IProject) getElement().getAdapter(IResource.class);
+ noDefaultAndApplyButton();
+ setDescription(Messages.ProjectNaturesPage_label);
+ }
+
+ /**
+ * @see PreferencePage#performOk
+ */
+ @Override
+ public boolean performOk() {
+ List<String> originalNatureIds = null;
+ try {
+ originalNatureIds = Arrays.asList(this.project.getDescription().getNatureIds());
+ } catch (CoreException ex) {
+ logger.log(IStatus.WARNING, "Error while loading project description for " + this.project.getName(), //$NON-NLS-1$
+ ex);
+ originalNatureIds = new ArrayList<String>();
+ }
+ if (this.naturesIdsWorkingCopy.size() == originalNatureIds.size()
+ && this.naturesIdsWorkingCopy.containsAll(originalNatureIds)) {
+ return true;
+ }
+
+ // set nature ids
+ IRunnableWithProgress runnable = new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException {
+
+ try {
+ IProjectDescription description = project.getDescription();
+ description.setNatureIds(ProjectNaturesPage.this.naturesIdsWorkingCopy
+ .toArray(new String[ProjectNaturesPage.this.naturesIdsWorkingCopy.size()]));
+ project.setDescription(description, monitor);
+ } catch (CoreException e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+ };
+ try {
+ new ProgressMonitorJobsDialog(getControl().getShell()).run(true, true, runnable);
+ } catch (InterruptedException e) {
+ // Ignore interrupted exceptions
+ } catch (InvocationTargetException e) {
+ handle(e);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/messages.properties b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/messages.properties
new file mode 100644
index 0000000..ca68eb0
--- /dev/null
+++ b/bundles/org.eclipse.e4.ui.naturist/src/org/eclipse/ui/resources/natures/messages.properties
@@ -0,0 +1,20 @@
+################################################################################
+# Copyright (c) 2016 Red Hat Inc. and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# - Mickael Istria (Red Hat Inc) - [102527] Reshaped UI, based on builders
+################################################################################
+# --- Project Natures ---
+ProjectNaturesPage_label = Projects may have natures assigned to enable additional functionalities.\nUse this page to specify which natures should be assigned to the project.
+ProjectNaturesPage_missingNatureText = {0} (missing)
+ProjectNaturesPage_addNature = &Add...
+ProjectNaturesPage_removeNature = &Remove
+ProjectNaturesPage_selectNatureToAddMessage = Select a Nature to add to the Project
+ProjectNaturesPage_selectNatureToAddTitle = Select Nature
+ProjectNaturesPage_changeWarningTitle = Confirm Project Nature update
+ProjectNaturesPage_warningMessage = Modifying natures is an advanced operation that can leave the project in the state requiring further extensive and non-obvious configuration changes before normal function is achieved. Do not attempt without a recent backup of the project.
+ProjectNaturesPage_changeWarningQuestion = Continue?
diff --git a/pom.xml b/pom.xml
index 55bb67d..2db0d56 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,8 @@
<module>bundles/org.eclipse.e4.ui.importer.pde</module>
<module>tests/org.eclipse.e4.ui.importer.tests</module>
+ <module>bundles/org.eclipse.e4.ui.naturist</module>
+
<module>build/org.eclipse.e4.ui.update</module>
<module>bundles/org.eclipse.e4.ui.macros</module>