blob: e321162d04f3234f856a4d4eaa03cde346f45dfc [file] [log] [blame]
/*******************************************************************************
* <copyright>
*
* Copyright (c) 2013, 2013 SAP AG.
* 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:
* SAP AG - initial API, implementation and documentation
*
* </copyright>
*
*******************************************************************************/
package org.eclipse.fmc.blockdiagram.editor.meta.features.update;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.fmc.blockdiagram.editor.meta.profile.IStereotypeProvider;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.IReason;
import org.eclipse.graphiti.features.context.IUpdateContext;
import org.eclipse.graphiti.features.impl.AbstractUpdateFeature;
import org.eclipse.graphiti.features.impl.Reason;
import org.eclipse.graphiti.mm.algorithms.AbstractText;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.fmc.blockdiagram.editor.algorithm.node.FMCNodeAlgorithm;
import org.eclipse.fmc.blockdiagram.editor.algorithm.node.FMCNodeAlgorithmFactory;
import org.eclipse.fmc.blockdiagram.editor.util.FMCUtil;
import org.eclipse.fmc.mm.FMCNode;
import org.eclipse.fmc.mm.MultiplicityType;
/**
* Feature Class for updating the graphical representation and the business
* model of a FMCNode.
*
* @author Benjamin Schmeling
*
*/
public class FMCNodeUpdateFeature extends AbstractUpdateFeature {
/** The algorithm factory of FMCNodes. */
protected FMCNodeAlgorithmFactory factory = FMCNodeAlgorithmFactory
.getInstance();
/**
* The stereotype provider (is not null only if the Stereotype Extension is
* installed).
*/
private IStereotypeProvider stereotypeProvider;
/**
* Instantiates a new FMC node update feature.
*
* @param fp
* the FeatureProvider Class.
* @param stereotypeProvider
* the StereotypeProvider Class.
*/
public FMCNodeUpdateFeature(IFeatureProvider fp,
IStereotypeProvider stereotypeProvider) {
super(fp);
this.stereotypeProvider = stereotypeProvider;
}
/**
* The FMCNode can only updated when the PictogramElement of a given context
* is a ContainerShape.
*/
@Override
public boolean canUpdate(IUpdateContext context) {
return context.getPictogramElement() instanceof ContainerShape;
}
/**
* Check if the linked business object of the PictogramElement of a given
* context is a FMCNode. If the linked business object is a FMCNode return
* the result of the protected updateNeeded method. Otherwise create a false
* reason.
*/
@Override
public IReason updateNeeded(IUpdateContext context) {
EObject bo = FMCUtil.getBO(context.getPictogramElement());
if (bo instanceof FMCNode) {
FMCNode node = (FMCNode) bo;
ContainerShape container = (ContainerShape) context
.getPictogramElement();
return updateNeeded(container, node);
}
return Reason.createFalseReason();
}
/**
* Checks if the given container is a container main multi part.
*
* @param algorithm
* the algorithm.
* @param container
* the container.
* @return true, if container is a container main multi part.
*/
protected boolean isContainerMainMultiPart(FMCNodeAlgorithm algorithm,
ContainerShape container) {
if (container.eContainer() == null
|| !(container.eContainer() instanceof ContainerShape))
return false;
ContainerShape containerParent = (ContainerShape) container
.eContainer();
return container.getGraphicsAlgorithm().equals(
algorithm.getMultiInstanceChild(containerParent, true));
}
/**
* Checks if the given container is a container multi part.
*
* @param algorithm
* the FMCNodeAlgorithm.
* @param container
* the ContainerShape.
* @return true, if container is a container multi part.
*/
protected boolean isContainerMultiPart(FMCNodeAlgorithm algorithm,
ContainerShape container) {
if (container.eContainer() == null
|| !(container.eContainer() instanceof ContainerShape))
return false;
ContainerShape containerParent = (ContainerShape) container
.eContainer();
return container.getGraphicsAlgorithm().equals(
algorithm.getMultiInstanceChild(containerParent, true))
|| container.getGraphicsAlgorithm()
.equals(algorithm.getMultiInstanceChild(
containerParent, false));
}
/**
* Checks if is multi part.
*
* @param algorithm
* the algorithm
* @param container
* the container
* @return true, if is multi part
*/
protected boolean isMultiPart(FMCNodeAlgorithm algorithm,
ContainerShape container) {
GraphicsAlgorithm invisibleGa = container.getGraphicsAlgorithm();
return invisibleGa.getGraphicsAlgorithmChildren().size() == 2;
}
/**
* Check if the main shape should update.
*
* @param algorithm
* the algorithm.
* @param container
* the container.
* @return true, if main shape should update.
*/
protected boolean shouldUpdateMainShape(FMCNodeAlgorithm algorithm,
ContainerShape container) {
boolean isThisContainerAMultiPart = isContainerMultiPart(algorithm,
container);
boolean isThisContainerMainMultiPart = isContainerMainMultiPart(
algorithm, container);
boolean isMultiInstance = algorithm.isMultipleInstances(container);
return (!isMultiInstance && !isThisContainerAMultiPart || isThisContainerMainMultiPart);
}
/**
* Check if update needed because of when the text or the multiplicity of
* the graphical representation is not synch with the domain.
*
* @param container
* the ContainerShape
* @param node
* the FMCNode
* @return the i reason
*/
protected IReason updateNeeded(ContainerShape container, FMCNode node) {
FMCNodeAlgorithm algorithm = factory.getShape(container);
if (algorithm != null) {
boolean isThisContainerAMultiPart = isContainerMultiPart(algorithm,
container);
boolean isMultiInstance = algorithm.isMultipleInstances(container);
AbstractText text = findText(container);
// Text not equal
if (shouldUpdateMainShape(algorithm, container)
&& !equalsText(text, node))
return Reason
.createTrueReason("The text is not in synch with domain model");
// Multiplicity not equal
boolean graphMulti = gaphicalMultiplicity(container, node);
if ((!isThisContainerAMultiPart
&& isMultiInstance != (node.getMultiplicity() == MultiplicityType.MANY) && (!graphMulti))
|| (graphMulti && (node.getMultiplicity() == MultiplicityType.MANY))) {
return Reason
.createTrueReason("The multiplicity is not in synch wiht domain model");
}
}
return Reason.createFalseReason();
}
/**
* Placeholder Method - will be overridden.
*
* @param container
* the ContainerShape
* @param node
* the FMCNode
* @return false
*/
protected boolean gaphicalMultiplicity(ContainerShape container,
FMCNode node) {
return false;
}
/**
* Find the AbstractText object in a given ContainerShape object.
*
* @param container
* the ContainerShape
* @return the AbstractText object or null.
*/
protected AbstractText findText(ContainerShape container) {
for (Shape shape : container.getChildren()) {
if (shape.getGraphicsAlgorithm() instanceof AbstractText) {
return (AbstractText) shape.getGraphicsAlgorithm();
}
}
AbstractText text = null;
for (Shape shape : container.getChildren()) {
if (text == null && shape instanceof ContainerShape) {
text = findText((ContainerShape) shape);
}
}
return text;
}
/**
* Update the Text and the mutiplicity if it's needed.
*/
@Override
public boolean update(IUpdateContext context) {
ContainerShape container = (ContainerShape) context
.getPictogramElement();
FMCNode node = (FMCNode) FMCUtil.getBO(container);
FMCNodeAlgorithm algorithm = factory.getShape(container);
if (algorithm == null)
return false;
boolean isMultiInstance = algorithm.isMultipleInstances(container);
if (!isMultiInstance || isContainerMainMultiPart(algorithm, container))
updateText(context, node);
boolean graphMulti = gaphicalMultiplicity(container, node);
if (((node.getMultiplicity() == MultiplicityType.MANY) != isMultiInstance
&& !isContainerMultiPart(algorithm, container) && !graphMulti)
|| (graphMulti
&& (node.getMultiplicity() == MultiplicityType.MANY) && isMultiPart(
algorithm, container)))
updateMultiplicity(context.getPictogramElement(), algorithm, node,
graphMulti);
return true;
}
/**
* Update text (and if the Stereotype Extension is installed the
* Stereotypetext).
*
* @param context
* the UpdateContext.
* @param node
* the FMCNode.
*/
protected void updateText(IUpdateContext context, FMCNode node) {
AbstractText text = findText((ContainerShape) context
.getPictogramElement());
if (text != null) {
String stereotypeText = "";
if (stereotypeProvider != null)
stereotypeText = stereotypeProvider.getStereotypeText(node);
String nodeText = node.getName();
text.setValue(nodeText == null ? stereotypeText : stereotypeText
+ nodeText);
} else {
// TODO Add new text
}
}
/**
* Update the multiplicity representation of the given ContainerShape
* object.
*
* @param picto
* the PictogramElement.
* @param algorithm
* the FMCNodeAlgorithm.
* @param node
* the FMCNode
* @param graphMulti
* Is the multiplicity set in the graphical representation.
*/
protected void updateMultiplicity(PictogramElement picto,
FMCNodeAlgorithm algorithm, FMCNode node, boolean graphMulti) {
algorithm
.setMultipleInstances(
(ContainerShape) picto,
getFeatureProvider(),
((node.getMultiplicity() == MultiplicityType.MANY) && (!graphMulti)));
}
/**
* Equals text between the graphical representation and the business object.
*
* @param text
* the AbstractText
* @param node
* the FMCNode
* @return true, if equals
*/
protected boolean equalsText(AbstractText text, FMCNode node) {
if ((text == null) || (node.getName() == null))
return true;
String substringText = text.getValue();
if (stereotypeProvider != null)
substringText = FMCUtil
.substringStereotype(substringText);
return substringText.equals(node.getName());
}
}