Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2014-04-09 22:53:30 +0000
committerChristian W. Damus2014-04-15 17:49:12 +0000
commit5ebf7f2fb8d1734fa7e18638df56ff8ce07be53f (patch)
tree1177a2e7a5023af2f8c760d996da57ddc6155c13 /plugins/uml
parenta69ae2b062345500a8aefc6c90d5795ecda3302b (diff)
downloadorg.eclipse.papyrus-5ebf7f2fb8d1734fa7e18638df56ff8ce07be53f.tar.gz
org.eclipse.papyrus-5ebf7f2fb8d1734fa7e18638df56ff8ce07be53f.tar.xz
org.eclipse.papyrus-5ebf7f2fb8d1734fa7e18638df56ff8ce07be53f.zip
431953: Stereotype garbage left in .uml file after removing profile (crash reason?)
https://bugs.eclipse.org/bugs/show_bug.cgi?id=431953 Implement a model-set snippet that detects and repairs (with user interaction) stereotype applications that either are not described by any profile application in the context of the a resource's root element when a resource is loaded. Includes refactoring of the UI and back-end of the Switch Profiles functionality. Cases of broken stereotypes include: - instances of EClasses from a different version of the profile's Ecore definition than what is currently applied - instances of EClasses from a profile that is not applied at all - instances of EClasses from a profile that may be applied but which is unresolved (no longer exists at its former location)
Diffstat (limited to 'plugins/uml')
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF1
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml7
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java367
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/AbstractRepairAction.java38
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java116
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/CreateMarkersAction.java72
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/DeleteAction.java47
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/IRepairAction.java98
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeApplicationRepairSnippet.java237
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java152
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesBlock.java207
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesDialog.java141
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java142
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypeDialogPresenter.java159
-rw-r--r--plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypesDialog.java473
15 files changed, 2113 insertions, 144 deletions
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
index 1c597de351a..55c14b8b9b8 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/META-INF/MANIFEST.MF
@@ -2,6 +2,7 @@ Manifest-Version: 1.0
Export-Package: org.eclipse.papyrus.uml.modelrepair,
org.eclipse.papyrus.uml.modelrepair.handler,
org.eclipse.papyrus.uml.modelrepair.internal.participants;x-internal:=true,
+ org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;x-internal:=true,
org.eclipse.papyrus.uml.modelrepair.ui,
org.eclipse.papyrus.uml.modelrepair.ui.providers
Require-Bundle: org.eclipse.ui,
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
index bd9c361fecd..1445b6a5011 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/plugin.xml
@@ -110,5 +110,12 @@
class="org.eclipse.papyrus.uml.modelrepair.internal.participants.StereotypeApplicationRepairParticipant">
</replaceParticipant>
</extension>
+ <extension
+ point="org.eclipse.papyrus.infra.core.model">
+ <modelSetSnippet
+ classname="org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.StereotypeApplicationRepairSnippet"
+ description="Initiates repair of zombie stereotype applications on load of a UML resource.">
+ </modelSetSnippet>
+ </extension>
</plugin>
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
index eaca8e89c36..5173794b52e 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/participants/StereotypeApplicationRepairParticipant.java
@@ -15,6 +15,7 @@ package org.eclipse.papyrus.uml.modelrepair.internal.participants;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
@@ -23,8 +24,12 @@ import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAnnotation;
+import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
@@ -34,6 +39,11 @@ import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.ExtendedMetaData;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.ecore.xmi.XMLResource;
+import org.eclipse.emf.ecore.xml.type.AnyType;
+import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.papyrus.infra.emf.resource.IDependencyReplacementParticipant;
import org.eclipse.papyrus.infra.emf.resource.Replacement;
import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
@@ -47,6 +57,7 @@ import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.ProfileApplication;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.internal.operations.PackageOperations;
+import org.eclipse.uml2.uml.util.UMLUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -123,8 +134,6 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
}
}
- EcoreUtil.Copier copier = new StereotypeApplicationRepairCopier(newProfile, diagnostics);
-
List<EObject> oldStereotypeApplications = Lists.newArrayList();
for(TreeIterator<EObject> iter = getAllContents(applyingPackage, true, false); iter.hasNext();) {
EObject element = iter.next();
@@ -137,14 +146,6 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
// Looks like a stereotype application. Do we need to rebuild it?
if(owner.eClass().getEPackage() == oldDefinition) {
oldStereotypeApplications.add(owner);
- EObject newInstance = copier.copy(owner);
- if((newInstance != null) && (newInstance != owner)) {
- // Depends how we copied the stereotype instance (by applying again or not),
- // it may not be attached, yet
- if(newInstance.eResource() == null) {
- EcoreUtil.replace(owner, newInstance);
- }
- }
}
}
}
@@ -154,9 +155,7 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
}
}
- copier.copyReferences();
-
- UML2Util.destroyAll(oldStereotypeApplications);
+ createStereotypeApplicationMigrator(newProfile, diagnostics).migrate(oldStereotypeApplications);
if(!newProfile.getOwnedExtensions(true).isEmpty()) {
// Ensure that required stereotypes of the new profile are applied
@@ -197,14 +196,48 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
return result;
}
+ public static StereotypeApplicationMigrator createStereotypeApplicationMigrator(Profile profile, DiagnosticChain diagnostics) {
+ return new StereotypeApplicationMigrator(profile, diagnostics);
+ }
+
//
// Nested types
//
+ public static class StereotypeApplicationMigrator {
+
+ private StereotypeApplicationRepairCopier copier;
+
+ StereotypeApplicationMigrator(Profile profile, DiagnosticChain diagnostics) {
+ copier = new StereotypeApplicationRepairCopier(profile, diagnostics);
+ }
+
+ public void migrate(Collection<? extends EObject> stereotypeApplications) {
+ for(EObject next : stereotypeApplications) {
+ EObject newInstance = copier.copy(next);
+ if((newInstance != null) && (newInstance != next)) {
+ // Depends how we copied the stereotype instance (by applying again or not),
+ // it may not be attached, yet
+ if(newInstance.eResource() == null) {
+ EcoreUtil.replace(next, newInstance);
+ }
+ }
+ }
+
+ copier.copyReferences();
+
+ UML2Util.destroyAll(stereotypeApplications);
+
+ copier.clear();
+ }
+ }
+
protected static class StereotypeApplicationRepairCopier extends StereotypeApplicationCopier {
private static final long serialVersionUID = 1L;
+ private final Pattern whitespace = Pattern.compile("\\s+"); //$NON-NLS-1$
+
private final DiagnosticChain diagnostics;
private EObject copying;
@@ -222,7 +255,7 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
@Override
public EObject copy(EObject eObject) {
final EObject previousCopying = copying;
-
+
try {
copying = eObject;
return super.copy(eObject);
@@ -230,19 +263,275 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
copying = previousCopying;
}
}
-
+
+ @Override
+ protected NamedElement getNamedElement(ENamedElement element) {
+ if(element instanceof EClassifier) {
+ EClassifier classifier = (EClassifier)element;
+ // Handle case of unrecognized schema
+ if(isUnrecognizedSchema(classifier.getEPackage()) && (profile.getDefinition() != null)) {
+ // It's unrecognized content. Force look-up in the profile chosen by the user
+ EClassifier force = profile.getDefinition().getEClassifier(classifier.getName());
+ if(force != null) {
+ element = force;
+ }
+ }
+ } else if(element instanceof EStructuralFeature) {
+ EStructuralFeature feature = (EStructuralFeature)element;
+ // Handle case of unrecognized schema
+ if(isUnrecognizedSchema(feature.getEContainingClass().getEPackage()) && (profile.getDefinition() != null)) {
+ EClassifier classifier = profile.getDefinition().getEClassifier(feature.getEContainingClass().getName());
+ if(classifier instanceof EClass) {
+ EStructuralFeature force = ((EClass)classifier).getEStructuralFeature(element.getName());
+ if(force != null) {
+ element = force;
+ }
+ }
+ }
+ }
+
+ return super.getNamedElement(element);
+ }
+
+ protected boolean isUnrecognizedSchema(EPackage ePackage) {
+ boolean result;
+
+ if(copying != null) {
+ result = getExtendedMetadata(copying).demandedPackages().contains(ePackage);
+ } else {
+ // Simple heuristic: unknown-schema packages don't have names, but profile-defined packages always do
+ result = (ePackage.getName() == null);
+ }
+
+ return result;
+ }
+
+ protected ExtendedMetaData getExtendedMetadata(EObject context) {
+ ExtendedMetaData result = ExtendedMetaData.INSTANCE;
+
+ Resource resource = context.eResource();
+ if(resource instanceof XMLResource) {
+ Object option = ((XMLResource)resource).getDefaultSaveOptions().get(XMLResource.OPTION_EXTENDED_META_DATA);
+ if(option instanceof ExtendedMetaData) {
+ result = (ExtendedMetaData)option;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject) {
+ if(copyEObject == null) {
+ // We couldn't find the corresponding stereotype/class/datatype in the profile, so it is dropped and we can't copy any properties
+ return;
+ }
+
+ if(eAttribute == XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE) {
+ // The 'anyAttribute' feature-map only appears in unknown schema content
+ copyUnrecognizedContentAnyAttribute(eAttribute, eObject, copyEObject);
+ } else if(eAttribute == XMLTypePackage.Literals.ANY_TYPE__MIXED) {
+ // UML stereotype applications will not have arbitrarily mixed content, but nested objects (further AnyTypes)
+ // and elements for multi-valued attributes will appear in this feature map
+ copyUnrecognizedContentMixed(eAttribute, eObject, copyEObject);
+ } else {
+ super.copyAttribute(eAttribute, eObject, copyEObject);
+ }
+ }
+
+ protected void copyUnrecognizedContentAnyAttribute(EAttribute anyAttribute, EObject eObject, EObject copyEObject) {
+ FeatureMap featureMap = (FeatureMap)eObject.eGet(anyAttribute);
+ for(FeatureMap.Entry next : featureMap) {
+ EStructuralFeature f = next.getEStructuralFeature();
+
+ EStructuralFeature copyFeature = copyEObject.eClass().getEStructuralFeature(f.getName());
+ if(copyFeature instanceof EReference) {
+ // values in the XMI will be IDREFs or HREFs
+ String refs = String.valueOf(next.getValue());
+ for(String ref : whitespace.split(refs)) {
+ EObject referenced = resolveRef(eObject, ref);
+ if(referenced == null) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Unresolved reference in stereotype property %s: %s", propertyName, ref))); //$NON-NLS-1$
+ } else if(!copyFeature.getEType().isInstance(referenced)) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
+ } else {
+ eAdd(copyEObject, copyFeature, referenced);
+ }
+ }
+ } else if(copyFeature instanceof EAttribute) {
+ // values in the XMI will be string serializations of data types
+ EDataType dataType = ((EAttribute)copyFeature).getEAttributeType();
+
+ try {
+ Object value = EcoreUtil.createFromString(dataType, String.valueOf(next.getValue()));
+ eAdd(copyEObject, copyFeature, value);
+ } catch (Exception e) {
+ handleException(e);
+ }
+ } else {
+ // feature not matched. Because this is unknown schema, the Ecore feature's actual qualified name is useless
+ // (it's something like '{EPackage}::DocumentRoot::foo')
+ String qualifiedName = String.format("%s::%s", UMLUtil.getNamedElement(copyEObject.eClass(), eObject).getName(), f.getName());
+ handleException(new IllegalStateException(String.format("Definition for property '%s' not found in profile '%s'", qualifiedName, getQualifiedName(profile)))); //$NON-NLS-1$
+ }
+ }
+ }
+
+ protected void eAdd(EObject owner, EStructuralFeature feature, Object value) {
+ if(feature.isChangeable() && !feature.isDerived()) {
+ if(feature.isMany()) {
+ @SuppressWarnings("unchecked")
+ Collection<Object> list = (Collection<Object>)owner.eGet(feature);
+ list.add(value);
+ } else {
+ owner.eSet(feature, value);
+ }
+ }
+ }
+
+ protected EObject resolveRef(EObject anyType, String ref) {
+ Resource baseResource = anyType.eResource();
+
+ URI uri;
+ if(ref.contains("#")) {
+ // HREF case
+ uri = baseResource.getURI().resolve(URI.createURI(ref));
+ } else {
+ // IDREF case
+ uri = baseResource.getURI().appendFragment(ref);
+ }
+
+ return baseResource.getResourceSet().getEObject(uri, true);
+ }
+
+ protected void copyUnrecognizedContentMixed(EAttribute mixed, EObject eObject, EObject copyEObject) {
+ FeatureMap featureMap = (FeatureMap)eObject.eGet(mixed);
+ for(FeatureMap.Entry next : featureMap) {
+ EStructuralFeature f = next.getEStructuralFeature();
+
+ // UML stereotypes do not use comments, arbitrary mixed text, processing instructions, etc.
+ if(f.getEContainingClass() != XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT) {
+ // The incoming thing is an element of some kind
+ if(f instanceof EReference) {
+ EObject anyType = (EObject)next.getValue();
+ EStructuralFeature copyFeature = copyEObject.eClass().getEStructuralFeature(f.getName());
+ if(copyFeature instanceof EAttribute) {
+ // Get the text value of the element, convert it to the appropriate data type, and set it into the attribute
+ try {
+ String text = getTextContent(anyType);
+ if(text != null) {
+ EDataType dataType = ((EAttribute)copyFeature).getEAttributeType();
+ Object value = EcoreUtil.createFromString(dataType, text);
+ eAdd(copyEObject, copyFeature, value);
+ }
+ } catch (Exception e) {
+ handleException(e);
+ }
+ } else if(copyFeature instanceof EReference) {
+ EReference reference = (EReference)copyFeature;
+ if(!reference.isContainment()) {
+ // Get the HREF/IDREF from the element, resolve the referenced object, and set it into the reference
+ String refs = getTextContent(anyType);
+ if(refs != null) {
+ for(String ref : whitespace.split(refs)) {
+ EObject referenced = resolveRef(eObject, ref);
+ if(referenced == null) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Unresolved reference in stereotype property %s: %s", propertyName, ref))); //$NON-NLS-1$
+ } else if(!copyFeature.getEType().isInstance(referenced)) {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(copyFeature, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to reference object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(referenced.eClass()), propertyName))); //$NON-NLS-1$
+ } else {
+ eAdd(copyEObject, reference, referenced);
+ }
+ }
+ }
+ } else {
+ // Handle the contained object
+ EObject containedCopy = copy(anyType);
+ if(containedCopy != null) {
+ if(reference.getEReferenceType().isInstance(containedCopy)) {
+ eAdd(copyEObject, reference, containedCopy);
+ } else {
+ String propertyName = getQualifiedName(UMLUtil.getNamedElement(reference, eObject));
+ handleException(new IllegalStateException(String.format("Attempt to contain object of type %s in stereotype property %s", UML2EcoreConverter.getOriginalName(containedCopy.eClass()), propertyName))); //$NON-NLS-1$
+ }
+ }
+ }
+ } else {
+ // feature not matched. Because this is unknown schema, the Ecore feature's actual qualified name is useless
+ // (it's something like '{EPackage}::DocumentRoot::foo')
+ String qualifiedName = String.format("%s::%s", UMLUtil.getNamedElement(copyEObject.eClass(), eObject).getName(), f.getName());
+ handleException(new IllegalStateException(String.format("Definition for property '%s' not found in profile '%s'", qualifiedName, getQualifiedName(profile)))); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+
+ protected String getTextContent(EObject anyType) {
+ String result = null;
+
+ Object value = anyType.eGet(XMLTypePackage.Literals.XML_TYPE_DOCUMENT_ROOT__TEXT);
+ if(value instanceof String) {
+ result = (String)value;
+ } else if(value instanceof List<?>) {
+ List<?> list = (List<?>)value;
+ if(!list.isEmpty()) {
+ result = (String)list.get(0);
+ }
+ }
+
+ return result;
+ }
+
@Override
protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject) {
- final EObject previousCopying = copying;
-
- try {
- copying = eObject;
- super.copyReference(eReference, eObject, copyEObject);
- } finally {
- copying = previousCopying;
+ if(copyEObject != null) {
+ final EObject previousCopying = copying;
+
+ try {
+ copying = eObject;
+ super.copyReference(eReference, eObject, copyEObject);
+ } finally {
+ copying = previousCopying;
+ }
+ } // Else we couldn't find the corresponding stereotype/class/datatype in the profile, so it is dropped and we can't copy any properties
+ }
+
+ @Override
+ protected void copyProxyURI(EObject eObject, EObject copyEObject) {
+ if(copyEObject != null) {
+ super.copyProxyURI(eObject, copyEObject);
+ } // Else we couldn't find the corresponding stereotype/class/datatype in the profile, so it is dropped and we can't copy the proxy URI
+ }
+
+ /**
+ * Override the EMF implementation to skip feature-maps, because we do not use them in UML Profiles.
+ */
+ @Override
+ public void copyReferences() {
+ for(Map.Entry<EObject, EObject> entry : entrySet()) {
+ EObject eObject = entry.getKey();
+ EObject copyEObject = entry.getValue();
+ EClass eClass = eObject.eClass();
+
+ for(int i = 0, size = eClass.getFeatureCount(); i < size; ++i) {
+ EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i);
+ if(eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived()) {
+ if(eStructuralFeature instanceof EReference) {
+ EReference eReference = (EReference)eStructuralFeature;
+ if(!eReference.isContainment() && !eReference.isContainer()) {
+ copyReference(eReference, eObject, copyEObject);
+ }
+ }
+ }
+ }
}
}
-
+
@Override
protected EObject createCopy(EObject eObject) {
try {
@@ -276,7 +565,7 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
Object[] data = null;
if(copying != null) {
- Element base = (copying == null) ? null : getBaseElement(copying);
+ Element base = (copying == null) ? null : (copying instanceof AnyType) ? guessAnyTypeBaseElement(copying) : getBaseElement(copying);
if(base != null) {
data = new Object[]{ base };
} else {
@@ -289,6 +578,36 @@ public class StereotypeApplicationRepairParticipant extends PackageOperations im
super.handleException(exception);
}
}
+
+ protected Element guessAnyTypeBaseElement(EObject anyType) {
+ Element result = null;
+
+ // The base_Xyz extension end is always at most one, so it should be serialized as an IDREF
+ for(FeatureMap.Entry next : (FeatureMap)anyType.eGet(XMLTypePackage.Literals.ANY_TYPE__ANY_ATTRIBUTE)) {
+ if(next.getEStructuralFeature().getName().startsWith("base_")) {
+ EObject referenced = resolveRef(anyType, String.valueOf(next.getValue()));
+ if(referenced instanceof Element) {
+ result = (Element)referenced;
+ break;
+ }
+ }
+ }
+
+ // But, if it's a cross-doc reference, it will be an HREF and thus probably an element
+ if(result == null) {
+ for(FeatureMap.Entry next : (FeatureMap)anyType.eGet(XMLTypePackage.Literals.ANY_TYPE__MIXED)) {
+ if((next.getEStructuralFeature() instanceof EReference) && next.getEStructuralFeature().getName().startsWith("base_")) {
+ EObject referenced = resolveRef(anyType, getTextContent((EObject)next.getValue()));
+ if(referenced instanceof Element) {
+ result = (Element)referenced;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+ }
private static NamedElement findNamedElement(NamedElement search, String qualifiedName, EClass metaclass) {
NamedElement result = null;
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/AbstractRepairAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/AbstractRepairAction.java
new file mode 100644
index 00000000000..6f72a1a82ba
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/AbstractRepairAction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import org.eclipse.uml2.uml.util.UMLUtil;
+
+
+
+/**
+ * This is the AbstractRepairAction type. Enjoy.
+ */
+abstract class AbstractRepairAction extends UMLUtil implements IRepairAction {
+
+ private final Kind kind;
+
+ protected AbstractRepairAction(Kind kind) {
+ this.kind = kind;
+ }
+
+ public Kind kind() {
+ return kind;
+ }
+
+ public boolean isNull() {
+ return kind() == null;
+ }
+
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java
new file mode 100644
index 00000000000..c7d456a8400
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ApplyProfileAction.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForEObject;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.services.labelprovider.service.impl.LabelProviderServiceImpl;
+import org.eclipse.papyrus.uml.modelrepair.Activator;
+import org.eclipse.papyrus.uml.modelrepair.internal.participants.StereotypeApplicationRepairParticipant;
+import org.eclipse.papyrus.uml.modelrepair.ui.BrowseProfilesDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.base.Supplier;
+
+
+/**
+ * This is the ApplyProfileAction type. Enjoy.
+ */
+public class ApplyProfileAction extends AbstractRepairAction {
+
+ private final Element root;
+
+ private Supplier<Profile> profileSupplier;
+
+ public ApplyProfileAction(Element root, Supplier<Profile> profileSupplier) {
+ super(Kind.APPLY_LATEST_PROFILE_DEFINITION);
+
+ this.root = root;
+ this.profileSupplier = profileSupplier;
+ }
+
+ public boolean repair(Resource resource, EPackage profileDefinition, Collection<? extends EObject> stereotypeApplications, DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ Profile profile = profileSupplier.get();
+ if(profile == null) {
+ return false;
+ }
+
+ // Get the topmost package
+ Package topPackage = root.getNearestPackage();
+ for(Element higher = topPackage; higher != null; higher = higher.getOwner()) {
+ Package next = higher.getNearestPackage();
+ if(next != null) {
+ topPackage = next;
+ }
+ higher = next;
+ }
+
+ // Apply the profile
+ if(topPackage != null) {
+ StereotypeApplicationRepairParticipant.createStereotypeApplicationMigrator(profile, diagnostics).migrate(stereotypeApplications);
+ topPackage.applyProfile(profile);
+ }
+
+ return true;
+ }
+
+ protected Profile promptForProfile(Shell parentShell) {
+ Profile result = null;
+
+ LabelProviderService labelProvider = null;
+ boolean localProvider = false;
+ try {
+ labelProvider = ServiceUtilsForEObject.getInstance().getService(LabelProviderService.class, root);
+ } catch (ServiceException e) {
+ labelProvider = new LabelProviderServiceImpl();
+ localProvider = true;
+ }
+
+ final BrowseProfilesDialog dlg = new BrowseProfilesDialog(parentShell, labelProvider);
+
+ parentShell.getDisplay().syncExec(new Runnable() {
+
+ public void run() {
+ dlg.setBlockOnOpen(true);
+ dlg.open();
+ }
+ });
+
+ if(localProvider) {
+ try {
+ labelProvider.disposeService();
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ }
+
+ if(dlg.getSelectedProfileURI() != null) {
+ result = UML2Util.load(root.eResource().getResourceSet(), dlg.getSelectedProfileURI(), UMLPackage.Literals.PROFILE);
+ }
+
+ return result;
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/CreateMarkersAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/CreateMarkersAction.java
new file mode 100644
index 00000000000..6739708d997
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/CreateMarkersAction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.papyrus.infra.services.markerlistener.providers.IMarkerProvider;
+import org.eclipse.papyrus.infra.services.markerlistener.util.MarkerListenerUtils;
+import org.eclipse.papyrus.uml.modelrepair.Activator;
+
+
+/**
+ * This is the CreateMarkersAction type. Enjoy.
+ */
+public class CreateMarkersAction extends AbstractRepairAction {
+
+ static final CreateMarkersAction INSTANCE = new CreateMarkersAction();
+
+ private CreateMarkersAction() {
+ super(Kind.CREATE_MARKERS);
+ }
+
+ public boolean repair(Resource resource, EPackage profileDefinition, Collection<? extends EObject> stereotypeApplications, DiagnosticChain problems, IProgressMonitor monitor) {
+ List<IMarkerProvider> providers = MarkerListenerUtils.getMarkerProviders(resource);
+ if(!providers.isEmpty()) {
+ IMarkerProvider provider = providers.get(0);
+ BasicDiagnostic diagnostics = new BasicDiagnostic();
+
+ for(EObject next : stereotypeApplications) {
+ EObject subject = getBaseElement(next);
+ if(subject == null) {
+ // OK, apply it to the application, instead
+ subject = next;
+ }
+
+ diagnostics.add(new BasicDiagnostic(Diagnostic.WARNING, Activator.PLUGIN_ID, 0, "Obsolete application of stereotype " + UML2EcoreConverter.getOriginalName(next.eClass()), new Object[]{ subject, next }));
+ }
+
+ try {
+ provider.createMarkers(resource, diagnostics, monitor);
+ } catch (CoreException e) {
+ if(problems == null) {
+ Activator.log.error(e);
+ } else {
+ problems.add(BasicDiagnostic.toDiagnostic(e.getStatus()));
+ }
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/DeleteAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/DeleteAction.java
new file mode 100644
index 00000000000..e39eb511902
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/DeleteAction.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+
+
+/**
+ * This is the DeleteAction type. Enjoy.
+ */
+public class DeleteAction extends AbstractRepairAction {
+
+ static final DeleteAction INSTANCE = new DeleteAction();
+
+ private DeleteAction() {
+ super(Kind.DELETE);
+ }
+
+ public boolean repair(Resource resource, EPackage profileDefinition, Collection<? extends EObject> stereotypeApplications, DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ monitor = SubMonitor.convert(monitor, stereotypeApplications.size());
+
+ for(EObject next : stereotypeApplications) {
+ destroy(next);
+ monitor.worked(1);
+ }
+
+ return true;
+ }
+
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/IRepairAction.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/IRepairAction.java
new file mode 100644
index 00000000000..ea6f2b61fbc
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/IRepairAction.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import com.google.common.base.Predicate;
+
+
+/**
+ * This is the IRepairAction type. Enjoy.
+ */
+public interface IRepairAction {
+
+ IRepairAction NO_OP = new IRepairAction() {
+
+ public Kind kind() {
+ return Kind.NO_OP;
+ }
+
+ public boolean isNull() {
+ return false;
+ }
+
+ public boolean repair(Resource resource, EPackage profileDefinition, java.util.Collection<? extends EObject> stereotypeApplications, DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ return true;
+ }
+ };
+
+ IRepairAction NULL = new IRepairAction() {
+
+ public Kind kind() {
+ return null;
+ }
+
+ public boolean isNull() {
+ return true;
+ }
+
+ public boolean repair(Resource resource, EPackage profileDefinition, java.util.Collection<? extends EObject> stereotypeApplications, DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ throw new UnsupportedOperationException("null repair action"); //$NON-NLS-1$
+ }
+ };
+
+ Predicate<IRepairAction> NOT_NULL = new Predicate<IRepairAction>() {
+
+ public boolean apply(IRepairAction input) {
+ return (input != null) && !input.isNull();
+ }
+ };
+
+ Kind kind();
+
+ boolean isNull();
+
+ boolean repair(Resource resource, EPackage profileDefinition, Collection<? extends EObject> stereotypeApplications, DiagnosticChain diagnostics, IProgressMonitor monitor);
+
+ //
+ // Nested types
+ //
+
+ enum Kind {
+ /** The lazy option. */
+ NO_OP("Postpone"),
+ /** The option to apply the profile to the model and migrate stereotypes to its latest definition. */
+ APPLY_LATEST_PROFILE_DEFINITION("Migrate Profile"),
+ /** The option to create problem markers for later review. */
+ CREATE_MARKERS("Create Markers"),
+ /** The option to delete all zombies. */
+ DELETE("Delete Stereotypes");
+
+ private final String displayName;
+
+ private Kind(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String displayName() {
+ return displayName;
+ }
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeApplicationRepairSnippet.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeApplicationRepairSnippet.java
new file mode 100644
index 00000000000..43f580e5840
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/StereotypeApplicationRepairSnippet.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.infra.core.editor.IMultiDiagramEditor;
+import org.eclipse.papyrus.infra.core.resource.IModelSetSnippet;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.EMFHelper;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.uml.modelrepair.ui.ZombieStereotypeDialogPresenter;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.ProfileApplication;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+
+
+/**
+ * A snippet on the UML Model for detecting and initiating repair of zombie stereotype applications.
+ */
+public class StereotypeApplicationRepairSnippet implements IModelSetSnippet {
+
+ private final UMLResourceLoadAdaper adapter = new UMLResourceLoadAdaper();
+
+ private final Supplier<Profile> dynamicProfileSupplier;
+
+ private ZombieStereotypeDialogPresenter presenter;
+
+ public StereotypeApplicationRepairSnippet() {
+ this(null);
+ }
+
+ protected StereotypeApplicationRepairSnippet(Supplier<Profile> dynamicProfileSupplier) {
+ super();
+
+ this.dynamicProfileSupplier = dynamicProfileSupplier;
+ }
+
+ protected void handleResourceLoaded(Resource resource) {
+ Element root = getRootUMLElement(resource);
+
+ // Only check for zombies in resources that we can modify (those being the resources in the user model opened in the editor)
+ if((root != null) && !EMFHelper.isReadOnly(resource, EMFHelper.resolveEditingDomain(root))) {
+ ZombieStereotypesDescriptor zombies = getZombieStereotypes(resource, root);
+ if((zombies != null) && (presenter != null)) {
+ presenter.addZombies(zombies);
+ }
+ }
+ }
+
+ protected Element getRootUMLElement(Resource resource) {
+ return (Element)EcoreUtil.getObjectByType(resource.getContents(), UMLPackage.Literals.ELEMENT);
+ }
+
+ protected ZombieStereotypesDescriptor getZombieStereotypes(Resource resource, Element root) {
+ ZombieStereotypesDescriptor result = null;
+
+ Package contextPackage = root.getNearestPackage();
+
+ // Could be a Class or something that is a disconnected controlled unit?
+ if(contextPackage != null) {
+ Collection<ProfileApplication> profileApplications = contextPackage.getAllProfileApplications();
+ Set<EPackage> appliedDefinitions = getAppliedDefinitions(profileApplications);
+ Supplier<Profile> profileSupplier = (dynamicProfileSupplier != null) ? dynamicProfileSupplier : presenter.getDynamicProfileSupplier();
+ ZombieStereotypesDescriptor zombies = new ZombieStereotypesDescriptor(resource, root, appliedDefinitions, profileSupplier);
+
+ for(EObject next : resource.getContents()) {
+ if(!(next instanceof Element)) {
+ zombies.analyze(next);
+ }
+ }
+
+ if(zombies.hasZombies()) {
+ result = zombies;
+ }
+ }
+
+ return result;
+ }
+
+ protected Set<EPackage> getAppliedDefinitions(Iterable<? extends ProfileApplication> profileApplications) {
+ Set<EPackage> result = Sets.newHashSet();
+
+ for(ProfileApplication next : profileApplications) {
+ EPackage definition = next.getAppliedDefinition();
+ if((definition != null) && !definition.eIsProxy()) {
+ result.add(definition);
+ }
+ }
+
+ return result;
+ }
+
+ //
+ // Snippet lifecycle
+ //
+
+ public void start(ModelSet modelsManager) {
+ try {
+ IEditorPart editor = ServiceUtilsForResourceSet.getInstance().getService(IMultiDiagramEditor.class, modelsManager);
+
+ if(editor != null) {
+ // this model is opened in an editor. That is the context in which we want to provide our services
+ presenter = new ZombieStereotypeDialogPresenter(editor.getSite().getShell(), modelsManager);
+ adapter.adapt(modelsManager);
+ }
+ } catch (ServiceException e) {
+ // OK, there is no editor, so we aren't needed
+ }
+ }
+
+ public void dispose(ModelSet modelsManager) {
+ if(presenter != null) {
+ presenter.dispose();
+ presenter = null;
+ }
+
+ adapter.unadapt(modelsManager);
+ }
+
+ //
+ // Nested types
+ //
+
+ private class UMLResourceLoadAdaper extends AdapterImpl {
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ Object notifier = msg.getNotifier();
+
+ if(notifier instanceof ResourceSet) {
+ handleNotification((ResourceSet)notifier, msg);
+ } else if(notifier instanceof Resource) {
+ handleNotification((Resource)notifier, msg);
+ }
+ }
+
+ ResourceSet getResourceSet() {
+ return (ResourceSet)getTarget();
+ }
+
+ @Override
+ public void setTarget(Notifier newTarget) {
+ if((newTarget == null) || (newTarget instanceof ResourceSet)) {
+ super.setTarget(newTarget);
+ }
+
+ if(newTarget instanceof ResourceSet) {
+ // Iterate a defensive copy because other adapters cause concurrent additions by loading additional resources
+ for(Resource next : ImmutableList.copyOf(((ResourceSet)newTarget).getResources())) {
+ adapt(next);
+ }
+ } else if(newTarget instanceof Resource) {
+ Resource resource = (Resource)newTarget;
+ if(resource.isLoaded()) {
+ // already loaded? Handled it
+ handleResourceLoaded(resource);
+ }
+ }
+ }
+
+ @Override
+ public void unsetTarget(Notifier oldTarget) {
+ if(oldTarget == getResourceSet()) {
+ for(Resource next : getResourceSet().getResources()) {
+ unadapt(next);
+ }
+ }
+
+ super.unsetTarget(oldTarget);
+ }
+
+ protected void adapt(Notifier notifier) {
+ if(!notifier.eAdapters().contains(this)) {
+ notifier.eAdapters().add(this);
+ }
+ }
+
+ protected void unadapt(Notifier notifier) {
+ notifier.eAdapters().remove(this);
+ }
+
+ protected void handleNotification(ResourceSet rset, Notification msg) {
+ switch(msg.getFeatureID(ResourceSet.class)) {
+ case ResourceSet.RESOURCE_SET__RESOURCES:
+ switch(msg.getEventType()) {
+ case Notification.ADD:
+ adapt((Resource)msg.getNewValue());
+ break;
+ case Notification.ADD_MANY:
+ for(Object next : (Collection<?>)msg.getNewValue()) {
+ adapt((Resource)next);
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ protected void handleNotification(Resource resource, Notification msg) {
+ switch(msg.getFeatureID(Resource.class)) {
+ case Resource.RESOURCE__IS_LOADED:
+ if(msg.getNewBooleanValue()) {
+ handleResourceLoaded(resource);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
new file mode 100644
index 00000000000..9ac171511ee
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/internal/stereotypes/ZombieStereotypesDescriptor.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.internal.stereotypes;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.util.UMLUtil;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+
+
+/**
+ * This is the ZombieStereotypesDescriptor type. Enjoy.
+ */
+public class ZombieStereotypesDescriptor {
+
+ private final Resource resource;
+
+ private final Element root;
+
+ private final Set<EPackage> appliedProfileDefinitions;
+
+ private final Multimap<EPackage, EObject> zombies = ArrayListMultimap.create();
+
+ private final Map<EPackage, IRepairAction> suggestedActions = Maps.newHashMap();
+
+ private final Supplier<Profile> dynamicProfileSupplier;
+
+ private Map<EPackage, Map<IRepairAction.Kind, IRepairAction>> repairActions = Maps.newHashMap();
+
+ public ZombieStereotypesDescriptor(Resource resource, Element root, Set<EPackage> appliedProfileDefinitions, Supplier<Profile> dynamicProfileSupplier) {
+ this.resource = resource;
+ this.root = root;
+ this.appliedProfileDefinitions = appliedProfileDefinitions;
+ this.dynamicProfileSupplier = dynamicProfileSupplier;
+ }
+
+ public void analyze(EObject stereotypeApplication) {
+ EPackage schema = getEPackage(stereotypeApplication);
+ if((schema == null) || !appliedProfileDefinitions.contains(schema)) {
+ // It's a zombie
+ zombies.put(schema, stereotypeApplication);
+
+ if((schema != null) && !suggestedActions.containsKey(schema)) {
+ suggestedActions.put(schema, computeSuggestedAction(schema));
+ }
+ }
+ }
+
+ public boolean hasZombies() {
+ return !zombies.isEmpty();
+ }
+
+ public Resource getResource() {
+ return resource;
+ }
+
+ public Collection<? extends EPackage> getZombiePackages() {
+ return zombies.keySet();
+ }
+
+ public int getZombieCount(EPackage schema) {
+ return zombies.get(schema).size();
+ }
+
+ public boolean repair(EPackage schema, IRepairAction repairAction, DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ return repairAction.repair(resource, schema, zombies.get(schema), diagnostics, monitor);
+ }
+
+ protected EPackage getEPackage(EObject object) {
+ EClass eclass = object.eClass();
+ return (eclass == null) ? null : eclass.getEPackage();
+ }
+
+ protected IRepairAction computeSuggestedAction(EPackage schema) {
+ // Try options in our preferred order
+ IRepairAction result = getRepairAction(schema, IRepairAction.Kind.APPLY_LATEST_PROFILE_DEFINITION);
+ if(result.isNull()) {
+ // This one is always available
+ result = getRepairAction(schema, IRepairAction.Kind.NO_OP);
+ }
+
+ return result;
+ }
+
+ protected Map<IRepairAction.Kind, IRepairAction> computeFeasibleRepairActions(EPackage schema) {
+ Map<IRepairAction.Kind, IRepairAction> result = Maps.newEnumMap(IRepairAction.Kind.class);
+
+ // Always available
+ result.put(IRepairAction.NO_OP.kind(), IRepairAction.NO_OP);
+ result.put(DeleteAction.INSTANCE.kind(), DeleteAction.INSTANCE);
+ result.put(CreateMarkersAction.INSTANCE.kind(), CreateMarkersAction.INSTANCE);
+
+ Profile profile = findProfile(schema);
+ Supplier<Profile> supplier = (profile == null) ? dynamicProfileSupplier : Suppliers.ofInstance(profile);
+ IRepairAction applyProfile = new ApplyProfileAction(root, supplier);
+ result.put(applyProfile.kind(), applyProfile);
+
+ return result;
+ }
+
+ public IRepairAction getSuggestedRepairAction(EPackage schema) {
+ return suggestedActions.get(schema);
+ }
+
+ public IRepairAction getRepairAction(EPackage schema, IRepairAction.Kind kind) {
+ Map<IRepairAction.Kind, IRepairAction> available = repairActions.get(schema);
+ if(available == null) {
+ available = computeFeasibleRepairActions(schema);
+ repairActions.put(schema, available);
+ }
+
+ return available.get(kind);
+ }
+
+ public List<IRepairAction> getAvailableRepairActions(EPackage schema) {
+ Map<IRepairAction.Kind, IRepairAction> actions = repairActions.get(schema);
+ return (actions == null) ? Collections.<IRepairAction> emptyList() : ImmutableList.copyOf(Iterables.filter(actions.values(), IRepairAction.NOT_NULL));
+ }
+
+ protected Profile findProfile(EPackage definition) {
+ return UMLUtil.getProfile(definition, root);
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesBlock.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesBlock.java
new file mode 100644
index 00000000000..eea58554438
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesBlock.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * CEA - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 431953 (extracted from SwitchProfileDialog)
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.ui;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.widgets.editors.TreeSelectorDialog;
+import org.eclipse.papyrus.infra.widgets.providers.EncapsulatedContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.StaticContentProvider;
+import org.eclipse.papyrus.infra.widgets.providers.WorkspaceContentProvider;
+import org.eclipse.papyrus.uml.extensionpoints.profile.RegisteredProfile;
+import org.eclipse.papyrus.uml.modelrepair.Activator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+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.Shell;
+
+import com.google.common.eventbus.EventBus;
+
+
+/**
+ * This is the BrowseProfilesBlock type. Enjoy.
+ */
+public class BrowseProfilesBlock {
+
+ /** Block style for icon browse buttons. */
+ public static final int ICON = 0x00;
+
+ /** Block style for text browser buttons. */
+ public static final int TEXT = 0x01;
+
+ private final EventBus bus;
+
+ private final LabelProviderService labelProviderService;
+
+ private Composite control;
+
+ private Button browseWorkspace;
+
+ private Button browseRegistered;
+
+ private boolean enabled = true;
+
+ public BrowseProfilesBlock(EventBus bus, LabelProviderService labelProviderService) {
+ super();
+
+ this.bus = bus;
+ this.labelProviderService = labelProviderService;
+ }
+
+ public Control createControl(Composite parent, int style) {
+ control = new Composite(parent, SWT.NONE);
+
+ GridLayout buttonsLayout = new GridLayout(2, false);
+ buttonsLayout.marginWidth = 0;
+
+ control.setLayout(buttonsLayout);
+
+ final boolean useText = (style & TEXT) == TEXT;
+
+ browseWorkspace = new Button(control, SWT.PUSH);
+ if(useText) {
+ browseWorkspace.setText("Workspace...");
+ } else {
+ browseWorkspace.setImage(org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage("icons/Add_12x12.gif"));
+ }
+
+ browseRegistered = new Button(control, SWT.PUSH);
+ if(useText) {
+ browseRegistered.setText("Registered...");
+ } else {
+ browseRegistered.setImage(org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(Activator.PLUGIN_ID, "icons/AddReg.gif"));
+ }
+
+ SelectionListener buttonListener = new SelectionAdapter() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if(e.widget == browseWorkspace) {
+ browseWorkspaceProfiles();
+ } else {
+ browseRegisteredProfiles();
+ }
+ }
+ };
+ browseWorkspace.addSelectionListener(buttonListener);
+ browseRegistered.addSelectionListener(buttonListener);
+
+ updateEnablement();
+
+ return control;
+ }
+
+ public void setEnabled(boolean enabled) {
+ if(enabled != this.enabled) {
+ this.enabled = enabled;
+ updateEnablement();
+ }
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ protected Shell getShell() {
+ return (control == null) ? null : control.getShell();
+ }
+
+ protected void updateEnablement() {
+ if((browseWorkspace != null) && !browseWorkspace.isDisposed()) {
+ browseWorkspace.setEnabled(enabled);
+ browseRegistered.setEnabled(enabled);
+ }
+ }
+
+ protected void browseWorkspaceProfiles() {
+ Map<String, String> extensionFilters = new LinkedHashMap<String, String>();
+ extensionFilters.put("*.profile.uml", "UML Profiles (*.profile.uml)");
+ extensionFilters.put("*.uml", "UML (*.uml)");
+ extensionFilters.put("*", "All (*)");
+
+ TreeSelectorDialog dialog = new TreeSelectorDialog(getShell());
+ dialog.setTitle("Browse Workspace");
+ dialog.setDescription("Select a profile in the workspace.");
+ WorkspaceContentProvider workspaceContentProvider = new WorkspaceContentProvider();
+ workspaceContentProvider.setExtensionFilters(extensionFilters);
+ dialog.setContentProvider(workspaceContentProvider);
+
+ dialog.setLabelProvider(labelProviderService.getLabelProvider());
+
+
+ if(dialog.open() == Window.OK) {
+ Object[] result = dialog.getResult();
+ if(result == null || result.length == 0) {
+ return;
+ }
+
+ Object selectedFile = result[0];
+
+ if(selectedFile instanceof IFile) {
+ bus.post((IFile)selectedFile);
+ }
+ }
+ }
+
+ protected void browseRegisteredProfiles() {
+ TreeSelectorDialog dialog = new TreeSelectorDialog(getShell());
+ dialog.setTitle("Browse Registered Profiles");
+ dialog.setDescription("Select one of the registered profiles below.");
+ dialog.setContentProvider(new EncapsulatedContentProvider(new StaticContentProvider(RegisteredProfile.getRegisteredProfiles())));
+ dialog.setLabelProvider(new LabelProvider() {
+
+ @Override
+ public Image getImage(Object element) {
+ if(element instanceof RegisteredProfile) {
+ RegisteredProfile profile = (RegisteredProfile)element;
+ return profile.getImage();
+ }
+ return super.getImage(element);
+ }
+
+ @Override
+ public String getText(Object element) {
+ if(element instanceof RegisteredProfile) {
+ RegisteredProfile profile = (RegisteredProfile)element;
+ return profile.name;
+ }
+
+ return super.getText(element);
+ }
+ });
+
+ if(dialog.open() == Window.OK) {
+ Object[] result = dialog.getResult();
+ if(result == null || result.length == 0) {
+ return;
+ }
+
+ Object selectedElement = result[0];
+ if(selectedElement instanceof RegisteredProfile) {
+ bus.post((RegisteredProfile)selectedElement);
+ }
+ }
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesDialog.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesDialog.java
new file mode 100644
index 00000000000..16d24a19084
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/BrowseProfilesDialog.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.ui;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.SameShellProvider;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.uml.extensionpoints.profile.RegisteredProfile;
+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.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
+
+/**
+ * This is the BrowseProfilesDialog type. Enjoy.
+ */
+public class BrowseProfilesDialog extends TrayDialog {
+
+ private final LabelProviderService labelProviderService;
+
+ private Text profileText;
+
+ private URI selectedProfileURI;
+
+ public BrowseProfilesDialog(Shell shell, LabelProviderService labelProviderService) {
+ this(new SameShellProvider(shell), labelProviderService);
+ }
+
+ public BrowseProfilesDialog(IShellProvider parentShell, LabelProviderService labelProviderService) {
+ super(parentShell);
+
+ this.labelProviderService = labelProviderService;
+ }
+
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+
+ newShell.setText("Apply Profile");
+ newShell.setMinimumSize(300, 150);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite contents = (Composite)super.createDialogArea(parent);
+
+ Composite main = new Composite(contents, SWT.NONE);
+ main.setLayout(new GridLayout(2, false));
+ main.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Label messageLabel = new Label(main, SWT.WRAP);
+ messageLabel.setText("Select a registered or a workspace profile to apply for recovery of unrecognized stereotypes.");
+ GridData span2 = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
+ span2.horizontalSpan = 2;
+ messageLabel.setLayoutData(span2);
+
+ EventBus bus = new EventBus("profileSelection"); //$NON-NLS-1$
+ BrowseProfilesBlock block = new BrowseProfilesBlock(bus, labelProviderService);
+ block.createControl(main, BrowseProfilesBlock.TEXT).setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false, 2, 1));
+
+ Label profileLabel = new Label(main, SWT.NONE);
+ profileLabel.setText("Profile:");
+ profileText = new Text(main, SWT.BORDER | SWT.READ_ONLY);
+ profileText.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+ bus.register(new Object() {
+
+ @Subscribe
+ public void workspaceProfileSelected(IFile file) {
+ IPath filePath = file.getFullPath();
+ setSelectedProfileURI(URI.createPlatformResourceURI(filePath.toPortableString(), true));
+
+ updateProfile();
+ }
+
+ @Subscribe
+ public void registeredProfileSelected(RegisteredProfile profile) {
+ setSelectedProfileURI(profile.uri);
+ }
+ });
+
+ return contents;
+ }
+
+ protected Control createContents(Composite parent) {
+ setHelpAvailable(false);
+ Control result = super.createContents(parent);
+ updateProfile();
+ return result;
+ }
+
+ public void setSelectedProfileURI(URI selectedProfileURI) {
+ this.selectedProfileURI = selectedProfileURI;
+ updateProfile();
+ }
+
+ public URI getSelectedProfileURI() {
+ return selectedProfileURI;
+ }
+
+ @Override
+ protected void cancelPressed() {
+ selectedProfileURI = null;
+ super.cancelPressed();
+ }
+
+ protected void updateProfile() {
+ if((profileText != null) && !profileText.isDisposed()) {
+ if(selectedProfileURI == null) {
+ profileText.setText(""); //$NON-NLS-1$
+ } else {
+ profileText.setText(selectedProfileURI.toString());
+ }
+
+ getButton(IDialogConstants.OK_ID).setEnabled(selectedProfileURI != null);
+ }
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java
index cc85cdfc6e3..4d714ed856c 100644
--- a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/SwitchProfileDialog.java
@@ -18,7 +18,6 @@ import static com.google.common.base.Strings.nullToEmpty;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
@@ -55,7 +54,6 @@ import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
@@ -64,20 +62,14 @@ import org.eclipse.papyrus.infra.emf.resource.Replacement;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
import org.eclipse.papyrus.infra.services.markerlistener.dialogs.DiagnosticDialog;
-import org.eclipse.papyrus.infra.widgets.editors.TreeSelectorDialog;
-import org.eclipse.papyrus.infra.widgets.providers.EncapsulatedContentProvider;
-import org.eclipse.papyrus.infra.widgets.providers.StaticContentProvider;
-import org.eclipse.papyrus.infra.widgets.providers.WorkspaceContentProvider;
import org.eclipse.papyrus.uml.extensionpoints.profile.RegisteredProfile;
import org.eclipse.papyrus.uml.modelrepair.Activator;
import org.eclipse.papyrus.uml.tools.util.ProfileHelper;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
-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;
@@ -89,6 +81,9 @@ import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.uml2.uml.Profile;
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+
/**
* The dialog to switch from a Profile application to another
*
@@ -100,10 +95,6 @@ public class SwitchProfileDialog extends SelectionDialog {
private static final String APPLY_LABEL = "Apply";
- private static final int BROWSE_WORKSPACE_ID = IDialogConstants.CLIENT_ID + 2;
-
- private static final int BROWSE_REGISTERED_ID = IDialogConstants.CLIENT_ID + 3;
-
private ModelSet modelSet;
private TransactionalEditingDomain editingDomain;
@@ -112,6 +103,8 @@ public class SwitchProfileDialog extends SelectionDialog {
protected Table table;
+ protected BrowseProfilesBlock browseBlock;
+
protected LabelProviderService labelProviderService;
protected final Map<Resource, Resource> profilesToEdit = new HashMap<Resource, Resource>();
@@ -148,20 +141,25 @@ public class SwitchProfileDialog extends SelectionDialog {
warningLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
- Composite buttonsBarComposite = new Composite(self, SWT.NONE);
-
- GridLayout buttonsLayout = new GridLayout(0, false);
- buttonsLayout.marginWidth = 0;
+ EventBus bus = new EventBus("profileSelection"); //$NON-NLS-1$
+ browseBlock = new BrowseProfilesBlock(bus, labelProviderService);
+ browseBlock.createControl(self, BrowseProfilesBlock.ICON).setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
+ bus.register(new Object() {
- buttonsBarComposite.setLayout(buttonsLayout);
- buttonsBarComposite.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
-
- Button browseWorkspace = createButton(buttonsBarComposite, BROWSE_WORKSPACE_ID, "", false);
- browseWorkspace.setImage(org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage("icons/Add_12x12.gif"));
- Button browseRegistered = createButton(buttonsBarComposite, BROWSE_REGISTERED_ID, "", false);
- browseRegistered.setImage(org.eclipse.papyrus.infra.widgets.Activator.getDefault().getImage(Activator.PLUGIN_ID, "icons/AddReg.gif"));
+ @Subscribe
+ public void workspaceProfileSelected(IFile file) {
+ IPath filePath = file.getFullPath();
+ URI workspaceURI = URI.createPlatformResourceURI(filePath.toPortableString(), true);
+ replaceSelectionWith(workspaceURI);
+ }
+ @Subscribe
+ public void registeredProfileSelected(RegisteredProfile profile) {
+ replaceSelectionWith(profile.uri);
+ }
+ });
+
viewer = new TableViewer(self, SWT.FULL_SELECTION | SWT.BORDER);
table = viewer.getTable();
TableLayout layout = new TableLayout();
@@ -266,22 +264,11 @@ public class SwitchProfileDialog extends SelectionDialog {
boolean enableBrowse = !viewer.getSelection().isEmpty();
- getButton(BROWSE_REGISTERED_ID).setEnabled(enableBrowse);
- getButton(BROWSE_WORKSPACE_ID).setEnabled(enableBrowse);
+ browseBlock.setEnabled(enableBrowse);
viewer.refresh();
}
- @Override
- protected void setButtonLayoutData(Button button) {
- int buttonId = ((Integer)button.getData()).intValue();
- if(buttonId == BROWSE_REGISTERED_ID || buttonId == BROWSE_WORKSPACE_ID) {
- return; //Don't change the layout data
- }
-
- super.setButtonLayoutData(button);
- }
-
protected void applyPressed() {
if(profilesToEdit.isEmpty()) {
return;
@@ -356,12 +343,6 @@ public class SwitchProfileDialog extends SelectionDialog {
case APPLY_ID:
applyPressed();
return;
- case BROWSE_REGISTERED_ID:
- browseRegisteredProfiles();
- return;
- case BROWSE_WORKSPACE_ID:
- browseWorkspaceProfiles();
- return;
}
super.buttonPressed(buttonId);
@@ -458,43 +439,6 @@ public class SwitchProfileDialog extends SelectionDialog {
}
}
- protected void browseWorkspaceProfiles() {
- if(getSelectedResource() == null) {
- return;
- }
-
- Map<String, String> extensionFilters = new LinkedHashMap<String, String>();
- extensionFilters.put("*.profile.uml", "UML Profiles (*.profile.uml)");
- extensionFilters.put("*.uml", "UML (*.uml)");
- extensionFilters.put("*", "All (*)");
-
- TreeSelectorDialog dialog = new TreeSelectorDialog(getShell());
- dialog.setTitle("Browse Workspace");
- dialog.setDescription("Select a profile in the workspace.");
- WorkspaceContentProvider workspaceContentProvider = new WorkspaceContentProvider();
- workspaceContentProvider.setExtensionFilters(extensionFilters);
- dialog.setContentProvider(workspaceContentProvider);
-
- dialog.setLabelProvider(labelProviderService.getLabelProvider());
-
-
- if(dialog.open() == Window.OK) {
- Object[] result = dialog.getResult();
- if(result == null || result.length == 0) {
- return;
- }
-
- Object selectedFile = result[0];
-
- if(selectedFile instanceof IFile) {
- IPath filePath = ((IFile)selectedFile).getFullPath();
- URI workspaceURI = URI.createPlatformResourceURI(filePath.toString(), true);
-
- replaceSelectionWith(workspaceURI);
- }
- }
- }
-
protected Resource getSelectedResource() {
ISelection selection = viewer.getSelection();
if(selection.isEmpty()) {
@@ -511,48 +455,6 @@ public class SwitchProfileDialog extends SelectionDialog {
return null;
}
- protected void browseRegisteredProfiles() {
- TreeSelectorDialog dialog = new TreeSelectorDialog(getShell());
- dialog.setTitle("Browse Registered Profiles");
- dialog.setDescription("Select one of the registered profiles below.");
- dialog.setContentProvider(new EncapsulatedContentProvider(new StaticContentProvider(RegisteredProfile.getRegisteredProfiles())));
- dialog.setLabelProvider(new LabelProvider() {
-
- @Override
- public Image getImage(Object element) {
- if(element instanceof RegisteredProfile) {
- RegisteredProfile profile = (RegisteredProfile)element;
- return profile.getImage();
- }
- return super.getImage(element);
- }
-
- @Override
- public String getText(Object element) {
- if(element instanceof RegisteredProfile) {
- RegisteredProfile profile = (RegisteredProfile)element;
- return profile.name;
- }
-
- return super.getText(element);
- }
- });
-
- if(dialog.open() == Window.OK) {
- Object[] result = dialog.getResult();
- if(result == null || result.length == 0) {
- return;
- }
-
- Object selectedElement = result[0];
- if(selectedElement instanceof RegisteredProfile) {
- RegisteredProfile profile = (RegisteredProfile)selectedElement;
-
- replaceSelectionWith(profile.uri);
- }
- }
- }
-
protected void replaceSelectionWith(URI targetURI) {
Resource targetResource = modelSet.getResource(targetURI, true);
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypeDialogPresenter.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypeDialogPresenter.java
new file mode 100644
index 00000000000..2ebb808daaa
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypeDialogPresenter.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 CEA 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:
+ * Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.ui;
+
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.window.Window;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.services.labelprovider.service.impl.LabelProviderServiceImpl;
+import org.eclipse.papyrus.uml.modelrepair.Activator;
+import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.ZombieStereotypesDescriptor;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.uml2.common.util.UML2Util;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.UMLPackage;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+
+/**
+ * This is the ZombieStereotypeDialogPresenter type. Enjoy.
+ */
+public class ZombieStereotypeDialogPresenter {
+
+ private final Shell parentShell;
+
+ private final ModelSet modelSet;
+
+ private final List<ZombieStereotypesDescriptor> zombieDescriptors = Lists.newArrayListWithExpectedSize(1);
+
+ private final BrowseProfileSupplier dynamicProfileSupplier = new BrowseProfileSupplier();
+
+ private Runnable presentation;
+
+ public ZombieStereotypeDialogPresenter(Shell parentShell, ModelSet modelSet) {
+ super();
+
+ this.parentShell = parentShell;
+ this.modelSet = modelSet;
+ }
+
+ public void dispose() {
+ synchronized(zombieDescriptors) {
+ zombieDescriptors.clear();
+ presentation = null;
+ }
+ }
+
+ public BrowseProfileSupplier getDynamicProfileSupplier() {
+ return dynamicProfileSupplier;
+ }
+
+ public void addZombies(ZombieStereotypesDescriptor zombies) {
+ synchronized(zombieDescriptors) {
+ zombieDescriptors.add(zombies);
+
+ if(presentation == null) {
+ presentation = new Runnable() {
+
+ public void run() {
+ List<ZombieStereotypesDescriptor> zombies;
+
+ synchronized(zombieDescriptors) {
+ if(presentation != this) {
+ // I have been cancelled
+ return;
+ }
+ zombies = ImmutableList.copyOf(zombieDescriptors);
+ dispose();
+ }
+
+ if(!zombies.isEmpty()) {
+ try {
+ ZombieStereotypesDialog zombieDialog = new ZombieStereotypesDialog(parentShell, modelSet, zombies);
+ dynamicProfileSupplier.setParentWindow(zombieDialog);
+ zombieDialog.setBlockOnOpen(true);
+ zombieDialog.open();
+ } catch (ServiceException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to open model repair dialog.", e), StatusManager.SHOW);
+ } finally {
+ dynamicProfileSupplier.setParentWindow(null);
+ }
+ }
+ }
+ };
+
+ parentShell.getDisplay().asyncExec(presentation);
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ private class BrowseProfileSupplier implements Supplier<Profile> {
+
+ private Window parentWindow;
+
+ void setParentWindow(Window parentWindow) {
+ this.parentWindow = parentWindow;
+ }
+
+ public Profile get() {
+ Profile result = null;
+
+ LabelProviderService labelProvider = null;
+ boolean localProvider = false;
+ try {
+ labelProvider = ServiceUtilsForResourceSet.getInstance().getService(LabelProviderService.class, modelSet);
+ } catch (ServiceException e) {
+ labelProvider = new LabelProviderServiceImpl();
+ localProvider = true;
+ }
+
+ final BrowseProfilesDialog dlg = new BrowseProfilesDialog(parentWindow.getShell(), labelProvider);
+
+ parentShell.getDisplay().syncExec(new Runnable() {
+
+ public void run() {
+ dlg.setBlockOnOpen(true);
+ dlg.open();
+ }
+ });
+
+ if(localProvider) {
+ try {
+ labelProvider.disposeService();
+ } catch (ServiceException e) {
+ Activator.log.error(e);
+ }
+ }
+
+ if(dlg.getSelectedProfileURI() != null) {
+ result = UML2Util.load(modelSet, dlg.getSelectedProfileURI(), UMLPackage.Literals.PROFILE);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypesDialog.java b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypesDialog.java
new file mode 100644
index 00000000000..6e1a095aad8
--- /dev/null
+++ b/plugins/uml/org.eclipse.papyrus.uml.modelrepair/src/org/eclipse/papyrus/uml/modelrepair/ui/ZombieStereotypesDialog.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2013, 2014 CEA 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:
+ * CEA - Initial API and implementation
+ * Christian W. Damus (CEA) - bug 431953 (adapted from SwitchProfileDialog)
+ *
+ */
+package org.eclipse.papyrus.uml.modelrepair.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.emf.common.util.BasicDiagnostic;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.eclipse.emf.common.util.DiagnosticChain;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.transaction.RecordingCommand;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnViewer;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ComboBoxViewerCellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.window.IShellProvider;
+import org.eclipse.jface.window.SameShellProvider;
+import org.eclipse.papyrus.infra.core.resource.ModelSet;
+import org.eclipse.papyrus.infra.core.services.ServiceException;
+import org.eclipse.papyrus.infra.core.utils.TransactionHelper;
+import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResourceSet;
+import org.eclipse.papyrus.infra.services.labelprovider.service.LabelProviderService;
+import org.eclipse.papyrus.infra.services.markerlistener.dialogs.DiagnosticDialog;
+import org.eclipse.papyrus.uml.modelrepair.Activator;
+import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.IRepairAction;
+import org.eclipse.papyrus.uml.modelrepair.internal.stereotypes.ZombieStereotypesDescriptor;
+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.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+
+
+/**
+ * This is the ZombieStereotypesDialog type. Enjoy.
+ */
+public class ZombieStereotypesDialog extends TrayDialog {
+
+ private static final int APPLY_ID = IDialogConstants.CLIENT_ID + 1;
+
+ private final TransactionalEditingDomain editingDomain;
+
+ private TableViewer table;
+
+ private LabelProviderService labelProviderService;
+
+ private final List<ZombieStereotypesDescriptor> zombieDescriptors;
+
+ private List<MissingSchema> missingSchemas;
+
+ private final Collection<MissingSchema> actionsToApply;
+
+ /**
+ * @param shell
+ */
+ public ZombieStereotypesDialog(Shell shell, ModelSet modelSet, Iterable<? extends ZombieStereotypesDescriptor> zombies) throws ServiceException {
+ this(new SameShellProvider(shell), modelSet, zombies);
+ }
+
+ /**
+ * @param parentShell
+ */
+ public ZombieStereotypesDialog(IShellProvider parentShell, ModelSet modelSet, Iterable<? extends ZombieStereotypesDescriptor> zombies) throws ServiceException {
+ super(parentShell);
+
+ this.editingDomain = modelSet.getTransactionalEditingDomain();
+ this.zombieDescriptors = Lists.newArrayList(zombies);
+ this.labelProviderService = ServiceUtilsForResourceSet.getInstance().getService(LabelProviderService.class, modelSet);
+ this.actionsToApply = createActionsToApply();
+ }
+
+ private Collection<MissingSchema> createActionsToApply() {
+ return new AbstractCollection<ZombieStereotypesDialog.MissingSchema>() {
+
+ private final Predicate<MissingSchema> filter = new Predicate<MissingSchema>() {
+
+ public boolean apply(MissingSchema input) {
+ return input.getSelectedRepairAction().kind() != IRepairAction.Kind.NO_OP;
+ }
+ };
+
+ @Override
+ public Iterator<MissingSchema> iterator() {
+ return Iterators.filter(getMissingSchemas().iterator(), filter);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return !Iterables.any(getMissingSchemas(), filter);
+ }
+
+ @Override
+ public int size() {
+ return Iterators.size(iterator());
+ }
+ };
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite contents = (Composite)super.createDialogArea(parent);
+
+ Composite self = new Composite(contents, SWT.NONE);
+ self.setLayout(new GridLayout(1, false));
+ self.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ Label descriptionLabel = new Label(self, SWT.WRAP);
+ String description = "For each missing profile definition, select an action to correct the problem. Recommended actions are selected already where appropriate.";
+ descriptionLabel.setText(description);
+ descriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
+
+ table = new TableViewer(self, SWT.FULL_SELECTION | SWT.BORDER);
+ Table tableControl = table.getTable();
+ TableLayout layout = new TableLayout();
+ tableControl.setLayout(layout);
+ tableControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ tableControl.setHeaderVisible(true);
+
+ TableColumn nameColumn = new TableColumn(tableControl, SWT.NONE);
+ nameColumn.setText("Resource");
+ layout.addColumnData(new ColumnWeightData(25, 250, true));
+
+ TableColumn affectedColumn = new TableColumn(tableControl, SWT.NONE);
+ affectedColumn.setText("Affected");
+ layout.addColumnData(new ColumnWeightData(5, 50, true));
+
+ TableColumn schemaColumn = new TableColumn(tableControl, SWT.NONE);
+ schemaColumn.setText("Profile");
+ layout.addColumnData(new ColumnWeightData(15, 150, true));
+
+ TableViewerColumn actionColumn = new TableViewerColumn(table, SWT.NONE);
+ actionColumn.getColumn().setText("Action");
+ layout.addColumnData(new ColumnWeightData(10, 100, true));
+ actionColumn.setEditingSupport(new ActionEditingSupport(table));
+
+ table.setContentProvider(ArrayContentProvider.getInstance());
+ table.setLabelProvider(new ZombiesLabelProvider());
+ table.setInput(getMissingSchemas());
+
+ return contents;
+ }
+
+ protected List<MissingSchema> getMissingSchemas() {
+ if(missingSchemas == null) {
+ missingSchemas = Lists.newArrayList();
+
+ for(ZombieStereotypesDescriptor next : zombieDescriptors) {
+ for(EPackage schema : next.getZombiePackages()) {
+ missingSchemas.add(new MissingSchema(schema, next));
+ }
+ }
+ }
+
+ return missingSchemas;
+ }
+
+ protected void updateControls() {
+ String newTitle = "Repair Stereotypes";
+ if(!actionsToApply.isEmpty()) {
+ newTitle = newTitle + " *";
+ }
+ getShell().setText(newTitle);
+ getButton(APPLY_ID).setEnabled(!actionsToApply.isEmpty());
+
+ table.refresh();
+ }
+
+ protected void applyPressed() {
+ if(actionsToApply.isEmpty()) {
+ return;
+ }
+
+ final List<MissingSchema> repairActions = Lists.newArrayList(actionsToApply);
+ editingDomain.getCommandStack().execute(new RecordingCommand(editingDomain, "Repair stereotypes") {
+
+ @Override
+ protected void doExecute() {
+
+ final BasicDiagnostic diagnostics = new BasicDiagnostic(Activator.PLUGIN_ID, 0, "Problems in repairing stereotypes", null);
+
+ IRunnableWithProgress runnable = TransactionHelper.createPrivilegedRunnableWithProgress(editingDomain, new IRunnableWithProgress() {
+
+ public void run(IProgressMonitor monitor) {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, actionsToApply.size());
+
+ for(Iterator<MissingSchema> iter = repairActions.iterator(); iter.hasNext();) {
+ if(!iter.next().apply(diagnostics, subMonitor.newChild(1))) {
+ // Leave this one to try it again
+ iter.remove();
+ }
+ }
+
+ subMonitor.done();
+ }
+ });
+
+ try {
+ PlatformUI.getWorkbench().getProgressService().busyCursorWhile(runnable);
+ } catch (Exception e) {
+ Throwable t = e;
+ if(e instanceof InvocationTargetException) {
+ t = ((InvocationTargetException)e).getTargetException();
+ }
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Failed to repair stereotypes.", t), StatusManager.BLOCK | StatusManager.LOG);
+ }
+
+ if(diagnostics.getSeverity() > Diagnostic.OK) {
+ DiagnosticDialog dialog = new DiagnosticDialog(getShell(), "Problems in Repairing Stereotypes", "Some repair actions could not be completed normally. Please review the specific details and take any corrective action that may be required.", diagnostics, Diagnostic.ERROR | Diagnostic.WARNING);
+ dialog.setBlockOnOpen(true);
+ dialog.open();
+ }
+ }
+ });
+
+ getMissingSchemas().removeAll(repairActions);
+ updateControls();
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ createButton(parent, APPLY_ID, "Apply", true);
+ super.createButtonsForButtonBar(parent);
+ }
+
+ @Override
+ protected void buttonPressed(int buttonId) {
+ switch(buttonId) {
+ case IDialogConstants.CANCEL_ID:
+ if(!actionsToApply.isEmpty() && !MessageDialog.openQuestion(getShell(), "Repair Stereotypes", "You have not yet applied the pending repair actions. Are you sure you want to cancel?")) {
+ // don't cancel
+ return;
+ }
+ break;
+ case APPLY_ID:
+ applyPressed();
+ return;
+ }
+
+ super.buttonPressed(buttonId);
+ }
+
+ @Override
+ public void create() {
+ super.create();
+
+ getShell().setText("Repair Stereotypes");
+ getShell().setMinimumSize(600, 400);
+ getShell().pack();
+
+ updateControls();
+ }
+
+ @Override
+ protected boolean isResizable() {
+ return true;
+ }
+
+ @Override
+ public boolean isHelpAvailable() {
+ return false;
+ }
+
+ @Override
+ protected void okPressed() {
+ applyPressed();
+
+ super.okPressed();
+ }
+
+ @Override
+ public boolean close() {
+ zombieDescriptors.clear();
+ if(missingSchemas != null) {
+ missingSchemas.clear();
+ }
+
+ return super.close();
+ }
+
+ //
+ // Nested types
+ //
+
+ private class ZombiesLabelProvider extends ColumnLabelProvider {
+
+ public ZombiesLabelProvider() {
+ super();
+ }
+
+ @Override
+ public void update(ViewerCell cell) {
+ switch(cell.getColumnIndex()) {
+ case 0:
+ updateResource(cell);
+ break;
+ case 1:
+ updateAffected(cell);
+ break;
+ case 2:
+ updateSchema(cell);
+ break;
+ case 3:
+ updateAction(cell);
+ break;
+ }
+ }
+
+ void updateResource(ViewerCell cell) {
+ Resource resource = ((MissingSchema)cell.getElement()).getResource();
+ cell.setText(labelProviderService.getLabelProvider().getText(resource));
+ cell.setImage(labelProviderService.getLabelProvider().getImage(resource));
+ }
+
+ void updateAffected(ViewerCell cell) {
+ int count = ((MissingSchema)cell.getElement()).getAffectedCount();
+ cell.setText(Integer.toString(count));
+ }
+
+ void updateSchema(ViewerCell cell) {
+ EPackage schema = ((MissingSchema)cell.getElement()).getSchema();
+
+ // If it's an unrecognized schema, then we're not going to have an EPackage name
+ cell.setText((schema.getName() == null) ? String.format("(%s)", schema.getNsPrefix()) : labelProviderService.getLabelProvider().getText(schema));
+ cell.setImage(labelProviderService.getLabelProvider().getImage(schema));
+ }
+
+ void updateAction(ViewerCell cell) {
+ IRepairAction action = ((MissingSchema)cell.getElement()).getSelectedRepairAction();
+ cell.setText(action.kind().displayName());
+ }
+ }
+
+ private class MissingSchema {
+
+ private final EPackage ePackage;
+
+ private final ZombieStereotypesDescriptor descriptor;
+
+ private IRepairAction selectedAction;
+
+ MissingSchema(EPackage ePackage, ZombieStereotypesDescriptor descriptor) {
+ this.ePackage = ePackage;
+ this.descriptor = descriptor;
+ this.selectedAction = descriptor.getSuggestedRepairAction(ePackage);
+ }
+
+ Resource getResource() {
+ return descriptor.getResource();
+ }
+
+ int getAffectedCount() {
+ return descriptor.getZombieCount(getSchema());
+ }
+
+ EPackage getSchema() {
+ return ePackage;
+ }
+
+ List<IRepairAction> getRepairActions() {
+ return descriptor.getAvailableRepairActions(ePackage);
+ }
+
+ IRepairAction getSelectedRepairAction() {
+ return selectedAction;
+ }
+
+ void setSelectedRepairAction(IRepairAction action) {
+ this.selectedAction = action;
+ }
+
+ boolean apply(DiagnosticChain diagnostics, IProgressMonitor monitor) {
+ return descriptor.repair(getSchema(), getSelectedRepairAction(), diagnostics, monitor);
+ }
+ }
+
+ private class ActionEditingSupport extends EditingSupport {
+
+ private ComboBoxViewerCellEditor editor;
+
+ ActionEditingSupport(ColumnViewer viewer) {
+ super(viewer);
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ if(editor == null) {
+ editor = new ComboBoxViewerCellEditor((Table)getViewer().getControl(), SWT.BORDER);
+ editor.setContentProvider(ArrayContentProvider.getInstance());
+ editor.setLabelProvider(new LabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ return ((IRepairAction)element).kind().displayName();
+ }
+ });
+ }
+
+ editor.setInput(((MissingSchema)element).getRepairActions());
+ return editor;
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ return true;
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ return ((MissingSchema)element).getSelectedRepairAction();
+ }
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ MissingSchema missing = (MissingSchema)element;
+ IRepairAction action = (IRepairAction)value;
+
+ if(missing.getSelectedRepairAction() != action) {
+ missing.setSelectedRepairAction(action);
+
+ editor.getControl().getDisplay().asyncExec(new Runnable() {
+
+ public void run() {
+ updateControls();
+ }
+ });
+ }
+ }
+ }
+}

Back to the top