Added extension point to support for unpacking selections from parts.

This change is made so that elements Capra can create traces to can be
extracted from ISelection instances that contain complex objects. Via
the new ISelectionSupport interface and the corresponding extension
points, plugins can register their own SelectionSupport clases that
take over the unwrapping.
SelectionSupportHelper will take over the functionality that has so
far been a part of TraceCreationHelper.

One example of this is the upcoming handler for Xtext. Xtext workbench
parts such as the Xtext editor and the outline part use selections that
contain instances of specialised Xtext classes. This means that  the
Xtext API must be used to extract the elements from the selection. In
order to avoid introducing dependencies to the Xtext framework into
the core Capra, an extension of the selection support extension point
will be used.

Signed-off-by: Dominique Blouin <dominique.blouin@laposte.net>
Change-Id: Iba72d37918474b7a6e0a0f1273a198de6fe2eaae
diff --git a/bundles/org.eclipse.capra.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.capra.ui/META-INF/MANIFEST.MF
index 368dc94..8e65903 100644
--- a/bundles/org.eclipse.capra.ui/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.capra.ui/META-INF/MANIFEST.MF
@@ -30,4 +30,5 @@
  org.eclipse.capra.ui.operations,
  org.eclipse.capra.ui.perspective,
  org.eclipse.capra.ui.preferences,
+ org.eclipse.capra.ui.selections,
  org.eclipse.capra.ui.views
diff --git a/bundles/org.eclipse.capra.ui/plugin.xml b/bundles/org.eclipse.capra.ui/plugin.xml
index cb0e45f..8f97461 100644
--- a/bundles/org.eclipse.capra.ui/plugin.xml
+++ b/bundles/org.eclipse.capra.ui/plugin.xml
@@ -155,4 +155,5 @@
 			schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" sequence="M2+DEL">
 		</key>
 	</extension>
+	<extension-point id="org.eclipse.capra.ui.selectionSupport" name="Selection Support" schema="schema/org.eclipse.capra.ui.selectionSupport.exsd"/>   
 </plugin>
diff --git a/bundles/org.eclipse.capra.ui/schema/org.eclipse.capra.ui.selectionSupport.exsd b/bundles/org.eclipse.capra.ui/schema/org.eclipse.capra.ui.selectionSupport.exsd
new file mode 100644
index 0000000..e79973e
--- /dev/null
+++ b/bundles/org.eclipse.capra.ui/schema/org.eclipse.capra.ui.selectionSupport.exsd
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.capra.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.capra.ui" id="org.eclipse.capra.ui.selectionSupport" name="Eclipse Capra Selection Support"/>
+      </appinfo>
+      <documentation>
+         Defines support for extracting elements from selections in WorkbenchPart instances.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <choice minOccurs="1" maxOccurs="unbounded">
+            <element ref="selectionSupport"/>
+         </choice>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="selectionSupport">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.capra.ui.selections.ISelectionSupport"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         0.7.2
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+
+</schema>
diff --git a/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/helpers/SelectionSupportHelper.java b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/helpers/SelectionSupportHelper.java
new file mode 100644
index 0000000..dbe776f
--- /dev/null
+++ b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/helpers/SelectionSupportHelper.java
@@ -0,0 +1,170 @@
+/*******************************************************************************

+ * Copyright (c) 2016, 2019 Chalmers | University of Gothenburg, rt-labs, IRT SystemX, and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v2.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v20.html

+ *  

+ * SPDX-License-Identifier: EPL-2.0

+ *  

+ * Contributors:

+ *      IRT SystemX - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.capra.ui.helpers;

+

+import java.util.ArrayList;

+import java.util.List;

+

+import org.eclipse.capra.core.helpers.ExtensionPointHelper;

+import org.eclipse.capra.ui.selections.ISelectionSupport;

+import org.eclipse.core.commands.ExecutionEvent;

+import org.eclipse.core.runtime.IAdaptable;

+import org.eclipse.emf.ecore.resource.ResourceSet;

+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;

+import org.eclipse.emf.edit.domain.IEditingDomainProvider;

+import org.eclipse.jface.viewers.ISelection;

+import org.eclipse.jface.viewers.IStructuredSelection;

+import org.eclipse.ui.IWorkbenchPart;

+import org.eclipse.ui.handlers.HandlerUtil;

+import org.eclipse.ui.part.WorkbenchPart;

+import org.eclipse.ui.views.properties.PropertySheet;

+

+/**

+ * A helper for extracting semantic elements from a selection of a workbench

+ * part. Handles the workbench part handler extensions.

+ * 

+ * @author Dominique Blouin

+ *

+ */

