/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.elementclass; import java.awt.Color; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.simantics.g2d.diagram.IDiagram; import org.simantics.g2d.diagram.handler.Topology; import org.simantics.g2d.diagram.handler.Topology.Terminal; import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.handler.Transform; import org.simantics.g2d.element.handler.impl.BranchPointTerminal; import org.simantics.g2d.element.handler.impl.DefaultTransform; import org.simantics.g2d.element.handler.impl.ObjectTerminal; import org.simantics.g2d.element.handler.impl.OutlinePick; import org.simantics.g2d.element.handler.impl.ParentImpl; import org.simantics.g2d.element.handler.impl.SimpleElementLayers; import org.simantics.g2d.element.handler.impl.StaticSymbolImageInitializer; import org.simantics.g2d.element.handler.impl.StaticSymbolImpl; import org.simantics.g2d.element.handler.impl.Terminals; import org.simantics.g2d.element.handler.impl.TextImpl; import org.simantics.g2d.elementclass.BranchPoint.Direction; import org.simantics.g2d.elementclass.ImageClass.ImageElementHandler; import org.simantics.g2d.image.Image; import org.simantics.g2d.image.impl.ShapeImage; import org.simantics.g2d.utils.geom.DirectionSet; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.nodes.BranchPointNode; import org.simantics.utils.datastructures.hints.IHintContext.Key; import org.simantics.utils.datastructures.hints.IHintContext.KeyOf; /** * @author Tuukka Lehtonen */ public class BranchPointClass { private static final Key KEY_DIRECTION = new KeyOf(BranchPoint.Direction.class, "BRANCH_POINT_DIRECTION"); private static final BranchPoint BRANCH_POINT = new BranchPoint() { private static final long serialVersionUID = 8529882246314074853L; @Override public Direction getDirectionPreference(IElement e, Direction defaultValue) { Direction d = e.getHint(KEY_DIRECTION); return d != null ? d : defaultValue; } @Override public void setDirectionPreference(IElement e, Direction value) { if (value == null) e.removeHint(KEY_DIRECTION); else e.setHint(KEY_DIRECTION, value); } }; public static final Image DEFAULT_IMAGE = new ShapeImage(BranchPointNode.SHAPE, Color.BLACK, null, Image.VOLATILE_VECTOR); public static final Image DEFAULT_IMAGE2 = new ShapeImage(BranchPointNode.SHAPE2, Color.LIGHT_GRAY, null, Image.VOLATILE_VECTOR); private static final ObjectTerminal TERMINAL = BranchPointTerminal.existingTerminal(new AffineTransform(), DirectionSet.ANY, DEFAULT_IMAGE.getOutline()); private static final Terminals TERMINALS = new Terminals( Collections.singletonList(TERMINAL) ) { private static final long serialVersionUID = -6094665667025529239L; private final Collection connections = new ArrayList(); @Override public Shape getTerminalShape(IElement e, Terminal t) { IDiagram d = ElementUtils.peekDiagram(e); if (d == null) return null; Topology topology = d.getDiagramClass().getAtMostOneItemOfClass(Topology.class); // NOTE: this is thread-safe because painting is single-threaded connections.clear(); topology.getConnections(e, TERMINAL, connections); int degree = connections.size(); connections.clear(); if (degree > 2) { return BranchPointNode.SHAPE; } else { //return null; return BranchPointNode.SHAPE2; } } }; private static final ImageElementHandler DEFAULT_IMAGE_ELEMENT_HANDLER = new ImageElementHandler() { private static final long serialVersionUID = 68445770951872084L; @Override public void init(final IElement e, final G2DParentNode parent) { BranchPointNode node = (BranchPointNode)e.getHint(KEY_SG_NODE); if (node == null) { node = parent.addNode("bp_" + e.hashCode(), BranchPointNode.class); e.setHint(KEY_SG_NODE, node); } Transform transform = e.getElementClass().getSingleItem(Transform.class); AffineTransform at = transform.getTransform(e); if (at != null) node.setTransform((AffineTransform) at.clone()); node.setDegree( getDegree(e) ); node.setDirection( getDirection(e) ); } private byte getDirection(IElement e) { return (byte) ElementUtils.getHintOrDefault(e, KEY_DIRECTION, Direction.Any).ordinal(); } private final Collection connections = new ArrayList(); private int getDegree(IElement e) { IDiagram d = ElementUtils.peekDiagram(e); if (d == null) return 0; Topology t = d.getDiagramClass().getAtMostOneItemOfClass(Topology.class); // NOTE: this is thread-safe because painting is single-threaded connections.clear(); t.getConnections(e, TERMINAL, connections); int degree = connections.size(); connections.clear(); return degree; } @Override public void cleanup(IElement e) { e.removeHint(KEY_SG_NODE); } }; public static final ElementClass CLASS = ElementClass.compile( TextImpl.INSTANCE, ParentImpl.INSTANCE, DefaultTransform.INSTANCE, DEFAULT_IMAGE_ELEMENT_HANDLER, OutlinePick.INSTANCE, StaticSymbolImageInitializer.INSTANCE, new StaticSymbolImpl(DEFAULT_IMAGE), TERMINALS, SimpleElementLayers.INSTANCE, BRANCH_POINT ).setId(BranchPointClass.class.getSimpleName()); }