/******************************************************************************* | |
* <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()); | |
} | |
} |