X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scenegraph%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fg2d%2Fnodes%2FLinkNode.java;h=aa570d6aa21144d3ea4dfd6eb9f2dd7d255de93e;hb=ff5dddc885c9b3e6e973cfa3eebe9c3d1013c304;hp=3527fec03fad5cf8f2f048655f605fe56e97fc9e;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/LinkNode.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/LinkNode.java index 3527fec03..aa570d6aa 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/LinkNode.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/LinkNode.java @@ -1,179 +1,184 @@ -/******************************************************************************* - * 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.scenegraph.g2d.nodes; - -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - -import org.simantics.scenegraph.ILookupService; -import org.simantics.scenegraph.INode; -import org.simantics.scenegraph.g2d.G2DParentNode; -import org.simantics.scenegraph.g2d.IG2DNode; -import org.simantics.scenegraph.utils.NodeUtil; - -/** - * A node that only contains a String ID to link to another node in the scene - * graph through {@link ILookupService}. In {@link #render(Graphics2D)}, - * LinkNode will try to lookup the node identified by the ID and - * delegate the important method invocations to it. - * - *

- * CAUTION: this node must be used with care! It can be used to - * generate cyclic scene graphs which may cause rendering to crash due to - * infinite recursion and in any case rendering will not work as intended. E.g. - * a scene graph could have a {@link NavigationNode} under its root node and - * under which a LinkNode could link back to the navigation node, - * which would cause everything to be rendered twice and with double - * transformations. As a safety measure against cyclic cases, this node contains - * state that prevents it from being invoked recursively. - * - *

- * CAVEAT: Nodes with internal state that is updated during rendering. - * Such nodes should not be used with {@link LinkNode}. - * - * @author Tuukka Lehtonen - * - * @see ILookupService - */ -public class LinkNode extends StateMaskNode { - - private static final long serialVersionUID = -7465071303188585400L; - - /** - * The ID of delegate node. - */ - protected String delegateId; - - /** - * true to only process the children of the delegate node and - * not the node itself. false for normal behavior which is the - * default. - */ - protected boolean ignoreDelegate = false; - - /** - * true to make this node responsible for removing the lookup - * id mapping after this node is disposed of. The default value is - * false. - */ - protected boolean lookupIdOwner = false; - - @SyncField("delegateId") - public void setDelegateId(String delegateId) { - this.delegateId = delegateId; - } - - @SyncField({"delegateId", "lookupIdOwner"}) - public void setDelegateId(String delegateId, boolean owner) { - this.delegateId = delegateId; - this.lookupIdOwner = owner; - } - - @SyncField("ignoreDelegate") - public void setIgnoreDelegate(boolean ignore) { - this.ignoreDelegate = ignore; - } - - @SyncField("lookupIdOwner") - public void setLookupIdOwner(boolean idOwner) { - this.lookupIdOwner = idOwner; - } - - @Override - public void cleanup() { - if (lookupIdOwner) - removeDelegateMapping(); - super.cleanup(); - } - - @Override - public void render(Graphics2D g2d) { - // Safety against cyclic cases. - if (hasFlags(IN_RENDER)) - return; - - IG2DNode n = getDelegate2D(); - if (n == null) - return; - if (ignoreDelegate && !(n instanceof G2DParentNode)) - return; - - setFlags(IN_RENDER); - AffineTransform oldTransform = null; - if (transform != null && !transform.isIdentity()) { - g2d.transform(transform); - oldTransform = g2d.getTransform(); - } - try { - if (!ignoreDelegate) { - n.render(g2d); - } else { - G2DParentNode parent = (G2DParentNode) n; - for (IG2DNode child : parent.getSortedNodes()) - child.render(g2d); - } - } finally { - if (oldTransform != null) - g2d.setTransform(oldTransform); - clearFlags(IN_RENDER); - } - } - - @Override - public Rectangle2D getBoundsInLocal() { - // Safety against cyclic cases. - if (hasFlags(IN_GET_BOUNDS)) - return new Rectangle2D.Double(); - - IG2DNode n = getDelegate2D(); - if (n == null) - return new Rectangle2D.Double(); - - setFlags(IN_GET_BOUNDS); - try { - Rectangle2D bounds = n.getBoundsInLocal(); - if (transform != null && !transform.isIdentity()) - bounds = transform.createTransformedShape(bounds).getBounds2D(); - return bounds; - } finally { - clearFlags(IN_GET_BOUNDS); - } - } - - protected IG2DNode getDelegate2D() { - INode node = NodeUtil.lookup(this, delegateId); - if (node instanceof IG2DNode) { - return (IG2DNode) node; - } - return null; - } - - public INode getDelegate() { - INode node = NodeUtil.lookup(this, delegateId); - if (node instanceof IG2DNode) { - return (IG2DNode) node; - } - return null; - } - - protected void removeDelegateMapping() { - ILookupService lookup = NodeUtil.getLookupService(this); - lookup.unmap(delegateId); - } - - @Override - public String toString() { - return super.toString() + "[delegateId=" + delegateId + "]"; - } - +/******************************************************************************* + * 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.scenegraph.g2d.nodes; + +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.simantics.scenegraph.ILookupService; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.G2DParentNode; +import org.simantics.scenegraph.g2d.IG2DNode; +import org.simantics.scenegraph.utils.NodeUtil; + +/** + * A node that only contains a String ID to link to another node in the scene + * graph through {@link ILookupService}. In {@link #render(Graphics2D)}, + * LinkNode will try to lookup the node identified by the ID and + * delegate the important method invocations to it. + * + *

+ * CAUTION: this node must be used with care! It can be used to + * generate cyclic scene graphs which may cause rendering to crash due to + * infinite recursion and in any case rendering will not work as intended. E.g. + * a scene graph could have a {@link NavigationNode} under its root node and + * under which a LinkNode could link back to the navigation node, + * which would cause everything to be rendered twice and with double + * transformations. As a safety measure against cyclic cases, this node contains + * state that prevents it from being invoked recursively. + * + *

+ * CAVEAT: Nodes with internal state that is updated during rendering. + * Such nodes should not be used with {@link LinkNode}. + * + * @author Tuukka Lehtonen + * + * @see ILookupService + */ +public class LinkNode extends StateMaskNode { + + private static final long serialVersionUID = -7465071303188585400L; + + /** + * The ID of delegate node. + */ + protected String delegateId; + + /** + * true to only process the children of the delegate node and + * not the node itself. false for normal behavior which is the + * default. + */ + protected boolean ignoreDelegate = false; + + /** + * true to make this node responsible for removing the lookup + * id mapping after this node is disposed of. The default value is + * false. + */ + protected boolean lookupIdOwner = false; + + @SyncField("delegateId") + public void setDelegateId(String delegateId) { + this.delegateId = delegateId; + } + + @SyncField({"delegateId", "lookupIdOwner"}) + public void setDelegateId(String delegateId, boolean owner) { + this.delegateId = delegateId; + this.lookupIdOwner = owner; + } + + @SyncField("ignoreDelegate") + public void setIgnoreDelegate(boolean ignore) { + this.ignoreDelegate = ignore; + } + + @SyncField("lookupIdOwner") + public void setLookupIdOwner(boolean idOwner) { + this.lookupIdOwner = idOwner; + } + + @Override + public void cleanup() { + if (lookupIdOwner) + removeDelegateMapping(); + super.cleanup(); + } + + @Override + public void render(Graphics2D g2d) { + // Safety against cyclic cases. + if (hasFlags(IN_RENDER)) + return; + + IG2DNode n = getDelegate2D(); + if (n == null) + return; + if (ignoreDelegate && !(n instanceof G2DParentNode)) + return; + + setFlags(IN_RENDER); + AffineTransform oldTransform = null; + if (transform != null && !transform.isIdentity()) { + g2d.transform(transform); + oldTransform = g2d.getTransform(); + } + try { + if (!ignoreDelegate) { + n.render(g2d); + } else { + G2DParentNode parent = (G2DParentNode) n; + for (IG2DNode child : parent.getSortedNodes()) + child.render(g2d); + } + } finally { + if (oldTransform != null) + g2d.setTransform(oldTransform); + clearFlags(IN_RENDER); + } + } + + @Override + public Rectangle2D getBoundsInLocal() { + return getBoundsInLocal(false); + } + + @Override + public Rectangle2D getBoundsInLocal(boolean ignoreNulls) { + // Safety against cyclic cases. + if (hasFlags(IN_GET_BOUNDS)) + return new Rectangle2D.Double(); + + IG2DNode n = getDelegate2D(); + if (n == null) + return new Rectangle2D.Double(); + + setFlags(IN_GET_BOUNDS); + try { + Rectangle2D bounds = n.getBoundsInLocal(ignoreNulls); + if (transform != null && !transform.isIdentity()) + bounds = transform.createTransformedShape(bounds).getBounds2D(); + return bounds; + } finally { + clearFlags(IN_GET_BOUNDS); + } + } + + protected IG2DNode getDelegate2D() { + INode node = NodeUtil.lookup(this, delegateId); + if (node instanceof IG2DNode) { + return (IG2DNode) node; + } + return null; + } + + public INode getDelegate() { + INode node = NodeUtil.lookup(this, delegateId); + if (node instanceof IG2DNode) { + return (IG2DNode) node; + } + return null; + } + + protected void removeDelegateMapping() { + ILookupService lookup = NodeUtil.getLookupService(this); + lookup.unmap(delegateId); + } + + @Override + public String toString() { + return super.toString() + "[delegateId=" + delegateId + "]"; + } + } \ No newline at end of file