/*****************************************************************************
* Copyright (c) 2009 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:
* Yann TANGUY (CEA LIST) yann.tanguy@cea.fr - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.tools.utils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
/**
* Utility class for <code>org.eclipse.uml2.uml.Property</code><BR>
*/
public class PropertyUtil {
/**
* Get all properties that can be subset by this {@link Property} checks the type and the
* multiplicity.
*
* @param property
* property for which the list of subsettable properties are made
* @param noCheck
* set this parameter to <code>true</code> if multiplicity and type check should be
* made for the computation
* @return all properties that can be subset
*/
public static List<Property> getSubsettablesProperties(Property property, boolean noCheck) {
List<Property> list = new ArrayList<Property>();
// subset properties:
Iterator<NamedElement> it = property.getClass_().getMembers().iterator();
while(it.hasNext()) {
NamedElement element = it.next();
if(element instanceof Property) {
boolean isValid = true;
Property subsettableProperty = (Property)element;
// check it is not itself....
if(subsettableProperty.equals(property)) {
isValid = false;
}
// check types conformity
if(!noCheck) {
if(property.getType() != null && subsettableProperty.getType() != null) {
if(!property.getType().conformsTo(subsettableProperty.getType())) {
isValid = false;
}
} else {
isValid = false;
}
// check multiplicity (only upper bound has an OCL rule)
if((subsettableProperty.getUpper() != -1) && (property.getUpper() > subsettableProperty.getUpper())) {
isValid = false;
}
}
if(isValid) {
list.add(subsettableProperty);
}
}
}
return list;
}
/**
* Find a subsetted property given its name and a context to find it.
*
* @param name
* the name of the property
* @return the property found or <code>null</code> if the element was not found.
*/
// @unused
public static Property findSusbsettedPropertyByName(String propertyName, Property property, boolean noCheck) {
Iterator<Property> it = PropertyUtil.getSubsettablesProperties(property, true).iterator();
while(it.hasNext()) {
Property tmpProperty = it.next();
String tmpPropertyName = tmpProperty.getName();
if(tmpPropertyName != null && propertyName.equals(tmpPropertyName.trim())) {
return tmpProperty;
}
}
return null;
}
/**
* Get all properties that can be redefined by this {@link Property}.
*
* @return all properties that can be redefined
*/
public static List<Property> getRedefinableProperties(Property property) {
List<Property> list = new ArrayList<Property>();
// redefine-able properties:
Iterator<NamedElement> it = property.getClass_().getInheritedMembers().iterator();
while(it.hasNext()) {
NamedElement element = it.next();
if(element instanceof Property) {
list.add((Property)element);
}
}
// adds also already redefined members. In fact, when properties are
// redefined, they
// disappear from the inherited members list
Iterator<Property> it2 = property.getRedefinedProperties().iterator();
while(it2.hasNext()) {
Property element = it2.next();
list.add(element);
}
return list;
}
/**
* Find a redefined property given its name and a context to find it.
*
* @param name
* the name of the property
* @return the property found or <code>null</code> if the element was not found.
*/
public static Property findRedefinedPropertyByName(String propertyName, Property property) {
Iterator<Property> it = PropertyUtil.getRedefinableProperties(property).iterator();
while(it.hasNext()) {
Property tmpProperty = it.next();
String tmpPropertyName = tmpProperty.getName();
if(tmpPropertyName != null && propertyName.equals(tmpPropertyName.trim())) {
return tmpProperty;
}
}
return null;
}
/**
* Get the displayed string for the derived attribute of the property.
*
* @param property
* the property
* @return If the property is derived, return "/". Otherwise return an empty String
*/
public static String getDerived(Property property) {
return property.isDerived() ? "/" : "";
}
/**
* return the full label of the property, given UML2 specification.
*
* @return the string corresponding to the label of the property
*/
public static String getLabel(Property property) {
StringBuffer buffer = new StringBuffer();
// visibility
buffer.append(" ");
buffer.append(NamedElementUtil.getVisibilityAsSign(property));
// derived property
buffer.append(getDerived(property));
// name
buffer.append(" ");
buffer.append(getName(property));
// type
if(property.getType() != null) {
buffer.append(" : " + property.getType().getName());
} else {
buffer.append(" : " + TypeUtil.UNDEFINED_TYPE_NAME);
}
// multiplicity -> do not display [1]
String multiplicity = MultiplicityElementUtil.getMultiplicityAsString(property);
if(!multiplicity.trim().equals("[1]")) {
buffer.append(multiplicity);
}
// default value
if(property.getDefault() != null) {
buffer.append(" = ");
buffer.append(property.getDefault());
}
// property modifiers
buffer.append(PropertyUtil.getModifiersAsString(property, false));
return buffer.toString();
}
public static String getName(Property property) {
if(property.getName() != null) {
return property.getName();
} else {
return (NamedElementUtil.getDefaultNameWithIncrement(property));
}
}
/**
* return the custom label of the property, given UML2 specification and a custom style.
*
* @param style
* the integer representing the style of the label
*
* @return the string corresponding to the label of the property
*/
public static String getCustomLabel(Property property, int style) {
StringBuffer buffer = new StringBuffer();
// visibility
buffer.append(" ");
if((style & ICustomAppearence.DISP_VISIBILITY) != 0) {
buffer.append(NamedElementUtil.getVisibilityAsSign(property));
}
// derived property
if((style & ICustomAppearence.DISP_DERIVE) != 0) {
if(property.isDerived()) {
buffer.append("/");
}
}
// name
if((style & ICustomAppearence.DISP_NAME) != 0) {
buffer.append(" ");
buffer.append(property.getName());
}
if((style & ICustomAppearence.DISP_TYPE) != 0) {
// type
if(property.getType() != null) {
buffer.append(": " + property.getType().getName());
} else {
buffer.append(": " + TypeUtil.UNDEFINED_TYPE_NAME);
}
}
if((style & ICustomAppearence.DISP_MULTIPLICITY) != 0) {
// multiplicity -> do not display [1]
String multiplicity = MultiplicityElementUtil.getMultiplicityAsString(property);
buffer.append(multiplicity);
}
if((style & ICustomAppearence.DISP_DFLT_VALUE) != 0) {
// default value
if(property.getDefault() != null) {
buffer.append(" = ");
buffer.append(property.getDefault());
}
}
if((style & ICustomAppearence.DISP_MOFIFIERS) != 0) {
boolean multiLine = ((style & ICustomAppearence.DISP_MULTI_LINE) != 0);
// property modifiers
String modifiers = PropertyUtil.getModifiersAsString(property, multiLine);
if(!modifiers.equals("")) {
if(multiLine) {
buffer.append("\n");
}
if (!buffer.toString().endsWith(" ")){
buffer.append(" ");
}
buffer.append(modifiers);
}
}
return buffer.toString();
}
/**
* Returns the modifier of the property, separated by a comma, as as single line if <code>multiline</code> is <code>false</code> or as a multiline
* string if <code>multiline</code> is <code>false</code>.
*
* @param multiLine
* boolean that indicates if the string should have several lines when set to <code>true</code> or only one line when set to
* <code>false</code>.
*
* @return a string giving all modifiers for the property
*/
public static String getModifiersAsString(Property property, boolean multiLine) {
StringBuffer buffer = new StringBuffer();
boolean needsComma = false;
String NL = (multiLine) ? "\n" : " ";
// Return property modifiers
if(property.isReadOnly()) {
buffer.append("readOnly");
needsComma = true;
}
if(property.isDerivedUnion()) {
needsComma = updateModifiersString(buffer, needsComma, NL, "union");
}
if(property.isOrdered()) {
needsComma = updateModifiersString(buffer, needsComma, NL, "ordered");;
}
if(property.isUnique()) {
needsComma = updateModifiersString(buffer, needsComma, NL, "unique");
}
// is the property redefining another property ?
for(Property current : property.getRedefinedProperties()) {
needsComma = updateModifiersString(buffer, needsComma, NL, "redefines ");
buffer.append(current.getName());
}
// is the property subsetting another property ?
for(Property current : property.getSubsettedProperties()) {
needsComma = updateModifiersString(buffer, needsComma, NL, "subsets ");
buffer.append(current.getName());
}
if(!buffer.toString().equals("")) {
buffer.insert(0, "{");
buffer.append("}");
}
return buffer.toString();
}
/**
* Update the modifiers string
*
* @param buffer
* the existing bufferString to append
* @param needsComma
* if it needs coma
* @param NL
* if it is multiline
* @param message
* the message top
* @return true because the modifier string is no more empty
*/
private static boolean updateModifiersString(StringBuffer buffer, boolean needsComma, String NL, String message) {
if(needsComma) {
buffer.append(",");
buffer.append(NL);
}
buffer.append(message);
return true;
}
}