/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* 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.
*/
package gov.redhawk.core.graphiti.ui.diagram.patterns;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.graphiti.datatypes.IDimension;
import org.eclipse.graphiti.features.IReason;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.ILayoutContext;
import org.eclipse.graphiti.features.context.IUpdateContext;
import org.eclipse.graphiti.features.impl.Reason;
import org.eclipse.graphiti.mm.algorithms.Rectangle;
import org.eclipse.graphiti.mm.algorithms.Text;
import org.eclipse.graphiti.mm.algorithms.styles.Orientation;
import org.eclipse.graphiti.mm.algorithms.styles.Point;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.FixPointAnchor;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.pattern.AbstractPattern;
import org.eclipse.graphiti.services.Graphiti;
import gov.redhawk.core.graphiti.ui.ext.RHContainerShape;
import gov.redhawk.core.graphiti.ui.util.DUtil;
import gov.redhawk.core.graphiti.ui.util.StyleUtil;
import gov.redhawk.core.graphiti.ui.util.UpdateUtil;
abstract class AbstractPortPattern< E extends EObject > extends AbstractPattern {
protected static final int PORT_SHAPE_HEIGHT = 15;
protected static final int PORT_SHAPE_WIDTH = AbstractPortPattern.PORT_SHAPE_HEIGHT;
protected static final int PORT_NAME_HORIZONTAL_PADDING = 5;
private Class<E> clazz;
protected AbstractPortPattern(Class<E> clazz) {
this.clazz = clazz;
}
@Override
public boolean isMainBusinessObjectApplicable(Object mainBusinessObject) {
return clazz.isInstance(mainBusinessObject);
}
@Override
protected boolean isPatternControlled(PictogramElement pictogramElement) {
return getPortContainerShapeId().equals(Graphiti.getPeService().getPropertyValue(pictogramElement, DUtil.SHAPE_TYPE));
}
@Override
protected boolean isPatternRoot(PictogramElement pictogramElement) {
return false;
}
@Override
public boolean update(IUpdateContext context) {
ContainerShape usesPortShape = (ContainerShape) context.getPictogramElement();
E port = getPortForPictogramElement(usesPortShape);
boolean updateStatus = UpdateUtil.update(getPortText(usesPortShape), getPortName(port));
Rectangle portRectangle = getPortRectangle(usesPortShape);
String styleId = getStyleId(port);
if (!styleId.equals(portRectangle.getStyle().getId())) {
StyleUtil.setStyle(portRectangle, styleId);
updateStatus = true;
}
return updateStatus;
}
@Override
public IReason updateNeeded(IUpdateContext context) {
ContainerShape usesPortShape = (ContainerShape) context.getPictogramElement();
E port = getPortForPictogramElement(usesPortShape);
if (UpdateUtil.updateNeeded(getPortText(usesPortShape), getPortName(port))) {
return Reason.createTrueReason("Uses port name needs update");
}
if (!StyleUtil.isStyleSet(getPortRectangle(usesPortShape), getStyleId(port))) {
return Reason.createTrueReason("Uses port style needs update");
}
return Reason.createFalseReason();
}
@Override
public boolean canAdd(IAddContext context) {
return isMainBusinessObjectApplicable(context.getNewObject());
}
@Override
public PictogramElement add(IAddContext context) {
ContainerShape parentShape = context.getTargetContainer();
E portStub = clazz.cast(context.getNewObject());
// Outer invisible container
ContainerShape portContainerShape = Graphiti.getCreateService().createContainerShape(parentShape, true);
Graphiti.getPeService().setPropertyValue(portContainerShape, DUtil.SHAPE_TYPE, getPortContainerShapeId());
Rectangle providesPortContainerShapeRectangle = Graphiti.getCreateService().createPlainRectangle(portContainerShape);
providesPortContainerShapeRectangle.setFilled(false);
providesPortContainerShapeRectangle.setLineVisible(false);
link(portContainerShape, portStub);
// Port rectangle; this is created as its own shape because Anchors do not support decorators (for things
// like highlighting)
ContainerShape portShape = Graphiti.getPeService().createContainerShape(portContainerShape, true);
Graphiti.getPeService().setPropertyValue(portShape, DUtil.SHAPE_TYPE, getPortRectangleShapeId());
Rectangle providesPortRectangle = Graphiti.getCreateService().createPlainRectangle(portShape);
StyleUtil.setStyle(providesPortRectangle, getStyleId(portStub));
Graphiti.getGaLayoutService().setSize(providesPortRectangle, AbstractPortPattern.PORT_SHAPE_WIDTH, AbstractPortPattern.PORT_SHAPE_HEIGHT);
link(portShape, portStub);
// Port anchor
Orientation orientation = getPortOrientation();
int anchorX;
if (Orientation.ALIGNMENT_LEFT.equals(orientation)) {
anchorX = 0;
} else {
anchorX = AbstractPortPattern.PORT_SHAPE_WIDTH;
}
FixPointAnchor fixPointAnchor = createPortAnchor(portShape, anchorX);
link(fixPointAnchor, portStub);
// Port text
Shape portTextShape = Graphiti.getPeService().createShape(portContainerShape, false);
Text portText = Graphiti.getCreateService().createPlainText(portTextShape, getPortName(portStub));
StyleUtil.setStyle(portText, StyleUtil.PORT_TEXT);
portText.setHorizontalAlignment(orientation);
// Based on orientation, set X position of text relative to port
int textX;
if (Orientation.ALIGNMENT_LEFT.equals(orientation)) {
textX = AbstractPortPattern.PORT_SHAPE_WIDTH + AbstractPortPattern.PORT_NAME_HORIZONTAL_PADDING;
} else {
textX = 0;
}
Graphiti.getGaLayoutService().setLocation(portText, textX, 0);
return portContainerShape;
}
@Override
public boolean layout(ILayoutContext context) {
ContainerShape portContainerShape = (ContainerShape) context.getPictogramElement();
// Resize the text
Text portText = getPortText(portContainerShape);
IDimension textSize = DUtil.calculateTextSize(portText);
// Graphiti appears to underestimate the width for some strings (e.g., those ending in "r"), so add a small
// amount of padding to ensure the entire letter is drawn
int textWidth = textSize.getWidth() + 2;
boolean layoutApplied = UpdateUtil.resizeIfNeeded(portText, textWidth, AbstractPortPattern.PORT_SHAPE_HEIGHT);
// Move port rectangle
int portX;
if (Orientation.ALIGNMENT_RIGHT.equals(getPortOrientation())) {
portX = portText.getWidth() + AbstractPortPattern.PORT_NAME_HORIZONTAL_PADDING;
} else {
portX = 0;
}
Rectangle portRectangle = getPortRectangle(portContainerShape);
if (UpdateUtil.moveIfNeeded(portRectangle, portX, 0)) {
layoutApplied = true;
}
// Resize invisible bounding rectangle
int portWidth = textWidth + AbstractPortPattern.PORT_NAME_HORIZONTAL_PADDING + AbstractPortPattern.PORT_SHAPE_WIDTH;
if (UpdateUtil.resizeIfNeeded(portContainerShape.getGraphicsAlgorithm(), portWidth, AbstractPortPattern.PORT_SHAPE_HEIGHT)) {
layoutApplied = true;
}
return layoutApplied;
}
protected E getPortForPictogramElement(PictogramElement pictogramElement) {
return clazz.cast(getBusinessObjectForPictogramElement(pictogramElement));
}
protected abstract String getPortContainerShapeId();
protected abstract String getPortRectangleShapeId();
protected abstract Orientation getPortOrientation();
protected abstract String getStyleId(E port);
protected abstract String getPortName(E port);
protected Text getPortText(ContainerShape portContainerShape) {
return (Text) portContainerShape.getChildren().get(1).getGraphicsAlgorithm();
}
protected Rectangle getPortRectangle(ContainerShape portContainerShape) {
return (Rectangle) portContainerShape.getChildren().get(0).getGraphicsAlgorithm();
}
/**
* Create an anchor overlay for a port, with the anchor point vertically centered at horizontal position x.
* The returned anchor has an invisible rectangle for its graphics algorithm.
*/
protected FixPointAnchor createPortAnchor(ContainerShape portShape, int x) {
FixPointAnchor fixPointAnchor = DUtil.createOverlayAnchor(portShape, x);
Rectangle fixPointAnchorRectangle = Graphiti.getCreateService().createPlainRectangle(fixPointAnchor);
Graphiti.getPeService().setPropertyValue(fixPointAnchorRectangle, DUtil.GA_TYPE, RHContainerShape.GA_FIX_POINT_ANCHOR_RECTANGLE);
fixPointAnchorRectangle.setFilled(false);
fixPointAnchorRectangle.setLineVisible(false);
layoutAnchor(portShape);
return fixPointAnchor;
}
private void layoutAnchor(Shape parentShape) {
// Layout and resize anchor
IDimension parentSize = Graphiti.getGaLayoutService().calculateSize(parentShape.getGraphicsAlgorithm());
FixPointAnchor portAnchor = (FixPointAnchor) parentShape.getAnchors().get(0);
Point anchorLocation = portAnchor.getLocation();
anchorLocation.setY(parentSize.getHeight() / 2);
Graphiti.getGaLayoutService().setLocationAndSize(portAnchor.getGraphicsAlgorithm(), -anchorLocation.getX(), -anchorLocation.getY(),
parentSize.getWidth(), parentSize.getHeight());
}
}