+public class SelectionSupportHelper {

+

+	private static final List<ISelectionSupport> SELECTION_SUPPORTS = new ArrayList<ISelectionSupport>();

+

+	static {

+		for (Object extension : ExtensionPointHelper.getExtensions("org.eclipse.capra.ui.selectionSupport",

+				"class")) {

+			SELECTION_SUPPORTS.add((ISelectionSupport) extension);

+		}

+	}

+

+	private SelectionSupportHelper() {

+	}

+

+	/**

+	 * Extract selected elements from an {@link ExecutionEvent}.

+	 * 

+	 * @param event

+	 *            This is the click event to create a trace

+	 * @return A list of all the selected elements

+	 */

+	public static List<Object> extractSelectedElements(final ExecutionEvent event) {

+		final IWorkbenchPart workbenchPart = HandlerUtil.getActivePart(event);

+		final ISelection currentSelection;

+

+		// For some reason HandlerUtil.getCurrentSelection(event) returns the

+		// previous selection in some cases so we look for

+		// the selection from the selection provider first

+		if (workbenchPart.getSite().getSelectionProvider() != null) {

+			currentSelection = workbenchPart.getSite().getSelectionProvider().getSelection();

+		} else {

+			currentSelection = HandlerUtil.getCurrentSelection(event);

+		}

+

+		return extractSelectedElements(currentSelection, workbenchPart);

+	}

+

+	/**

+	 * Extract selected elements from an {@link ISelection} by delegating the

+	 * retrieval and unwrapping of the selection to the registered

+	 * {@link ISelectionSupport} instances. If this fails, the selected

+	 * elements of type {@link IAdaptable} are retrieved using

+	 * {@link IAdaptable#getAdapter(Class)}. If this fails, too, the list is

+	 * either empty or only contains those elements that are instances of type

+	 * {@code IAdaptable}.

+	 * 

+	 * @param selection

+	 *            the selection from the workbench part

+	 * @param workbenchPart

+	 *            the workbench part from which the selection should be

+	 *            extracted

+	 * @return a list of all selected elements retrieved using the first

+	 *         {@code IWorkbenchSelectionSupport} instance registered for the

+	 *         {@code WorkbenchPart} or all selected elements of type

+	 *         {@code IAdaptable}

+	 */

+	public static List<Object> extractSelectedElements(final ISelection selection, final IWorkbenchPart workbenchPart) {

+		List<Object> selectedElem = new ArrayList<>();

+

+		for (final ISelectionSupport handler : SELECTION_SUPPORTS) {

+			if (handler.supportsWorkbenchPart(workbenchPart)) {

+				List<Object> extractedElements = handler.extractSelectedElements(selection, workbenchPart);

+				if (extractedElements != null) {

+					selectedElem.addAll(extractedElements);

+					break;

+				}

+			}

+		}

+

+		if (selectedElem.isEmpty()) {

+			selectedElem = new ArrayList<>();

+

+			if (selection instanceof IStructuredSelection) {

+				for (final Object selElement : ((IStructuredSelection) selection).toList()) {

+					final Object element = AdapterFactoryEditingDomain.unwrap(selElement);

+					Object selectedElement = element;

+

+					if (element instanceof IAdaptable) {

+						final Object adaptedElement = ((IAdaptable) element).getAdapter(Object.class);

+

+						if (adaptedElement != null) {

+							selectedElement = adaptedElement;

+						}

+					}

+

+					selectedElem.add(selectedElement);

+				}

+			}

+		}

+

+		return selectedElem;

+	}

+

+	/**

+	 * Attempts to retrieve the {@link ResourceSet} instance that is used by the

+	 * {@link WorkbenchPart}. The {@code ResourceSet} is only available if the

+	 * {@code WorkbenchPart} handles EMF models. If this is not the case, this

+	 * method returns {@code null}.

+	 * 

+	 * @param part

+	 *            the {@code WorkbenchPart} whose {@code ResourceSet} should be

+	 *            retrieved

+	 * @return the {@code ResourceSet} used by {@code part} or {@code null} if

+	 *         no {@code ResourceSet} can be found

+	 */

+	public static ResourceSet getResourceSet(final IWorkbenchPart part) {

+		ResourceSet resourceSet = null;

+		if (!(part instanceof PropertySheet)) {

+			// Iterate over the WorkbenchPartHandlers and find one that can take

+			// care of the part

+			for (final ISelectionSupport handler : SELECTION_SUPPORTS) {

+				if (handler.supportsWorkbenchPart(part)) {

+					final ResourceSet resSet = handler.getResourceSet(part);

+					if (resSet != null) {

+						resourceSet = resSet;

+					}

+				}

+

+			}

+			// If that fails, see if we can get the resource set from the

+			// EditingDomain

+			if (resourceSet == null) {

+				final IEditingDomainProvider domainProvider = part.getAdapter(IEditingDomainProvider.class);

+

+				if (domainProvider != null) {

+					return domainProvider.getEditingDomain().getResourceSet();

+				}

+			}

+		}

+		return resourceSet;

+	}

+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/selections/ISelectionSupport.java b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/selections/ISelectionSupport.java
new file mode 100644
index 0000000..d981acb
--- /dev/null
+++ b/bundles/org.eclipse.capra.ui/src/org/eclipse/capra/ui/selections/ISelectionSupport.java
@@ -0,0 +1,69 @@
+/*******************************************************************************

+ * Copyright (c) 2016, 2019 Chalmers | University of Gothenburg, rt-labs, IRT SystemX, and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v2.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v20.html

+ *  

+ * SPDX-License-Identifier: EPL-2.0

+ *  

+ * Contributors:

+ *      IRT SystemX - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.capra.ui.selections;

+

+import java.util.List;

+

+import org.eclipse.emf.ecore.resource.ResourceSet;

+import org.eclipse.jface.viewers.ISelection;

+import org.eclipse.ui.IWorkbenchPart;

+import org.eclipse.ui.part.WorkbenchPart;

+

+/**

+ * Interface for supporting selections in {@link WorkbenchPart} instances. This

+ * allows customization of how semantic objects are extracted from an

+ * {@link ISelection} and is useful when, e.g., the selection contains wrapper

+ * objects that need to be resolved.

+ * 

+ * @author Dominique Blouin

+ *

+ */

+public interface ISelectionSupport {

+

+	/**

+	 * Checks if the given {@link WorkbenchPart} instance is supported.

+	 * 

+	 * @param workbenchPart

+	 *            the workbench part

+	 * @return {@code true} if this handler supports the given workbench part,

+	 *         {@code false} otherwise.

+	 */

+	boolean supportsWorkbenchPart(IWorkbenchPart workbenchPart);

+

+	/**

+	 * Extracts objects from an {@link ISelection}, resolving or unwrapping them

+	 * when necessary to return types that can be handled by one of the Capra

+	 * handlers.

+	 * 

+	 * @param selection

+	 *            the selection from the workbench part

+	 * @param workbenchPart

+	 *            the workbench part

+	 * @return a list of the selected elements

+	 */

+	List<Object> extractSelectedElements(ISelection selection, IWorkbenchPart workbenchPart);

+

+	/**

+	 * Attempts to retrieve the {@link ResourceSet} instance that is used by the

+	 * {@link WorkbenchPart}. The {@code ResourceSet} is only available if the

+	 * {@code WorkbenchPart} handles EMF models. If this is not the case, this

+	 * method returns {@code null}.

+	 * 

+	 * @param workbenchPart

+	 *            the {@code WorkbenchPart} whose {@code ResourceSet} should be

+	 *            retrieved

+	 * @return the {@code ResourceSet} used by {@code part} or {@code null} if

+	 *         no {@code ResourceSet} can be found

+	 */

+	ResourceSet getResourceSet(IWorkbenchPart workbenchPart);

+}