/*****************************************************************************
* Copyright (c) 2009 CEA
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Atos Origin - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.diagram.sequence.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.emf.transaction.Transaction;
import org.eclipse.emf.transaction.TransactionalCommandStack;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.TransactionalCommandStackImpl;
import org.eclipse.gef.EditDomain;
import org.eclipse.gef.Tool;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.menus.PopupMenu;
import org.eclipse.gmf.runtime.diagram.ui.parts.DiagramEditor;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.IEditCommandRequest;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.infra.core.editor.CoreMultiDiagramEditor;
import org.eclipse.papyrus.infra.core.utils.EditorUtils;
import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
import org.eclipse.papyrus.uml.diagram.common.util.MessageDirection;
import org.eclipse.papyrus.uml.diagram.sequence.part.Messages;
import org.eclipse.papyrus.uml.diagram.sequence.part.UMLDiagramEditorPlugin;
import org.eclipse.papyrus.uml.diagram.sequence.part.UMLPaletteFactory.AspectUnspecifiedTypeConnectionToolEx;
import org.eclipse.papyrus.uml.diagram.sequence.providers.ElementInitializers;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ElementListSelectionDialog;
import org.eclipse.uml2.uml.ActionExecutionSpecification;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.CombinedFragment;
import org.eclipse.uml2.uml.ConnectableElement;
import org.eclipse.uml2.uml.DestructionOccurrenceSpecification;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Event;
import org.eclipse.uml2.uml.ExecutionOccurrenceSpecification;
import org.eclipse.uml2.uml.ExecutionSpecification;
import org.eclipse.uml2.uml.Gate;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.InteractionOperatorKind;
import org.eclipse.uml2.uml.InteractionUse;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageEnd;
import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
import org.eclipse.uml2.uml.MessageSort;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.OccurrenceSpecification;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Signal;
import org.eclipse.uml2.uml.StateInvariant;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
/**
* A helper class for the command.
*
*/
public class CommandHelper {
/**
* Title for dialog of no referenced interaction error
*/
private static final String NO_REFERENCED_INTERACTION_DIALOG_TITLE = "No referenced interaction"; //$NON-NLS-1$
/**
* Message for dialog of no referenced interaction error
*/
private static final String NO_REFERENCED_INTERACTION_DIALOG_MSG = "Couldn't had message if there isn't referenced interaction"; //$NON-NLS-1$
/**
* Message for wrong gate container type error
*/
private static final String WRONG_GATE_CONTAINER_TYPE_ERROR_MSG = "Wrong element UML type for create a gate"; //$NON-NLS-1$
/**
* Title for dialog of choose actual gate
*/
private static final String CHOOSE_GATE_DIALOG_TITLE = "Actual gates of the interaction use"; //$NON-NLS-1$
/**
* Message for dialog of choose actual gate
*/
private static final String CHOOSE_GATE_DIALOG_MSG = "Choose the gate to attach the message"; //$NON-NLS-1$
/**
* Create a message on the given interaction. It only creates the message and not its messages end.
*
* @param interaction
* the containing interaction
* @param messageSort
* the messageSort.
* @return the created message
*/
public static Message doCreateMessage(Interaction interaction, MessageSort messageSort, NamedElement signature) {
Message message = interaction.createMessage(null);
// Set the interaction that will contain the message
message.setInteraction(interaction);
// Set MessageSort
message.setMessageSort(messageSort);
String prefix = "";
if(signature != null) {
prefix = signature.getName() + "_";
}
ElementInitializers.init_NamedElement(message, prefix);
if(signature != null) {
message.setSignature(signature);
}
return message;
}
/**
* Create message occurence specification
*
* @param interaction
* The interaction
* @param event
* The event to attach
* @return The message occurence specification
*/
public static MessageOccurrenceSpecification doCreateMessageOccurrence(InteractionFragment fragment, Event event, Lifeline lifeline) {
// Create the MOS
MessageOccurrenceSpecification mos = UMLFactory.eINSTANCE.createMessageOccurrenceSpecification();
// Configure the MOS
doConfigureOccurenceSpecification(mos, event, fragment, lifeline);
return mos;
}
/**
* Create an ExecutionOccurrenceSpecification
*
* @param es
* the ExecutionSpecification associated with this ExecutionOccurrenceSpecification.
* @param event
* the event associated with this OccurrenceSpecification. It must be of type ExecutionEvent.
* @param fragment
* the fragment enclosing this OccurenceSpecifcation. It must be an Interaction or an Operand.
* @return the Execution Occurrence Specification
*/
public static ExecutionOccurrenceSpecification doCreateExecutionOccurenceSpecification(ExecutionSpecification es, InteractionFragment fragment, Lifeline lifeline) {
// Create the ExecutionOccurrenceSpecification
ExecutionOccurrenceSpecification eos = UMLFactory.eINSTANCE.createExecutionOccurrenceSpecification();
// Configure the EOS.
// The event is an ExecutionEvent
doConfigureOccurenceSpecification(eos, null, fragment, lifeline);
// Set the executionSpecification of the ExecutionOccurrenceSpecification
eos.setExecution(es);
return eos;
}
/**
* Configure an OccurrenceSpecification
*
* @param os
* the occurrenceSpecification to configure
* @param event
* the event to associated with the {@link OccurrenceSpecification}
* @param fragment
* the fragment containing the {@link OccurrenceSpecification}. It can be an {@link Interaction} or an {@link InteractionOperand}
* @param lifeline
* the covered lifeline
*/
private static void doConfigureOccurenceSpecification(OccurrenceSpecification os, Event event, InteractionFragment fragment, Lifeline lifeline) {
// Set the Container of the OccurrenceSpecification
if(fragment instanceof Interaction) {
os.setEnclosingInteraction((Interaction)fragment);
} else if(fragment instanceof InteractionOperand) {
os.setEnclosingOperand((InteractionOperand)fragment);
}
// Set the covered lifeline
os.getCovereds().add(lifeline);
// Set the event of the OccurrenceSpecification
//now it doesn't exist
//os.setEvent(event);
}
/**
* Attach an Interaction on a Lifeline
*
* @param lifeline
* The lifeline
* @param fragment
* The interaction fragment
*/
public static void setSingleCovered(Lifeline lifeline, InteractionFragment fragment) {
if(!fragment.getCovereds().contains(lifeline)) {
fragment.getCovereds().add(lifeline);
}
}
/**
* Get the signature of the message. Opens a dialog box to select a signature.
*
* @param model
* The model
* @param source
* The source of the message
* @param target
* The target of the message
* @return null, if cancel has been pressed. An empty list if the null Element has been
* selected, or a list with the selected element.
*/
public static List<NamedElement> getSignature(Element model, Element source, Element target) {
return getSignature(model, source, target, null);
}
/**
* Get the signature of the message. Opens a dialog box to select a signature. Inputs depends on
* the messageSort, if any.
*
* @param model
* The model
* @param source
* The source of the message
* @param target
* The target of the message
* @param messageSort
* true if message sort is set
* @return null, if cancel has been pressed. An empty list if the null Element has been
* selected, or a list with the selected element.
*/
public static List<NamedElement> getSignature(Element model, Element source, Element target, MessageSort messageSort) {
// element where to look for parents
Element parentsOwner = target;
// default values
// used for asynch message where messageSort = null
boolean useOperations = true;
boolean useSignals = true;
// according to the type of the message
// choose which types we should care of
if(MessageSort.SYNCH_CALL_LITERAL.equals(messageSort)) {
useSignals = false;
} else if(MessageSort.CREATE_MESSAGE_LITERAL.equals(messageSort) || MessageSort.DELETE_MESSAGE_LITERAL.equals(messageSort)) {
useOperations = false;
} else if(MessageSort.REPLY_LITERAL.equals(messageSort)) {
parentsOwner = source;
useSignals = false;
}
LinkedHashMap<EClass, List<EObject>> mapTypesPossibleParents = new LinkedHashMap<EClass, List<EObject>>();
if(useSignals) {
mapTypesPossibleParents.put(UMLPackage.eINSTANCE.getSignal(), new LinkedList<EObject>());
}
if(useOperations) {
mapTypesPossibleParents.put(UMLPackage.eINSTANCE.getOperation(), new LinkedList<EObject>());
}
// add the parents we can find
boolean existingParent = false;
List<Type> types = new ArrayList<Type>();
if(parentsOwner instanceof InteractionFragment) {
EList<Lifeline> lifelines = ((InteractionFragment)parentsOwner).getCovereds();
for(Lifeline l : lifelines) {
if(l.getRepresents() != null && l.getRepresents().getType() != null)
types.add(l.getRepresents().getType());
boolean result = addParentsFromLifeline(l, mapTypesPossibleParents);
if(result) {
existingParent = true;
}
}
} else if(parentsOwner instanceof Lifeline) {
Lifeline l = (Lifeline)parentsOwner;
if(l.getRepresents() != null && l.getRepresents().getType() != null)
types.add(l.getRepresents().getType());
existingParent = addParentsFromLifeline(l, mapTypesPossibleParents);
}
// if no parent available => no signature
if(!existingParent) {
return new ArrayList<NamedElement>();
}
Set<EObject> existingElements = getExistingElementsFromParents(mapTypesPossibleParents);
// fix bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=383420, remove connection feedbacks before opening dialog
clearConnectionFeedback();
// Open the selection dialog
SelectOrCreateDialog dialog = new SelectOrCreateDialog(Display.getCurrent().getActiveShell(), Messages.CommandHelper_CreateMessage, createTypeLabelProvider(), new AdapterFactoryLabelProvider(UMLDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory()), EditorUtils.getTransactionalEditingDomain(), existingElements, mapTypesPossibleParents, types);
// Get the selected result
if(dialog.open() == Window.OK) {
// list to return
List<NamedElement> returnElements = new ArrayList<NamedElement>();
EObject element = dialog.getSelected();
if(element instanceof NamedElement) {
returnElements.add((NamedElement)element);
return returnElements;
}
return returnElements;
}
return null;
}
private static void clearConnectionFeedback() {
AspectUnspecifiedTypeConnectionToolEx conTool = null;
IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
if(editor instanceof CoreMultiDiagramEditor) {
editor = ((CoreMultiDiagramEditor) editor).getActiveEditor();
if(editor instanceof DiagramEditor){
DiagramEditor de = (DiagramEditor)editor;
DiagramEditPart diagramEP = de.getDiagramEditPart();
EditDomain domain = diagramEP.getRoot().getViewer().getEditDomain();
Tool tool = domain.getActiveTool();
if(tool instanceof AspectUnspecifiedTypeConnectionToolEx){
conTool = (AspectUnspecifiedTypeConnectionToolEx)tool;
conTool.clearConnectionFeedback();
}
}
}
}
/**
* find the existing elements from the possible parents
*
* @param mapTypesPossibleParents
* map of list containing the possible parents
* @return
*/
private static Set<EObject> getExistingElementsFromParents(Map<EClass, List<EObject>> mapTypesPossibleParents) {
// find the existing elements using the parents we just found
Set<EObject> existingElements = new HashSet<EObject>();
for(EClass eClass : mapTypesPossibleParents.keySet()) {
List<EObject> parents = mapTypesPossibleParents.get(eClass);
for(EObject parent : parents) {
if(parent instanceof Classifier) {
existingElements.addAll(((Classifier)parent).getAllOperations());
// add operations from port
EList<Property> attrs = ((Classifier)parent).getAllAttributes();
for(Property p : attrs)
if(p instanceof Port && p.getType() instanceof Classifier){
existingElements.addAll(((Classifier)p.getType()).getAllOperations());
}
} else if(parent instanceof Package) {
EList<Element> ownedElements = ((Package)parent).allOwnedElements();
for(Element e : ownedElements) {
if(e instanceof Signal) {
existingElements.add(e);
}
}
}
}
}
return existingElements;
}
/**
* Create a specific label provider for types
* which remove everything after the first space
*
* @return the label provider
*/
private static AdapterFactoryLabelProvider createTypeLabelProvider() {
AdapterFactoryLabelProvider typeLabelProvider = new AdapterFactoryLabelProvider(UMLDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory()) {
@Override
public String getText(Object object) {
// remove the supertypes from the label
// => keep only the first word
String text = super.getText(object);
int index = text.indexOf(" "); //$NON-NLS-1$
if(index != -1) {
text = text.substring(0, index);
}
return text;
}
};
return typeLabelProvider;
}
/**
* add to the map the possible parents (classes, packages)
* founded "in" the lifeline
*
* @param l
* The lifeline where to look for possible parents
* @param mapTypesPossibleParents
* The map where to store this parents
* @return true if at least one parent was added
*/
private static boolean addParentsFromLifeline(Lifeline l, Map<EClass, List<EObject>> mapTypesPossibleParents) {
ConnectableElement e = l.getRepresents();
boolean existingParent = false;
// If there is no connectable element (ie : lifeline doesn't have a represents property yet)
if(e == null) {
return false;
}
Type type = e.getType();
if(type == null) {
return false;
}
// the classes are related to operation
List<EObject> possibleClassifier = mapTypesPossibleParents.get(UMLPackage.eINSTANCE.getOperation());
if(possibleClassifier != null) {
if(type instanceof Classifier) {
Classifier classifier = (Classifier)type;
possibleClassifier.add(classifier);
// add the supertypes of the class
possibleClassifier.addAll(classifier.allParents());
existingParent = true;
}
}
// and the packages to signal
List<EObject> possiblePackages = mapTypesPossibleParents.get(UMLPackage.eINSTANCE.getSignal());
if(possiblePackages != null && type.getPackage()!= null) {
Package package_ = type.getPackage();
possiblePackages.add(package_);
// add the owners of the package
possiblePackages.addAll(package_.allOwningPackages());
existingParent = true;
}
return existingParent;
}
/**
* Get the signature of the message. Opens a dialog box to select a signature. Inputs depends on
* the messageSort, if any.
*
* @param availableProperties
* list of available properties
* @return null, if cancel has been pressed. An empty list if the null Element has been
* selected, or a list with the selected element.
*/
public static Property getProperties(List<Property> availableProperties) {
ILabelProvider labelProvider = new AdapterFactoryLabelProvider(UMLDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory());
ElementListSelectionDialog dialog = new ElementListSelectionDialog(Display.getCurrent().getActiveShell(), labelProvider);
dialog.setTitle("Property Selection"); //$NON-NLS-1$
dialog.setMessage("Select a property (* = any string, ? = any char):"); //$NON-NLS-1$
if(availableProperties == null || availableProperties.isEmpty()) {
return null;
}
dialog.setElements(availableProperties.toArray());
Property element = null;
int dialogResult = dialog.open();
if(dialogResult == Window.OK) {
if(!"".equals(dialog.getFirstResult())) { //$NON-NLS-1$
element = (Property)dialog.getFirstResult();
}
}
return element;
}
/**
* Execute a EMF command without history (cancelation usage)
*
* @param editingDomain
* The editing domain
* @param command
* The command
*/
public static void executeCommandWithoutHistory(EditingDomain editingDomain, org.eclipse.emf.common.command.Command command) {
try {
CommandStack commandStack = editingDomain.getCommandStack();
if(commandStack instanceof TransactionalCommandStack) {
((TransactionalCommandStack)commandStack).execute(command, Collections.singletonMap(Transaction.OPTION_UNPROTECTED, Boolean.TRUE));
} else {
commandStack.execute(command);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RollbackException e) {
e.printStackTrace();
}
}
/**
* Execute a EMF command without history
*
* @param editingDomain
* The editing domain
* @param command
* The command
* @param flag
*/
public static void executeCommandWithoutHistory(EditingDomain editingDomain, org.eclipse.emf.common.command.Command command,boolean flag) {
TransactionalCommandStackImpl stack = new TransactionalCommandStackImpl();
stack.setEditingDomain((InternalTransactionalEditingDomain)editingDomain);
try {
stack.execute(command,Collections.singletonMap(Transaction.OPTION_UNPROTECTED, Boolean.TRUE));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (RollbackException e) {
e.printStackTrace();
}
}
/**
* Retrieve the Lifeline associated with an ExecutionSpecification.
* According to the UML Specification, an ExecutionSpecification must have a start and a finish.
*
* In Papyrus, an ExecutionSpecification may not have a start and finish.
* To handle this specific case, we return the first lifeline that the ES covered.
*
* @param es
* the targeted execution specification
* @return the associated lifeline, or null if the ES has no start, no finish, no covered lifelines.
*/
public static Lifeline getExecutionSpecificationLifeline(ExecutionSpecification es) {
Lifeline lifeline = null;
if(es.getStart() != null) {
lifeline = es.getStart().getCovereds().get(0);
} else if(es.getFinish() != null) {
lifeline = es.getFinish().getCovereds().get(0);
}
if(lifeline == null) {
if(!es.getCovereds().isEmpty()) {
lifeline = es.getCovereds().get(0);
}
}
return lifeline;
}
/**
* Create an DestructionEvent and an occurrenceSpecification bounds to the lifeline
*
* @param destructionEvent
* the destructionEvent
* @param lifeline
* the lifeline associated with the destructionEvent
* @param modelContainer
* the container of the occurrenceSpecification that will bound the lifeline and the destructionEvent.
* @return
*/
// public static DestructionEvent doCreateDestructionEvent(Lifeline lifeline, Object modelContainer) {
//
// // Get the nearest package
// Package pack = lifeline.getNearestPackage();
//
// EClass destructionEventEClass = UMLPackage.eINSTANCE.getDestructionEvent();
// // Add the destructionEvent to the Package
// DestructionEvent destructionEvent = (DestructionEvent)pack.createPackagedElement(ElementInitializers.getNextNumberedName(pack.getOwnedElements(), destructionEventEClass.getName()), destructionEventEClass);
//
// // Create an occurrenceSpecification
// Element element = createElement(modelContainer, UMLPackage.eINSTANCE.getOccurrenceSpecification());
// OccurrenceSpecification os = null;
// if(element instanceof OccurrenceSpecification) {
// os = (OccurrenceSpecification)element;
// doConfigureOccurenceSpecification(os, destructionEvent, (InteractionFragment)modelContainer, lifeline);
// }
//
// return destructionEvent;
// }
/**
* Create an DestructionOccurrenceSpecification bounds to the lifeline
*
* @param lifeline
* the lifeline associated with the destructionEvent
* @param modelContainer
* the container of the occurrenceSpecification that will bound the lifeline and the destructionEvent.
* @return
*/
public static DestructionOccurrenceSpecification doCreateDestructionOccurrenceSpecification(Lifeline lifeline, Object modelContainer) {
// Get the nearest package
Package pack = lifeline.getNearestPackage();
// Create an occurrenceSpecification
Element element = createElement(modelContainer, UMLPackage.eINSTANCE.getDestructionOccurrenceSpecification());
DestructionOccurrenceSpecification os = null;
if(element instanceof DestructionOccurrenceSpecification) {
os = (DestructionOccurrenceSpecification)element;
doConfigureOccurenceSpecification(os, null, (InteractionFragment)modelContainer, lifeline);
}
return os;
}
/**
* Create an StateInvariant
*
* @param lifeline
* the lifeline on which the stateInvariant is created (or which is covered by the StateInvariant).
* @param modelContainer
* the model container
* @return the created stateInvariant or null
*/
public static StateInvariant doCreateStateInvariant(Lifeline lifeline, Object modelContainer) {
StateInvariant stateInvariant = null;
Element element = createElement(modelContainer, UMLPackage.eINSTANCE.getStateInvariant());
if(element instanceof StateInvariant) {
stateInvariant = (StateInvariant)element;
// Get the covered lifeline
stateInvariant.getCovereds().add(lifeline);
// Create the associated invariant
stateInvariant.createInvariant("");
}
return stateInvariant;
}
private static Element createElement(Object modelContainer, EClass eClass) {
// Get the enclosing interaction fragment
if(modelContainer instanceof InteractionOperand) {
InteractionOperand interactionOperand = (InteractionOperand)modelContainer;
// Create the ES
return interactionOperand.createFragment(ElementInitializers.getNextNumberedName(interactionOperand.getFragments(), eClass.getName()), eClass);
} else if(modelContainer instanceof Interaction) {
Interaction interaction = (Interaction)modelContainer;
// Create the ES
return interaction.createFragment(ElementInitializers.getNextNumberedName(interaction.getFragments(), eClass.getName()), eClass);
}
return null;
}
/**
* Create a CombinedFragment and its associated interaction Operand
*
* @param modelContainer
* the container of the CF. It could be an InteractionOperand or an Interaction.
* @param operatorKind
* the operatorKind of the combinedFragment
* @return the created CombinedFragment or null
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static CombinedFragment doCreateCombinedFragment(Object modelContainer, InteractionOperatorKind operatorKind, Collection coveredLifelines) {
CombinedFragment combinedFragment = null;
Element element = createElement(modelContainer, UMLPackage.eINSTANCE.getCombinedFragment());
if(element instanceof CombinedFragment) {
combinedFragment = (CombinedFragment)element;
combinedFragment.getCovereds().addAll(coveredLifelines);
// Set the operator kind
combinedFragment.setInteractionOperator(operatorKind);
// Create the operand
createCoRegionInteractionOperand(combinedFragment);
}
return combinedFragment;
}
/**
* Create a CoRegion element :
* a CombinedFragment with InteractionOperator set to 'Parallel'
*
* @param modelContainer
* the parent element of the CoRegion
* @param coveredLifeline
* the lifeline on which the CoRegion is created
* @return the created CoRegion or null
*/
public static CombinedFragment doCreateCoRegion(Object modelContainer, Lifeline coveredLifeline) {
// Create a Parallel CombinedFragment
Element element = createElement(modelContainer, UMLPackage.eINSTANCE.getCombinedFragment());
if(element instanceof CombinedFragment) {
CombinedFragment combinedFragment = (CombinedFragment)element;
combinedFragment = (CombinedFragment)element;
combinedFragment.getCovereds().add(coveredLifeline);
// Set the operator kind
combinedFragment.setInteractionOperator(InteractionOperatorKind.PAR_LITERAL);
return combinedFragment;
}
return null;
}
/**
* Create an ExecutionSpecification. It also creates the start and finish ExecutionOccurenceSpecification of the ExecutionSpecification, and their
* corresponding events.
*
* @param es
* the executionSpecification to create.
* @param lifeline
* the lifeline covered by the ExecutionSpecification.
* @return the created executionSpecification
*/
public static ExecutionSpecification doCreateExecutionSpecification(ExecutionSpecification es, Lifeline lifeline, Object modelContainer) {
InteractionFragment interactionFragment = null;
// Get the enclosing interaction fragment
if(modelContainer instanceof InteractionOperand) {
InteractionOperand interactionOperand = (InteractionOperand)modelContainer;
interactionFragment = interactionOperand;
} else {
Interaction interaction = lifeline.getInteraction();
interactionFragment = interaction;
}
// Create events
org.eclipse.uml2.uml.Package eventContainer = interactionFragment.getNearestPackage();
// ExecutionEvent startingExecutionEvent = EventHelper.doCreateExecutionEvent(eventContainer);
// ExecutionEvent finishingExecutionEvent = EventHelper.doCreateExecutionEvent(eventContainer);
// Create fragments in the correct order : start OccurenceSpecification, ExecutionSpecification, finish OccurenceSpecification
// start
ExecutionOccurrenceSpecification start = CommandHelper.doCreateExecutionOccurenceSpecification(null, interactionFragment, lifeline);
// Create the ExecutionSpecification
if(modelContainer instanceof InteractionOperand) {
InteractionOperand interactionOperand = (InteractionOperand)modelContainer;
// Create the ES
es = (ExecutionSpecification)interactionOperand.createFragment(null, es.eClass());
} else {
Interaction interaction = lifeline.getInteraction();
// Create the ES
es = (ExecutionSpecification)interaction.createFragment(null, es.eClass());
}
// finish
ExecutionOccurrenceSpecification finish = CommandHelper.doCreateExecutionOccurenceSpecification(es, interactionFragment, lifeline);
// Get the covered lifeline
es.getCovereds().add(lifeline);
// Set the start and the finish ExecutionOccurrenceSpecification
es.setStart(start);
es.setFinish(finish);
start.setExecution(es);
// Init the name of the ES and its EOS
initExecutionSpecificationName(es);
return es;
}
private static void initExecutionSpecificationName(ExecutionSpecification es) {
String body = ""; //$NON-NLS-1$
if(es instanceof ActionExecutionSpecification) {
body = "ActionExecSpec"; //$NON-NLS-1$
} else {
body = "BehaviorExecSpec"; //$NON-NLS-1$
}
// Init the name
ElementInitializers.init_NamedElement(es, "", body, ""); //$NON-NLS-1$ //$NON-NLS-2$
// Init the name of the related executionOccurrenceSpecification
ElementInitializers.init_NamedElement(es.getStart(), "", es.getName(), "Start"); //$NON-NLS-1$ //$NON-NLS-2$
ElementInitializers.init_NamedElement(es.getFinish(), "", es.getName(), "Finish"); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Create a MessageEnd
*
* @param interaction
* fragment
* The Interaction fragment
* @param callEvent
* The call event
* @param element
* The element
* @param direction
* The message direction
* @return A MessageOccurrenceSpecification if element is ExecutionSpecification or Lifeline. A
* Gate if element is Interaction or CombinedFragment or InteractionUse
*/
public static MessageEnd createMessageEnd(InteractionFragment interactionFragment, Event event, Element element, MessageDirection direction) {
MessageEnd endMsg = null;
if(element instanceof Lifeline) {
endMsg = doCreateMessageOccurrence(interactionFragment, event, (Lifeline)element);
} else if(element instanceof ExecutionSpecification) {
Lifeline lifeline = getExecutionSpecificationLifeline((ExecutionSpecification)element);
endMsg = doCreateMessageOccurrence(interactionFragment, event, lifeline);
} else if(element instanceof Interaction || element instanceof CombinedFragment || element instanceof InteractionUse) {
endMsg = doCreateGate(element, direction);
}
return endMsg;
}
/**
* Create gate if element is a Interaction, a Combined Fragment or a Interaction Use
*
* @param element
* The element
* @param direction
* The message direction
* @return The gate
* @throws IllegalArgumentException
* if the element is not a right element type
*/
public static Gate doCreateGate(Element element, MessageDirection direction) {
Gate gate = null;
if(element instanceof Interaction) {
gate = ((Interaction)element).createFormalGate(null);
} else if(element instanceof CombinedFragment) {
CombinedFragment combinedFragment = (CombinedFragment) element;
EList<Gate> cfragmentGates = combinedFragment.getCfragmentGates();
if (cfragmentGates.isEmpty()) {
gate = ((CombinedFragment) element).createCfragmentGate(null);
} else {
// remove connection feedbacks before opening dialog
clearConnectionFeedback();
Shell shell = Display.getCurrent().getActiveShell();
ILabelProvider labelProvider = new AdapterFactoryLabelProvider(
UMLDiagramEditorPlugin.getInstance()
.getItemProvidersAdapterFactory());
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
shell, labelProvider);
dialog.setTitle("Gates of the CombinedFragment has");
dialog.setMessage(CHOOSE_GATE_DIALOG_MSG);
dialog.setMultipleSelection(false);
List<Gate> gates = new ArrayList<Gate>();
for (Gate actualGate : cfragmentGates) {
gates.add(actualGate);
}
dialog.setElements(gates.toArray());
if (dialog.open() == Window.OK) {
gate = (Gate) dialog.getFirstResult();
}else{ // cancel button
throw new OperationCanceledException();
}
}
} else if(element instanceof InteractionUse) {
Shell shell = Display.getCurrent().getActiveShell();
InteractionUse interactionUse = (InteractionUse)element;
if(interactionUse.getRefersTo() == null) {
MessageDialog.openError(shell, NO_REFERENCED_INTERACTION_DIALOG_TITLE, NO_REFERENCED_INTERACTION_DIALOG_MSG);
return null;
}
ILabelProvider labelProvider = new AdapterFactoryLabelProvider(UMLDiagramEditorPlugin.getInstance().getItemProvidersAdapterFactory());
ElementListSelectionDialog dialog = new ElementListSelectionDialog(shell, labelProvider);
dialog.setTitle(CHOOSE_GATE_DIALOG_TITLE);
dialog.setMessage(CHOOSE_GATE_DIALOG_MSG);
dialog.setMultipleSelection(false);
List<Gate> gates = new ArrayList<Gate>();
for(Gate actualGate : ((InteractionUse)element).getActualGates()) {
if(actualGate.getName().startsWith(direction.getName())) {
gates.add(actualGate);
}
}
dialog.setElements(gates.toArray());
if(dialog.open() == Window.OK) {
gate = (Gate)dialog.getFirstResult();
}
} else {
throw new IllegalArgumentException(WRONG_GATE_CONTAINER_TYPE_ERROR_MSG);
}
if(gate != null) {
ElementInitializers.init_NamedElement(gate, direction.toString().toLowerCase() + "_"); //$NON-NLS-1$
}
return gate;
}
/**
* Creates a message and manage the creation of a message from/to a CoRegion
*
* @param interaction
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @param params
* a map of params. It must at least contain the source and target container;
* @return the created message.
*/
public static Message doCreateMessage(Interaction interaction, MessageSort messageSort, Element source, Element target, Map<Object, Object> params) {
InteractionFragment sourceContainer = (InteractionFragment)params.get(SequenceRequestConstant.SOURCE_MODEL_CONTAINER);
InteractionFragment targetContainer = (InteractionFragment)params.get(SequenceRequestConstant.TARGET_MODEL_CONTAINER);
Lifeline lifeline = (Lifeline)params.get(SequenceRequestConstant.LIFELINE_GRAPHICAL_CONTAINER);
if(lifeline != null) {
if(source instanceof CombinedFragment) {
CombinedFragment cf = (CombinedFragment)source;
if(InteractionOperatorKind.PAR_LITERAL.equals(cf.getInteractionOperator())) {
InteractionOperand interactionOperand = getCoRegionInteractionOperand(cf);
sourceContainer = interactionOperand;
targetContainer = interactionOperand;
source = lifeline;
if(target instanceof Lifeline) {
addCoveredLifelineToCombinedFragment((Lifeline)target, cf);
}
}
} else if(target instanceof CombinedFragment) {
CombinedFragment cf = (CombinedFragment)target;
if(InteractionOperatorKind.PAR_LITERAL.equals(cf.getInteractionOperator())) {
InteractionOperand interactionOperand = getCoRegionInteractionOperand(cf);
sourceContainer = interactionOperand;
targetContainer = interactionOperand;
target = lifeline;
if(source instanceof Lifeline) {
addCoveredLifelineToCombinedFragment((Lifeline)source, cf);
}
}
}
}
return doCreateMessage(interaction, messageSort, source, target, sourceContainer, targetContainer);
}
private static void addCoveredLifelineToCombinedFragment(Lifeline coveredLifeline, CombinedFragment cf) {
cf.getCovereds().add(coveredLifeline);
for(InteractionOperand io : cf.getOperands()) {
io.getCovereds().add(coveredLifeline);
}
}
/**
* Get the interactionOperand where the occurrenceSpecification will be created
*/
public static InteractionOperand getCoRegionInteractionOperand(CombinedFragment cf) {
InteractionOperand interactionOperand = null;
// Search in the existing operands if there are any operand without fragments.
for(InteractionOperand existingOperand : cf.getOperands()) {
if(existingOperand.getFragments().isEmpty()) {
interactionOperand = existingOperand;
break;
}
}
// If the operand is still null, we create a new operand in the combinedFragment.
if(interactionOperand == null) {
interactionOperand = createCoRegionInteractionOperand(cf);
}
return interactionOperand;
}
private static InteractionOperand createCoRegionInteractionOperand(CombinedFragment cf) {
InteractionOperand interactionOperand = cf.createOperand("");
interactionOperand.getCovereds().addAll(cf.getCovereds());
interactionOperand.setName(ElementInitializers.getNextNumberedName(cf.getOperands(), interactionOperand.eClass().getName()));
return interactionOperand;
}
/**
* Create a message. It also creates its message end, their corresponding events and updates the signature of the message.
*
* @param container
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @return the created message
*/
public static Message doCreateMessage(Interaction container, MessageSort messageSort, Element source, Element target, InteractionFragment sourceContainer, InteractionFragment targetContainer) {
return doCreateMessage(container, messageSort, source, target, sourceContainer, targetContainer, null, null);
}
/**
* Create a message. It also creates its message end (if not provided), their corresponding events and updates the signature of the message.
*
* @param container
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @param sendMessageEnd
* the existing Send MessageEnd of the message
* @param receiveMessageEnd
* the existing Receive MessageEnd of the message
* @return the created message
*/
public static Message doCreateMessage(Interaction container, MessageSort messageSort, Element source, Element target, InteractionFragment sourceContainer, InteractionFragment targetContainer, MessageEnd sendMessageEnd, MessageEnd receiveMessageEnd) {
List<NamedElement> signatures = getSignature(container.getModel(), source, target, messageSort);
// If signatures == null, means the user click on cancel button during selection --> Cancel the whole process of creation
if(signatures == null) {
return null;
}
NamedElement signature = null;
if(!signatures.isEmpty()) {
signature = signatures.get(0);
}
// Get the correct MessageSort
messageSort = getMessageSort(signature, messageSort);
// Create the message
Message message = doCreateMessage(container, messageSort, signature);
// Create the two message ends
if(sendMessageEnd == null && source != null) {
sendMessageEnd = createMessageEnd(sourceContainer, EventHelper.doCreateSendEvent(messageSort, container, signature), source, MessageDirection.OUT);
}
if(receiveMessageEnd == null && target != null) {
receiveMessageEnd = createMessageEnd(targetContainer, EventHelper.doCreateReceiveEvent(messageSort, container, signature), target, MessageDirection.IN);
}
// Update the messages end with the message
if(sendMessageEnd != null) {
sendMessageEnd.setMessage(message);
ElementInitializers.init_NamedElement(sendMessageEnd, "", message.getName(), "Send"); //$NON-NLS-1$ //$NON-NLS-2$
// Update the message with the messages end
message.setSendEvent(sendMessageEnd);
}
if(receiveMessageEnd != null) {
receiveMessageEnd.setMessage(message);
ElementInitializers.init_NamedElement(receiveMessageEnd, "", message.getName(), "Recv"); //$NON-NLS-1$ //$NON-NLS-2$
// Update the message with the messages end
message.setReceiveEvent(receiveMessageEnd);
}
return message;
}
/**
* Get the messageSort of a message if it doesn't exist yet depending of the messageSignature.
* If no messageSort exists, and if the signature is null, then return a MessageSort.ASYNCH_CALL_LITERAL
*
* @param signature
* the signature of the message or null
* @param messageSort
* a messageSort or null
* @return the messageSort
*/
private static MessageSort getMessageSort(NamedElement signature, MessageSort messageSort) {
if(messageSort == null) {
if(signature instanceof Signal) {
return MessageSort.ASYNCH_SIGNAL_LITERAL;
} else {
return MessageSort.ASYNCH_CALL_LITERAL;
}
}
return messageSort;
}
/**
* A method to validate that both source and target of a request have valid container for the creation of a message.
*
* @param request
* the request
* @return false if the container of the source or the target is null and if the two container are not equals
*/
public static boolean hasValidContainer(IEditCommandRequest request) {
Object srcEndContainer = request.getParameter(SequenceRequestConstant.SOURCE_MODEL_CONTAINER);
Object tgtEndContainer = request.getParameter(SequenceRequestConstant.TARGET_MODEL_CONTAINER);
if(srcEndContainer == null || tgtEndContainer == null) {
return false;
}
/*
* Message cannot cross InteractionFragment.
* Either the two message ends are contained into the same InteractionFragment,
* or one is a gate and the other is in the InteractionFragment containing the gate's CF,
* or one is a gate and the other is a gate in a CF containing the first gate's CF.
*/
// into the same InteractionFragment
if(srcEndContainer.equals(tgtEndContainer)) {
return true;
}
// one is a gate
if(request instanceof CreateRelationshipRequest) {
EObject src = ((CreateRelationshipRequest)request).getSource();
EObject tgt = ((CreateRelationshipRequest)request).getTarget();
if(!(src instanceof Lifeline)) {
// send is a gate
if(src instanceof InteractionOperand) {
// consider the containing CF
src = src.eContainer();
}
if(src instanceof InteractionFragment) {
// check whether container of gate is in the target's fragment container
if(tgtEndContainer instanceof Interaction) {
if(((Interaction)tgtEndContainer).getFragments().contains(src)) {
return true;
}
}
if(tgtEndContainer instanceof InteractionOperand) {
if(((InteractionOperand)tgtEndContainer).getFragments().contains(src)) {
return true;
}
}
}
}
if(!(tgt instanceof Lifeline)) {
// receive is a gate
if(tgt instanceof InteractionOperand) {
// consider the containing CF
tgt = tgt.eContainer();
}
if(tgt instanceof InteractionFragment) {
// check whether container of gate is in the source's fragment container
if(srcEndContainer instanceof Interaction && ((Interaction)srcEndContainer).getFragments().contains(tgt)) {
return true;
}
if(srcEndContainer instanceof InteractionOperand && ((InteractionOperand)srcEndContainer).getFragments().contains(tgt)) {
return true;
}
}
}
}
return false;
}
/**
* apex
* {@link #doCreateMessage(Interaction, MessageSort, Element, Element, InteractionFragment, InteractionFragment, MessageEnd, MessageEnd)}를 변형
*
* @param container
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @param sendMessageEnd
* the existing Send MessageEnd of the message
* @param receiveMessageEnd
* the existing Receive MessageEnd of the message
* @return the created message
*/
public static Message apexDoCreateMessage(Interaction container, MessageSort messageSort, Element source, Element target, InteractionFragment sourceContainer, InteractionFragment targetContainer, MessageEnd sendMessageEnd, MessageEnd receiveMessageEnd) {
NamedElement signature = null;
// Get the correct MessageSort
messageSort = getMessageSort(signature, messageSort);
// Create the message
Message message = doCreateMessage(container, messageSort, signature);
// Create the two message ends
if(sendMessageEnd == null && source != null) {
sendMessageEnd = createMessageEnd(sourceContainer, EventHelper.doCreateSendEvent(messageSort, container, signature), source, MessageDirection.OUT);
}
if(receiveMessageEnd == null && target != null) {
receiveMessageEnd = createMessageEnd(targetContainer, EventHelper.doCreateReceiveEvent(messageSort, container, signature), target, MessageDirection.IN);
}
// Update the messages end with the message
if(sendMessageEnd != null) {
sendMessageEnd.setMessage(message);
ElementInitializers.init_NamedElement(sendMessageEnd, "", message.getName(), "Send"); //$NON-NLS-1$ //$NON-NLS-2$
// Update the message with the messages end
message.setSendEvent(sendMessageEnd);
}
if(receiveMessageEnd != null) {
receiveMessageEnd.setMessage(message);
ElementInitializers.init_NamedElement(receiveMessageEnd, "", message.getName(), "Recv"); //$NON-NLS-1$ //$NON-NLS-2$
// Update the message with the messages end
message.setReceiveEvent(receiveMessageEnd);
}
return message;
}
/**
* apex
* {@link #doCreateMessage(Interaction, MessageSort, Element, Element, InteractionFragment, InteractionFragment)}를 변형
*
* @param container
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @return the created message
*/
public static Message apexDoCreateMessage(Interaction container, MessageSort messageSort, Element source, Element target, InteractionFragment sourceContainer, InteractionFragment targetContainer) {
return apexDoCreateMessage(container, messageSort, source, target, sourceContainer, targetContainer, null, null);
}
/**
* apex
* {@link #doCreateMessage(Interaction, MessageSort, Element, Element, Map)}를 변형
*
* @param interaction
* the interaction containing the message.
* @param messageSort
* the messageSort of the message, it can be null
* @param source
* the source of the message, it can be null
* @param target
* the target of the message, it can be null
* @param params
* a map of params. It must at least contain the source and target container;
* @return the created message.
*/
public static Message apexDoCreateMessage(Interaction interaction, MessageSort messageSort, Element source, Element target, Map<Object, Object> params) {
InteractionFragment sourceContainer = (InteractionFragment)params.get(SequenceRequestConstant.SOURCE_MODEL_CONTAINER);
InteractionFragment targetContainer = (InteractionFragment)params.get(SequenceRequestConstant.TARGET_MODEL_CONTAINER);
Lifeline lifeline = (Lifeline)params.get(SequenceRequestConstant.LIFELINE_GRAPHICAL_CONTAINER);
if(lifeline != null) {
if(source instanceof CombinedFragment) {
CombinedFragment cf = (CombinedFragment)source;
if(InteractionOperatorKind.PAR_LITERAL.equals(cf.getInteractionOperator())) {
InteractionOperand interactionOperand = getCoRegionInteractionOperand(cf);
sourceContainer = interactionOperand;
targetContainer = interactionOperand;
source = lifeline;
if(target instanceof Lifeline) {
addCoveredLifelineToCombinedFragment((Lifeline)target, cf);
}
}
} else if(target instanceof CombinedFragment) {
CombinedFragment cf = (CombinedFragment)target;
if(InteractionOperatorKind.PAR_LITERAL.equals(cf.getInteractionOperator())) {
InteractionOperand interactionOperand = getCoRegionInteractionOperand(cf);
sourceContainer = interactionOperand;
targetContainer = interactionOperand;
target = lifeline;
if(source instanceof Lifeline) {
addCoveredLifelineToCombinedFragment((Lifeline)source, cf);
}
}
}
}
return apexDoCreateMessage(interaction, messageSort, source, target, sourceContainer, targetContainer);
}
/**
* apex
* {@link #getSignature(Element, Element, Element)}를 변형
*
* @param model
* The model
* @param source
* The source of the message
* @param target
* The target of the message
* @param messageSort
* true if message sort is set
* @return null, if cancel has been pressed. An empty list if the null Element has been
* selected, or a list with the selected element.
*/
public static List<NamedElement> apexGetSignature(Element model, Element source, Element target, MessageSort messageSort) {
// element where to look for parents
Element parentsOwner = target;
// default values
// used for asynch message where messageSort = null
boolean useOperations = true;
boolean useSignals = true;
// according to the type of the message
// choose which types we should care of
if(MessageSort.SYNCH_CALL_LITERAL.equals(messageSort)) {
useSignals = false;
} else if(MessageSort.CREATE_MESSAGE_LITERAL.equals(messageSort) || MessageSort.DELETE_MESSAGE_LITERAL.equals(messageSort)) {
useOperations = false;
} else if(MessageSort.REPLY_LITERAL.equals(messageSort)) {
parentsOwner = source;
useSignals = false;
}
LinkedHashMap<EClass, List<EObject>> mapTypesPossibleParents = new LinkedHashMap<EClass, List<EObject>>();
if(useSignals) {
mapTypesPossibleParents.put(UMLPackage.eINSTANCE.getSignal(), new LinkedList<EObject>());
}
if(useOperations) {
mapTypesPossibleParents.put(UMLPackage.eINSTANCE.getOperation(), new LinkedList<EObject>());
}
// add the parents we can find
boolean existingParent = false;
List<Type> types = new ArrayList<Type>();
if(parentsOwner instanceof InteractionFragment) {
EList<Lifeline> lifelines = ((InteractionFragment)parentsOwner).getCovereds();
for(Lifeline l : lifelines) {
if(l.getRepresents() != null && l.getRepresents().getType() != null)
types.add(l.getRepresents().getType());
boolean result = addParentsFromLifeline(l, mapTypesPossibleParents);
if(result) {
existingParent = true;
}
}
} else if(parentsOwner instanceof Lifeline) {
Lifeline l = (Lifeline)parentsOwner;
if(l.getRepresents() != null && l.getRepresents().getType() != null)
types.add(l.getRepresents().getType());
existingParent = addParentsFromLifeline(l, mapTypesPossibleParents);
}
// if no parent available => no signature
if(!existingParent) {
return new ArrayList<NamedElement>();
}
Set<EObject> existingElements = getExistingElementsFromParents(mapTypesPossibleParents);
List<NamedElement> returnElements = new ArrayList<NamedElement>();
for (EObject element : existingElements) {
if(element instanceof NamedElement) {
returnElements.add((NamedElement)element);
}
}
return returnElements;
}
}