/******************************************************************************* | |
* <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.features.create; | |
import org.eclipse.fmc.blockdiagram.editor.BlockDiagramConstants; | |
import org.eclipse.fmc.blockdiagram.editor.model.ConnectionStyle; | |
import org.eclipse.fmc.blockdiagram.editor.model.FMCType; | |
import org.eclipse.fmc.blockdiagram.editor.model.FMCTypeChecker; | |
import org.eclipse.fmc.blockdiagram.editor.model.FMCTypeCheckerFactory; | |
import org.eclipse.graphiti.datatypes.ILocation; | |
import org.eclipse.graphiti.features.IFeatureProvider; | |
import org.eclipse.graphiti.features.context.ICreateConnectionContext; | |
import org.eclipse.graphiti.features.context.impl.AddConnectionContext; | |
import org.eclipse.graphiti.features.context.impl.AddContext; | |
import org.eclipse.graphiti.features.context.impl.AreaContext; | |
import org.eclipse.graphiti.features.impl.AbstractCreateConnectionFeature; | |
import org.eclipse.graphiti.mm.algorithms.AbstractText; | |
import org.eclipse.graphiti.mm.algorithms.PlatformGraphicsAlgorithm; | |
import org.eclipse.graphiti.mm.pictograms.Anchor; | |
import org.eclipse.graphiti.mm.pictograms.BoxRelativeAnchor; | |
import org.eclipse.graphiti.mm.pictograms.Connection; | |
import org.eclipse.graphiti.mm.pictograms.Diagram; | |
import org.eclipse.graphiti.mm.pictograms.PictogramElement; | |
import org.eclipse.graphiti.mm.pictograms.Shape; | |
import org.eclipse.graphiti.services.Graphiti; | |
import org.eclipse.graphiti.services.IPeService; | |
/** | |
* Create feature for connections. The class can be used for all types of | |
* connections. Furthermore, the class checks whether it is allowed to connect | |
* two shapes according to the rules of block diagrams. | |
* | |
* @author Benjamin Schmeling | |
* | |
*/ | |
public class ConnectionCreateFeature extends AbstractCreateConnectionFeature { | |
/** | |
* The model object to be created. | |
*/ | |
protected Object type = null; | |
/** | |
* The id of the icon for the create image. | |
*/ | |
private String icon = null; | |
/** | |
* The style of the connection. | |
*/ | |
private ConnectionStyle style = null; | |
/** | |
* Reference to the type checker. | |
*/ | |
protected FMCTypeChecker checker = FMCTypeCheckerFactory.getInstance(); | |
/** | |
* The default constructor. | |
* | |
* @param featureProvider | |
* The feature provider. | |
* @param name | |
* The name of the create feature displayed as palette tool entry | |
* label. | |
* @param description | |
* The description palette tool entry | |
* @param type | |
* The object model instance to be created. | |
* @param style | |
* The style of the connection. | |
* @param icon | |
* The icon to be used for the palette tool entry. | |
*/ | |
public ConnectionCreateFeature(IFeatureProvider featureProvider, String name, | |
String description, Object type, ConnectionStyle style, String icon) { | |
super(featureProvider, name, description); | |
this.type = type; | |
this.icon = icon; | |
this.style = style; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.func.ICreateConnection#canCreate(org.eclipse.graphiti | |
* .features.context.ICreateConnectionContext) | |
*/ | |
@Override | |
public boolean canCreate(ICreateConnectionContext context) { | |
PictogramElement targetPictogramElement = context | |
.getTargetPictogramElement(); | |
PictogramElement sourcePictogramElement = context | |
.getSourcePictogramElement(); | |
// Special Case for BoxRelative Anchor | |
if (context.getTargetAnchor() instanceof BoxRelativeAnchor) { | |
targetPictogramElement = context.getTargetAnchor().getParent(); | |
} | |
if (context.getSourceAnchor() instanceof BoxRelativeAnchor) { | |
sourcePictogramElement = context.getSourceAnchor().getParent(); | |
} | |
if (sourcePictogramElement instanceof Shape | |
&& targetPictogramElement instanceof Shape) { | |
Shape shapeBehindTextOrPictureSource = getShapeBehindTextOrPicture((Shape) sourcePictogramElement); | |
Shape shapeBehindTextOrPictureTarget = getShapeBehindTextOrPicture((Shape) targetPictogramElement); | |
if (type != FMCType.Dots | |
&& !isSourceAndTargetTypesValid( | |
shapeBehindTextOrPictureSource, | |
shapeBehindTextOrPictureTarget) | |
) | |
return false; | |
return type == FMCType.Dots | |
|| !(targetPictogramElement instanceof Diagram) | |
&& shapeBehindTextOrPictureTarget != null | |
&& shapeBehindTextOrPictureSource != null; | |
} | |
return type == FMCType.Dots; | |
// return true; | |
} | |
/** | |
* Checks whether the shapes to be connected are compatible according to | |
* block diagram rules. | |
* | |
* @param shapeBehindTextOrPictureSource | |
* The source shape to be connected. | |
* @param shapeBehindTextOrPictureTarget | |
* The target shape to be connected. | |
* @return True if both are compatible and valid. | |
*/ | |
protected boolean isSourceAndTargetTypesValid( | |
Shape shapeBehindTextOrPictureSource, | |
Shape shapeBehindTextOrPictureTarget) { | |
if (checker.isChannelType(type)) | |
return checker.isAgent(shapeBehindTextOrPictureSource) | |
&& checker.isAgent(shapeBehindTextOrPictureTarget); | |
else | |
return checker.isAgent(shapeBehindTextOrPictureSource) | |
&& (checker.isStorage(shapeBehindTextOrPictureTarget) || checker | |
.isStructureVariance(shapeBehindTextOrPictureTarget)) | |
|| checker.isAgent(shapeBehindTextOrPictureTarget) | |
&& checker.isStorage(shapeBehindTextOrPictureSource); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.func.ICreateConnection#create(org.eclipse.graphiti | |
* .features.context.ICreateConnectionContext) | |
*/ | |
@Override | |
public Connection create(ICreateConnectionContext context) { | |
Anchor source = context.getSourceAnchor(); | |
Anchor target = context.getTargetAnchor(); | |
IPeService pe = Graphiti.getPeService(); | |
if (source == null | |
&& context.getSourcePictogramElement() instanceof Shape) { | |
Shape container = getShapeBehindTextOrPicture((Shape) context | |
.getSourcePictogramElement()); | |
if (container != null) { | |
if (container.getAnchors().isEmpty()) | |
source = pe.createChopboxAnchor(container); | |
else | |
source = container.getAnchors().get(0); | |
} | |
} | |
if (target == null | |
&& context.getTargetPictogramElement() instanceof Shape) { | |
Shape container = getShapeBehindTextOrPicture((Shape) context | |
.getTargetPictogramElement()); | |
if (container != null) { | |
if (container.getAnchors().isEmpty()) | |
target = pe.createChopboxAnchor(container); | |
else | |
target = container.getAnchors().get(0); | |
} else { | |
AreaContext areaContext = new AreaContext(); | |
ILocation targetLocation = context.getTargetLocation(); | |
areaContext.setLocation(targetLocation.getX(), | |
targetLocation.getY()); | |
areaContext.setSize(getDiagram().getGraphicsAlgorithm() | |
.getWidth(), getDiagram().getGraphicsAlgorithm() | |
.getHeight()); | |
AddContext addContext = new AddContext(areaContext, | |
FMCType.Invisible); | |
addContext.setTargetContainer(getDiagram()); | |
// addContext.setLocation(targetLocation.getX(), | |
// targetLocation.getY()); | |
Shape invisible = (Shape) getFeatureProvider().addIfPossible( | |
addContext); | |
target = invisible.getAnchors().get(0); | |
} | |
} | |
AddConnectionContext addContext = new AddConnectionContext(source, | |
target); | |
if (type instanceof FMCType) | |
addContext.setNewObject(type); | |
else { | |
createConnectionModel(addContext, source, target); | |
} | |
addContext.putProperty(BlockDiagramConstants.GRAPHICAL_TYPE_KEY, this.style); | |
Connection connection = (Connection) getFeatureProvider() | |
.addIfPossible(addContext); | |
// connection.setEnd(getAdditionalBoxAnchor(target, connection, | |
// context.getTargetLocation())); | |
return connection; | |
} | |
/** | |
* Does nothing because the simple enumeration-based object model is used. | |
* However, this method should be overridden in case of a real meta model | |
* being used. | |
* | |
* @param context | |
* The add context. | |
* @param source | |
* Source anchor. | |
* @param target | |
* Target anchor. | |
*/ | |
protected void createConnectionModel(AddConnectionContext context, | |
Anchor source, Anchor target) { | |
} | |
/** | |
* If a shape is not allowed as connection source or target return the | |
* container shape. | |
* | |
* @param shape | |
* The selected shape to be analyzed. | |
* | |
* @return Container shape of shape if shape is image or text. | |
*/ | |
public static Shape getShapeBehindTextOrPicture(Shape shape) { | |
if (shape != null) { | |
if (!shape.isActive() | |
|| shape.getGraphicsAlgorithm() instanceof AbstractText | |
|| shape.getGraphicsAlgorithm() instanceof PlatformGraphicsAlgorithm) { | |
return shape.getContainer(); | |
} | |
// human agent figures | |
if (shape.getGraphicsAlgorithm().getGraphicsAlgorithmChildren() | |
.size() > 4) | |
return shape.getContainer(); | |
} | |
if (shape instanceof Diagram) | |
return null; | |
return shape; | |
} | |
/** | |
* If a shape is not allowed as connection source or target return the | |
* container shape. If no such shape exists, the parent of the anchor is | |
* returned. | |
* | |
* @param shape | |
* The selected shape to be analyzed. | |
* @param anchor | |
* The anchor to be analyzed. | |
* @return Container shape of shape if shape is image or text. | |
*/ | |
public static Shape getShapeBehindTextOrPicture(Shape shape, Anchor anchor) { | |
Shape shapeBehindTextOrPicture = getShapeBehindTextOrPicture(shape); | |
if (anchor != null && shapeBehindTextOrPicture == null | |
&& anchor.getParent() instanceof Shape) | |
return (Shape) anchor.getParent(); | |
return shapeBehindTextOrPicture; | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see | |
* org.eclipse.graphiti.func.ICreateConnection#canStartConnection(org.eclipse | |
* .graphiti.features.context.ICreateConnectionContext) | |
*/ | |
@Override | |
public boolean canStartConnection(ICreateConnectionContext context) { | |
PictogramElement sourcePictogramElement = context | |
.getSourcePictogramElement(); | |
Shape shapeBehindTextOrPicture = null; | |
if (sourcePictogramElement instanceof Shape) | |
shapeBehindTextOrPicture = getShapeBehindTextOrPicture( | |
(Shape) sourcePictogramElement, context.getSourceAnchor()); | |
if (shapeBehindTextOrPicture == null | |
&& context.getSourceAnchor() != null) | |
shapeBehindTextOrPicture = (Shape) context.getSourceAnchor() | |
.getReferencedGraphicsAlgorithm().getPictogramElement(); | |
return !(sourcePictogramElement instanceof Diagram) | |
&& shapeBehindTextOrPicture != null | |
&& checker.isAgent(shapeBehindTextOrPicture) | |
|| (checker.isStorage(shapeBehindTextOrPicture) && !checker | |
.isChannelType(type)); | |
} | |
/* | |
* (non-Javadoc) | |
* | |
* @see org.eclipse.graphiti.features.impl.AbstractCreateConnectionFeature# | |
* getCreateImageId() | |
*/ | |
@Override | |
public String getCreateImageId() { | |
return icon; | |
} | |
} |