blob: 344859fb3f6b58ac2704b7cbadc85b604a036f6c [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2018 Fondazione Bruno Kessler.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Luca Cristoforetti - initial API and implementation
******************************************************************************/
package org.polarsys.chess.diagramsCreator.actions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.diagram.ui.OffscreenEditPartFactory;
import org.eclipse.gmf.runtime.diagram.ui.editparts.GraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.editparts.IGraphicalEditPart;
import org.eclipse.gmf.runtime.diagram.ui.requests.CreateConnectionViewRequest;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.notation.Bounds;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.gmf.runtime.notation.impl.LocationImpl;
import org.eclipse.papyrus.commands.wrappers.GEFtoEMFCommandWrapper;
import org.eclipse.papyrus.infra.core.resource.ModelSet;
import org.eclipse.papyrus.infra.core.services.ServiceException;
import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
import org.eclipse.papyrus.infra.emf.utils.ServiceUtilsForResource;
import org.eclipse.papyrus.infra.gmfdiag.css.CSSDecorationNodeImpl;
import org.eclipse.papyrus.infra.gmfdiag.css.CSSShapeImpl;
import org.eclipse.papyrus.sysml.diagram.common.edit.part.BlockPropertyCompositeEditPart;
import org.eclipse.papyrus.sysml.diagram.common.edit.part.FlowPortAffixedLabelNameEditPart;
import org.eclipse.papyrus.sysml.diagram.common.edit.part.FlowPortAffixedNodeEditPart;
import org.eclipse.papyrus.sysml.diagram.internalblock.InternalBlockDiagramCreateCommand;
import org.eclipse.papyrus.uml.diagram.common.actions.ShowHideContentsAction;
import org.eclipse.papyrus.uml.diagram.common.commands.ShowHideElementsRequest;
import org.eclipse.papyrus.uml.diagram.common.edit.part.ConnectorEditPart;
import org.eclipse.papyrus.uml.diagram.common.edit.part.PortAffixedLabelNameEditPart;
import org.eclipse.papyrus.uml.diagram.common.edit.part.PortAffixedNodeEditPart;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.ConnectorEnd;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.polarsys.chess.contracts.profile.chesscontract.util.ContractEntityUtil;
import org.polarsys.chess.contracts.profile.chesscontract.util.EntityUtil;
/**
* This class creates an Internal Block Diagram and populates it with elements.
* @author cristofo
*
*/
public class ShowIBDElementsAction extends ShowHideContentsAction {
// Constant values for the size of IBD elements
private static final int MAIN_WIDTH = 1000;
private static final int MIN_MAIN_HEIGHT = 600;
private static final int MAX_MAIN_HEIGHT = 6000;
private static final int MIN_SUB_WIDTH = 150;
private static final int MAX_SUB_WIDTH = 1000;
private static final int MIN_SUB_HEIGHT = 150;
private static final int MAX_SUB_HEIGHT = 2000;
/** INCREMENT for the location of the elements to show (ports and properties) */
private static final int INCREMENT = 40;
/** the main EditPart */
private EditPart host;
/** Selection of all the possible elements */
private List<Object> selection;
/** Logger for messages */
private static final Logger logger = Logger.getLogger(ShowIBDElementsAction.class);
final EntityUtil entityUtil = EntityUtil.getInstance();
final ContractEntityUtil contractEntityUtil = ContractEntityUtil.getInstance();
private boolean sortedPorts; // Sort the ports in alphabetical order
/** The instance of this class */
private static ShowIBDElementsAction classInstance;
/**
* Gets an instance of the class if already present, or a new one if not.
* @return the instance of this class
*/
public static ShowIBDElementsAction getInstance() {
if (classInstance == null) {
classInstance = new ShowIBDElementsAction();
}
return classInstance;
}
/**
* Adds a IBD diagram to the given block.
* @param owner the selected block
* @throws Exception
*/
public Diagram addIBD(Class owner) throws Exception {
// Get the services registry
final ServicesRegistry servicesRegistry = ServiceUtilsForResource.getInstance().getServiceRegistry(owner.eResource());
// Also this should work
// ServicesRegistry serviceRegistry = ServiceUtilsForActionHandlers.getInstance().getServiceRegistry();
// Get the modelSet
final ModelSet modelSet = ServiceUtils.getInstance().getModelSet(servicesRegistry);
// Equivalent way to get modelSet
// ModelSet modelSet = ServiceUtilsForResource.getInstance().getModelSet(owner.eResource());
// Create a IBD diagram for the selected owner
final InternalBlockDiagramCreateCommand command = new InternalBlockDiagramCreateCommand();
return command.createDiagram(modelSet, owner, owner.getName() + "_IBD");
}
/**
* Builds a list of elements I'm interested to display.
* @param results the list of all the possible EditPartRepresentation elements
*/
@Override
protected void buildShowHideElementsList(Object[] results) {
viewsToCreate = new ArrayList<EditPartRepresentation>();
viewsToDestroy = new ArrayList<EditPartRepresentation>();
List<Object> result = new ArrayList<>();
for (int i = 0; i < results.length; i++) {
final EditPartRepresentation editPartRepresentation = (EditPartRepresentation) results[i];
// logger.debug("\n\n\nWorking on results[" + i + "] = " + editPartRepresentation);
final Element semanticElement = (Element) editPartRepresentation.getSemanticElement();
// logger.debug("Semantic Element = " + semanticElement);
// logger.debug("Label = " + editPartRepresentation.getLabel());
// If the element is interesting, add it
if(entityUtil.isPort(semanticElement) ||
entityUtil.isComponentInstance(semanticElement) ||
entityUtil.isDelegationConstraint(semanticElement)) {
result.add(editPartRepresentation);
}
}
// Add the result to the views to create, but only if not already displayed
for (Object element : result) {
if (initialSelection.contains(element)) {
// we do nothing
continue;
} else if (element instanceof EditPartRepresentation) {
viewsToCreate.add((EditPartRepresentation) element);
}
}
}
/**
* Completes the list of selection for the given representation and its potential children.
* @param listToComplete the list of selected elements to complete
* @param representation the edit part representation that completes the list
*/
private void contributeToSelection(List<Object> listToComplete, EditPartRepresentation representation) {
// logger.debug("\n\nrepresentation = " + representation);
// logger.debug("\tlistToComplete.size = " + listToComplete.size());
listToComplete.addAll(representation.getPossibleElement());
// logger.debug("\tlistToComplete.size = " + listToComplete.size());
final List<EditPartRepresentation> children = representation.getPossibleElement();
// logger.debug("\tChildren di representation size = " + children.size());
if (children != null) {
for (EditPartRepresentation child : children) {
// logger.debug("Working on child " + child);
contributeToSelection(listToComplete, child);
}
}
}
/**
* Builds the selection with all the possible elements.
*/
private void buildSelection() {
selection = new ArrayList<Object>();
for (EditPartRepresentation current : representations) {
contributeToSelection(selection, current);
}
}
/**
* Creates the list of commands to show the various elements.
*/
@Override
protected Command getActionCommand() {
final CompoundCommand completeCmd = new CompoundCommand("Show/Hide Inherited Elements Command");
ShowHideElementsRequest request = null;
// Initial position of the elements
// final Point propertyLocation = new Point(500, 20);
final Point propertyLocation = new Point(20, 20);
final Point portLocationLeft = new Point(-10, 20);
final Point portLocationRight = new Point(-10, 20);
// Get the ports of the main component
final Class mainElement = (Class) ((IGraphicalEditPart) getHost()).resolveSemanticElement();
final EList<Port> ports = mainElement.getOwnedPorts();
final ArrayList<Port> inputPorts = getPorts(ports, true, sortedPorts);
final ArrayList<Port> outputPorts = getPorts(ports, false, sortedPorts);
for (EditPartRepresentation rep : this.viewsToCreate) {
if (!(rep instanceof OptionalEditPartRepresentation)) {
continue;
}
final EditPart editPart = ((OptionalEditPartRepresentation) rep).getParentRepresentation().getParentRepresentation().getRepresentedEditPart();
final View compartmentView = ((OptionalEditPartRepresentation) rep).getParentRepresentation().getRepresentedEditPart().getNotationView();
// logger.debug("\n\nep = " + editPart);
// logger.debug("compView = " + compartmentView);
// Get the width of the component to set the position of output ports
// final CSSShapeImpl viewShape = (CSSShapeImpl) ((IGraphicalEditPart) editPart).getNotationView();
// final Bounds layout = (Bounds) viewShape.getLayoutConstraint();
// portLocationRight.x = layout.getWidth() + 20;
portLocationRight.x = 10000; // Huge value to avoid ports being not put on the border
if (compartmentView != null) {
request = new ShowHideElementsRequest(compartmentView, ((OptionalEditPartRepresentation) rep).getSemanticElement());
if (isXYLayout(compartmentView, editPart)) {
propertyLocation.x += INCREMENT;
propertyLocation.y += INCREMENT;
request.setLocation(new Point(propertyLocation));
} else if (isAffixedChildNode(editPart, ((OptionalEditPartRepresentation) rep).getSemanticElement())) {
Element element = (Element) ((OptionalEditPartRepresentation) rep).getSemanticElement();
if (element instanceof Port) {
if (inputPorts.indexOf(element) != -1) {
portLocationLeft.y = 20 + INCREMENT * (inputPorts.indexOf(element) + 1);
request.setLocation(new Point(portLocationLeft));
} else if (outputPorts.indexOf(element) != -1){
portLocationRight.y = 20 + INCREMENT * (outputPorts.indexOf(element) + 1);
request.setLocation(new Point(portLocationRight));
}
}
}
Command cmd = editPart.getCommand(request);
if (cmd != null && cmd.canExecute()) {
completeCmd.add(cmd);
}
}
}
return completeCmd;
}
/**
* Returns a list of ports, with direction and sorting as specified.
* @param ports the list of Ports to process
* @param inputType true to get input direction, false for the rest
* @param sorted true to get an alphabetically ordered list
* @return the list of requested ports
*/
private ArrayList<Port> getPorts(EList<Port> ports, boolean inputType, boolean sorted) {
ArrayList<Port> listPorts = new ArrayList<Port>();
// Fill the list with the requested type
for (Port port : ports) {
if (inputType) {
if (entityUtil.isInputPort(port)) {
listPorts.add(port);
}
} else {
if (!entityUtil.isInputPort(port)) {
listPorts.add(port);
}
}
}
// Sort list in alphabetical order if requested
if (sorted) {
Comparator<Port> comparator = new Comparator<Port>() {
@Override
public int compare(Port left, Port right) {
return left.getName().compareToIgnoreCase(right.getName());
}
};
Collections.sort(listPorts, comparator);
}
return listPorts;
}
private void drawAllComponentInstancesPorts(IGraphicalEditPart elementEP) {
final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
// Get the compartment edit part
final IGraphicalEditPart compartmentEP = (IGraphicalEditPart) elementEP.getChildren().get(1);
final List<?>compartmentChildren = compartmentEP.getChildren();
for (Object childEP : compartmentChildren) {
// Get the UML element associated to the EP
final EObject semanticElement = ((IGraphicalEditPart) childEP).resolveSemanticElement();
if (semanticElement instanceof Property) {
command.add(drawComponentInstancePorts((IGraphicalEditPart) childEP));
}
}
// Execute the command
final TransactionalEditingDomain domain = elementEP.getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
}
// /**
// * Draws the ports on the inner instances.
// * @param diagramEP the EditPart of the diagram
// */
// private void drawComponentInstancesPorts(IGraphicalEditPart diagramEP) {
// final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
// Property prop = null;
// Class propertyType = null;
// View compartmentView = null;
// Point portLocationLeft = null;
// Point portLocationRight = null;
//
// // Get the edit part of the main element, from the diagram edit part
// final IGraphicalEditPart elementEP = (IGraphicalEditPart) diagramEP.getChildren().get(0);
//
// // Get the compartment edit part
// final IGraphicalEditPart compartmentEP = (IGraphicalEditPart) elementEP.getChildren().get(1);
//
// logger.debug("\nCompartment edit part = " + compartmentEP);
//
// final List<?>compartmentChildren = compartmentEP.getChildren();
// for (Object childEP : compartmentChildren) {
//
// // Get the UML element associated to the EP
// final EObject semanticElement = ((IGraphicalEditPart) childEP).resolveSemanticElement();
// logger.debug("SemanticElement of compartment = " + semanticElement);
//
// if (semanticElement instanceof Property) {
//
// // Get the element type
// prop = (Property) semanticElement;
// propertyType = (Class) prop.getType();
//
// // Get the compartment view of the property
// compartmentView = ((IGraphicalEditPart) childEP).getNotationView();
//
// // Set the initial position of the ports
// portLocationLeft = new Point(-10, 20);
// portLocationRight = new Point(-10, 20);
//
// // Get the width of the component to set the position of output ports
// final CSSShapeImpl viewShape = (CSSShapeImpl) ((IGraphicalEditPart) childEP).getNotationView();
// final Bounds layout = (Bounds) viewShape.getLayoutConstraint();
// portLocationRight.x += layout.getWidth() + 20;
//
// // Get the ports of the property
// final EList<Port> ports = propertyType.getOwnedPorts();
// final ArrayList<Port> inputPorts = getPorts(ports, true, sortedPorts);
// final ArrayList<Port> outputPorts = getPorts(ports, false, sortedPorts);
//
// // Display the ports
// for (Port port : ports) {
// if (compartmentView != null) {
// final ShowHideElementsRequest request = new ShowHideElementsRequest(compartmentView, port);
// if (inputPorts.indexOf(port) != -1) {
// portLocationLeft.y = 20 + INCREMENT * (inputPorts.indexOf(port) + 1);
// request.setLocation(new Point(portLocationLeft));
// } else if (outputPorts.indexOf(port) != -1){
// portLocationRight.y = 20 + INCREMENT * (outputPorts.indexOf(port) + 1);
// request.setLocation(new Point(portLocationRight));
// }
//
// final Command cmd = ((IGraphicalEditPart) childEP).getCommand(request);
// if (cmd != null && cmd.canExecute()) {
// ((CompoundCommand) command).add(cmd);
// }
// }
// }
// }
// }
//
// // Execute the commands
// final TransactionalEditingDomain domain = elementEP.getEditingDomain();
// domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
// }
/**
* Draws the ports on the given component instance.
* @param diagramEP the EditPart of the component instance
* @return the command to be executed
*/
private CompoundCommand drawComponentInstancePorts(IGraphicalEditPart componentInstanceEP) {
final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
Point portLocationLeft = null;
Point portLocationRight = null;
final EObject semanticElement = componentInstanceEP.resolveSemanticElement();
// Get the component element type
final Class component = (Class) ((Property) semanticElement).getType();
// Get the compartment view of the property
final View compartmentView = componentInstanceEP.getNotationView();
// Set the initial position of the ports
portLocationLeft = new Point(-10, 20);
portLocationRight = new Point(-10, 20);
// Get the width of the component to set the position of output ports
final CSSShapeImpl viewShape = (CSSShapeImpl) componentInstanceEP.getNotationView();
final Bounds layout = (Bounds) viewShape.getLayoutConstraint();
portLocationRight.x += layout.getWidth() + 20;
// Get the ports of the property
final EList<Port> ports = component.getOwnedPorts();
final ArrayList<Port> inputPorts = getPorts(ports, true, sortedPorts);
final ArrayList<Port> outputPorts = getPorts(ports, false, sortedPorts);
// Display the ports
for (Port port : ports) {
if (compartmentView != null) {
final ShowHideElementsRequest request = new ShowHideElementsRequest(compartmentView, port);
if (inputPorts.indexOf(port) != -1) {
portLocationLeft.y = 20 + INCREMENT * (inputPorts.indexOf(port) + 1);
request.setLocation(new Point(portLocationLeft));
} else if (outputPorts.indexOf(port) != -1){
portLocationRight.y = 20 + INCREMENT * (outputPorts.indexOf(port) + 1);
request.setLocation(new Point(portLocationRight));
}
final Command cmd = componentInstanceEP.getCommand(request);
if (cmd != null && cmd.canExecute()) {
((CompoundCommand) command).add(cmd);
}
}
}
if (command.canExecute()) {
return command;
} else {
return null;
}
}
/**
* Computes the ideal size for the element, depending on its features.
* @param element the Element to analyze
* @return an array with ideal dimensions
*/
private int[] getSize(Element element) {
int width = 0;
int height = 60;
final int[] size = new int[2];
int inputPorts = 0;
int outputPorts = 0;
EList<Port> ports;
int maxLengthInput = 0;
int maxLengthOutput = 0;
boolean isMain = false;
if (element instanceof Property) {
// Subcomponent, get the length of its name
Property property = (Property) element;
// maxLengthInput = property.getName().length();
// maxLengthInput += property.getType().getName().length();
// Get the ports of the component
ports = ((Class) property.getType()).getOwnedPorts();
} else {
// Main component
isMain = true;
// Get the ports of the component
ports = ((Class) element).getOwnedPorts();
}
// Count the number of input and output ports and their length
for (Port port : ports) {
if (entityUtil.isInputPort(port)) {
inputPorts++;
// Get the text size for enlarging the box
int textLength = port.getName().length();
// If port type is not defined, add some space for <Undefined>
textLength += (port.getType() != null) ? port.getType().getName().length() : 11;
if (textLength > maxLengthInput) {
maxLengthInput = textLength;
}
} else {
outputPorts++;
// Get the text size for enlarging the box
int textLength = port.getName().length();
// If port type is not defined, add some space for <Undefined>
textLength += (port.getType() != null) ? port.getType().getName().length() : 11;
if (textLength > maxLengthOutput) {
maxLengthOutput = textLength;
}
}
}
// Empirical value for the width of the element
width = (int) Math.round(100 + 7.5 * (maxLengthInput + maxLengthOutput));
// Compute the height of the element based on number of ports
if (inputPorts > outputPorts) {
height += INCREMENT * inputPorts;
} else {
height += INCREMENT * outputPorts;
}
// logger.debug("Element width = " + width);
// logger.debug("Element height = " + height);
// Check box limits
if (isMain) {
size[0] = MAIN_WIDTH;
if (height < MIN_MAIN_HEIGHT) {
size[1] = MIN_MAIN_HEIGHT;
} else if (height > MAX_MAIN_HEIGHT) {
size[1] = MAX_MAIN_HEIGHT;
} else {
size[1] = height;
}
} else {
if (width < MIN_SUB_WIDTH) {
size[0] = MIN_SUB_WIDTH;
} else if (width > MAX_SUB_WIDTH) {
size[0] = MAX_SUB_WIDTH;
} else {
size[0] = width;
}
if (height < MIN_SUB_HEIGHT) {
size[1] = MIN_SUB_HEIGHT;
} else if (height > MAX_SUB_HEIGHT) {
size[1] = MAX_SUB_HEIGHT;
} else {
size[1] = height;
}
}
return size;
}
/**
* Resizes the component blocks.
* @param diagramEP the diagram EditPart
*/
private void resizeElements(IGraphicalEditPart diagramEP) {
// Get the edit part of the main element, from the diagram edit part
final IGraphicalEditPart elementEP = (IGraphicalEditPart) diagramEP.getChildren().get(0);
// Get the view of the main element
final View elementView = elementEP.getNotationView();
final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(elementView);
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
// Enlarge the main component
if (elementView instanceof CSSShapeImpl) {
final CSSShapeImpl viewShape = (CSSShapeImpl) elementView;
final Bounds layout = (Bounds) viewShape.getLayoutConstraint();
final int[] size = getSize((Element) elementView.getElement());
layout.setWidth(size[0]);
layout.setHeight(size[1]);
}
// Now I should resize also the inner components
final EList<?> compartmentChildren = ((View) elementView.getChildren().get(1)).getChildren();
EObject semanticElement = null;
int offset = 100;
// Loop on the children on the compartment view
for (Object child : compartmentChildren) {
// Get the UML element associated to the EP
semanticElement = ((View) child).getElement();
if (semanticElement instanceof Property) {
if (child instanceof CSSShapeImpl) {
final CSSShapeImpl viewShape = (CSSShapeImpl) child;
final Bounds layout = NotationFactory.eINSTANCE.createBounds();
final int[] size = getSize((Property) semanticElement);
layout.setWidth(size[0]);
layout.setHeight(size[1]);
layout.setX(offset);
layout.setY(200);
offset += 250;
viewShape.setLayoutConstraint(layout);
}
}
}
}
});
}
/**
* Resizes the missing component instances.
* @param mainElementEP the editpart of the main element
* @param missingComponentInstances the list of component instances to resize
*/
private void resizeMissingComponentInstances(IGraphicalEditPart mainElementEP, EList<Property> missingComponentInstances) {
// Get the view of the main element
final View elementView = mainElementEP.getNotationView();
final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(elementView);
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
final EList<?> compartmentChildren = ((View) elementView.getChildren().get(1)).getChildren();
EObject semanticElement = null;
int offset = INCREMENT;
// Loop on the children on the compartment view
for (Object child : compartmentChildren) {
// Get the UML element associated to the EP
semanticElement = ((View) child).getElement();
if (semanticElement instanceof Property && missingComponentInstances.contains(semanticElement) ) {
if (child instanceof CSSShapeImpl) {
final CSSShapeImpl viewShape = (CSSShapeImpl) child;
final Bounds layout = NotationFactory.eINSTANCE.createBounds();
final int[] size = getSize((Property) semanticElement);
layout.setWidth(size[0]);
layout.setHeight(size[1]);
layout.setX(INCREMENT);
layout.setY(offset);
offset += INCREMENT;
viewShape.setLayoutConstraint(layout);
}
}
}
}
});
}
/**
* Returns the diagram EditPart.
* @return
*/
public EditPart getHost() {
return host;
}
/**
* Gets the editpart from view.
* @param view the view
* @return the EditPart from the view
*/
private EditPart getEditPartFromView(View view) {
if (view != null) {
return (EditPart) getHost().getViewer().getEditPartRegistry().get(view);
}
return null;
}
/**
* Gets the EditPart related to the given port.
* @param role the port
* @param property the component instance containing the port
* @param elementView the view of the element containing the component instance
* @return the requested EditPart
*/
private EditPart getPortEditPart(Port role, Property property, View elementView) {
logger.debug("\n\nLooking for port " + role.getQualifiedName());
// If the port is inside a component instance, go inside the element
if (property != null) {
logger.debug("Containing property: " + property.getQualifiedName());
// Get the comparment view of the element
final View compartmentView = (View) elementView.getChildren().get(1);
// Loop on the contained elements
for (Object child : compartmentView.getChildren()) {
if (child instanceof CSSShapeImpl) {
final CSSShapeImpl shape = (CSSShapeImpl) child;
// Check if the element is a property
if (shape.getElement() instanceof Property) {
final Property propertyImpl = (Property) shape.getElement();
if (propertyImpl != null) {
if (property.getQualifiedName().equals(propertyImpl.getQualifiedName())) {
// Found the property containing the port, look inside the children
final EList<?> shapeChildren = shape.getChildren();
for (Object childView : shapeChildren) {
final IGraphicalEditPart ep = (IGraphicalEditPart) getEditPartFromView((View) childView);
if (ep instanceof FlowPortAffixedNodeEditPart || ep instanceof PortAffixedNodeEditPart) {
if (role == ep.resolveSemanticElement()) {
logger.debug("\nPort found in part, view = " + ep);
return ep;
}
}
}
}
}
}
}
}
} else {
// The port is of the main element
EList<?> elementChildren = elementView.getChildren();
for (Object childView : elementChildren) {
IGraphicalEditPart ep = (IGraphicalEditPart) getEditPartFromView((View) childView);
if (ep instanceof FlowPortAffixedNodeEditPart || ep instanceof PortAffixedNodeEditPart) {
if (role == ep.resolveSemanticElement()) {
logger.debug("\nPort found in main elemement, view = " + ep);
return ep;
}
}
}
}
return null;
}
/**
* Returns the command to show the connection line between the given edit parts.
* @param sourceEP the EditPart of the source port
* @param targetEP the EditPart of the target port
* @param connector the Connector between the ports
* @return the Command to display the link
*/
private Command getShowLinkCommand(EditPart sourceEP, EditPart targetEP, Connector connector) {
String semanticHint = "link_uml_connector";
IAdaptable mySemanticAdapter = new EObjectAdapter(connector) {
public Object getAdapter(@SuppressWarnings("rawtypes") java.lang.Class adapter) {
if (IElementType.class.equals(adapter)) {
return org.eclipse.papyrus.uml.diagram.composite.providers.UMLElementTypes.Connector_Edge;
}
return super.getAdapter(adapter);
}
};
CreateConnectionViewRequest.ConnectionViewDescriptor viewDescriptor =
new CreateConnectionViewRequest.ConnectionViewDescriptor(mySemanticAdapter, semanticHint,
ViewUtil.APPEND, false, ((GraphicalEditPart) getHost()).getDiagramPreferencesHint());
CreateConnectionViewRequest ccr = new CreateConnectionViewRequest(viewDescriptor);
ccr.setType(org.eclipse.gef.RequestConstants.REQ_CONNECTION_START);
ccr.setSourceEditPart(sourceEP);
sourceEP.getCommand(ccr);
ccr.setTargetEditPart(targetEP);
ccr.setType(org.eclipse.gef.RequestConstants.REQ_CONNECTION_END);
return targetEP.getCommand(ccr);
}
/**
* Draws the connector lines inside the given element.
* @param elementEP the EditPart of the element to browse
* @param connectors the list of connectors to draw
*/
public void drawConnectors(IGraphicalEditPart elementEP, EList<Connector> connectors) {
final View elementView = elementEP.getNotationView();
final CompoundCommand compoundCommand = new CompoundCommand("Restore A Related Link");
// Loop on all the connectors
for (Connector connector : connectors) {
EditPart sourceEP = null;
EditPart targetEP = null;
// Retrieve the EP for the source port
final ConnectorEnd sourceEnd = connector.getEnds().get(0);
if (sourceEnd != null) {
sourceEP = getPortEditPart((Port) sourceEnd.getRole(), sourceEnd.getPartWithPort(), elementView);
}
// Retrieve the EP for the target port
final ConnectorEnd targetEnd = connector.getEnds().get(1);
if (targetEnd != null) {
targetEP = getPortEditPart((Port) targetEnd.getRole(), targetEnd.getPartWithPort(), elementView);
}
if (sourceEP != null && targetEP != null) {
Command cmd = getShowLinkCommand(sourceEP, targetEP, connector);
if (cmd != null && cmd.canExecute()) {
compoundCommand.add(cmd);
}
}
}
// Execute the commands
final TransactionalEditingDomain domain = elementEP.getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(compoundCommand));
}
/**
* Fills the diagram with graphical components.
* @param diagram
* @throws ServiceException
*/
public void populateDiagram(Diagram diagram, boolean sortedPorts) {
final Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
// The EditPart associated to the diagram
final IGraphicalEditPart diagramEP = OffscreenEditPartFactory.getInstance().createDiagramEditPart(diagram, shell);
// Store the EditPart
setHost(diagramEP);
this.sortedPorts = sortedPorts;
// The main EditPart
final IGraphicalEditPart selectedElementEP = (IGraphicalEditPart) diagramEP.getChildren().get(0);
// logger.debug("\n\nselectedElement EditPart = " + selectedElementEP + "\n\n");
// Add the selected element to the list, there could be more than one...
selectedElements = new ArrayList<IGraphicalEditPart>();
selectedElements.add(selectedElementEP);
// Call superclass methods to setup the action
initAction();
buildInitialSelection();
// Get a selection with all the possible elements
buildSelection();
// logger.debug("Selection size = " + selection.size());
if (selection.size() > 0) {
// Filter the list to extract only the elements I'm interested in
buildShowHideElementsList(selection.toArray());
// Create the list of commands to display the elements
final Command command = getActionCommand();
// Execute the commands
final TransactionalEditingDomain domain = selectedElements.get(0).getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
// Resize the graphical elements
resizeElements(diagramEP);
// Draw the ports on the inner components
// NB: labels are put in the wrong place, but if done in another command they are fine!
drawAllComponentInstancesPorts(selectedElementEP);
// Draw all the connectors
drawConnectors(selectedElementEP, ((Class) selectedElementEP.resolveSemanticElement()).getOwnedConnectors());
}
}
public void setHost(IGraphicalEditPart diagramEP) {
this.host = diagramEP;
}
/**
* Draws the missing ports of the given element, on the lower border.
* @param elementEP the EditPart of the element
* @param missingPorts the Ports to be drawn
*/
private CompoundCommand drawMissingPorts(IGraphicalEditPart elementEP, EList<Port> missingPorts) {
final CompoundCommand command = new CompoundCommand("Draw Missing Ports Commands");
// Get the compartment view
final View compartmentView = elementEP.getNotationView();
// Loop on the missing ports and draw them, on the lower border
for (Port port : missingPorts) {
final ShowHideElementsRequest request = new ShowHideElementsRequest(compartmentView, port);
request.setLocation(new Point(missingPorts.indexOf(port) * INCREMENT, 10000));
final Command cmd = elementEP.getCommand(request);
if (cmd != null && cmd.canExecute()) {
((CompoundCommand) command).add(cmd);
}
}
return command;
}
/**
* Returns the edit part associated to the given component instance
* @param owner the editpart of the owner element
* @param componentInstance the component instance to process
* @return the edit part of the given component istance
*/
private IGraphicalEditPart getComponentInstanceEditPart(IGraphicalEditPart owner, Property componentInstance) {
// The list of children edit parts, from the container of the owning element
final List<?> compartmentChildrenEP = ((EditPart) owner.getChildren().get(1)).getChildren();
// Loop on the edit parts to find the right one
for (Object childEP : compartmentChildrenEP) {
if (childEP instanceof IGraphicalEditPart) {
final EObject semanticElement = ((IGraphicalEditPart) childEP).resolveSemanticElement();
if (semanticElement == componentInstance) {
return (IGraphicalEditPart) childEP;
}
}
}
return null;
}
/**
* Draws the ports on the newly added component instances
* @param mainElementEP the editpart of the main element
* @param missingComponentInstances the list of component instances to enrich
*/
private void drawMissingComponentsPorts(IGraphicalEditPart mainElementEP, EList<Property> missingComponentInstances) {
final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
for (Property componentInstance : missingComponentInstances) {
command.add(drawComponentInstancePorts(getComponentInstanceEditPart(mainElementEP, componentInstance)));
}
// Execute the command
final TransactionalEditingDomain domain = mainElementEP.getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
}
/**
* Moves up the position of the newly added ports.
* @param elementEP the editpart of the element
* @param missingPorts the list of ports to adjust
*/
private void adjustMissingPortsLabels(IGraphicalEditPart elementEP, EList<Port> missingPorts) {
// Get all the EditParts of the element
final Map<?, ?> elements = elementEP.getViewer().getEditPartRegistry();
final Object[] editParts = elements.values().toArray();
final TransactionalEditingDomain domain =
TransactionUtil.getEditingDomain(((IGraphicalEditPart) elementEP).getNotationView());
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
for (int i = 0; i < editParts.length; i++) {
if (editParts[i] instanceof FlowPortAffixedLabelNameEditPart) {
// Label containing the name of the port
final FlowPortAffixedLabelNameEditPart labelEditPart = (FlowPortAffixedLabelNameEditPart) editParts[i];
final CSSDecorationNodeImpl view = (CSSDecorationNodeImpl) labelEditPart.getNotationView();
final LocationImpl layout = (LocationImpl) view.getLayoutConstraint();
// Get the port owning the label
final Port port = (Port) ((FlowPortAffixedLabelNameEditPart) editParts[i]).resolveSemanticElement();
if (missingPorts.contains(port)) {
layout.setY(layout.getY() - 20);
}
} else if (editParts[i] instanceof PortAffixedLabelNameEditPart) {
// Label containing the name of the port
final PortAffixedLabelNameEditPart editPart = (PortAffixedLabelNameEditPart) editParts[i];
final CSSDecorationNodeImpl view = (CSSDecorationNodeImpl) editPart.getNotationView();
final LocationImpl layout = (LocationImpl) view.getLayoutConstraint();
// Get the port owning the label
final Port port = (Port) ((PortAffixedLabelNameEditPart) editParts[i]).resolveSemanticElement();
if (missingPorts.contains(port)) {
layout.setY(layout.getY() - 20);
}
}
}
}
});
}
/**
* Draws the ports that are missing for the given component instances.
* @param mainElementEP the editpart of the main element
* @param displayedComponentInstances the list of component instances to enrich
* @param displayedPorts the list of ports that are already present on the diagram
*/
private boolean drawUpdatedComponentInstancesPorts(IGraphicalEditPart mainElementEP,
EList<Property> displayedComponentInstances, EList<Port> displayedPorts) {
final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
final EList<Port> totalMissingComponentPorts = new BasicEList<Port>();
for (Property componentInstance : displayedComponentInstances) {
// All the existing ports, from the component instance type (block)
Class component = (Class) componentInstance.getType();
final EList<Port> existingComponentPorts = component.getOwnedPorts();
// Loop on the ports to find those not displayed and draw them
final EList<Port> missingComponentPorts = new BasicEList<Port>();
for (Port port : existingComponentPorts) {
if (displayedPorts.contains(port)) {
logger.debug("port already present in diagram");
} else {
logger.debug("port is not present in diagram: " + port);
missingComponentPorts.add(port);
totalMissingComponentPorts.add(port);
}
}
if (missingComponentPorts.size() > 0) {
command.add(drawMissingPorts(getComponentInstanceEditPart(mainElementEP, componentInstance), missingComponentPorts));
}
}
// Execute the command
final TransactionalEditingDomain domain = mainElementEP.getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
// Ajust the labels of the newly created ports
adjustMissingPortsLabels(mainElementEP, totalMissingComponentPorts);
return command.size() > 0;
}
/**
* Draws the ports that are missing for the given main component.
* @param mainElementEP the editpart of the element
* @param displayedPorts the list of ports that are already present on the diagram
* @return true if some ports have been drawn
*/
private boolean drawUpdatedMainComponentPorts(IGraphicalEditPart mainElementEP, EList<Port> displayedPorts) {
final CompoundCommand command = new CompoundCommand("Draw Component Instances Ports Commands");
// All the existing ports of the main element
final EList<Port> existingMainComponentPorts = ((Class) mainElementEP.resolveSemanticElement()).getOwnedPorts();
// Loop on the ports to find those not displayed and draw them
final EList<Port> missingMainComponentPorts = new BasicEList<Port>();
for (Port port : existingMainComponentPorts) {
if (displayedPorts.contains(port)) {
logger.debug("port already present in diagram");
} else {
logger.debug("port is not present in diagram: " + port);
missingMainComponentPorts.add(port);
}
}
if (missingMainComponentPorts.size() > 0) {
command.add(drawMissingPorts(mainElementEP, missingMainComponentPorts));
// Execute the command
final TransactionalEditingDomain domain = mainElementEP.getEditingDomain();
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
// Ajust the labels of the newly created ports
adjustMissingPortsLabels(mainElementEP, missingMainComponentPorts);
}
return command.size() > 0;
}
/**
* Displays missing elements in the given diagram.
* @param diagramEditPart the diagram editpart
*/
public boolean refreshDiagram(IGraphicalEditPart diagramEditPart) {
boolean isDiagramChanged = false; // Indicates whether the diagram has been modified
// The main element EditPart
final IGraphicalEditPart mainElementEP = (IGraphicalEditPart) diagramEditPart.getChildren().get(0);
// The main element of the diagram
final Class mainElement = (Class) mainElementEP.resolveSemanticElement();
// Get all the EditParts of the diagram
final Map<?, ?> elements = diagramEditPart.getViewer().getEditPartRegistry();
final Object[] editParts = elements.values().toArray();
// Lists of displayed elements
final EList<Property> displayedComponentInstances = new BasicEList<Property>();
final EList<Connector> displayedConnectors = new BasicEList<Connector>();
final EList<Port> displayedPorts = new BasicEList<Port>();
// Loop on all the editparts to collect the displayed elements
for (int i = 0; i < editParts.length; i++) {
if (editParts[i] instanceof BlockPropertyCompositeEditPart) {
displayedComponentInstances.add((Property) ((BlockPropertyCompositeEditPart) editParts[i]).resolveSemanticElement());
} else if (editParts[i] instanceof ConnectorEditPart) {
displayedConnectors.add((Connector) ((ConnectorEditPart) editParts[i]).resolveSemanticElement());
} else if (editParts[i] instanceof FlowPortAffixedNodeEditPart) {
displayedPorts.add((Port) ((FlowPortAffixedNodeEditPart) editParts[i]).resolveSemanticElement());
}
}
// Sort ports by default
this.sortedPorts = true;
// Draw the missing ports on the main component
if (drawUpdatedMainComponentPorts(mainElementEP, displayedPorts)) {
isDiagramChanged = true;
}
// Draw the missing ports on displayed component instances
if (drawUpdatedComponentInstancesPorts(mainElementEP, displayedComponentInstances, displayedPorts)) {
isDiagramChanged = true;
}
// All the existing component instances of the main element
EList<Property> existingComponentInstances = new BasicEList<Property>(entityUtil.getSubComponentsInstances(mainElement));
// Loop on the component instances to find those not displayed
final EList<Property> missingComponentInstances = new BasicEList<Property>();
for (Property property : existingComponentInstances) {
if (displayedComponentInstances.contains(property)) {
logger.debug("component instance already present in diagram");
} else {
logger.debug("component instance is not present in diagram: " + property);
missingComponentInstances.add(property);
}
}
// Setup the variables to draw the component instances
selectedElements = new ArrayList<IGraphicalEditPart>();
selectedElements.add(mainElementEP);
host = diagramEditPart;
// Call superclass methods to setup the action
initAction();
buildInitialSelection();
// Get a selection with all the possible elements
buildSelection();
// Draw the missing component instances
if (selection.size() > 0) {
// Filter the list to extract only the elements I'm interested in
buildShowHideElementsList(selection.toArray());
// Create the list of commands to display the component instances
final CompoundCommand command = (CompoundCommand) getActionCommand();
// Execute the commands
if (command.size() > 0) {
isDiagramChanged = true;
final TransactionalEditingDomain domain = TransactionUtil.getEditingDomain(diagramEditPart.getNotationView());
domain.getCommandStack().execute(new GEFtoEMFCommandWrapper(command));
}
}
// Resize the missing component instances
resizeMissingComponentInstances(mainElementEP, missingComponentInstances);
// Draw the ports for the new component instances
drawMissingComponentsPorts(mainElementEP, missingComponentInstances);
// All the existing connectors of the main element
final EList<Connector>existingConnectors = mainElement.getOwnedConnectors();
// Loop on the connectors to find those not displayed
final EList<Connector> missingConnectors = new BasicEList<Connector>();
for (Connector connector : existingConnectors) {
if (displayedConnectors.contains(connector)) {
logger.debug("connector already present in diagram");
} else {
logger.debug("connector is not present in diagram: " + connector);
missingConnectors.add(connector);
}
}
// Draw the missing connectors
if (missingConnectors.size() > 0) {
isDiagramChanged = true;
drawConnectors(mainElementEP, missingConnectors);
}
return isDiagramChanged;
}
}