Bug 534155 - [SysML 1.4] Provide QuickFix for validation errors

 - create SysMLMarkerResolutionGenerator to dispatch resolutions for the
different issues
 - create ConsumerElementMarkerResolution a generic resolution wrapping
an <T extends UML element> consumer
 - add a logger
 - add quick fixes for the most basic constraints

Change-Id: If2050fdee51f387fc1796ebca8ee652d0e9a775e
Signed-off-by: Benoit Maggi <benoit.maggi@cea.fr>
diff --git a/core/org.eclipse.papyrus.sysml14.validation/META-INF/MANIFEST.MF b/core/org.eclipse.papyrus.sysml14.validation/META-INF/MANIFEST.MF
index 29f52ed..1fc753e 100644
--- a/core/org.eclipse.papyrus.sysml14.validation/META-INF/MANIFEST.MF
+++ b/core/org.eclipse.papyrus.sysml14.validation/META-INF/MANIFEST.MF
@@ -6,6 +6,7 @@
 Bundle-Version: 1.2.0.qualifier
 Bundle-Activator: org.eclipse.papyrus.sysml14.validation.Activator
 Require-Bundle: org.eclipse.core.resources;bundle-version="[3.9.0,4.0.0)",
+ org.eclipse.ui.ide;bundle-version="[3.13.1,4.0.0)",
  org.eclipse.emf.validation.ocl;bundle-version="[1.4.0,2.0.0)",
  org.eclipse.ocl.pivot;bundle-version="[1.1.0,2.0.0)",
  org.eclipse.ocl.pivot.uml;bundle-version="[1.1.0,2.0.0)",
@@ -13,6 +14,9 @@
  org.eclipse.ocl.ecore;bundle-version="[3.6.0,4.0.0)",
  org.eclipse.uml2.uml.validation;bundle-version="[5.0.0,6.0.0)",
  org.eclipse.papyrus.infra.services.validation;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.infra.ui;bundle-version="[2.0.0,3.0.0)",
+ org.eclipse.papyrus.infra.emf;bundle-version="[3.0.0,4.0.0)",
+ org.eclipse.papyrus.uml.tools;bundle-version="[3.0.0,4.0.0)", 
  org.eclipse.papyrus.uml.oclconstraintevaluation;bundle-version="[1.2.0,2.0.0)",
  org.eclipse.papyrus.uml.xtext.integration.validation;bundle-version="[2.0.0,3.0.0)",
  org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext;bundle-version="[1.2.0,2.0.0)",
@@ -22,6 +26,7 @@
 Bundle-Localization: plugin
 Export-Package: org.eclipse.papyrus.sysml14.validation,
  org.eclipse.papyrus.sysml14.validation.internal.utils,
+ org.eclipse.papyrus.sysml14.validation.quickfix,
  org.eclipse.papyrus.sysml14.validation.rules.activities,
  org.eclipse.papyrus.sysml14.validation.rules.allocations,
  org.eclipse.papyrus.sysml14.validation.rules.blocks,
diff --git a/core/org.eclipse.papyrus.sysml14.validation/plugin.xml b/core/org.eclipse.papyrus.sysml14.validation/plugin.xml
index a301134..1c901f4 100644
--- a/core/org.eclipse.papyrus.sysml14.validation/plugin.xml
+++ b/core/org.eclipse.papyrus.sysml14.validation/plugin.xml
@@ -1,6 +1,13 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?eclipse version="3.4"?>
 <plugin>
+<extension point="org.eclipse.ui.ide.markerResolution">
+      <markerResolutionGenerator
+         markerType="org.eclipse.emf.ecore.diagnostic"
+         class="org.eclipse.papyrus.sysml14.validation.quickfix.SysMLMarkerResolutionGenerator"/>
+   </extension>
+
+
   <extension name="org.eclipse.papyrus.sysml14.validation.constraintProviders" point="org.eclipse.emf.validation.constraintProviders">
      <category id="org.eclipse.papyrus.sysml14.validation.category.normative" mandatory="false" name="SysML 1.4 normative constraints">
      	Constraints listed in SysML 1.4 norm.
diff --git a/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/Activator.java b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/Activator.java
index 96e2219..7844e8c 100644
--- a/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/Activator.java
+++ b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/Activator.java
@@ -12,6 +12,8 @@
  *****************************************************************************/
 package org.eclipse.papyrus.sysml14.validation;
 
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
 
@@ -58,5 +60,28 @@
 	public static Activator getDefault() {
 		return plugin;
 	}
+	/**
+	 * Log the status
+	 * @param status
+	 */
+	public static void log(IStatus status) {
+		Activator.getDefault().getLog().log(status);
+	}
 
+	/**
+	 * Log the message
+	 * @param severity
+	 * @param message
+	 */
+	public static void log(int severity, String message) {
+		log(new Status(severity, PLUGIN_ID, message));
+	}	
+
+	/**
+	 * Log the exception
+	 * @param throwable
+	 */
+	public static void log(Throwable throwable) {
+		log(new Status(IStatus.ERROR, PLUGIN_ID, "An exception occured", throwable)); //$NON-NLS-1$
+	}
 }
