blob: 27055b5e5583d737b4819713664f331fee0da1d1 [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.algorithm.node;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.fmc.blockdiagram.editor.util.FMCUtil;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.mm.algorithms.Ellipse;
import org.eclipse.graphiti.mm.algorithms.GraphicsAlgorithm;
import org.eclipse.graphiti.mm.algorithms.MultiText;
import org.eclipse.graphiti.mm.pictograms.Anchor;
import org.eclipse.graphiti.mm.pictograms.BoxRelativeAnchor;
import org.eclipse.graphiti.mm.pictograms.CompositeConnection;
import org.eclipse.graphiti.mm.pictograms.Connection;
import org.eclipse.graphiti.mm.pictograms.ConnectionDecorator;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.CurvedConnection;
import org.eclipse.graphiti.mm.pictograms.Diagram;
import org.eclipse.graphiti.mm.pictograms.Shape;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.graphiti.services.IGaService;
import org.eclipse.graphiti.services.IPeService;
/**
* This abstract class implements methods for nodes with anchors and
* multiplicity property. The node can be named and may contain nested nodes.
*
* @author Benjamin Schmeling
* @author Heiko Witteborg
*
*/
public abstract class AbstractNode implements AnchoredNode, MultipleNode,
NamedNode, ResizableNode, ContainerNode {
protected IGaService ga = Graphiti.getGaService();
protected IPeService pe = Graphiti.getPeService();
protected int textMargin = DEFAULT_MARGIN;
// ----------------------------------------
// ----------- Anchored Node --------------
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#setBoxAnchorsVisible(org
* .eclipse.graphiti.mm.pictograms.Shape, boolean)
*/
public void setBoxAnchorsVisible(Shape shape, boolean visible) {
for (Anchor anchor : shape.getAnchors()) {
if (anchor instanceof BoxRelativeAnchor) {
anchor.getGraphicsAlgorithm().setFilled(visible);
anchor.getGraphicsAlgorithm().setLineVisible(visible);
}
}
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#isBoxAnchorsVisible(org
* .eclipse.graphiti.mm.pictograms.Shape)
*/
public boolean isBoxAnchorsVisible(Shape shape) {
for (Anchor anchor : shape.getAnchors()) {
if (anchor instanceof BoxRelativeAnchor) {
return anchor.getGraphicsAlgorithm().getLineVisible();
}
}
return false;
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#resizeBoxAnchorSet(org.
* eclipse.graphiti.mm.pictograms.ContainerShape, int, int, int, int)
*/
public void resizeBoxAnchorSet(ContainerShape container, int x, int y,
int width, int height) {
createBoxAnchorSet(container);
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#createBoxAnchorSet(org.
* eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public void createBoxAnchorSet(Shape shape) {
boolean isAnchorsVisible = isBoxAnchorsVisible(shape);
FMCUtil.removeObsoleteAnchors(shape);
addBoxAnchorSet(shape);
this.setBoxAnchorsVisible(shape, isAnchorsVisible);
// removeInnerUnusedAnchors(container);
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#removeUnusedBoxAnchors(
* org.eclipse.graphiti.mm.pictograms.Shape)
*/
public void removeUnusedBoxAnchors(Shape shape) {
FMCUtil.removeObsoleteAnchors(shape);
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.AnchoredNode#hasUnusedAnchors(org.eclipse
* .graphiti.mm.pictograms.Shape)
*/
public boolean hasUnusedAnchors(Shape shape) {
for (Anchor anchor : new HashSet<Anchor>(shape.getAnchors())) {
if (anchor instanceof BoxRelativeAnchor) {
if (anchor.getIncomingConnections().isEmpty()
&& anchor.getOutgoingConnections().isEmpty()) {
return true;
}
}
}
return false;
}
protected abstract void addBoxAnchorSet(Shape container);
public BoxRelativeAnchor createBoxAnchor(Shape shape, double rw, double rh,
int w, int h) {
BoxRelativeAnchor boxRelativeAnchor = pe.createBoxRelativeAnchor(shape);
// boxRelativeAnchor.setActive(true);
boxRelativeAnchor.setRelativeWidth(rw);
boxRelativeAnchor.setRelativeHeight(rh);
boxRelativeAnchor.setReferencedGraphicsAlgorithm(shape
.getGraphicsAlgorithm());
final Ellipse ellipse = ga.createEllipse(boxRelativeAnchor);
ellipse.setBackground(ga.manageColor(
pe.getDiagramForPictogramElement(shape), 195, 195, 240));
ellipse.setTransparency(0.3);
ellipse.setLineVisible(false);
ellipse.setFilled(false);
ga.setLocationAndSize(ellipse, 0, 0, w, h);
return boxRelativeAnchor;
}
// ----------------------------------------
// ----------- Multiple Node --------------
@Override
/*
* (non-Javadoc)
*
* @see org.eclipse.fmc.blockdiagram.editor.graphicsalgorithms.MultipleBox#
* setMultipleInstances(org.eclipse.graphiti.mm.pictograms.ContainerShape,
* org.eclipse.graphiti.features.IFeatureProvider, boolean)
*/
public void setMultipleInstances(ContainerShape container,
IFeatureProvider provider, boolean multipleInstances) {
if (multipleInstances) {
GraphicsAlgorithm mainShapeGa = container.getGraphicsAlgorithm()
.getGraphicsAlgorithmChildren().get(0);
// Resize main shape
this.resize(mainShapeGa, mainShapeGa.getX() + MULTI_INSTANCE_GAP,
mainShapeGa.getY(), mainShapeGa.getWidth()
- MULTI_INSTANCE_GAP, mainShapeGa.getHeight()
- MULTI_INSTANCE_GAP);
// Create background shape
Diagram diagram = Graphiti.getPeService()
.getDiagramForPictogramElement(container);
GraphicsAlgorithm bgShapeGa = createGraphics(diagram,
container.getGraphicsAlgorithm(), 0, MULTI_INSTANCE_GAP,
mainShapeGa.getWidth(), mainShapeGa.getHeight());
bgShapeGa.setBackground(mainShapeGa.getBackground());
bgShapeGa.setForeground(mainShapeGa.getForeground());
bgShapeGa.setTransparency(mainShapeGa.getTransparency());
bgShapeGa.setStyle(mainShapeGa.getStyle());
// Synchronize polygons (e.g. rotation, flip)
synchronizeMultiInstanceChildren(container);
// Adapt first level container (relative anchors + invisible shape)
createBoxAnchorSet(container);
synchronizeFirstLevelShape(container);
// Adapt position of text field
relocateText(mainShapeGa);
} else {
GraphicsAlgorithm backgroundGa = getMultiInstanceChild(container,
false);
GraphicsAlgorithm foregroundGa = getMultiInstanceChild(container,
true);
// Remove background shape
container.getGraphicsAlgorithm().getGraphicsAlgorithmChildren()
.remove(backgroundGa);
// Resize main shape
this.resize(foregroundGa, foregroundGa.getX() - MULTI_INSTANCE_GAP,
foregroundGa.getY(), foregroundGa.getWidth()
+ MULTI_INSTANCE_GAP, foregroundGa.getHeight()
+ MULTI_INSTANCE_GAP);
// Adapt position of text field
relocateText(foregroundGa);
// Adapt first level container (relative anchors + invisible shape)
createBoxAnchorSet(container);
synchronizeFirstLevelShape(container);
}
}
/**
* Synchronize invisible shape of the first level container (do nothing by
* default).
*
* @param firstLevelContainer
* the ContainerShape of the node.
*/
protected void synchronizeFirstLevelShape(ContainerShape firstLevelContainer) {
// synchronize invisible shape of the first level container (do nothing
// by default)
}
@Override
/*
* (non-Javadoc)
*
* @see org.eclipse.fmc.blockdiagram.editor.node.MultipleNode#
* synchronizeMultiInstanceChildren
* (org.eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public void synchronizeMultiInstanceChildren(
ContainerShape firstLevelContainer) {
// synchronize foreground and background ga (do nothing by default)
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.MultipleNode#getMultiInstanceChild(org
* .eclipse.graphiti.mm.pictograms.ContainerShape, boolean)
*/
public GraphicsAlgorithm getMultiInstanceChild(ContainerShape container,
boolean main) {
GraphicsAlgorithm invisibleGa = container.getGraphicsAlgorithm();
if (invisibleGa.getGraphicsAlgorithmChildren().size() > 1) {
return invisibleGa.getGraphicsAlgorithmChildren().get(main ? 0 : 1);
}
return null;
}
@Override
/*
* (non-Javadoc)
*
* @see org.eclipse.fmc.blockdiagram.editor.graphicsalgorithms.MultipleBox#
* isMultipleInstances(org.eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public boolean isMultipleInstances(ContainerShape container) {
return getMultiInstanceChild(container, false) != null;
}
// ----------------------------------------
// ----------- Container Node -------------
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#getContainerShape(org.
* eclipse.graphiti.mm.algorithms.GraphicsAlgorithm)
*/
public ContainerShape getContainerShape(GraphicsAlgorithm ga) {
if (ga.getPictogramElement() != null)
return (ContainerShape) ga.getPictogramElement();
return this.getContainerShape(ga.getParentGraphicsAlgorithm());
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#isEmpty(org.eclipse.graphiti
* .mm.pictograms.ContainerShape)
*/
public boolean isEmpty(ContainerShape cs) {
return this.getContainedShapes(cs).isEmpty();
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#isHiding(org.eclipse.graphiti
* .mm.pictograms.ContainerShape)
*/
public boolean isHiding(ContainerShape cs) {
for (Shape child : this.getContainedShapes(cs)) {
if (child.isVisible())
return false;
}
return true;
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#getContainedShapes(org
* .eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public EList<Shape> getContainedShapes(ContainerShape cs) {
EList<Shape> results = new BasicEList<Shape>();
for (Shape shape : cs.getChildren()) {
if (!(shape.getGraphicsAlgorithm() instanceof MultiText))
results.add(shape);
}
return results;
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#hideContainedShapes(org
* .eclipse.graphiti.mm.pictograms.ContainerShape, boolean)
*/
public void hideContainedShapes(ContainerShape cs, boolean hideChildren) {
for (Shape child : this.getContainedShapes(cs)) {
child.setVisible(!hideChildren);
this.hideContainedConnections(child, hideChildren);
}
// Resize node
// final ContainerShape container = cs;
// final GraphicsAlgorithm containerGa =
// container.getGraphicsAlgorithm();
// final int adaptedWidth = this.getContainedWidth(cs);
// final int adaptedHeight = this.getContainedHeight(cs);
// final IFeatureProvider fp =
// Util.getActiveEditor().getDiagramTypeProvider().getFeatureProvider();
// final TransactionalEditingDomain editingDomain =
// this.getEditingDomain();
//
// editingDomain.getCommandStack().execute(
// new RecordingCommand(editingDomain) {
// @Override
// protected void doExecute() {
// if(isWriteTransaction(editingDomain)){
// ResizeShapeContext ctx = new ResizeShapeContext(container);
// ctx.setX(containerGa.getX());
// ctx.setY(containerGa.getY());
// ctx.setWidth(adaptedWidth);
// ctx.setHeight(adaptedHeight);
// IResizeShapeFeature resizeShapeFeature =
// fp.getResizeShapeFeature(ctx);
// if(resizeShapeFeature.canExecute(ctx))
// resizeShapeFeature.execute(ctx);
// }
// }
// }
// );
}
private void hideContainedConnections(Shape s, boolean hideChildren) {
for (Anchor anchor : s.getAnchors()) {
List<Connection> connections = new ArrayList<Connection>();
connections.addAll(anchor.getIncomingConnections());
connections.addAll(anchor.getOutgoingConnections());
for (Connection con : connections) {
// unhide connection only if both start and end shape is visible
if (hideChildren
|| (con.getStart().getParent().isVisible() && con
.getEnd().getParent().isVisible())) {
con.setVisible(!hideChildren);
for (ConnectionDecorator conDecorator : con
.getConnectionDecorators()) {
conDecorator.setVisible(!hideChildren);
}
if (con instanceof CompositeConnection) {
CompositeConnection cc = (CompositeConnection) con;
con.setVisible(!hideChildren);
for (CurvedConnection conChild : cc.getChildren()) {
// TODO setVisible has no effect for composite
// connections - why? (workaround via transparency)
conChild.setVisible(!hideChildren);
conChild.getGraphicsAlgorithm().setTransparency(
hideChildren ? 1.0 : 0.0);
for (ConnectionDecorator conChildDecorator : conChild
.getConnectionDecorators()) {
conChildDecorator.setVisible(!hideChildren);
conChildDecorator.getGraphicsAlgorithm()
.setTransparency(
hideChildren ? 1.0 : 0.0);
}
}
}
}
}
}
// Hide connections of children, unhide connections only if the child
// element is visible
if (s instanceof ContainerShape) {
for (Shape childShape : ((ContainerShape) s).getChildren()) {
if (hideChildren || childShape.isVisible())
this.hideContainedConnections(childShape, hideChildren);
}
}
}
// private boolean isWriteTransaction(TransactionalEditingDomain domain){
// if(domain instanceof TransactionalEditingDomainImpl)
// return !((TransactionalEditingDomainImpl)
// domain).getActiveTransaction().isReadOnly();
// else
// return true;
// }
//
// private TransactionalEditingDomain getEditingDomain(){
// IWorkbenchPart activePart = PlatformUI.getWorkbench()
// .getActiveWorkbenchWindow().getActivePage().getActivePart();
//
// IEditingDomainProvider provider = (IEditingDomainProvider) activePart
// .getAdapter(IEditingDomainProvider.class);
// assert provider.getEditingDomain() instanceof TransactionalEditingDomain;
// return (TransactionalEditingDomain) provider.getEditingDomain();
// }
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#getContainedWidth(org.
* eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public int getContainedWidth(ContainerShape cs) {
int result = 0;
for (Shape child : this.getContainedShapes(cs)) {
if (child.isVisible())
result = Math.max(result, child.getGraphicsAlgorithm().getX()
+ child.getGraphicsAlgorithm().getWidth());
}
if (result == 0)
return this.getDefaultWidth();
return result + CONTAINER_MARGIN;
}
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.ContainerNode#getContainedHeight(org
* .eclipse.graphiti.mm.pictograms.ContainerShape)
*/
public int getContainedHeight(ContainerShape cs) {
int result = 0;
for (Shape child : this.getContainedShapes(cs)) {
if (child.isVisible())
result = Math.max(result, child.getGraphicsAlgorithm().getY()
+ child.getGraphicsAlgorithm().getHeight());
}
if (result == 0)
return this.getDefaultHeight();
return result + CONTAINER_MARGIN;
}
// ----------------------------------------
// ----------- Named Node -----------------
@Override
/*
* (non-Javadoc)
*
* @see
* org.eclipse.fmc.blockdiagram.editor.node.NamedNode#getText(org.eclipse.graphiti
* .mm.algorithms.GraphicsAlgorithm)
*/
public MultiText getText(GraphicsAlgorithm graphicsAlgorithm) {
ContainerShape container = this.getContainerShape(graphicsAlgorithm);
for (Shape child : container.getChildren()) {
if (child.getGraphicsAlgorithm() instanceof MultiText) {
return (MultiText) child.getGraphicsAlgorithm();
}
}
return null;
}
@Override
/*
* (non-Javadoc)
*
* @see org.eclipse.fmc.blockdiagram.editor.node.NamedNode#setTextMargin(int)
*/
public void setTextMargin(int margin) {
this.textMargin = margin;
}
}