/*****************************************************************************
* Copyright (c) 2008 CEA LIST.
*
*
* 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:
* Chokri Mraidha (CEA LIST) Chokri.Mraidha@cea.fr - Initial API and implementation
* Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Modification
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.common.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.BorderedBorderItemEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.DataType;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageImport;
import org.eclipse.uml2.uml.PrimitiveType;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.Type;
/**
* Some utils extracted from org.eclipse.papyrus.profile.utils
*/
public class Util {
/**
* Check if a type is a metaclass.
*
* @param type
* to check
*
* @return true if type is metaclass, else false
*/
public static boolean isMetaclass(Type type) {
boolean isMetaclass = false;
if((type instanceof org.eclipse.uml2.uml.Class) && (type.getAppliedStereotypes() != null) && (type.getAppliedStereotypes().size() > 0)) {
Stereotype firstStereotype = type.getAppliedStereotypes().get(0);
if(firstStereotype.getName().equals("Metaclass")) {
isMetaclass = true;
}
}
return isMetaclass;
}
/**
* Retrieve an arraylist of all instances in the model that are instances of
* the java.lang.Class metaType or with a stereotype applied
*
* @param metaType
* selected classes
* @param model
* to check
* @param appliedStereotype
* may be null, metatype is ignored if not null
* @return an arraylist containing the selected instances
*/
public static ArrayList getInstancesFilteredByType(Package topPackage, Class metaType, Stereotype appliedStereotype) {
// retrieve parent element
// Package topPackage = Util.topPackage(element);
// Assert.isNotNull(topPackage,
// "Top package should not be null for element " + element);
Iterator iter = topPackage.eAllContents();
ArrayList filteredElements = new ArrayList();
while(iter.hasNext()) {
Object currentElt = iter.next();
// If currentElt is an ElementImport, it is replaced by the imported
// Element.
if(currentElt instanceof ElementImport) {
ElementImport elementImport = (ElementImport)currentElt;
currentElt = elementImport.getImportedElement();
}
/* package imports treatment */
else if(currentElt instanceof PackageImport) {
Iterator piIter = ((PackageImport)currentElt).getImportedPackage().eAllContents();
while(piIter.hasNext()) {
Object piCurrentElt = piIter.next();
if(piCurrentElt instanceof Element) {
if(appliedStereotype != null) {
Iterator appStIter = ((Element)piCurrentElt).getAppliedStereotypes().iterator();
while(appStIter.hasNext()) {
Stereotype currentSt = (Stereotype)appStIter.next();
if(currentSt.conformsTo(appliedStereotype)) {
filteredElements.add(piCurrentElt);
}
}
} else { // if (appliedStereotype == null)
if(metaType.isInstance(piCurrentElt)) {
filteredElements.add(piCurrentElt);
}
/** add imported meta elements */
else if(piCurrentElt instanceof ElementImport) {
Iterator eIter = ((ElementImport)piCurrentElt).getImportedElement().eAllContents();
while(eIter.hasNext()) {
Object currentEIelt = eIter.next();
if(metaType.isInstance(currentEIelt))
filteredElements.add(currentEIelt);
}
}
}
}
}
}
// Filtering elements
if(currentElt instanceof Element) {
if(appliedStereotype != null) {
Iterator appStIter = ((Element)currentElt).getAppliedStereotypes().iterator();
while(appStIter.hasNext()) {
Stereotype currentSt = (Stereotype)appStIter.next();
if(currentSt.conformsTo(appliedStereotype)) {
filteredElements.add(currentElt);
}
}
} else { // if (appliedStereotype == null)
if(metaType.isInstance(currentElt)) {
filteredElements.add(currentElt);
}
/** add imported meta elements */
else if(currentElt instanceof ElementImport) {
Iterator eIter = ((ElementImport)currentElt).getImportedElement().eAllContents();
while(eIter.hasNext()) {
Object currentEIelt = eIter.next();
if(metaType.isInstance(currentEIelt))
filteredElements.add(currentEIelt);
}
}
}
}
}
return filteredElements;
}
/**
* This method is used to look for the top package that contains this
* element.
*
* @param element
* the element for which top package must be returned
* @return the top package
*/
public static Package topPackage(Element element) {
if(element.getOwner() == null) {
return (Package)element;
} else {
return topPackage(element.getOwner());
}
}
/**
* This method is used to look for the nearest common parent of two
* elements.
*
* @param element1
* the first element to find a parent
* @param element2
* the other element to find a parent
* @param parentClass
* the class the common parent must be (otherwise, search in its
* parents)
* @return the common parent (not element1 or element2 themselves) or null
*/
@SuppressWarnings("unchecked")
public static <T extends Element> T getCommonParent(Element element1, Element element2, Class<T> parentClass) {
// compute depth of each element
int depth1 = 0;
Element ancestor1 = element1.getOwner();
while(ancestor1 != null) {
depth1++;
ancestor1 = ancestor1.getOwner();
}
int depth2 = 0;
Element ancestor2 = element2.getOwner();
while(ancestor2 != null) {
depth2++;
ancestor2 = ancestor2.getOwner();
}
// reset to direct parents
ancestor1 = element1.getOwner();
ancestor2 = element2.getOwner();
// explore owners from bottom to top to find common parent
Element commonParent = null;
while(depth1 > 0 && depth2 > 0 && commonParent == null) {
if(depth1 > depth2) {
ancestor1 = ancestor1.getOwner();
depth1--;
} else if(depth2 > depth1) {
ancestor2 = ancestor2.getOwner();
depth2--;
} else {
// depth1 == depth2
if(ancestor1 == ancestor2) {
commonParent = ancestor1;
} else {
ancestor1 = ancestor1.getOwner();
depth1--;
ancestor2 = ancestor2.getOwner();
depth2--;
}
}
}
// find common parent with correct class
while(commonParent != null && !parentClass.isInstance(commonParent)) {
commonParent = commonParent.getOwner();
}
return (T)commonParent;
}
/**
* This function refind the value from a string for the following types :
* <ul>
* <li>Boolean</li>
* <li>Integer</li>
* <li>String</li>
* <li>UnlimitedNatural</li>
* <li>DataType</li>
* </ul>
*
* @param property
* : the property to edit
* @param propertyValue
* : the value to find
* @return the set of value to apply to the property
*
*/
public static Object getValueFromString(Property property, ArrayList<String> stringValues) {
ArrayList returnedValue = new ArrayList();
Type type = property.getType();
if(type instanceof PrimitiveType) {
if(type.getQualifiedName().equals("UMLPrimitiveTypes::Integer")) {
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(Integer.valueOf(stringValues.get(i)));
}
} else if(type.getQualifiedName().equals("UMLPrimitiveTypes::UnlimitedNatural")) {
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(Integer.valueOf(stringValues.get(i)));
}
} else if(type.getQualifiedName().equals("UMLPrimitiveTypes::String")) {
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(stringValues.get(i));
}
} else if(type.getQualifiedName().equals("UMLPrimitiveTypes::Boolean")) {
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(Boolean.valueOf(stringValues.get(i)));
}
} else { // user defined primitive type
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(stringValues.get(i));
}
}
} else if(type instanceof DataType) {
for(int i = 0; i < stringValues.size(); i++) {
returnedValue.add(stringValues.get(i));
}
}
if(property.getUpper() == 1) {
return returnedValue.get(0);
}
return returnedValue;
}
/**
*
* @param property
* : the property to edit
* @param propertyValue
* : the value to find
* @param objectToEdit
* @return the set of the element representing the value to apply to the
* property or <code>null</code>
*
*/
public static Object retrievesMetaclassElementFromString(Property property, ArrayList<String> stringValues, org.eclipse.uml2.uml.Element packageContainer) {
// the applied profiles
EList<Profile> profiles = ((org.eclipse.uml2.uml.Package)packageContainer).getAllAppliedProfiles();
ArrayList<Object> returnedValues = new ArrayList<Object>();
ArrayList<Object> metaclassElement = new ArrayList<Object>();
String metaclassName = ((org.eclipse.uml2.uml.Class)property.getType()).getName();
/*
* we research all the representation of the metaclass in the Profiles
*/
// Try to retrieve type of the metaclass
java.lang.Class metaType = null;
try {
metaType = java.lang.Class.forName("org.eclipse.uml2.uml." + metaclassName); //$NON-NLS-1$
} catch (Exception e) {
e.printStackTrace();
}
for(Profile profile : profiles) {
metaclassElement.addAll(Util.getInstancesFilteredByType(profile, metaType, null));
}
/*
* we retrieve the element with its QualifiedName
*/
for(String valuesQualifiedName : stringValues) {
for(Object metaclassRepresentation : metaclassElement) {
if(metaclassRepresentation instanceof NamedElement) {
if(((NamedElement)metaclassRepresentation).getQualifiedName().equals(valuesQualifiedName)) {
((ArrayList)returnedValues).add(metaclassRepresentation);
}
}
}
}
if(property.getUpper() != 1) {
return returnedValues;
} else if(returnedValues.size() > 0) {
return returnedValues.get(0);
}
return null;
}
/**
*
* @param property
* : the property to edit
* @param propertyValue
* : the value to find
* @return the set of the stereotyped element to apply to the property or <code>null</code>
*
*/
public static Object retrievesStereotypedElementFromString(Property property, ArrayList<String> stringValues, org.eclipse.uml2.uml.Element packageContainer) {
ArrayList<Object> returnedValues = new ArrayList<Object>();
ArrayList<Object> stereotypedElement = new ArrayList<Object>();
EList<Profile> profiles = ((org.eclipse.uml2.uml.Package)packageContainer).getAllAppliedProfiles();
/*
* we research all the representation of the stereotype in the Profiles
*/
for(Profile profile : profiles) {
stereotypedElement.addAll(Util.getInstancesFilteredByType(profile, null, (Stereotype)property.getType()));
}
/*
* we retrieve the element with its QualifiedName
*/
for(String valuesQualifiedName : stringValues) {
for(Object element : stereotypedElement) {
if(element instanceof NamedElement) {
if(((NamedElement)element).getQualifiedName().equals(valuesQualifiedName)) {
// Like in AppliedStereotypePropertyEditor
EObject newValue = ((NamedElement)element).getStereotypeApplication((Stereotype)property.getType());
if(newValue == null) {
List<?> subStereotypes = ((NamedElement)element).getAppliedSubstereotypes((Stereotype)property.getType());
if(!subStereotypes.isEmpty()) {
newValue = ((NamedElement)element).getStereotypeApplication((Stereotype)subStereotypes.get(0));
}
}
// Like in StereotypeValueTreeObject
if(newValue != null) {
returnedValues.add(newValue);
}
returnedValues.add(element);
break;
}
} else {
// TODO for the element which aren't NamedElement
}
}
}
if(property.getUpper() != 1) {
return returnedValues;
} else if(returnedValues.size() > 0) {
return returnedValues.get(0);
}
return null;
}
/**
*
* @param property
* : the property to edit
* @param propertyValue
* : the value to find
* @return the set of EnumerationLiteral to apply to the property
*
*/
public static Object retrievesEnumerationLiteralFromString(Property property, ArrayList<String> stringValues, org.eclipse.uml2.uml.Element packageContainer) {
Enumeration enume = null;
Type type = property.getType();
Assert.isTrue(type instanceof Enumeration);
enume = (Enumeration) type;
ArrayList<Object> returnedValues = new ArrayList<Object>();
// we research the enumerationLiteral
for(int i = 0; i < stringValues.size(); i++) {
Object obj = enume.getOwnedLiteral(stringValues.get(i));
returnedValues.add(obj);
}
if(property.getUpper() != 1) {
return returnedValues;
} else if(returnedValues.size() > 0) {
return returnedValues.get(0);
}
return null;
}
/**
* Test if an EditPart is an Affixed Child Node or not
*
* @param ep
* an editpart
* @return <ul>
* <li> <code>true</code> if the editpart is an Affixed Child Node</li>
* <li> <code>false</code>if not</li>
* </ul>
*/
public static boolean isAffixedChildNode(EditPart ep) {
if(ep instanceof BorderedBorderItemEditPart) {
if(ep.getParent() instanceof CompartmentEditPart) {
return false;
} else if(ep.getParent() instanceof DiagramEditPart) {
return false;
}
return true;
}
return false;
}
/**
*
* Returns a {@link Set} owning all the level of super classes for the
* Classifier With this method we don't have loop problems with {@link Generalization}
*
* @param visitedClassifier
* the list of the visited Classifier (can be <code>null</code>)
* @param clazz
* the classifier to visit
* @return a {@link Set} owning all the level of super classes for the
* Classifier
*/
public static Set<Classifier> getAllSuperClasses(Set<Classifier> visitedClassifier, Classifier clazz) {
Assert.isNotNull(clazz);
if(visitedClassifier == null) {
visitedClassifier = new HashSet<Classifier>();
}
for(Classifier classifier : clazz.getGenerals()) {
if(!visitedClassifier.contains(classifier)) {
visitedClassifier.add(classifier);
visitedClassifier.addAll(getAllSuperClasses(visitedClassifier, classifier));
}
}
return visitedClassifier;
}
}