diff --git a/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/ConsumerElementMarkerResolution.java b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/ConsumerElementMarkerResolution.java
new file mode 100644
index 0000000..81a2e31
--- /dev/null
+++ b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/ConsumerElementMarkerResolution.java
@@ -0,0 +1,81 @@
+/*****************************************************************************
+ * Copyright (c) 2018 CEA.
+ * 
+ * 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:
+ *  Benoit Maggi (CEA LIST) benoit.maggi@cea.fr - Initial API and implementation
+ *   
+ *****************************************************************************/
+package org.eclipse.papyrus.sysml14.validation.quickfix;
+
+import java.util.function.Consumer;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+import org.eclipse.papyrus.infra.ui.util.ServiceUtilsForHandlers;
+import org.eclipse.papyrus.sysml14.validation.Activator;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.uml2.uml.Element;
+
+/**
+ * A generic class to solve a problem with an UML element consumer very handy
+ * for simple use case
+ */
+public class ConsumerElementMarkerResolution<T extends Element> implements IMarkerResolution {
+
+	private String label;
+	private Consumer<T> consumer;
+
+	public ConsumerElementMarkerResolution(String label, Consumer<T> consumer) {
+		this.label = label;
+		this.consumer = consumer;
+	}
+
+	public String getLabel() {
+		return label;
+	}
+
+	public void run(IMarker marker) {
+		try {
+			Object uri = marker.getAttribute("uri");
+			if (uri instanceof String) {
+				ModelSet currentModelSet = ServiceUtilsForHandlers.getInstance().getModelSet(null);
+				EObject eObject = currentModelSet.getEObject(URI.createURI((String) uri), true);
+				if (eObject instanceof Element) {
+					Element element = (Element) eObject;
+					InternalTransactionalEditingDomain transactionalEditingDomain = (InternalTransactionalEditingDomain) ServiceUtilsForEObject
+							.getInstance().getTransactionalEditingDomain(element);
+					RecordingCommand unapplyStereotypeCommand = new RecordingCommand(transactionalEditingDomain,
+							label) {
+
+						@SuppressWarnings("unchecked")
+						@Override
+						protected void doExecute() {
+							try {
+								consumer.accept((T) element);
+							} catch (ClassCastException e) {
+								Activator.log(e); // When using generic ensure that the referenced element can be cast
+							}
+
+						}
+					};
+					transactionalEditingDomain.getCommandStack().execute(unapplyStereotypeCommand);
+					marker.delete();
+				}
+			}
+		} catch (ServiceException | CoreException e) {
+			Activator.log(e);
+		}
+	}
+}
\ No newline at end of file
diff --git a/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/SysMLMarkerResolutionGenerator.java b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/SysMLMarkerResolutionGenerator.java
new file mode 100644
index 0000000..e6c237a
--- /dev/null
+++ b/core/org.eclipse.papyrus.sysml14.validation/src/org/eclipse/papyrus/sysml14/validation/quickfix/SysMLMarkerResolutionGenerator.java
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Copyright (c) 2018 CEA.
+ * 
+ * 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:
+ *  Benoit Maggi (CEA LIST) benoit.maggi@cea.fr - Initial API and implementation
+ *   
+ *****************************************************************************/
+package org.eclipse.papyrus.sysml14.validation.quickfix;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.IMarkerResolutionGenerator;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Parameter;
+
+/**
+ * Provide the list of specific solutions for problems related to SysML 1.4
+ */
+public class SysMLMarkerResolutionGenerator implements IMarkerResolutionGenerator {
+
+	public IMarkerResolution[] getResolutions(IMarker mk) {
+		try {
+	        //mk.getAttributes().forEach((k,v)->System.out.println("(" + k + " , " + v+")"));
+			Object source = mk.getAttribute("source");
+			if (source instanceof String) {
+				switch ((String)source) {
+				case "org.eclipse.papyrus.sysml14.validation.constraint.discrete.nocontinuous": // See DiscreteNoContinuousModelConstraint
+					return new IMarkerResolution[] { 
+							new ConsumerElementMarkerResolution<Element>("Unapply stereotype Continuous", element -> element.unapplyStereotype(element.getAppliedStereotype("SysML::Activities::Continuous"))),
+							new ConsumerElementMarkerResolution<Element>("Unapply stereotype Discrete", element -> element.unapplyStereotype(element.getAppliedStereotype("SysML::Activities::Discrete"))),
+							};
+				case "org.eclipse.papyrus.sysml14.validation.constraint.requirement.emptyownedattribute":
+					return new IMarkerResolution[] {
+							new ConsumerElementMarkerResolution<Element>("Remove all attributes from Requirement", element -> element.getOwnedElements().forEach(Element::destroy)),
+							};
+				case "org.eclipse.papyrus.sysml14.validation.constraint.verify.supplier":
+					return new IMarkerResolution[] {
+							new ConsumerElementMarkerResolution<Element>("Delete element", Element::destroy),
+							};
+				case "org.eclipse.papyrus.sysml14.validation.constraint.rate.parameterisstream":
+					return new IMarkerResolution[] {
+							new ConsumerElementMarkerResolution<Parameter>("Set stream to true", parameter -> parameter.setIsStream(true)), 
+							};					
+				case "org.eclipse.papyrus.sysml14.validation.constraint.block.specialization":
+					return new IMarkerResolution[] {
+							new ConsumerElementMarkerResolution<Element>("Apply Block stereotype", element -> element.applyStereotype(element.getApplicableStereotype("SysML::Blocks::Block"))), 
+							};							
+					
+					
+				default:
+					break;
+				}
+			}
+		} catch (CoreException e) { // missing source of error => no resolution available
+			return new IMarkerResolution[0];
+		}
+		return new IMarkerResolution[0];
+	}
+}
\ No newline at end of file