/******************************************************************************* * 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.diagram.adapter; import java.awt.Shape; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.EnumSet; import java.util.List; import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.ElementUtils; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.SceneGraphNodeKey; import org.simantics.g2d.element.handler.SceneGraph; import org.simantics.g2d.image.Image; import org.simantics.scenegraph.INode; import org.simantics.scenegraph.Node; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.nodes.SingleElementNode; import org.simantics.utils.datastructures.hints.IHintContext.Key; /** * Element Composition -> Image * * @author Toni Kalajainen */ public class CompositeImage implements Image { Collection elements; private Shape shape; private Rectangle2D bounds; //IHintContext parentHints; static EnumSet feats = VOLATILE_VECTOR; public static final Key KEY_SG_NODE = new SceneGraphNodeKey(Node.class, "COMPOSITE_IMAGE_SG_NODE"); public CompositeImage(Collection elements) { //this.nodeIdentifier = nodeIdentifier; this.elements = elements; // ITask task = ThreadLogger.getInstance().begin("getElementShapesOnDiagram"); // getElementShapesOnDiagram is ridiculously slow with some input data.. // With Balas it took almost 2sec to calculate one Area.add() for the last terminal element. //shape = ElementUtils.getElementShapesOnDiagram(elements); // shape = ElementUtils.getElementBoundsOnDiagram(elements); // task.finish(); // bounds = shape.getBounds2D(); } @Override public Rectangle2D getBounds() { if(bounds == null) { Shape shape = getShape(); // Shape may be null. if (shape == null) return new Rectangle2D.Double(); bounds = shape.getBounds2D(); } return bounds; } @Override public EnumSet getFeatures() { return feats; } private final Shape getShape() { if(shape == null) { shape = ElementUtils.getElementBoundsOnDiagram(elements); } return shape; } @Override public Shape getOutline() { return getShape(); } public Collection getElements() { return elements; } @Override public void addImageListener(ImageListener listener) { } @Override public void removeImageListener(ImageListener listener) { } // public void setParentHints(IHintContext hints) { // this.parentHints = hints; // } // Rendering is single-threaded, this is used while rendering. //Rectangle2D tempBounds = new Rectangle2D.Double(0, 0, 0, 0); @Override public Node init(G2DParentNode parent) { if (elements.size() < 2) { // Optimization for 0..1 element composites for (IElement e : elements) { ElementClass ec = e.getElementClass(); G2DParentNode node = getOrCreateParentNode(parent); List nodeHandlers = ec.getItemsByClass(SceneGraph.class); for (SceneGraph n : nodeHandlers) { // n.init(e, parent); n.init(e, node); } return node; // Valid node must be returned because transform is set afterwards } } // For N element composites G2DParentNode node = getOrCreateParentNode(parent); // Rectangle2D bounds = tempBounds; int zIndex = 0; for (IElement e : elements) { ElementClass ec = e.getElementClass(); // InternalSize size = ec.getSingleItem(InternalSize.class); // size.getBounds(e, bounds); // Transform transform = e.getElementClass().getSingleItem(Transform.class); // AffineTransform at2 = transform.getTransform(e); // if (at2 == null) // continue; SingleElementNode holder = node.getOrCreateNode(ElementUtils.generateNodeId(e), SingleElementNode.class); //SingleElementNode holder = parent.getOrCreateNode(ElementUtils.generateNodeId(e), SingleElementNode.class); holder.setZIndex(++zIndex); holder.setKey(e.getHint(ElementHints.KEY_OBJECT)); holder.setTypeClass(e.getHint(ElementHints.KEY_TYPE_CLASS)); List nodeHandlers = ec.getItemsByClass(SceneGraph.class); for(SceneGraph n : nodeHandlers) { n.init(e, holder); } } return node; // Valid node must be returned because transform is set afterwards } private G2DParentNode getOrCreateParentNode(G2DParentNode parent) { G2DParentNode node = (G2DParentNode)parent.getNode("composite_image_"+this.hashCode()); if (node == null) { for (INode n : parent.getNodes()) { // #7663: prevent the code from removing other element graphics from directly under another element if (!(n instanceof SingleElementNode)) n.remove(); } // Removed this grouping node as unnecessary, just use the given parent node node = parent.getOrCreateNode("composite_image_"+this.hashCode(), G2DParentNode.class); } return node; } }