package gov.nasa.jpl.mbee.mdk.util;
import com.nomagic.actions.NMAction;
import com.nomagic.magicdraw.annotation.Annotation;
import com.nomagic.magicdraw.core.Application;
import com.nomagic.magicdraw.core.GUILog;
import com.nomagic.magicdraw.core.Project;
import com.nomagic.magicdraw.core.project.ProjectDescriptorsFactory;
import com.nomagic.magicdraw.esi.EsiUtils;
import com.nomagic.magicdraw.ui.MainFrame;
import com.nomagic.magicdraw.ui.dialogs.MDDialogParentProvider;
import com.nomagic.magicdraw.ui.dialogs.SelectElementInfo;
import com.nomagic.magicdraw.ui.dialogs.SelectElementTypes;
import com.nomagic.magicdraw.ui.dialogs.selection.ElementSelectionDlg;
import com.nomagic.magicdraw.ui.dialogs.selection.ElementSelectionDlgFactory;
import com.nomagic.magicdraw.uml.BaseElement;
import com.nomagic.magicdraw.uml.RepresentationTextCreator;
import com.nomagic.magicdraw.uml.symbols.DiagramPresentationElement;
import com.nomagic.magicdraw.validation.RuleViolationResult;
import com.nomagic.magicdraw.validation.ValidationRunData;
import com.nomagic.magicdraw.validation.ui.ValidationResultsWindowManager;
import com.nomagic.uml2.ext.jmi.helpers.ModelHelper;
import com.nomagic.uml2.ext.jmi.helpers.StereotypesHelper;
import com.nomagic.uml2.ext.magicdraw.actions.mdbasicactions.CallBehaviorAction;
import com.nomagic.uml2.ext.magicdraw.actions.mdbasicactions.CallOperationAction;
import com.nomagic.uml2.ext.magicdraw.activities.mdbasicactivities.ActivityEdge;
import com.nomagic.uml2.ext.magicdraw.activities.mdfundamentalactivities.ActivityNode;
import com.nomagic.uml2.ext.magicdraw.activities.mdintermediateactivities.ActivityPartition;
import com.nomagic.uml2.ext.magicdraw.classes.mddependencies.Dependency;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.*;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Class;
import com.nomagic.uml2.ext.magicdraw.classes.mdkernel.Package;
import com.nomagic.uml2.ext.magicdraw.commonbehaviors.mdbasicbehaviors.Behavior;
import com.nomagic.uml2.ext.magicdraw.components.mdbasiccomponents.Component;
import com.nomagic.uml2.ext.magicdraw.compositestructures.mdinternalstructures.ConnectableElement;
import com.nomagic.uml2.ext.magicdraw.compositestructures.mdinternalstructures.Connector;
import com.nomagic.uml2.ext.magicdraw.compositestructures.mdinternalstructures.ConnectorEnd;
import com.nomagic.uml2.ext.magicdraw.mdprofiles.Stereotype;
import com.nomagic.uml2.impl.ElementsFactory;
import gov.nasa.jpl.mbee.mdk.api.incubating.MDKConstants;
import gov.nasa.jpl.mbee.mdk.api.incubating.convert.Converters;
import gov.nasa.jpl.mbee.mdk.docgen.DocGenUtils;
import gov.nasa.jpl.mbee.mdk.docgen.docbook.*;
import gov.nasa.jpl.mbee.mdk.docgen.table.EditableTable;
import gov.nasa.jpl.mbee.mdk.docgen.table.EditableTableModel;
import gov.nasa.jpl.mbee.mdk.docgen.table.PropertyEnum;
import gov.nasa.jpl.mbee.mdk.emf.EmfUtils;
import gov.nasa.jpl.mbee.mdk.generator.CollectFilterParser;
import gov.nasa.jpl.mbee.mdk.generator.DocumentValidator;
import gov.nasa.jpl.mbee.mdk.mms.sync.local.LocalSyncProjectEventListenerAdapter;
import gov.nasa.jpl.mbee.mdk.mms.sync.local.LocalSyncTransactionCommitListener;
import gov.nasa.jpl.mbee.mdk.ocl.GetCallOperation;
import gov.nasa.jpl.mbee.mdk.ocl.GetCallOperation.CallReturnType;
import gov.nasa.jpl.mbee.mdk.ocl.OclEvaluator;
import gov.nasa.jpl.mbee.mdk.validation.*;
import gov.nasa.jpl.mbee.mdk.util.Pair;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This class contains utility methods for collection and filtering on magicdraw
* elements.<br/>
* All collection and filter methods will return an empty list if there's
* nothing matching the criteria.<br/>
* For filter*** methods, if the criteria collection is empty, then the include
* flag will determine whether you get an empty list or a list containing all
* the source elements.<br/>
* Element collections passed in will never be modified or returned. All methods
* return new collections.
* <p>
* For methods that change the model in some way, no check are performed on
* whether element is editable or not. Sessions are also not created. The caller
* will need to manage sessions themselves and wrap any call in a session.
*
* @author dlam
*/
@Deprecated
public class Utils {
public static Logger log = Logger.getLogger(Utils.class);
private static boolean forceDialogFalse = false;
private static boolean forceDialogTrue = false;
private static boolean forceDialogCancel = false;
private static boolean popupsDisabled = false;
private Utils() {
}
/******************************************** Collect/Filter/Sort *******************************************************/
/**
* This does not change the passed in elements collection, it returns a new
* list Compared to just using Set, this preserves the order of the passed
* in collection
*
* @param elements
* @return
*/
public static <T> List<T> removeDuplicates(Collection<T> elements) {
Set<T> added = new HashSet<>();
List<T> res = new ArrayList<>();
for (T e : elements) {
if (!added.contains(e)) {
res.add(e);
added.add(e);
}
}
return res;
}
/**
* returns collection of model elements that's on the diagram
*
* @param diagram selected diagram
* @return
*/
public static Collection<Element> getElementsOnDiagram(Diagram diagram) {
return Project.getProject(diagram).getDiagram(diagram).getUsedModelElements(true);
}
/**
* like it says
*
* @param diagrams can be a list of any model element, only diagrams will be
* tested and returned
* @param types this needs to be a list of the diagram type names. This
* usually shows up when you hover over the new diagram icon in
* magicdraw
* @param include whether to include the diagram type or not
* @return
*/
public static List<Diagram> filterDiagramsByDiagramTypes(Collection<Element> diagrams, List<String> types, boolean include) {
List<Diagram> res = new ArrayList<>();
for (Element d : diagrams) {
Project project = Project.getProject(d);
if (!(d instanceof Diagram)) {
continue;
}
DiagramPresentationElement dpe = project.getDiagram((Diagram) d);
if (types.contains(dpe.getDiagramType().getType())) {
if (include) {
res.add((Diagram) d);
}
}
else if (!include) {
res.add((Diagram) d);
}
}
return res;
}
public static List<Element> filterElementsByStereotype(Collection<Element> elements,
Stereotype stereotype, boolean include, boolean derived) {
List<Element> res = new ArrayList<>();
if (include) {
for (Element e : elements) {
if (derived && StereotypesHelper.hasStereotypeOrDerived(e, stereotype) || !derived
&& StereotypesHelper.hasStereotype(e, stereotype)) {
res.add(e);
}
}
}
else {
for (Element e : elements) {
if (derived && !StereotypesHelper.hasStereotypeOrDerived(e, stereotype) || !derived
&& !StereotypesHelper.hasStereotype(e, stereotype)) {
res.add(e);
}
}
}
return res;
}
protected static final String[] trueStrings = new String[]{"t", "true", "1", "1.0", "yes", "y"};
public static Boolean isTrue(Object o, boolean strict) {
if (o == null) {
return strict ? null : false;
}
if (Boolean.class.isAssignableFrom(o.getClass())) {
return (Boolean) o;
}
String lower = o.toString().toLowerCase();
if (lower.equals("true")) {
return true;
}
if (lower.equals("false")) {
return false;
}
if (strict) {
return null;
}
for (String t : trueStrings) {
if (lower.equals(t)) {
return true;
}
}
return false;
}
/**
* @param elements
* @param query ocl expression
* @param include whether to include element or not if query is true
* @param iterate whether to apply query to each element or collection as a whole
* @return
*/
public static List<Element> filterElementsByExpression(Collection<Element> elements, String query,
boolean include, boolean iterate) {
List<Element> res = new ArrayList<>();
OclEvaluator evaluator;
if (!iterate) {
Object o;
DocumentValidator dv = CollectFilterParser.getValidator();
o = DocumentValidator.evaluate(query, elements, dv, true);
evaluator = OclEvaluator.instance;
if (evaluator != null && (evaluator.isValid() || !Utils2.isNullOrEmpty(o))) {
Boolean istrue = isTrue(o, false);
if (include == (istrue == null ? false : istrue)) {
res.addAll(elements);
}
}
}
else {
for (Element e : elements) {
Object o;
DocumentValidator dv = CollectFilterParser.getValidator();
o = DocumentValidator.evaluate(query, e, dv, true);
evaluator = OclEvaluator.instance;
if (evaluator != null && (evaluator.isValid() || !Utils2.isNullOrEmpty(o))) {
Boolean istrue = isTrue(o, false);
if (include == (istrue == null ? false : istrue)) {
res.add(e);
}
}
}
}
return res;
}
/**
* @param elements
* @param stereotypes
* @param include whether to include or exclude elements with given stereotypes
* @param derived whether to consider derived stereotypes
* @return
*/
public static List<Element> filterElementsByStereotypes(Collection<Element> elements,
Collection<Stereotype> stereotypes, boolean include, boolean derived) {
List<Element> res = new ArrayList<>();
if (stereotypes.isEmpty() && include) {
return res;
}
if (stereotypes.isEmpty() && !include) {
res.addAll(elements);
return res;
}
if (include) {
for (Element e : elements) {
if (derived && StereotypesHelper.hasStereotypeOrDerived(e, stereotypes) || !derived
&& StereotypesHelper.hasStereotype(e, stereotypes)) {
res.add(e);
}
}
}
else {
for (Element e : elements) {
if (derived && !StereotypesHelper.hasStereotypeOrDerived(e, stereotypes) || !derived
&& !StereotypesHelper.hasStereotype(e, stereotypes)) {
res.add(e);
}
}
}
return res;
}
/**
* matches name of elements against a collect of regular expression strings,
* see java.util.regex.Pattern for regex patterns
*
* @param elements
* @param regex
* @param include element will be returned if include is true and matched, or include is false and not matched
* @return
*/
public static List<Element> filterElementsByNameRegex(Collection<Element> elements,
Collection<String> regex, boolean include) {
List<Element> res = new ArrayList<>();
if (regex.isEmpty() && include) {
return res;
}
if (regex.isEmpty() && !include) {
res.addAll(elements);
return res;
}
List<Pattern> patterns = new ArrayList<>();
for (String s : regex) {
patterns.add(Pattern.compile(s));
}
for (Element e : elements) {
boolean matched = false;
if (e instanceof NamedElement) {
String name = ((NamedElement) e).getName();
for (Pattern p : patterns) {
if (p.matcher(name).matches()) {
matched = true;
break;
}
}
if ((include && matched) || (!include && !matched)) {
res.add(e);
}
}
}
return res;
}
/**
* @param elements
* @param javaClasses
* @param include
* @return
*/
public static List<Element> filterElementsByJavaClasses(Collection<Element> elements,
Collection<java.lang.Class<?>> javaClasses, boolean include) {
List<Element> res = new ArrayList<>();
if (Utils2.isNullOrEmpty(elements) || javaClasses == null) {
return res;
}
if (javaClasses.isEmpty() && !include) {
res.addAll(elements);
return res;
}
if (javaClasses.isEmpty() && include) {
return res;
}
if (include) {
for (Element e : elements) {
for (java.lang.Class<?> c : javaClasses) {
if (c != null && e != null && c.isInstance(e)) {
res.add(e);
break;
}
}
}
}
else {
for (Element e : elements) {
boolean add = true;
for (java.lang.Class<?> c : javaClasses) {
if (c != null && e != null && c.isInstance(e)) {
add = false;
break;
}
}
if (add) {
res.add(e);
}
}
}
return res;
}
/**
* @param elements
* @param metaclasses these are the metaclass element classes from magicdraw's uml
* profile
* @param include whether to include elements with given metaclasses or not,
* this will always include derived
* @return
*/
public static List<Element> filterElementsByMetaclasses(Collection<Element> elements,
Collection<Class> metaclasses, boolean include) {
List<java.lang.Class<?>> javaClasses = new ArrayList<>();
for (Class c : metaclasses) {
javaClasses.add(StereotypesHelper.getClassOfMetaClass(c));
}
return filterElementsByJavaClasses(elements, javaClasses, include);
}
/**
* collect the owner of the element recursively up to depth (intermediate
* owners will be returned also)
*
* @param e
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectOwners(Element e, int depth) {
List<Element> res = new ArrayList<>();
collectRecursiveOwners(e, res, depth, 1);
return res;
}
private static void collectRecursiveOwners(Element e, List<Element> all, int depth, int current) {
if (depth != 0 && current > depth) {
return;
}
Element owner = e.getOwner();
if (owner != null) {
all.add(owner);
collectRecursiveOwners(owner, all, depth, current + 1);
}
}
/**
* Collects ownedElements recursively, returned collection will not include
* source
*
* @param e
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectOwnedElements(Element e, int depth) {
List<Element> res = new ArrayList<>();
collectRecursiveOwnedElements(e, res, depth, 1);
return res;
}
private static void collectRecursiveOwnedElements(Element e, List<Element> all, int depth, int current) {
if (depth != 0 && current > depth) {
return;
}
Collection<Element> owned = e.getOwnedElement();
for (Element o : owned) {
all.add(o);
collectRecursiveOwnedElements(o, all, depth, current + 1);
}
}
/**
* Get a list including all objects that are of the specified type and are o
* or a child/grandchild of o if o is a Collection. type and the items in o
* that are of the specified type if o is a Collection.
*
* @param o
* @param type
* @return a list of objects of the specified type or an empty list if there
* are none
*/
public static <T> List<T> getListOfType(Object o, java.lang.Class<T> type) {
return getListOfType(o, type, null);
}
/**
* Get a list including all objects that are of the specified type and are o
* or a child/grandchild of o if o is a Collection. type and the items in o
* that are of the specified type if o is a Collection.
*
* @param o
* @param type
* @param seen a list of already visited objects to avoid infinite recursion
* @return a list of objects of the specified type or an empty list if there
* are none
*/
@SuppressWarnings("unchecked")
public static <T> List<T> getListOfType(Object o, java.lang.Class<T> type, Set<Object> seen) {
List<T> res = new ArrayList<T>();
if (type == null || o == null) {
return res;
}
Pair<Boolean, Set<Object>> p = Utils2.seen(o, true, seen);
if (p.getKey()) {
return res;
}
seen = p.getValue();
if (type.isInstance(o)) {
res.add((T) o);
}
else if (o instanceof Collection) {
for (Object obj : (Collection<?>) o) {
res.addAll(getListOfType(obj, type, seen));
}
}
return res;
}
/**
* Get elements returned by evaluating a query expression on an element.
*
* @param element the context of the query
* @param query a query expression, such as OCL text in a String
* @return a list containing the result of the query if it is an Element,
* the Elements in the result if it is a collection, or else an
* empty list
*/
public static List<Element> collectByExpression(Object element, Object query) {
List<Element> res = new ArrayList<Element>();
Object o = null;
DocumentValidator dv = CollectFilterParser.getValidator();
o = DocumentValidator.evaluate(query, element, dv, true);
OclEvaluator evaluator = OclEvaluator.instance;
// try {
// o = OclEvaluator.evaluateQuery(element, query);
if (evaluator.isValid() || !Utils2.isNullOrEmpty(o)) {
res.addAll(getListOfType(o, Element.class));
}
// } catch ( ParserException e ) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
return res;
}
/**
* Collect all objects of type Element in each of the results of evaluating
* the query expression on each of the elements.
*
* @param elements contexts for evaluating the expression
* @param query
* @param iterate
* @return a List of Elements
*/
public static List<Element> collectByExpression(List<Element> elements, String query, boolean iterate) {
List<Element> res = new ArrayList<>();
if (!iterate) {
res.addAll(collectByExpression(elements, query));
}
else {
for (Element e : elements) {
res.addAll(collectByExpression(e, query));
}
}
return res;
}
/**
* @param e needs to be a Classifier, else empty list will be returned
* @param depth collect to what level of depth - 0 is infinite
* @param kind
* @return
*/
public static List<Element> collectAssociatedElements(Element e, int depth, AggregationKind kind) {
List<Element> res = new ArrayList<>();
if (e instanceof Classifier) {
collectRecursiveAssociatedElements((Classifier) e, res, depth, 1, kind);
}
return res;
}
private static void collectRecursiveAssociatedElements(Classifier e, List<Element> all, int depth,
int current, AggregationKind kind) {
if (depth != 0 && current > depth) {
return;
}
Collection<Property> owned = e.getAttribute();
for (Property o : owned) {
if (all.contains(o)) {
continue;
}
if (o.getAggregation() != kind) {
continue;
}
Type type = o.getType();
if (type == null) {
continue;
}
if (all.contains(type)) {
continue;
}
all.add(type);
if (type instanceof Classifier) {
collectRecursiveAssociatedElements((Classifier) type, all, depth, current + 1, kind);
}
}
}
/**
* This will consider all relationships that are also specializations of
* javaClasses
*
* @param e
* @param javaClasses this is the class of the relationships to consider
* @param direction 0 is both, 1 is outward, 2 is inward
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipJavaClasses(Element e,
Collection<java.lang.Class<?>> javaClasses, int direction, int depth) {
List<Element> res = new ArrayList<Element>();
if (e == null) {
return res;
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipJavaClasses()");
direction = 0;
}
collectDirectedRelatedElementsByRelationshipJavaClassesRecursive(e, javaClasses, direction, depth, 1,
res);
return res;
}
private static void collectDirectedRelatedElementsByRelationshipJavaClassesRecursive(Element e,
Collection<java.lang.Class<?>> javaClasses, int direction, int depth, int curdepth,
List<Element> res) {
if (e == null) {
return;
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipJavaClassesRecursive()");
direction = 0;
}
if (depth != 0 && curdepth > depth) {
return;
}
if (direction == 0 || direction == 1) {
for (DirectedRelationship dr : e.get_directedRelationshipOfSource()) {
for (java.lang.Class<?> c : javaClasses) {
if (c.isInstance(dr)) {
if (!res.contains(ModelHelper.getSupplierElement(dr))) {
res.add(ModelHelper.getSupplierElement(dr));
collectDirectedRelatedElementsByRelationshipJavaClassesRecursive(
ModelHelper.getSupplierElement(dr), javaClasses, direction, depth,
curdepth + 1, res);
break;
}
}
}
}
}
if (direction == 0 || direction == 2) {
for (DirectedRelationship dr : e.get_directedRelationshipOfTarget()) {
for (java.lang.Class<?> c : javaClasses) {
if (c.isInstance(dr)) {
if (!res.contains(ModelHelper.getClientElement(dr))) {
res.add(ModelHelper.getClientElement(dr));
collectDirectedRelatedElementsByRelationshipJavaClassesRecursive(
ModelHelper.getClientElement(dr), javaClasses, direction, depth,
curdepth + 1, res);
break;
}
}
}
}
}
}
/**
* @param e
* @param c
* @param direction 0 is both, 1 is outward, 2 is inward
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipJavaClass(Element e, java.lang.Class<?> c, int direction, int depth) {
if (e == null) {
return Utils2.newList();
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipJavaClass()");
direction = 0;
}
List<java.lang.Class<?>> classes = new ArrayList<>();
classes.add(c);
return collectDirectedRelatedElementsByRelationshipJavaClasses(e, classes, direction, depth);
}
/**
* @param e
* @param metaclasses these are the metaclass element classes from magicdraw's uml
* profile, this will always considered derived relationship
* metaclasses
* @param direction 0 means both, 1 means e is the client, 2 means e is the
* supplier
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipMetaclasses(Element e,
Collection<Class> metaclasses, int direction, int depth) {
if (e == null) {
return null;
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipMetaclasses()");
direction = 0;
}
List<java.lang.Class<?>> javaClasses = new ArrayList<java.lang.Class<?>>();
for (Class c : metaclasses) {
javaClasses.add(StereotypesHelper.getClassOfMetaClass(c));
}
return collectDirectedRelatedElementsByRelationshipJavaClasses(e, javaClasses, direction, depth);
}
/**
* @param e
* @param stereotypes
* @param direction 0 means both, 1 means e is the client, 2 means e is the
* supplier
* @param derived whether to consider derived stereotypes
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipStereotypes(Element e,
Collection<Stereotype> stereotypes, int direction, boolean derived, int depth) {
List<Element> res = new ArrayList<Element>();
if (e == null) {
return res;
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipStereotypes()");
direction = 0;
}
// client: 0 is both, 1 is client, 2 is supplier
collectDirectedRelatedElementsByRelationshipStereotypesRecursive(e, stereotypes, direction, derived,
depth, 1, res);
return res;
}
private static void collectDirectedRelatedElementsByRelationshipStereotypesRecursive(Element e, Collection<Stereotype> stereotypes, int direction, boolean derived, int depth, int curdepth, List<Element> res) {
if (e == null) {
return;
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipStereotypesRecursive()");
direction = 0;
}
if (depth != 0 && curdepth > depth) {
return;
}
// client: 0 is both, 1 is client, 2 is supplier
if (direction == 0 || direction == 1) {
for (DirectedRelationship dr : e.get_directedRelationshipOfSource()) {
if (derived && StereotypesHelper.hasStereotypeOrDerived(dr, stereotypes) || !derived
&& StereotypesHelper.hasStereotype(dr, stereotypes)) {
if (!res.contains(ModelHelper.getSupplierElement(dr))) {
res.add(ModelHelper.getSupplierElement(dr));
collectDirectedRelatedElementsByRelationshipStereotypesRecursive(
ModelHelper.getSupplierElement(dr), stereotypes, direction, derived, depth,
curdepth + 1, res);
}
}
}
}
if (direction == 0 || direction == 2) {
for (DirectedRelationship dr : e.get_directedRelationshipOfTarget()) {
if (derived && StereotypesHelper.hasStereotypeOrDerived(dr, stereotypes) || !derived
&& StereotypesHelper.hasStereotype(dr, stereotypes)) {
if (!res.contains(ModelHelper.getClientElement(dr))) {
res.add(ModelHelper.getClientElement(dr));
collectDirectedRelatedElementsByRelationshipStereotypesRecursive(
ModelHelper.getClientElement(dr), stereotypes, direction, derived, depth,
curdepth + 1, res);
}
}
}
}
}
/**
* @param e
* @param stereotype
* @param direction direction 0 means both, 1 means e is the client, 2 means e is
* the supplier
* @param derived
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipStereotype(Element e, Stereotype stereotype, int direction, boolean derived, int depth) {
if (e == null) {
return Utils2.newList();
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipStereotype()");
direction = 0;
}
List<Stereotype> s = new ArrayList<Stereotype>();
s.add(stereotype);
return collectDirectedRelatedElementsByRelationshipStereotypes(e, s, direction, derived, depth);
}
public static List<Object> collectByStereotypeProperty(Element e, Property p) {
List<Object> results = new ArrayList<Object>();
if (p.getOwner() instanceof Stereotype) {
results.addAll(StereotypesHelper.getStereotypePropertyValue(e, (Stereotype) p.getOwner(), p));
}
if (results.isEmpty()) {
try {
Object value = e.refGetValue(p.getName()); // i think this
// only works
// for derived
// properties
if (value != null) {
if (value instanceof Collection) {
results.addAll((Collection<?>) value);
}
else {
results.add(value);
}
}
} catch (Throwable t) { // ignore
}
}
return results;
}
protected static void badDirectionError(int direction, String methodSignature) {
Debug.error("Error! Bad direction " + direction + " for " + methodSignature
+ "; using direction = 0 (both directions).");
}
/**
* @param e
* @param stereotype
* @param direction direction 0 means both, 1 means e is the client, 2 means e is
* the supplier
* @param derived
* @param depth collect to what level of depth - 0 is infinite
* @return
*/
public static List<Element> collectDirectedRelatedElementsByRelationshipStereotypeString(Element e, String stereotype, int direction, boolean derived, int depth) {
Project project = Project.getProject(e);
if (e == null) {
return Utils2.newList();
}
if (direction < 0 || direction > 2) {
badDirectionError(direction, "collectDirectedRelatedElementsByRelationshipStereotype()");
direction = 0;
}
Stereotype s = StereotypesHelper.getStereotype(project, stereotype);
if (s != null) {
return collectDirectedRelatedElementsByRelationshipStereotype(e, s, direction, derived, depth);
}
return Utils2.newList();
}
/**
* depending on includeInherited flag, gets all the attributes of e based on
* redefinition (if e is not a classifier it'll be ignored) if
* includeInherited is false, will get the owned attributes of the
* classifiers
*
* @param e
* @param includeInherited
* @return
*/
public static List<Property> getAttributes(Element e, boolean includeInherited) {
List<Property> res = new ArrayList<Property>();
if (!(e instanceof Classifier)) {
return res;
}
List<Property> owned = new ArrayList<>(((Classifier) e).getAttribute());
res.addAll(owned);
if (includeInherited) {
Collection<NamedElement> inherited = new ArrayList<>(
((Classifier) e).getInheritedMember());
List<NamedElement> inheritedCopy = new ArrayList<>(inherited);
for (NamedElement ne : inherited) {
if (ne instanceof Property) {
for (Property redef : ((Property) ne).getRedefinedProperty()) {
inheritedCopy.remove(redef);
}
}
else {
inheritedCopy.remove(ne);
}
}
for (Property p : owned) {
for (Property redef : p.getRedefinedProperty()) {
inheritedCopy.remove(redef);
}
}
for (NamedElement ee : inheritedCopy) {
res.add((Property) ee);
}
}
return res;
}
public static List<Element> intersectionOfCollections(Collection<? extends Collection<Element>> a) {
List<Element> i = new ArrayList<Element>();
Set<Element> inter = new HashSet<Element>(a.iterator().next());
for (Collection<Element> es : a) {
inter.retainAll(es);
}
i.addAll(inter);
return i;
}
public static List<Element> unionOfCollections(Collection<? extends Collection<Element>> a) {
List<Element> i = new ArrayList<Element>();
Set<Element> union = new HashSet<Element>(a.iterator().next());
for (Collection<Element> c : a) {
union.addAll(c);
}
i.addAll(union);
return i;
}
/**
* returns elements not shared
* misnomer - this is really doing the symmetric difference
*
* @param cc
* @return
*/
public static List<Element> xorOfCollections(Collection<? extends Collection<Element>> cc) {
if (cc.size() > 1) {
Iterator<? extends Collection<Element>> i = cc.iterator();
Set<Element> a = new HashSet<>(i.next());
Set<Element> b = new HashSet<>(i.next());
Set<Element> c = new HashSet<>();
c.addAll(a);
c.addAll(b);
a.retainAll(b);
c.removeAll(a);
return new ArrayList<>(c);
}
return new ArrayList<>();
}
/**
* Sorts e by name, returns a new list with name ordered elements
*
* @param e
* @return
*/
public static <T, TT extends T> List<T> sortByName(Collection<TT> e) {
List<T> n = new ArrayList<T>(e);
Collections.sort(n, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
if (o1 == o2) {
return 0;
}
if (o1 == null) {
return -1;
}
if (o2 == null) {
return 1;
}
if (o1 instanceof NamedElement && o2 instanceof NamedElement) {
return ((NamedElement) o1).getName().toLowerCase().compareTo(((NamedElement) o2).getName().toLowerCase());
}
return CompareUtils.compare(o1, o2);
}
});
return n;
}
/**
* Sorts elements by a specific attribute limited to the enumeration below,
* which is suspiciously similar to the possible attributes in
* tableAttributeColumn...
*
* @param elem
* @param attr
* @return
*/
public static List<Element> sortByAttribute(Collection<? extends Element> elem, AvailableAttribute attr) {
List<Element> list = new ArrayList<Element>(elem);
switch (attr) {
case Name:
Collections.sort(list, getAttributeComparator(AvailableAttribute.Name, false));
break;
case Documentation:
Collections.sort(list, getAttributeComparator(AvailableAttribute.Documentation, false));
break;
case Value:
boolean isAllNumbers = true;
for (Element e : list) {
if (!Utils2.isNumber(DocGenUtils.fixString(getElementAttribute(e, attr)))) {
isAllNumbers = false;
break;
}
}
Collections.sort(list, getAttributeComparator(AvailableAttribute.Value, isAllNumbers));
break;
}
return list;
}
private static Comparator<Element> getAttributeComparator(AvailableAttribute attr, boolean isAllNumbers) {
final AvailableAttribute attribute = attr;
final boolean allNums = isAllNumbers;
return new Comparator<Element>() {
@Override
public int compare(Element A, Element B) {
if (A == B) {
return 0;
}
if (A == null) {
return -1;
}
if (B == null) {
return 1;
}
Object a = getElementAttribute(A, attribute);
Object b = getElementAttribute(B, attribute);
if (a == b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
switch (attribute) {
case Name:
return CompareUtils.compare(a.toString().toLowerCase(), b.toString().toLowerCase(), true);
case Documentation:
return CompareUtils.compare(a.toString().length(), b.toString().length(), true);
case Value:
if (allNums) {
Double da = Utils2.toDouble(DocGenUtils.fixString(a));
Double db = Utils2.toDouble(DocGenUtils.fixString(b));
return CompareUtils.compare(da, db, true);
}
return CompareUtils.compare(a, b, true);
default:
return CompareUtils.compare(a, b, true);
}
}
};
}
/**
* Sorts elements by a any property. Strings treated alphabetically, numbers
* treated least on top.
*
* @param elem
* @param prop
* @return
*/
public static List<Element> sortByProperty(Collection<? extends Element> elem, Property prop) {
List<Element> list = new ArrayList<Element>(elem);
// Check if all numbers first
boolean isAllNumbers = true;
for (Element e : list) {
List<Object> temp = getElementPropertyValues(e, prop, true);
if (temp.size() != 1) {
isAllNumbers = false;
break;
}
for (Object o : temp) {
if (!Utils2.isNumber(DocGenUtils.fixString(o))) {
isAllNumbers = false;
break;
}
}
if (!isAllNumbers) {
break;
}
}
Collections.sort(list, getPropertyComparator(prop, isAllNumbers));
return list;
}
private static Comparator<Element> getPropertyComparator(Property prop, boolean isAllNumbers) {
final Property property = prop;
final boolean allNums = isAllNumbers;
return new Comparator<Element>() {
@Override
public int compare(Element A, Element B) {
if (A == B) {
return 0;
}
if (A == null) {
return -1;
}
if (B == null) {
return 1;
}
List<Object> a = getElementPropertyValues(A, property, true);
List<Object> b = getElementPropertyValues(B, property, true);
if (a == b) {
return 0;
}
if (a == null) {
return -1;
}
if (b == null) {
return 1;
}
if (a.size() == 1 && b.size() == 1) {
Object a0 = a.get(0);
Object b0 = b.get(0);
String as = DocGenUtils.fixString(a0);
String bs = DocGenUtils.fixString(b0);
if (allNums) {
Double da0 = Utils2.toDouble(as);
Double db0 = Utils2.toDouble(bs);
return CompareUtils.compare(da0, db0, true);
}
else {
return CompareUtils.compare(as, bs, true);
}
}
else {
return a.size() - b.size();
}
}
};
}
/**
* Sorts elements by attribute, provided it is one of those supported by
*
* @param elem the element whose attribute is sought
* @param attr the type of attribute (name, value, ...)
* @return
*/
public static List<Element> sortByAttribute(Collection<? extends Element> elem, Object attr) {
return sortByAttribute(elem, getAvailableAttribute(attr));
}
public static List<Element> sortByExpression(Collection<? extends Element> elem, Object o) {
List<Element> list = new ArrayList<Element>(elem);
// Check if all numbers
boolean isAllNumbers = true;
Map<Element, Object> resultMap = new HashMap<Element, Object>();
Map<Element, Object> resultNumberMap = new HashMap<Element, Object>();
for (Element e : list) {
Object result = null;
DocumentValidator dv = CollectFilterParser.getValidator();
result = DocumentValidator.evaluate(o, e, dv, true);
// try {
// result = OclEvaluator.evaluateQuery(e, o);
// } catch ( ParserException e1 ) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
resultMap.put(e, result);
if (!isAllNumbers) {
continue;
}
Collection<?> coll = null;
if (result instanceof Collection) {
coll = ((Collection<?>) result);
}
if (coll != null && coll.size() > 0) {
isAllNumbers = false;
continue;
}
if (coll != null) {
List<Object> numbers = new ArrayList<Object>();
for (Object c : coll) {
String s = DocGenUtils.fixString(c);
if (isAllNumbers) {
if (Utils2.isNumber(s)) {
numbers.add(Utils2.toDouble(s));
}
else {
isAllNumbers = false;
break;
}
}
}
if (isAllNumbers) {
resultNumberMap.put(e, numbers);
}
}
else {
String s = DocGenUtils.fixString(result);
if (!Utils2.isNumber(s)) {
isAllNumbers = false;
}
else {
resultNumberMap.put(e, Utils2.toDouble(s));
}
}
}
if (isAllNumbers) {
resultMap = resultNumberMap;
}
Collections.sort(list, new DocGenComparator(resultMap, isAllNumbers));
return list;
}
public static class DocGenComparator implements Comparator<Object> {
final boolean allNums;
Map<Element, Object> resultMap = null;
public DocGenComparator(boolean isAllNumbers) {
allNums = isAllNumbers;
}
public DocGenComparator(Map<Element, Object> resultMap, boolean isAllNumbers) {
this.resultMap = resultMap;
allNums = isAllNumbers;
}
@Override
public int compare(Object A, Object B) {
Object resultA = resultMap == null ? A : resultMap.get(A);
Object resultB = resultMap == null ? B : resultMap.get(B);
return docgenCompare(resultA, resultB, allNums);
}
}
private static int docgenCompare(Object a0, Object b0, boolean asNumbers) {
if (a0 == b0) {
return 0;
}
if (a0 == null) {
return -1;
}
if (b0 == null) {
return 1;
}
String as = DocGenUtils.fixString(a0);
String bs = DocGenUtils.fixString(b0);
if (as == bs) {
return 0;
}
if (as == null) {
return -1;
}
if (bs == null) {
return 1;
}
if (asNumbers) {
Double da0 = Utils2.toDouble(as);
Double db0 = Utils2.toDouble(bs);
return CompareUtils.compare(da0, db0, true);
}
else {
return CompareUtils.compare(as, bs, true);
}
}
/**
* returns all directed relationships where client element is source and
* supplier element is target
*
* @param source
* @param target
* @return
*/
public static List<DirectedRelationship> findDirectedRelationshipsBetween(Element source, Element target) {
List<DirectedRelationship> res = new ArrayList<DirectedRelationship>();
for (DirectedRelationship dr : source.get_directedRelationshipOfSource()) {
if (ModelHelper.getSupplierElement(dr) == target) {
res.add(dr);
}
}
return res;
}
/**
* @param object the object to test for a match
* @param typeName regular expression String according to Pattern
* @return whether the name of the object's Stereotype, EClass, or Java
* class matches the typeName regular expression pattern
*/
public static boolean isTypeOf(Object object, String typeName) {
GetCallOperation op = new GetCallOperation(CallReturnType.TYPE, true, true);
Object result = op.callOperation(object, new Object[]{typeName});
if (result instanceof Collection && ((Collection<?>) result).size() == 1) {
if (matches(((Collection<?>) result).iterator().next(), typeName)) {
return true;
}
}
return matches(result, typeName);
}
/**
* See if the object matches the regular expression pattern by its name,
* type, or string value.
*
* @param object the object to test
* @param pattern a Pattern regular expression string to match to the object
* @return whether the name, type, or String value of the object matches the
* regular expression pattern
*/
private static boolean matches(Object object, String pattern) {
// TODO -- types are limited to Stereotypes, EClasses, and Java Classes,
// but metaclasses/base classes are left out here and in other methods
// here that use regex patterns.
String name = getName(object);
if (EmfUtils.matches(name, pattern)) {
return true;
}
boolean matched = EmfUtils.matches(object, pattern);
return matched;
}
/**
* @return the element at the top of the MagicDraw containment tree
*/
public static Package getRootElement(Project project) {
return project == null ? null : project.getPrimaryModel();
}
public static boolean isSiteChar(Project project, Package e) {
Stereotype characterizes = Utils.getCharacterizesStereotype(project);
if (characterizes != null) {
List<Element> sites = Utils.collectDirectedRelatedElementsByRelationshipStereotype(e, characterizes, 2, false, 1);
boolean found = false;
for (Element l : sites) {
/*if (l instanceof NamedElement && ((NamedElement)l).getName().equals("Site Characterization")) {
found = true;
break;
}*/
if (l instanceof Classifier) {
for (Classifier g : ((Classifier) l).getGeneral()) {
if (g.getName().equals("Site Characterization")) {
found = true;
break;
}
}
}
}
return found;
}
return false;
}
public static Map<Element, Map<String, Collection<Element>>> nameOrIdSearchOwnerCache =
new HashMap<Element, Map<String, Collection<Element>>>();
public static Map<String, Collection<Element>> nameOrIdSearchCache =
new HashMap<String, Collection<Element>>();
public static Map<String, Element> nameOrIdSingleElementSearchCache =
new HashMap<String, Element>();
public static Map<Element, Map<String, Element>> nameOrIdSingleElementSearchOwnerCache =
new HashMap<Element, Map<String, Element>>();
public static List<Element> findByName(Project project, String pattern, boolean getJustFirst) {
// check cache
if (getJustFirst) {
Element e = nameOrIdSingleElementSearchCache.get(pattern);
if (e != null) {
return Utils2.newList(e);
}
}
else {
Collection<Element> res = nameOrIdSearchCache.get(pattern);
return Utils2.asList(res);
}
// start at root and search recursively through children
if (Utils2.isNullOrEmpty(pattern)) {
return null;
}
Element root = getRootElement(project);
List<Element> results = findByName(root, pattern, getJustFirst);
nameOrIdSearchCache.put(pattern, results);
return results;
}
public static List<Element> findByName(Element owner,
String pattern,
boolean getJustFirst) {
// check cache
if (getJustFirst) {
Element e = Utils2.get(nameOrIdSingleElementSearchOwnerCache,
owner, pattern);
if (e != null) {
return Utils2.newList(e);
}
}
else {
Collection<Element> res =
Utils2.get(nameOrIdSearchOwnerCache, owner, pattern);
return Utils2.asList(res);
}
// check immediate children
List<Element> results = new ArrayList<Element>();
for (Element e : owner.getOwnedElement()) {
if (e instanceof NamedElement) {
Pattern p = Pattern.compile(pattern);
Matcher matcher = p.matcher(((NamedElement) e).getName());
if (matcher.matches()) {
results.add(e);
// Utils2.add( nameOrIdSearchOwnerCache, owner, pattern, e );
if (getJustFirst) {
nameOrIdSingleElementSearchCache.put(pattern, e);
return results;
}
}
}
}
// check children of children
for (Element e : owner.getOwnedElement()) {
results.addAll(findByName(e, pattern, getJustFirst));
if (getJustFirst && results.size() > 0) {
Utils2.put(nameOrIdSingleElementSearchOwnerCache, owner, pattern, e);
return results;
}
}
Utils2.put(nameOrIdSearchOwnerCache, owner, pattern, results);
return results;
}
public static Stereotype getStereotype(Project project, String stereotypeName) {
return StereotypesHelper.getStereotype(project, stereotypeName);
}
/********************************************** Direct Stereotype Utils **********************************************/
/*** SysML::Model Elements ***/
public static Stereotype getConformsStereotype(Project project) {
return (Stereotype) project.getElementByID("_11_5EAPbeta_be00301_1147420728091_674481_152");
}
public static Stereotype get18ExposeStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5beta_17530432_1382587480303_325976_12505");
}
public static Stereotype getElementGroupStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5beta_17530432_1382588727729_600191_12925");
}
public static Stereotype getViewStereotype(Project project) {
return (Stereotype) project.getElementByID("_11_5EAPbeta_be00301_1147420760998_43940_227");
}
public static Stereotype getViewpointStereotype(Project project) {
return (Stereotype) project.getElementByID("_11_5EAPbeta_be00301_1147420812402_281263_364");
}
/*** SysML Extensions::_Stereotypes ***/
public static Stereotype getAccountableForStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_e9f034d_1371599170030_696081_43276");
}
public static Stereotype getApprovesStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_e9f034d_1375464433330_503144_31131");
}
public static Stereotype getAspectStereotype(Project project) {
return (Stereotype) project.getElementByID("_18_0_2_407019f_1449688347122_736579_14412");
}
public static Stereotype getCharacterizesStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5_1_8660276_1407362513794_939259_26181");
}
public static Stereotype getConcursStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_e9f034d_1375464334580_276276_31083");
}
public static Stereotype getDirectedConnectorStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5_1_407019f_1404149304683_834035_15551");
}
public static Stereotype getDocumentStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_87b0275_1371477871400_792964_43374");
}
public static Stereotype getJobStereotype(Project project) {
return (Stereotype) project.getElementByID("_18_0_5_407019f_1458258829038_313297_14086");
}
public static Stereotype getPrecedesStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5_1_407019f_1404148746390_373063_15528");
}
public static Stereotype getProjectStaffStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_8850274_1368737927790_384872_57206");
}
public static Stereotype getRoleStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_8850274_1368582235157_5746_56799");
}
public static Stereotype getTicketStereotype(Project project) {
return (Stereotype) project.getElementByID("_18_0_5_407019f_1462145965413_380403_14076");
}
/*** SysML Extensions::DocGen::MDK EMP Client::Document Profile ***/
public static Stereotype getCommentStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5_407019f_1337877314051_474317_11891");
}
public static Stereotype getSysML14ConformsStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_407019f_1389807639137_860750_29082");
}
public static Stereotype getExposeStereotype(Project project) {
return (Stereotype) project.getElementByID("_16_5_4_409a058d_1259862803278_226185_1083");
}
/*** SysML Extensions::DocGen::MDK EMP Client::Document Profile::Containers ***/
public static Stereotype getProductStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_1_407019f_1326996604350_494231_11646");
}
public static Stereotype getExpressionStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_e9f034d_1382549095816_841656_29288");
}
public static Stereotype getExpressionLibraryStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_2_3_e9f034d_1382560401073_180081_29279");
}
@Deprecated
public static Stereotype getViewClassStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_1_232f03dc_1325612611695_581988_21583");
}
/*** SysML Extensions::DocGen::MDK EMP Client::Presentation Elements ***/
public static Stereotype getPresentsStereotype(Project project) {
return (Stereotype) project.getElementByID("_17_0_5_1_407019f_1430628469999_419411_12119");
}
/********************************************** Direct Property Utils **********************************************/
/*** SysML Extensions::DocGen::MDK EMP Client::Presentation Elements::PresentationElement ***/
public static Property getGeneratedFromViewProperty(Project project) {
return (Property) project.getElementByID("_17_0_5_1_407019f_1430628276506_565_12080");
}
/*** SysML Extensions::DocGen::MDK EMP Client::Presentation Elements::OpaqueSection ***/
public static Property getGeneratedFromElementProperty(Project project) {
return (Property) project.getElementByID("_17_0_5_1_407019f_1430628376067_525763_12104");
}
public static Property getViewElementsProperty(Project project) {
return (Property) project.getElementByID("_18_0_2_407019f_1433361787467_278914_14410");
}
/********************************************** Direct Component Utils **********************************************/
/*** SysML Extensions::Model Management Helpers::Model Management Profile::Site Package Characterization::Library ***/
public static Component getSiteCharacterizationComponent(Project project) {
return (Component) project.getElementByID("_17_0_5_1_8660276_1415063844134_132446_18688");
}
/********************************************** Constraint Utils **********************************************/
public static Constraint getViewConstraint(Element view) {
if (view != null) {
Collection<Constraint> constraints = view.get_constraintOfConstrainedElement();
for (Constraint constraint : constraints) {
if (constraint != null && Converters.getElementToIdConverter().apply(constraint).endsWith((MDKConstants.VIEW_CONSTRAINT_SYSML_ID_SUFFIX))) {
return constraint;
}
}
}
return null;
}
public static Constraint getWarningConstraint(Project project) {
return (Constraint) project.getElementByID("_17_0_2_2_f4a035d_1360957024690_702520_27755");
}
public static Constraint getErrorConstraint(Project project) {
return (Constraint) project.getElementByID("_17_0_2_407019f_1354058024392_224770_12910");
}
public static Constraint getFatalConstraint(Project project) {
return (Constraint) project.getElementByID("_17_0_2_2_f4a035d_1360957445325_901851_27756");
}
public static Constraint getInfoConstraint(Project project) {
return (Constraint) project.getElementByID("_17_0_2_2_f4a035d_1360957474351_901777_27765");
}
/********************************************* User interaction ****************************************************/
/**
* Log to GUILog in UI's event dispatcher
*/
public static void guilog(final String s) {
Application.getInstance().getGUILog().log(s, !s.startsWith("[INFO]"));
}
/**
* @param types
* @param title title of the dialog box
* @return
*/
public static BaseElement getUserSelection(List<java.lang.Class<?>> types, String title) {
SelectElementTypes a = new SelectElementTypes(null, types);
SelectElementInfo b = new SelectElementInfo(false, false, Application.getInstance().getProject().getPrimaryModel(), true);
Frame dialogParent = MDDialogParentProvider.getProvider().getDialogParent();
ElementSelectionDlg dlg = ElementSelectionDlgFactory.create(dialogParent);
ElementSelectionDlgFactory.initSingle(dlg, a, b, null);
dlg.setTitle(title);
dlg.show();
if (dlg.isOkClicked()) {
return dlg.getSelectedElement();
}
return null;
}
public static void showPopupMessage(String message) {
if (popupsDisabled || MainFrame.isSilentMode()) {
Utils.guilog("[POPUP] " + message);
}
else {
JOptionPane.showMessageDialog(Application.getInstance().getMainFrame(), message);
}
}
public static Boolean getUserYesNoAnswerWithButton(String question, String[] buttons, boolean includeCancel) {
if (forceDialogFalse) {
forceDialogFalse = false;
return false;
}
if (forceDialogTrue) {
forceDialogTrue = false;
return true;
}
if (forceDialogCancel) {
forceDialogCancel = false;
return null;
}
int option = includeCancel ? JOptionPane.YES_NO_CANCEL_OPTION : JOptionPane.YES_NO_OPTION;
int res = JOptionPane.showOptionDialog(Application.getInstance().getMainFrame(), question, "Choose", option, JOptionPane.QUESTION_MESSAGE, null, buttons, buttons[0]);
if (res == JOptionPane.YES_OPTION) {
return true;
}
else if (res == JOptionPane.NO_OPTION) {
return false;
}
return null;
}
/**
* @param question
* @return null if user hits cancel
*/
public static Boolean getUserYesNoAnswer(String question) {
if (forceDialogFalse) {
forceDialogFalse = false;
return false;
}
if (forceDialogTrue) {
forceDialogTrue = false;
return true;
}
if (forceDialogCancel) {
forceDialogCancel = false;
return null;
}
int res = JOptionPane.showConfirmDialog(Application.getInstance().getMainFrame(), question);
if (res == JOptionPane.YES_OPTION) {
return true;
}
else if (res == JOptionPane.NO_OPTION) {
return false;
}
return null;
}
public static Set<Annotation> getAnnotations(ValidationRule vr, Project project, Constraint cons) {
Set<Annotation> annotations = new LinkedHashSet<Annotation>();
List<RuleViolationResult> results = getRuleViolations(vr, project, cons);
for (RuleViolationResult violation : results) {
annotations.add(violation.getAnnotation());
}
return annotations;
}
public static List<RuleViolationResult> getRuleViolations(ValidationRule vr, Project project, Constraint cons) {
List<RuleViolationResult> results = new ArrayList<RuleViolationResult>();
EnumerationLiteral severity;
/*
* Switch added by Peter Di Pasquale 02/15/2013 Changelog: switch
* statement added, selects element highlight and icon color according
* to severity of error.
*/
switch (vr.getSeverity()) {
case WARNING:
severity = Annotation.getSeverityLevel(project, Annotation.WARNING);
cons = Utils.getWarningConstraint(project);
break;
case ERROR:
severity = Annotation.getSeverityLevel(project, Annotation.ERROR);
cons = Utils.getErrorConstraint(project);
break;
case FATAL:
severity = Annotation.getSeverityLevel(project, Annotation.FATAL);
cons = Utils.getFatalConstraint(project);
break;
case INFO:
severity = Annotation.getSeverityLevel(project, Annotation.INFO);
cons = Utils.getInfoConstraint(project);
break;
default:
severity = Annotation.getSeverityLevel(project, Annotation.WARNING);
break;
}
for (ValidationRuleViolation vrv : vr.getViolations()) {
Annotation anno;
if (vrv.getActions() != null && vrv.getActions().size() > 0) {
anno = new Annotation(severity, vr.getName(), vrv.getComment(), vrv.getElement(), vrv.getActions());
for (NMAction action : vrv.getActions()) {
if (action instanceof IRuleViolationAction) {
((IRuleViolationAction) action).setAnnotation(anno);
}
}
}
else {
anno = new Annotation(severity, vr.getName(), vrv.getComment(), vrv.getElement());
}
RuleViolationResult rvr = new RuleViolationResult(anno, cons);
results.add(rvr);
if (vrv.getActions() != null && vrv.getActions().size() > 0) {
for (NMAction action : vrv.getActions()) {
if (action instanceof IRuleViolationAction) {
((IRuleViolationAction) action).setRuleViolationResult(rvr);
}
}
}
}
return results;
}
public static List<RuleViolationResult> getRuleViolations(Project project, Collection<ValidationSuite> vss) {
List<RuleViolationResult> results = new ArrayList<>();
Constraint cons = Utils.getWarningConstraint(project);
for (ValidationSuite vs : vss) {
for (ValidationRule vr : vs.getValidationRules()) {
results.addAll(getRuleViolations(vr, project, cons));
}
}
return results;
}
public static void displayValidationWindow(Project project, ValidationSuite vs, String title) {
final List<ValidationSuite> vss = new ArrayList<>();
vss.add(vs);
displayValidationWindow(project, vss, title);
}
public static void displayValidationWindow(Project project, Collection<ValidationSuite> vss, String title) {
List<RuleViolationResult> results = getRuleViolations(project, vss);
Set<Element> elements = new LinkedHashSet<>();
for (RuleViolationResult violation : results) {
elements.add((Element) violation.getElement());
}
Package dummyvs = (Package) project.getElementByID("_17_0_2_407019f_1354124289134_280378_12909");
if (dummyvs == null) {
Application.getInstance().getGUILog().log("You don't have SysML Extensions mounted! You need it in order for the validations to show.");
return;
}
EnumerationLiteral severitylevel = Annotation.getSeverityLevel(project, Annotation.INFO);
ValidationRunData runData = new ValidationRunData(dummyvs, false, elements, severitylevel);
// TODO @donbot change the id here from ms to the action name - this will cause windows to be reused
String id = "" + System.currentTimeMillis();
Map<Annotation, RuleViolationResult> mapping = new HashMap<>();
ValidationWindowRun vwr = new ValidationWindowRun(id, title, runData, results, mapping);
for (RuleViolationResult rvr : results) {
for (NMAction action : rvr.getAnnotation().getActions()) {
if (action instanceof IRuleViolationAction) {
((IRuleViolationAction) action).setValidationWindowRun(vwr);
}
}
mapping.put(rvr.getAnnotation(), rvr);
}
ValidationResultsWindowManager.updateValidationResultsWindow(id, title, runData, results);
}
/************************************************ Model Modification **************************************/
/**
* Copies all stereotypes of element a to element b if b doesn't already
* have it (including derived)
*
* @param a
* @param b
*/
public static void copyStereotypes(Element a, Element b) {
for (Stereotype s : StereotypesHelper.getStereotypes(a)) {
if (!StereotypesHelper.hasStereotypeOrDerived(b, s)) {
StereotypesHelper.addStereotype(b, s);
}
}
}
/**
* Creates a generalization relationship between parent and child
*
* @param parent
* @param child
*/
public static void createGeneralization(Classifier parent, Classifier child) {
Generalization g = Project.getProject(parent).getElementsFactory().createGeneralizationInstance();
ModelHelper.setClientElement(g, child);
ModelHelper.setSupplierElement(g, parent);
g.setOwner(child);
}
private static void setOwnerPackage(Element child, Element parent) {
while (!(parent instanceof Package)) {
parent = parent.getOwner();
}
child.setOwner(parent);
}
public static void createDependencyWithStereotype(Element from, Element to, Stereotype s) {
Dependency d = Project.getProject(from).getElementsFactory().createDependencyInstance();
ModelHelper.setClientElement(d, from);
ModelHelper.setSupplierElement(d, to);
StereotypesHelper.addStereotype(d, s);
setOwnerPackage(d, from);
}
/**
* This will set the default value of p to value, based on what type the
* default value currently is right now, it'll try to convert to:
* LiteralBoolean, LiteralInteger, LiteralUnlimitedNatural, otherwise it'll
* be a LiteralString more options possibly in future like durations, etc
*
* @param p
* @param value
*/
public static void setPropertyValue(Property p, String value) {
Project project = Project.getProject(p);
ValueSpecification valueSpec = p.getDefaultValue();
ValueSpecification v = makeValueSpecification(project, value, valueSpec);
p.setDefaultValue(v);
}
/**
* This will set the default value of p to value, based on what type the
* default value currently is right now, it'll try to convert to:
* LiteralBoolean, LiteralInteger, LiteralUnlimitedNatural, otherwise it'll
* be a LiteralString more options possibly in future like durations, etc
*
* @param slot
* @param value
*/
public static void setSlotValue(Slot slot, Object value) {
Project project = Project.getProject(slot);
List<ValueSpecification> valueSpecs = slot.getValue();
ValueSpecification v = null;
if (value instanceof ValueSpecification) {
v = (ValueSpecification) value;
}
else {
for (ValueSpecification valueSpec : valueSpecs) {
v = makeValueSpecification(project, value.toString(), valueSpec);
break;
}
}
valueSpecs.clear();
valueSpecs.add(v);
}
/**
* Creates a new {@link ValueSpecification} of the same type as valueSpec
* but with a new value to be parsed from a {@link String}. It'll try to
* convert to: LiteralBoolean, LiteralInteger, LiteralUnlimitedNatural,
* otherwise it'll be a LiteralString more options possibly in future like
* durations, etc
*
* @param value
* @param valueSpec
* @return
*/
public static ValueSpecification makeValueSpecification(Project project, String value, ValueSpecification valueSpec) {
ElementsFactory ef = project.getElementsFactory();
ValueSpecification v;
try {
if (valueSpec instanceof LiteralBoolean) {
v = ef.createLiteralBooleanInstance();
if (value.equals("false") || value.equals("False") || value.equals("F") || value.equals("f")
|| value.equals("no") || value.equals("n") || value.isEmpty()
|| value.equals("FALSE") || value.equals("NO") || value.equals("No")) {
((LiteralBoolean) v).setValue(false);
}
else {
((LiteralBoolean) v).setValue(true);
}
}
else if (valueSpec instanceof LiteralInteger) {
v = ef.createLiteralIntegerInstance();
((LiteralInteger) v).setValue(Integer.parseInt(value));
}
else if (valueSpec instanceof LiteralUnlimitedNatural) {
v = ef.createLiteralUnlimitedNaturalInstance();
((LiteralUnlimitedNatural) v).setValue(Integer.parseInt(value));
}
else if (valueSpec instanceof LiteralReal) {
v = ef.createLiteralRealInstance();
((LiteralReal) v).setValue(Double.parseDouble(value));
}
else {
v = ef.createLiteralStringInstance();
((LiteralString) v).setValue(value);
}
} catch (NumberFormatException e) {
// The field is no longer a number; treat it as a string
// REVIEW -- This may conflict with the element's type. Should we
// change the type of the element?
// TODO -- Only some of the ValueSpecifications are supported here.
// The
// subclasses of ValueSpecification and supportive factory methods
// in
// ElementFactory can guide the addition of types.
v = makeValueSpecification(project, value, ef.createLiteralStringInstance());
}
return v;
}
/************************* Getting element attributes and properties/values ****************************/
public enum AvailableAttribute {
Name, Documentation, Value
}
/**
* Convert to an From enum value
*
* @param attr the attribute of some type
* @return the corresponding From value
*/
public static From getFromAttribute(Object attr) {
if (attr instanceof From) {
return (From) attr;
}
if (attr instanceof AvailableAttribute) {
AvailableAttribute aattr = (AvailableAttribute) attr;
switch (aattr) {
case Name:
return From.NAME;
case Documentation:
return From.DOCUMENTATION;
case Value:
return From.DVALUE;
default:
}
}
if (attr instanceof EnumerationLiteral) {
return getFromAttribute(((EnumerationLiteral) attr).getName());
}
From f = null;
if (attr instanceof String) {
try {
f = getFromAttribute(From.valueOf((String) attr));
} catch (Exception e) {
}
try {
if (f == null) {
f = getFromAttribute(AvailableAttribute.valueOf((String) attr));
}
} catch (Exception e) {
}
}
if (f == null) {
Debug.error(false, "Unexpected argument " + attr + " to getFromAttribute().");
}
return f;
}
/**
* Convert the input Object to an availableAttribute enum value. Supported
* attribute objects include AvailableAttribute, From, EnumerationLiteral,
* and String.
*
* @param attr the attribute of some type
* @return the corresponding AvailableAttribute
*/
public static AvailableAttribute getAvailableAttribute(Object attr) {
if (attr instanceof AvailableAttribute) {
return (AvailableAttribute) attr;
}
if (attr instanceof From) {
From fattr = (From) attr;
switch (fattr) {
case NAME:
return AvailableAttribute.Name;
case DOCUMENTATION:
return AvailableAttribute.Documentation;
case DVALUE:
return AvailableAttribute.Value;
default:
}
}
if (attr instanceof EnumerationLiteral) {
return getAvailableAttribute(((EnumerationLiteral) attr).getName());
}
AvailableAttribute aattr = null;
if (attr instanceof String) {
try {
aattr = getAvailableAttribute(AvailableAttribute.valueOf((String) attr));
} catch (Exception e) {
}
try {
if (aattr == null) {
aattr = getAvailableAttribute(From.valueOf((String) attr));
}
} catch (Exception e) {
}
}
if (aattr == null) {
Debug.error(false, "Unexpected argument " + attr + " to getFromAttribute().");
}
return aattr;
}
/**
* Returns an attribute of the element based on the input availableAttribute
* type.
*
* @param elem the element whose attribute is sought
* @param attr the type of attribute (name, value, ...)
* @return possible return values are String for name or documentation,
* ValueSpec, or List of ValueSpec
*/
public static Object getElementAttribute(Element elem, AvailableAttribute attr) {
switch (attr) {
case Name:
if (elem instanceof NamedElement) {
return ((NamedElement) elem).getName();
}
else {
return elem.getHumanName();
}
case Documentation:
return ModelHelper.getComment(elem);
case Value:
if (elem instanceof Property) {
return ((Property) elem).getDefaultValue();
}
else if (elem instanceof Slot) {
return ((Slot) elem).getValue();
}
else if (elem instanceof Constraint) {
return ((Constraint) elem).getSpecification();
}
default:
return null;
}
}
/**
* Get Class Properties with a name matching that of the input Property.
*
* @param elem the owner of the Property
* @param prop a property of the same name as that owned by the input Element
* @param inherited ignored for now, should indicate whether to look for inherited
* properties
* @return the Properties of the input Element whose names match that of the
* input Property
*/
public static Property getClassProperty(Element elem, Property prop, boolean inherited) {
if (prop == null) {
return null;
}
Collection<Element> rOwned = elem.getOwnedElement();
for (Element o : rOwned) {
if (o instanceof Property && ((Property) o).getName().equals(prop.getName())) {
return (Property) o;
}
}
return null;
}
/**
* Get the element's matching Slot.
*
* @param elem the source Element
* @param prop the Stereotype tag that the Slot instantiates
* @return a Slot with zero or more values or null if no such Slot exists
*/
public static Slot getSlot(Element elem, Property prop) {
if (prop == null || elem == null) {
return null;
}
Element myOwner = prop.getOwner();
if (myOwner instanceof Stereotype
&& StereotypesHelper.hasStereotypeOrDerived(elem, (Stereotype) myOwner)) { // REVIEW
// may not be able to get slot from derived stereotype
Slot slot = StereotypesHelper.getSlot(elem, prop, false);
if (slot != null) {
return slot;
}
}
return null;
}
/**
* @param elem
* @return all slots for the element's applied stereotype instance
*/
public static List<Slot> getSlots(Element elem) {
List<Slot> slots = new ArrayList<Slot>();
InstanceSpecification localInstanceSpecification = elem.getAppliedStereotypeInstance();
if (localInstanceSpecification != null) {
slots.addAll(localInstanceSpecification.getSlot());
}
return slots;
}
/**
* Get the element's matching Slots or Properties.
*
* @param elem the Element with the sought Properties.
* @param prop the Stereotype tag or Class Property
* @return a slot that matches the input property or null
*/
public static Slot getStereotypeProperty(Element elem, Property prop) {
return getSlot(elem, prop);
}
public static Property getClassProperty(Element elem, String propName,
boolean inherited) {
for (Element e : elem.getOwnedElement()) {
if (e instanceof Property) {
if (((Property) e).getName().equals(propName)) {
return (Property) e;
}
}
}
return null;
}
public static Property getElementStereotypeProperty(Element elem,
String propName) {
List<Stereotype> stereotypes = StereotypesHelper.getStereotypes(elem);
for (Stereotype stereotype : stereotypes) {
Property prop = getStereotypePropertyByName(stereotype, propName);
if (prop != null) {
return prop;
}
}
return null;
}
/**
* Get the property of the stereotype by name.
*
* @param stereotype
* @param propName
* @return
*/
public static Property getStereotypePropertyByName(Stereotype stereotype,
String propName) {
return StereotypesHelper.getPropertyByName(stereotype, propName);
}
/**
* Get the element's matching Slot or Properties.
*
* @param elem the Element with the sought Properties.
* @param prop the Stereotype tag or Class Property
* @return a Property or Slot that corresponds to the input property
*/
public static Element getElementProperty(Element elem, Property prop) {
if (prop == null) {
return null;
}
if (prop.getOwner() instanceof Stereotype) {
Slot slot = getStereotypeProperty(elem, prop);
if (slot != null) {
return slot;
}
}
else {
Property result = getClassProperty(elem, prop, true);
if (result != null) {
return result;
}
}
return null;
}
/**
* A list of property values will always be returned. Gets default value of
* a stereotype property when there's no slot for the element. Class value
* properties will be collected by name matching.
*
* @param elem the owner of the Property
* @param prop a property of the same name as that owned by the input Element
* @return values for Properties with a name matching that of the input
* Property
*/
public static List<Object> getElementPropertyValues(Element elem, Property prop,
boolean allowStereotypeDefaultOrInherited) {
if (elem == null) {
return Collections.emptyList();
}
if (prop == null) {
return Collections.emptyList();
}
List<Object> results = getStereotypePropertyValues(elem, prop, allowStereotypeDefaultOrInherited);
if (!Utils2.isNullOrEmpty(results)) {
return results;
}
ValueSpecification vs = getClassPropertyValue(elem, prop, allowStereotypeDefaultOrInherited);
if (vs != null) {
results.add(vs);
}
if (results.isEmpty()) {
try {
Object value = elem.refGetValue(prop.getName()); // i think this
// only works
// for derived
// properties
if (value != null) {
if (value instanceof Collection) {
results.addAll((Collection<?>) value);
}
else {
results.add(value);
}
}
} catch (Throwable e) { // ignore
}
}
return results;
}
public static List<Object> getElementPropertyValues(Element elem,
String propName,
boolean allowStereotypeDefaultOrInherited) {
Property prop = getClassProperty(elem, propName, allowStereotypeDefaultOrInherited);
//return Utils2.newList( (Object)getClassPropertyValue( elem, prop, allowStereotypeDefaultOrInherited ) );
if (prop == null) {
prop = getElementStereotypeProperty(elem, propName);
}
return getElementPropertyValues(elem, prop, allowStereotypeDefaultOrInherited);
}
/**
* Get Class Property values for Properties with a name matching that of the
* input Property.
*
* @param elem the owner of the Property
* @param prop a property of the same name as that owned by the input Element
* @return values for Properties with a name matching that of the input
* Property
*/
public static ValueSpecification getClassPropertyValue(Element elem, Property prop,
boolean includeInherited) {
Property cprop = getClassProperty(elem, prop, includeInherited);
if (cprop == null) {
return null;
}
return cprop.getDefaultValue();
}
/**
* Gets list of values for a stereotype property, this returns valuespecs
*
* @param elem
* @param prop
* @param useDefaultIfNoSlot
* @return
*/
public static List<Object> getStereotypePropertyValues(Element elem, Property prop,
boolean useDefaultIfNoSlot) {
List<Object> results = new ArrayList<Object>();
Slot elemProp = getStereotypeProperty(elem, prop);
if (elemProp != null) {
if (elemProp.getValue() != null) {
results.addAll(elemProp.getValue());
}
}
Element propOwner = prop.getOwner();
if (useDefaultIfNoSlot && results.isEmpty() && prop != null) {
if (propOwner instanceof Stereotype
&& StereotypesHelper.hasStereotypeOrDerived(elem, (Stereotype) propOwner)) {
ValueSpecification v = prop.getDefaultValue();
if (v != null) {
results.add(v);
}
}
}
return results;
}
/*****************************************************************************************/
public static void log(Object o) {
if (o == null) {
o = "null";
}
log(o, (Color) null);
}
/**
* Get the Color by name or by RGB specification.
*
* @param colorString
* @return the Color constant with the same name as the input (forgiving
* capitalization, hyphens, underscores, etc.) or the RGB Color
* specified as 3 comma separated integers
*/
public static Color toColor(String colorString) {
if (Utils2.isNullOrEmpty(colorString)) {
return null;
}
Color color = null;
// try to find a field in the Color class that has the same name
Field f;
LinkedHashSet<String> set = new LinkedHashSet<String>();
set.add(colorString);
String colorNameLetters = colorString.replaceAll("[^A-Za-z]*", "");
set.add(colorNameLetters);
set.add(colorString.toLowerCase());
set.add(colorString.toUpperCase());
set.add(colorNameLetters.toLowerCase());
set.add(colorNameLetters.toUpperCase());
for (String cName : set) {
try {
f = Color.class.getField(cName);
if (f != null) {
color = (Color) f.get(null);
if (color != null) {
break;
}
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
}
}
// try to parse RGB integers separated by commas
if (color == null) {
Pattern p = Pattern.compile("[^0-9]*([0-9]+), *([0-9]+), *([0-9]+).*");
Matcher m = p.matcher(colorString);
if (m.matches()) {
if (m.groupCount() == 3) {
Integer r = Integer.valueOf(m.group(1));
Integer g = Integer.valueOf(m.group(2));
Integer b = Integer.valueOf(m.group(3));
color = new Color(r == null ? 0 : r,
g == null ? 0 : g,
b == null ? 0 : b);
}
}
}
return color;
}
public static boolean isColor(Object o) {
if (o == null) {
return false;
}
if (o instanceof Color) {
return true;
}
return (toColor(o.toString()) != null);
}
public static void log(Object o, String colorName) {
Color c = toColor(colorName);
log(o, c);
}
public static void log(Object o, Color color) {
if (o == null) {
o = "null";
}
if (!(o instanceof String)) {
// To handle arrays, etc.
o = MoreToString.Helper.toString(o);
}
GUILog log = Application.getInstance().getGUILog();
if (log != null) {
log.log("" + o);
}
//MdDebug.logForce( o.toString(), true, false, color );
}
public static void log(Object o, Object color) {
if (color == null || color instanceof Color) {
log(o, (Color) color);
}
else {
log(o, color.toString());
}
}
/**
* @param slot
* @return the "represented text" for the slot values as a single String
*/
public static String slotValueToString(Slot slot) {
List<ValueSpecification> list = slot.getValue();
List<String> sList = new ArrayList<String>();
String s = ""; // if slot is empty or has nothing, show as empty string
// If there is only one element in the list, just use that element
// instead
// of the list.
for (ValueSpecification vs : list) {
s = RepresentationTextCreator.getRepresentedText(vs);
sList.add(s);
}
if (sList != null && !sList.isEmpty()) {
if (sList.size() == 1) {
s = sList.get(0);
}
else {
s = sList.toString();
}
}
return s;
}
/**
* Given a string f and integer p, if f is a floating point number, returns
* the string with precision p
* <p>
* ex. if f is 2.31111111 and p is 2, returns 2.31
*
* @param f
* @param p
* @return
*/
public static String floatTruncate(String f, int p) {
if (p < 0) {
return f;
}
if (f.indexOf(".") != -1) {
try {
double d = Double.parseDouble(f);
String pattern = "#.";
if (p == 0) {
pattern = "#";
}
for (int i = 0; i < p; i++) {
pattern += "#";
}
return new DecimalFormat(pattern).format(d);
// return String.format("%." + Integer.toString(p) + "f", d);
} catch (Exception e) {
return f;
}
}
return f;
}
/**
* For user scripts, if you have a pop up table that should look the same as
* the docgen output, you can just use this method to get back a DBTable to
* pass back to the output.
*
* @param et
* @return
*/
public static DBTable getDBTableFromEditableTable(EditableTable et, boolean addLineNum) {
EditableTableModel tm = (EditableTableModel) et.getTable().getModel();
DBTable res = new DBTable();
List<List<DocumentElement>> headers = new ArrayList<List<DocumentElement>>();
List<List<DocumentElement>> body = new ArrayList<List<DocumentElement>>();
int cols = tm.getColumnCount();
if (addLineNum) {
cols++;
}
List<DocumentElement> header = new ArrayList<DocumentElement>();
headers.add(header);
if (addLineNum) {
header.add(new DBText(""));
}
for (int i = 0; i < tm.getColumnCount(); i++) {
header.add(new DBText(tm.getColumnName(i)));
}
int rows = tm.getRowCount();
for (int i = 0; i < rows; i++) {
List<DocumentElement> row = new ArrayList<DocumentElement>();
body.add(row);
if (addLineNum) {
row.add(new DBText(Integer.toString(i + 1)));
}
for (int j = 0; j < tm.getColumnCount(); j++) {
PropertyEnum what = tm.getWhatToChangeAt(i, j);
boolean editable = tm.isCellEditable(i, j);
Object cell = tm.getObjectAt(i, j);
if (cell instanceof Element && what != null && editable) {
if (what == PropertyEnum.NAME) {
row.add(new DBText(tm.getValueAt(i, j).toString(), (Element) cell, From.NAME));
}
else if (what == PropertyEnum.VALUE) {
row.add(new DBText(tm.getValueAt(i, j).toString(), (Element) cell, From.DVALUE));
}
else {
row.add(new DBParagraph(tm.getValueAt(i, j).toString(), (Element) cell,
From.DOCUMENTATION));
}
}
else {
row.add(new DBText(tm.getValueAt(i, j).toString()));
}
}
}
res.setBody(body);
res.setHeaders(headers);
res.setCols(cols);
res.setTitle(et.getTitle());
return res;
}
/**
* For user scripts, if you have a pop up table, but you want to merge the
* first x columns into a column with indentations (like properties table).
* this assumes that for each merging, you have empty cells until the cell
* to be indented.
*
* @param et the editable table.
* @param merge this is a variable length parameter, indicates how many
* columns you want to merge consecutively. For example, if you
* want to merge the first 2 columns and then the next 2
* columnes, do getDBTableFromEditableTable(et, 2, 2)
* @return
*/
public static DBTable getDBTableFromEditableTable(EditableTable et, boolean addLineNum, Integer... merge) {
EditableTableModel tm = (EditableTableModel) et.getTable().getModel();
DBTable res = new DBTable();
List<List<DocumentElement>> headers = new ArrayList<List<DocumentElement>>();
List<List<DocumentElement>> body = new ArrayList<List<DocumentElement>>();
int total = 0;
int adds = 0;
for (Integer i : merge) {
total += i;
adds++;
}
int cols = tm.getColumnCount() - total + adds;
if (addLineNum) {
cols++;
}
List<DocumentElement> header = new ArrayList<DocumentElement>();
headers.add(header);
if (addLineNum) {
header.add(new DBText(""));
}
int curCol = 0;
for (Integer i : merge) {
header.add(new DBText(tm.getColumnName(curCol)));
for (int j = 0; j < i; j++) {
curCol++;
}
}
for (int i = curCol; i < tm.getColumnCount(); i++) {
header.add(new DBText(tm.getColumnName(i)));
}
int rows = tm.getRowCount();
for (int row = 0; row < rows; row++) {
List<DocumentElement> rowl = new ArrayList<DocumentElement>();
body.add(rowl);
if (addLineNum) {
rowl.add(new DBText(Integer.toString(row + 1)));
}
curCol = 0;
for (Integer i : merge) {
String s = "";
for (int j = 0; j < i; j++) {
Object val = tm.getValueAt(row, curCol);
if (val.toString().isEmpty()) {
s += " ";
curCol++;
}
else {
s += DocGenUtils.fixString(val.toString());
for (int k = j; k < i; k++) {
curCol++;
}
break;
}
}
rowl.add(new DBText(s));
}
for (int j = curCol; j < tm.getColumnCount(); j++) {
PropertyEnum what = tm.getWhatToChangeAt(row, j);
boolean editable = tm.isCellEditable(row, j);
Object cell = tm.getObjectAt(row, j);
if (cell instanceof Element && what != null && editable) {
if (what == PropertyEnum.NAME) {
rowl.add(new DBText(tm.getValueAt(row, j).toString(), (Element) cell, From.NAME));
}
else if (what == PropertyEnum.VALUE) {
rowl.add(new DBText(tm.getValueAt(row, j).toString(), (Element) cell, From.DVALUE));
}
else {
rowl.add(new DBParagraph(tm.getValueAt(row, j).toString(), (Element) cell,
From.DOCUMENTATION));
}
}
else {
rowl.add(new DBText(tm.getValueAt(row, j).toString()));
}
}
}
res.setBody(body);
res.setHeaders(headers);
res.setCols(cols);
res.setTitle(et.getTitle());
return res;
}
public static final Pattern HTML_WRAPPER_START = Pattern.compile("^<html>.*<body>\\s*", Pattern.DOTALL);
public static final Pattern HTML_WRAPPER_END = Pattern.compile("\\s*</body>.*</html>\\s*$",
Pattern.DOTALL);
/**
* Remove HTML wrapper. This might include a head element or some amount of
* whitespace.
*
* @param before
* @return
*/
public static String stripHtmlWrapper(String before) {
if (before == null) {
return null;
}
String startRemoved = HTML_WRAPPER_START.matcher(before).replaceAll("");
return HTML_WRAPPER_END.matcher(startRemoved).replaceAll("");
}
/**
* Given a collection of stuff, joins their string representation into one
* string using delimiter
*
* @param s
* @param delimiter
* @return
*/
public static String join(Collection<?> s, String delimiter) {
StringBuilder builder = new StringBuilder();
Iterator<?> iter = s.iterator();
while (iter.hasNext()) {
builder.append(iter.next());
if (!iter.hasNext()) {
break;
}
builder.append(delimiter);
}
return builder.toString();
}
/**
* @param obj
* @return a name associated with this object whether a NameElement, an
* Element with a humanName, an EObject with a name property, or a
* Java Object with a name member.
*/
public static String getName(Object obj) {
if (obj instanceof NamedElement) {
return ((NamedElement) obj).getName();
}
if (obj instanceof BaseElement) {
String humanName = ((BaseElement) obj).getHumanName();
String[] arr = humanName.trim().split(" ");
if (arr != null) {
if (arr.length == 2) {
if (!Utils2.isNullOrEmpty(arr[0]) && !Utils2.isNullOrEmpty(arr[1])) {
return arr[1];
}
}
}
// REVIEW -- this seems like a bad place to be -- error messages?
}
return EmfUtils.getName(obj);
}
public static String getTypeName(Object obj) {
if (obj instanceof BaseElement) {
String humanType = ("" + ((BaseElement) obj).getHumanType()).trim();
if (!Utils2.isNullOrEmpty(humanType)) {
return humanType;
}
String humanName = ((BaseElement) obj).getHumanName();
String[] arr = humanName.trim().split(" ");
if (arr != null) {
if (arr.length == 2) {
if (!Utils2.isNullOrEmpty(arr[0]) && !Utils2.isNullOrEmpty(arr[1])) {
return arr[0];
}
}
}
// REVIEW -- this seems like a bad place to be -- error messages?
}
// try stereotype
if (obj instanceof Element) {
Element elem = (Element) obj;
List<Stereotype> sTypes = StereotypesHelper.getStereotypes(elem);
if (!Utils2.isNullOrEmpty(sTypes)) {
for (Stereotype st : sTypes) {
String t = st.getName();
if (!Utils2.isNullOrEmpty(t)) {
return t;
}
}
}
}
return EmfUtils.getTypeName(obj);
}
public static String toStringNameAndType(final Object o, final boolean includeId,
final boolean useToStringIfNull) {
if (o == null) {
return "null";
}
// if list, call recursively
if (o instanceof Collection || o instanceof Map || o.getClass().isArray() || o instanceof Entry) {
StringBuffer sb = new StringBuffer();
sb.append("( ");
boolean first = true;
Collection<?> c = null;
String sep = ", ";
if (o instanceof Collection) {
c = (Collection<?>) o;
}
else if (o instanceof Map) {
c = ((Map<?, ?>) o).entrySet();
}
else if (o.getClass().isArray()) {
c = Arrays.asList((Object[]) o);
}
else if (o instanceof Entry) {
Entry<?, ?> entry = (Entry<?, ?>) o;
c = Utils2.newList(entry.getKey(), entry.getValue());
sep = " = ";
}
// TODO -- avoid infinite recursion with Utils2.seen()
for (Object i : c) {
if (first) {
first = false;
}
else {
sb.append(sep);
}
sb.append(toStringNameAndType(i, includeId, useToStringIfNull));
}
sb.append(" )");
return sb.toString();
}
// Not a list
String name = ("" + getName(o)).trim();
String type = ("" + getTypeName(o)).trim();
String s = name;
if (!Utils2.isNullOrEmpty(name)) {
if (!Utils2.isNullOrEmpty(type)) {
s = s + ":" + type;
}
}
else {
s = type;
}
// TODO @donbot BaseElement doesn't have getLocalID(), confirm that this doesn't need to be migrated to getElementToIDConverter
if (includeId && o instanceof BaseElement) {
if (!Utils2.isNullOrEmpty(s)) {
s = s + ":" + ((BaseElement) o).getID();
}
else {
s = ((BaseElement) o).getID();
}
}
if (useToStringIfNull && Utils2.isNullOrEmpty(s)) {
s = MoreToString.Helper.toString(o);
}
return s;
}
/**
* return names of a collection of named elements
*
* @param elements
* @return
*/
public static List<String> getElementNames(Collection<NamedElement> elements) {
List<String> names = new ArrayList<String>();
for (NamedElement e : elements) {
names.add(e.getName());
}
return names;
}
/**
* if multiplicity is not a range, returns the number if upper limit is
* infinity and lower limit > 0, returns lower else returns 1
*
* @param p
* @return
*/
public static int getMultiplicity(Property p) {
int lower = p.getLower();
int upper = p.getUpper();
if (lower == upper) {
return lower;
}
if (upper == -1 && lower > 0) {
return lower;
}
return 1;
}
public static void printException(Exception ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
Application.getInstance().getGUILog().log(sw.toString()); // stack trace as a string
ex.printStackTrace();
}
public static boolean recommendUpdateFromRemote(Project project) {
return recommendUpdateFromRemote(project, "");
}
public static boolean recommendUpdateFromRemote(Project project, String add) {
if (forceDialogFalse) {
forceDialogFalse = false;
return false;
}
if (forceDialogTrue) {
forceDialogTrue = false;
return true;
}
if (!project.isRemote()) {
return true;
}
String user = EsiUtils.getLoggedUserName();
try {
long lastVersion = EsiUtils.getLastVersion(ProjectDescriptorsFactory.createAnyRemoteProjectDescriptor(project));
if (user == null || lastVersion < 0) {
Utils.guilog("[ERROR] You must be logged into Teamwork Cloud first.");
return false;
}
if (lastVersion == MDUtils.getRemoteVersion(project)) {
return true;
}
} catch (Exception ex) {
Utils.guilog("[ERROR] Unexpected exception occurred when trying to verify Teamwork Cloud state.");
ex.printStackTrace();
return false;
}
String[] buttons = {"Update", "Ignore"};
Boolean reply = Utils.getUserYesNoAnswerWithButton("There is a new project version available on Teamwork Cloud.\nIt is highly recommended that you update before proceeding.\n"
+ add, buttons, false);
if (reply == null || !reply) {
return false;
}
LocalSyncTransactionCommitListener listener = LocalSyncProjectEventListenerAdapter.getProjectMapping(project).getLocalSyncTransactionCommitListener();
if (listener != null) {
listener.setDisabled(true);
}
EsiUtils.updateProject(project);
if (listener != null) {
listener.setDisabled(false);
}
return true;
}
/**
* Sets boolean that can disabled popups and redirect their messages to the GUI log.
*
* @param disable true to redirect popups to gui log, false to renable normal popup behavior
*/
public static void setPopupsDisabled(boolean disable) {
Utils.popupsDisabled = disable;
}
public static boolean isPopupsDisabled() {
return Utils.popupsDisabled || MainFrame.isSilentMode();
}
/**
* Causes the next call of a user dialog generating method to return the indicated value
* The called method should then reset these values, so they don't accidentally get used again
*/
public static void forceDialogReturnFalse() {
Utils.forceDialogFalse = true;
}
/**
* Resets all unconsumed forced return values
*/
public static void resetForcedReturns() {
Utils.forceDialogTrue = false;
Utils.forceDialogFalse = false;
Utils.forceDialogCancel = false;
}
}