blob: 677308b8ea0744cdadde8fba3656ec194c67527e [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.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;
}
}