diff --git a/core/src/main/java/edu/umd/cs/piccolo/PNode.java b/core/src/main/java/edu/umd/cs/piccolo/PNode.java index 62a041e..7a1cd33 100644 --- a/core/src/main/java/edu/umd/cs/piccolo/PNode.java +++ b/core/src/main/java/edu/umd/cs/piccolo/PNode.java @@ -95,3902 +95,3672 @@ * @author Jesse Grosjean */ public class PNode implements Cloneable, Serializable, Printable { - /** - * The minimum difference in transparency required before the transparency - * is allowed to change. Done for efficiency reasons. I doubt very much that - * the human eye could tell the difference between 0.01 and 0.02 - * transparency. - */ - private static final float TRANSPARENCY_RESOLUTION = 0.01f; + /** + * The minimum difference in transparency required before the transparency + * is allowed to change. Done for efficiency reasons. I doubt very much that + * the human eye could tell the difference between 0.01 and 0.02 + * transparency. + */ + private static final float TRANSPARENCY_RESOLUTION = 0.01f; - /** - * Allows for future serialization code to understand versioned binary - * formats. - */ - private static final long serialVersionUID = 1L; + /** + * Allows for future serialization code to understand versioned binary + * formats. + */ + private static final long serialVersionUID = 1L; - /** - * The property name that identifies a change in this node's client - * propertie (see {@link #getClientProperty getClientProperty}). In an - * property change event the new value will be a reference to the map of - * client properties but old value will always be null. - */ - public static final String PROPERTY_CLIENT_PROPERTIES = "clientProperties"; + /** + * The property name that identifies a change in this node's client + * propertie (see {@link #getClientProperty getClientProperty}). In an + * property change event the new value will be a reference to the map of + * client properties but old value will always be null. + */ + public static final String PROPERTY_CLIENT_PROPERTIES = "clientProperties"; - /** - * The property code that identifies a change in this node's client - * propertie (see {@link #getClientProperty getClientProperty}). In an - * property change event the new value will be a reference to the map of - * client properties but old value will always be null. - */ - public static final int PROPERTY_CODE_CLIENT_PROPERTIES = 1 << 0; + /** + * The property code that identifies a change in this node's client + * propertie (see {@link #getClientProperty getClientProperty}). In an + * property change event the new value will be a reference to the map of + * client properties but old value will always be null. + */ + public static final int PROPERTY_CODE_CLIENT_PROPERTIES = 1 << 0; - /** - * The property name that identifies a change of this node's bounds (see - * {@link #getBounds getBounds}, {@link #getBoundsReference - * getBoundsReference}). In any property change event the new value will be - * a reference to this node's bounds, but old value will always be null. - */ - public static final String PROPERTY_BOUNDS = "bounds"; + /** + * The property name that identifies a change of this node's bounds (see + * {@link #getBounds getBounds}, {@link #getBoundsReference + * getBoundsReference}). In any property change event the new value will be + * a reference to this node's bounds, but old value will always be null. + */ + public static final String PROPERTY_BOUNDS = "bounds"; - /** - * The property code that identifies a change of this node's bounds (see - * {@link #getBounds getBounds}, {@link #getBoundsReference - * getBoundsReference}). In any property change event the new value will be - * a reference to this node's bounds, but old value will always be null. - */ - public static final int PROPERTY_CODE_BOUNDS = 1 << 1; + /** + * The property code that identifies a change of this node's bounds (see + * {@link #getBounds getBounds}, {@link #getBoundsReference + * getBoundsReference}). In any property change event the new value will be + * a reference to this node's bounds, but old value will always be null. + */ + public static final int PROPERTY_CODE_BOUNDS = 1 << 1; - /** - * The property name that identifies a change of this node's full bounds - * (see {@link #getFullBounds getFullBounds}, - * {@link #getFullBoundsReference getFullBoundsReference}). In any property - * change event the new value will be a reference to this node's full bounds - * cache, but old value will always be null. - */ - public static final String PROPERTY_FULL_BOUNDS = "fullBounds"; + /** + * The property name that identifies a change of this node's full bounds + * (see {@link #getFullBounds getFullBounds}, + * {@link #getFullBoundsReference getFullBoundsReference}). In any property + * change event the new value will be a reference to this node's full bounds + * cache, but old value will always be null. + */ + public static final String PROPERTY_FULL_BOUNDS = "fullBounds"; - /** - * The property code that identifies a change of this node's full bounds - * (see {@link #getFullBounds getFullBounds}, - * {@link #getFullBoundsReference getFullBoundsReference}). In any property - * change event the new value will be a reference to this node's full bounds - * cache, but old value will always be null. - */ - public static final int PROPERTY_CODE_FULL_BOUNDS = 1 << 2; + /** + * The property code that identifies a change of this node's full bounds + * (see {@link #getFullBounds getFullBounds}, + * {@link #getFullBoundsReference getFullBoundsReference}). In any property + * change event the new value will be a reference to this node's full bounds + * cache, but old value will always be null. + */ + public static final int PROPERTY_CODE_FULL_BOUNDS = 1 << 2; - /** - * The property name that identifies a change of this node's transform (see - * {@link #getTransform getTransform}, {@link #getTransformReference - * getTransformReference}). In any property change event the new value will - * be a reference to this node's transform, but old value will always be - * null. - */ - public static final String PROPERTY_TRANSFORM = "transform"; + /** + * The property name that identifies a change of this node's transform (see + * {@link #getTransform getTransform}, {@link #getTransformReference + * getTransformReference}). In any property change event the new value will + * be a reference to this node's transform, but old value will always be + * null. + */ + public static final String PROPERTY_TRANSFORM = "transform"; - /** - * The property code that identifies a change of this node's transform (see - * {@link #getTransform getTransform}, {@link #getTransformReference - * getTransformReference}). In any property change event the new value will - * be a reference to this node's transform, but old value will always be - * null. - */ - public static final int PROPERTY_CODE_TRANSFORM = 1 << 3; + /** + * The property code that identifies a change of this node's transform (see + * {@link #getTransform getTransform}, {@link #getTransformReference + * getTransformReference}). In any property change event the new value will + * be a reference to this node's transform, but old value will always be + * null. + */ + public static final int PROPERTY_CODE_TRANSFORM = 1 << 3; - /** - * The property name that identifies a change of this node's visibility (see - * {@link #getVisible getVisible}). Both old value and new value will be - * null in any property change event. - */ - public static final String PROPERTY_VISIBLE = "visible"; + /** + * The property name that identifies a change of this node's visibility (see + * {@link #getVisible getVisible}). Both old value and new value will be + * null in any property change event. + */ + public static final String PROPERTY_VISIBLE = "visible"; - /** - * The property code that identifies a change of this node's visibility (see - * {@link #getVisible getVisible}). Both old value and new value will be - * null in any property change event. - */ - public static final int PROPERTY_CODE_VISIBLE = 1 << 4; + /** + * The property code that identifies a change of this node's visibility (see + * {@link #getVisible getVisible}). Both old value and new value will be + * null in any property change event. + */ + public static final int PROPERTY_CODE_VISIBLE = 1 << 4; - /** - * The property name that identifies a change of this node's paint (see - * {@link #getPaint getPaint}). Both old value and new value will be set - * correctly in any property change event. - */ - public static final String PROPERTY_PAINT = "paint"; + /** + * The property name that identifies a change of this node's paint (see + * {@link #getPaint getPaint}). Both old value and new value will be set + * correctly in any property change event. + */ + public static final String PROPERTY_PAINT = "paint"; - /** - * The property code that identifies a change of this node's paint (see - * {@link #getPaint getPaint}). Both old value and new value will be set - * correctly in any property change event. - */ - public static final int PROPERTY_CODE_PAINT = 1 << 5; + /** + * The property code that identifies a change of this node's paint (see + * {@link #getPaint getPaint}). Both old value and new value will be set + * correctly in any property change event. + */ + public static final int PROPERTY_CODE_PAINT = 1 << 5; - /** - * The property name that identifies a change of this node's transparency - * (see {@link #getTransparency getTransparency}). Both old value and new - * value will be null in any property change event. - */ - public static final String PROPERTY_TRANSPARENCY = "transparency"; + /** + * The property name that identifies a change of this node's transparency + * (see {@link #getTransparency getTransparency}). Both old value and new + * value will be null in any property change event. + */ + public static final String PROPERTY_TRANSPARENCY = "transparency"; - /** - * The property code that identifies a change of this node's transparency - * (see {@link #getTransparency getTransparency}). Both old value and new - * value will be null in any property change event. - */ - public static final int PROPERTY_CODE_TRANSPARENCY = 1 << 6; + /** + * The property code that identifies a change of this node's transparency + * (see {@link #getTransparency getTransparency}). Both old value and new + * value will be null in any property change event. + */ + public static final int PROPERTY_CODE_TRANSPARENCY = 1 << 6; - /** - * The property name that identifies a change of this node's pickable status - * (see {@link #getPickable getPickable}). Both old value and new value will - * be null in any property change event. - */ - public static final String PROPERTY_PICKABLE = "pickable"; - /** - * The property code that identifies a change of this node's pickable status - * (see {@link #getPickable getPickable}). Both old value and new value will - * be null in any property change event. - */ - public static final int PROPERTY_CODE_PICKABLE = 1 << 7; + /** + * The property name that identifies a change of this node's pickable status + * (see {@link #getPickable getPickable}). Both old value and new value will + * be null in any property change event. + */ + public static final String PROPERTY_PICKABLE = "pickable"; + /** + * The property code that identifies a change of this node's pickable status + * (see {@link #getPickable getPickable}). Both old value and new value will + * be null in any property change event. + */ + public static final int PROPERTY_CODE_PICKABLE = 1 << 7; - /** - * The property name that identifies a change of this node's children - * pickable status (see {@link #getChildrenPickable getChildrenPickable}). - * Both old value and new value will be null in any property change event. - */ - public static final String PROPERTY_CHILDREN_PICKABLE = "childrenPickable"; + /** + * The property name that identifies a change of this node's children + * pickable status (see {@link #getChildrenPickable getChildrenPickable}). + * Both old value and new value will be null in any property change event. + */ + public static final String PROPERTY_CHILDREN_PICKABLE = "childrenPickable"; - /** - * The property code that identifies a change of this node's children - * pickable status (see {@link #getChildrenPickable getChildrenPickable}). - * Both old value and new value will be null in any property change event. - */ - public static final int PROPERTY_CODE_CHILDREN_PICKABLE = 1 << 8; + /** + * The property code that identifies a change of this node's children + * pickable status (see {@link #getChildrenPickable getChildrenPickable}). + * Both old value and new value will be null in any property change event. + */ + public static final int PROPERTY_CODE_CHILDREN_PICKABLE = 1 << 8; - /** - * The property name that identifies a change in the set of this node's - * direct children (see {@link #getChildrenReference getChildrenReference}, - * {@link #getChildrenIterator getChildrenIterator}). In any property change - * event the new value will be a reference to this node's children, but old - * value will always be null. - */ - public static final String PROPERTY_CHILDREN = "children"; + /** + * The property name that identifies a change in the set of this node's + * direct children (see {@link #getChildrenReference getChildrenReference}, + * {@link #getChildrenIterator getChildrenIterator}). In any property change + * event the new value will be a reference to this node's children, but old + * value will always be null. + */ + public static final String PROPERTY_CHILDREN = "children"; - /** - * The property code that identifies a change in the set of this node's - * direct children (see {@link #getChildrenReference getChildrenReference}, - * {@link #getChildrenIterator getChildrenIterator}). In any property change - * event the new value will be a reference to this node's children, but old - * value will always be null. - */ - public static final int PROPERTY_CODE_CHILDREN = 1 << 9; + /** + * The property code that identifies a change in the set of this node's + * direct children (see {@link #getChildrenReference getChildrenReference}, + * {@link #getChildrenIterator getChildrenIterator}). In any property change + * event the new value will be a reference to this node's children, but old + * value will always be null. + */ + public static final int PROPERTY_CODE_CHILDREN = 1 << 9; - /** - * The property name that identifies a change of this node's parent (see - * {@link #getParent getParent}). Both old value and new value will be set - * correctly in any property change event. - */ - public static final String PROPERTY_PARENT = "parent"; + /** + * The property name that identifies a change of this node's parent (see + * {@link #getParent getParent}). Both old value and new value will be set + * correctly in any property change event. + */ + public static final String PROPERTY_PARENT = "parent"; - /** - * The property code that identifies a change of this node's parent (see - * {@link #getParent getParent}). Both old value and new value will be set - * correctly in any property change event. - */ - public static final int PROPERTY_CODE_PARENT = 1 << 10; + /** + * The property code that identifies a change of this node's parent (see + * {@link #getParent getParent}). Both old value and new value will be set + * correctly in any property change event. + */ + public static final int PROPERTY_CODE_PARENT = 1 << 10; - /** Is an optimization for use during repaints. */ - private static final PBounds TEMP_REPAINT_BOUNDS = new PBounds(); + /** Is an optimization for use during repaints. */ + private static final PBounds TEMP_REPAINT_BOUNDS = new PBounds(); - /** The single scene graph delegate that receives low level node events. */ - public static PSceneGraphDelegate SCENE_GRAPH_DELEGATE = null; + /** The single scene graph delegate that receives low level node events. */ + public static PSceneGraphDelegate SCENE_GRAPH_DELEGATE = null; - /** Tracks the parent of this node, may be null. */ - private transient PNode parent; + /** Tracks the parent of this node, may be null. */ + private transient PNode parent; - /** Tracks all immediate child nodes. */ - private List children; + /** Tracks all immediate child nodes. */ + private List children; - /** Bounds of the PNode. */ - private final PBounds bounds; + /** Bounds of the PNode. */ + private final PBounds bounds; - /** Transform that applies to this node in relation to its parent. */ - private PAffineTransform transform; + /** Transform that applies to this node in relation to its parent. */ + private PAffineTransform transform; - /** The paint to use for the background of this node. */ - private Paint paint; + /** The paint to use for the background of this node. */ + private Paint paint; - /** - * How Opaque this node should be 1f = fully opaque, 0f = completely - * transparent. - */ - private float transparency; + /** + * How Opaque this node should be 1f = fully opaque, 0f = completely + * transparent. + */ + private float transparency; - /** A modifiable set of client properties. */ - private MutableAttributeSet clientProperties; + /** A modifiable set of client properties. */ + private MutableAttributeSet clientProperties; - /** - * An optimization that remembers the full bounds of a node rather than - * computing it every time. - */ - private PBounds fullBoundsCache; + /** + * An optimization that remembers the full bounds of a node rather than + * computing it every time. + */ + private PBounds fullBoundsCache; - /** - * Mask used when deciding whether to bubble up property change events to - * parents. - */ - private int propertyChangeParentMask = 0; + /** + * Mask used when deciding whether to bubble up property change events to + * parents. + */ + private int propertyChangeParentMask = 0; - /** Used to handle property change listeners. */ - private transient SwingPropertyChangeSupport changeSupport; + /** Used to handle property change listeners. */ + private transient SwingPropertyChangeSupport changeSupport; - /** List of event listeners. */ - private transient EventListenerList listenerList; + /** List of event listeners. */ + private transient EventListenerList listenerList; - /** Whether this node is pickable or not. */ - private boolean pickable; + /** Whether this node is pickable or not. */ + private boolean pickable; - /** - * Whether to stop processing pick at this node and not bother drilling down - * into children. - */ - private boolean childrenPickable; + /** + * Whether to stop processing pick at this node and not bother drilling down + * into children. + */ + private boolean childrenPickable; - /** Whether this node will be rendered. */ - private boolean visible; + /** Whether this node will be rendered. */ + private boolean visible; - private boolean childBoundsVolatile; + private boolean childBoundsVolatile; - /** Whether this node needs to be repainted. */ - private boolean paintInvalid; + /** Whether this node needs to be repainted. */ + private boolean paintInvalid; - /** Whether children need to be repainted. */ - private boolean childPaintInvalid; + /** Whether children need to be repainted. */ + private boolean childPaintInvalid; - /** Whether this node's bounds have changed, and so needs to be relaid out. */ - private boolean boundsChanged; + /** Whether this node's bounds have changed, and so needs to be relaid out. */ + private boolean boundsChanged; - /** Whether this node's full bounds need to be recomputed. */ - private boolean fullBoundsInvalid; + /** Whether this node's full bounds need to be recomputed. */ + private boolean fullBoundsInvalid; - /** Whether this node's child bounds need to be recomputed. */ - private boolean childBoundsInvalid; + /** Whether this node's child bounds need to be recomputed. */ + private boolean childBoundsInvalid; - private boolean occluded; + private boolean occluded; - /** Stores the name associated to this node. */ - private String name; + /** Stores the name associated to this node. */ + private String name; - /** - * toImage fill strategy that stretches the node be as large as possible - * while still retaining its aspect ratio. - * - * @since 1.3 - */ - public static final int FILL_STRATEGY_ASPECT_FIT = 1; + /** + * toImage fill strategy that stretches the node be as large as possible + * while still retaining its aspect ratio. + * + * @since 1.3 + */ + public static final int FILL_STRATEGY_ASPECT_FIT = 1; - /** - * toImage fill strategy that stretches the node be large enough to cover - * the image, and centers it. - * - * @since 1.3 - */ - public static final int FILL_STRATEGY_ASPECT_COVER = 2; + /** + * toImage fill strategy that stretches the node be large enough to cover + * the image, and centers it. + * + * @since 1.3 + */ + public static final int FILL_STRATEGY_ASPECT_COVER = 2; - /** - * toImage fill strategy that stretches the node to be exactly the - * dimensions of the image. Will result in distortion if the aspect ratios - * are different. - * - * @since 1.3 - */ - public static final int FILL_STRATEGY_EXACT_FIT = 4; + /** + * toImage fill strategy that stretches the node to be exactly the + * dimensions of the image. Will result in distortion if the aspect ratios + * are different. + * + * @since 1.3 + */ + public static final int FILL_STRATEGY_EXACT_FIT = 4; - /** - * Creates a new PNode with the given name. - * - * @since 1.3 - * @param newName - * name to assign to node - */ - public PNode(final String newName) { - this(); - setName(newName); - } + /** + * Creates a new PNode with the given name. + * + * @since 1.3 + * @param newName name to assign to node + */ + public PNode(final String newName) { + this(); + setName(newName); + } - /** - * Constructs a new PNode. - *

- * By default a node's paint is null, and bounds are empty. These values - * must be set for the node to show up on the screen once it's added to a - * scene graph. - */ - public PNode() { - bounds = new PBounds(); - fullBoundsCache = new PBounds(); - transparency = 1.0f; - pickable = true; - childrenPickable = true; - visible = true; - } + /** + * Constructs a new PNode. + *

+ * By default a node's paint is null, and bounds are empty. These values + * must be set for the node to show up on the screen once it's added to a + * scene graph. + */ + public PNode() { + bounds = new PBounds(); + fullBoundsCache = new PBounds(); + transparency = 1.0f; + pickable = true; + childrenPickable = true; + visible = true; + } - // **************************************************************** - // Animation - Methods to animate this node. - // - // Note that animation is implemented by activities (PActivity), - // so if you need more control over your animation look at the - // activities package. Each animate method creates an animation that - // will animate the node from its current state to the new state - // specified over the given duration. These methods will try to - // automatically schedule the new activity, but if the node does not - // descend from the root node when the method is called then the - // activity will not be scheduled and you must schedule it manually. - // **************************************************************** + // **************************************************************** + // Animation - Methods to animate this node. + // + // Note that animation is implemented by activities (PActivity), + // so if you need more control over your animation look at the + // activities package. Each animate method creates an animation that + // will animate the node from its current state to the new state + // specified over the given duration. These methods will try to + // automatically schedule the new activity, but if the node does not + // descend from the root node when the method is called then the + // activity will not be scheduled and you must schedule it manually. + // **************************************************************** - /** - * Animate this node's bounds from their current location when the activity - * starts to the specified bounds. If this node descends from the root then - * the activity will be scheduled, else the returned activity should be - * scheduled manually. If two different transform activities are scheduled - * for the same node at the same time, they will both be applied to the - * node, but the last one scheduled will be applied last on each frame, so - * it will appear to have replaced the original. Generally you will not want - * to do that. Note this method animates the node's bounds, but does not - * change the node's transform. Use animateTransformToBounds() to animate - * the node's transform instead. - * - * @param x - * left of target bounds - * @param y - * top of target bounds - * @param width - * width of target bounds - * @param height - * height of target bounds - * @param duration - * amount of time that the animation should take - * @return the newly scheduled activity - */ - public PInterpolatingActivity animateToBounds(final double x, - final double y, final double width, final double height, - final long duration) { - if (duration == 0) { - setBounds(x, y, width, height); - return null; - } + /** + * Animate this node's bounds from their current location when the activity + * starts to the specified bounds. If this node descends from the root then + * the activity will be scheduled, else the returned activity should be + * scheduled manually. If two different transform activities are scheduled + * for the same node at the same time, they will both be applied to the + * node, but the last one scheduled will be applied last on each frame, so + * it will appear to have replaced the original. Generally you will not want + * to do that. Note this method animates the node's bounds, but does not + * change the node's transform. Use animateTransformToBounds() to animate + * the node's transform instead. + * + * @param x left of target bounds + * @param y top of target bounds + * @param width width of target bounds + * @param height height of target bounds + * @param duration amount of time that the animation should take + * @return the newly scheduled activity + */ + public PInterpolatingActivity animateToBounds(final double x, final double y, final double width, + final double height, final long duration) { + if (duration == 0) { + setBounds(x, y, width, height); + return null; + } - final PBounds dst = new PBounds(x, y, width, height); + final PBounds dst = new PBounds(x, y, width, height); - final PInterpolatingActivity interpolatingActivity = new PInterpolatingActivity( - duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE) { - private PBounds src; + final PInterpolatingActivity interpolatingActivity = new PInterpolatingActivity(duration, + PUtil.DEFAULT_ACTIVITY_STEP_RATE) { + private PBounds src; - protected void activityStarted() { - src = getBounds(); - startResizeBounds(); - super.activityStarted(); - } + protected void activityStarted() { + src = getBounds(); + startResizeBounds(); + super.activityStarted(); + } - public void setRelativeTargetValue(final float zeroToOne) { - PNode.this.setBounds(src.x + zeroToOne * (dst.x - src.x), src.y - + zeroToOne * (dst.y - src.y), src.width + zeroToOne - * (dst.width - src.width), src.height + zeroToOne - * (dst.height - src.height)); - } + public void setRelativeTargetValue(final float zeroToOne) { + PNode.this.setBounds(src.x + zeroToOne * (dst.x - src.x), src.y + zeroToOne * (dst.y - src.y), + src.width + zeroToOne * (dst.width - src.width), src.height + zeroToOne + * (dst.height - src.height)); + } - protected void activityFinished() { - super.activityFinished(); - endResizeBounds(); - } - }; + protected void activityFinished() { + super.activityFinished(); + endResizeBounds(); + } + }; - addActivity(interpolatingActivity); - return interpolatingActivity; - } + addActivity(interpolatingActivity); + return interpolatingActivity; + } - /** - * Animate this node from it's current transform when the activity starts a - * new transform that will fit the node into the given bounds. If this node - * descends from the root then the activity will be scheduled, else the - * returned activity should be scheduled manually. If two different - * transform activities are scheduled for the same node at the same time, - * they will both be applied to the node, but the last one scheduled will be - * applied last on each frame, so it will appear to have replaced the - * original. Generally you will not want to do that. Note this method - * animates the node's transform, but does not directly change the node's - * bounds rectangle. Use animateToBounds() to animate the node's bounds - * rectangle instead. - * - * @param x - * left of target bounds - * @param y - * top of target bounds - * @param width - * width of target bounds - * @param height - * height of target bounds - * @param duration - * amount of time that the animation should take - * @return the newly scheduled activity - */ - public PTransformActivity animateTransformToBounds(final double x, - final double y, final double width, final double height, - final long duration) { - final PAffineTransform t = new PAffineTransform(); - t.setToScale(width / getWidth(), height / getHeight()); - final double scale = t.getScale(); - t.setOffset(x - getX() * scale, y - getY() * scale); - return animateToTransform(t, duration); - } + /** + * Animate this node from it's current transform when the activity starts a + * new transform that will fit the node into the given bounds. If this node + * descends from the root then the activity will be scheduled, else the + * returned activity should be scheduled manually. If two different + * transform activities are scheduled for the same node at the same time, + * they will both be applied to the node, but the last one scheduled will be + * applied last on each frame, so it will appear to have replaced the + * original. Generally you will not want to do that. Note this method + * animates the node's transform, but does not directly change the node's + * bounds rectangle. Use animateToBounds() to animate the node's bounds + * rectangle instead. + * + * @param x left of target bounds + * @param y top of target bounds + * @param width width of target bounds + * @param height height of target bounds + * @param duration amount of time that the animation should take + * @return the newly scheduled activity + */ + public PTransformActivity animateTransformToBounds(final double x, final double y, final double width, + final double height, final long duration) { + final PAffineTransform t = new PAffineTransform(); + t.setToScale(width / getWidth(), height / getHeight()); + final double scale = t.getScale(); + t.setOffset(x - getX() * scale, y - getY() * scale); + return animateToTransform(t, duration); + } - /** - * Animate this node's transform from its current location when the activity - * starts to the specified location, scale, and rotation. If this node - * descends from the root then the activity will be scheduled, else the - * returned activity should be scheduled manually. If two different - * transform activities are scheduled for the same node at the same time, - * they will both be applied to the node, but the last one scheduled will be - * applied last on each frame, so it will appear to have replaced the - * original. Generally you will not want to do that. - * - * @param x - * the final target x position of node - * @param y - * the final target y position of node - * @param duration - * amount of time that the animation should take - * @param scale - * the final scale for the duration - * @param theta - * final theta value (in radians) for the animation - * @return the newly scheduled activity - */ - public PTransformActivity animateToPositionScaleRotation(final double x, - final double y, final double scale, final double theta, - final long duration) { - final PAffineTransform t = getTransform(); - t.setOffset(x, y); - t.setScale(scale); - t.setRotation(theta); - return animateToTransform(t, duration); - } + /** + * Animate this node's transform from its current location when the activity + * starts to the specified location, scale, and rotation. If this node + * descends from the root then the activity will be scheduled, else the + * returned activity should be scheduled manually. If two different + * transform activities are scheduled for the same node at the same time, + * they will both be applied to the node, but the last one scheduled will be + * applied last on each frame, so it will appear to have replaced the + * original. Generally you will not want to do that. + * + * @param x the final target x position of node + * @param y the final target y position of node + * @param duration amount of time that the animation should take + * @param scale the final scale for the duration + * @param theta final theta value (in radians) for the animation + * @return the newly scheduled activity + */ + public PTransformActivity animateToPositionScaleRotation(final double x, final double y, final double scale, + final double theta, final long duration) { + final PAffineTransform t = getTransform(); + t.setOffset(x, y); + t.setScale(scale); + t.setRotation(theta); + return animateToTransform(t, duration); + } - /** - * Animate this node's transform from its current values when the activity - * starts to the new values specified in the given transform. If this node - * descends from the root then the activity will be scheduled, else the - * returned activity should be scheduled manually. If two different - * transform activities are scheduled for the same node at the same time, - * they will both be applied to the node, but the last one scheduled will be - * applied last on each frame, so it will appear to have replaced the - * original. Generally you will not want to do that. - * - * @param destTransform - * the final transform value - * @param duration - * amount of time that the animation should take - * @return the newly scheduled activity - */ - public PTransformActivity animateToTransform( - final AffineTransform destTransform, final long duration) { - if (duration == 0) { - setTransform(destTransform); - return null; - } else { - final PTransformActivity.Target t = new PTransformActivity.Target() { - public void setTransform(final AffineTransform aTransform) { - PNode.this.setTransform(aTransform); - } + /** + * Animate this node's transform from its current values when the activity + * starts to the new values specified in the given transform. If this node + * descends from the root then the activity will be scheduled, else the + * returned activity should be scheduled manually. If two different + * transform activities are scheduled for the same node at the same time, + * they will both be applied to the node, but the last one scheduled will be + * applied last on each frame, so it will appear to have replaced the + * original. Generally you will not want to do that. + * + * @param destTransform the final transform value + * @param duration amount of time that the animation should take + * @return the newly scheduled activity + */ + public PTransformActivity animateToTransform(final AffineTransform destTransform, final long duration) { + if (duration == 0) { + setTransform(destTransform); + return null; + } + else { + final PTransformActivity.Target t = new PTransformActivity.Target() { + public void setTransform(final AffineTransform aTransform) { + PNode.this.setTransform(aTransform); + } - public void getSourceMatrix(final double[] aSource) { - PNode.this.getTransformReference(true).getMatrix(aSource); - } - }; + public void getSourceMatrix(final double[] aSource) { + PNode.this.getTransformReference(true).getMatrix(aSource); + } + }; - final PTransformActivity ta = new PTransformActivity(duration, - PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destTransform); - addActivity(ta); - return ta; - } - } + final PTransformActivity ta = new PTransformActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, + destTransform); + addActivity(ta); + return ta; + } + } - /** - * Animate this node's color from its current value to the new value - * specified. This meathod assumes that this nodes paint property is of type - * color. If this node descends from the root then the activity will be - * scheduled, else the returned activity should be scheduled manually. If - * two different color activities are scheduled for the same node at the - * same time, they will both be applied to the node, but the last one - * scheduled will be applied last on each frame, so it will appear to have - * replaced the original. Generally you will not want to do that. - * - * @param destColor - * final color value. - * @param duration - * amount of time that the animation should take - * @return the newly scheduled activity - */ - public PInterpolatingActivity animateToColor(final Color destColor, - final long duration) { - if (duration == 0) { - setPaint(destColor); - return null; - } else { - final PColorActivity.Target t = new PColorActivity.Target() { - public Color getColor() { - return (Color) getPaint(); - } + /** + * Animate this node's color from its current value to the new value + * specified. This meathod assumes that this nodes paint property is of type + * color. If this node descends from the root then the activity will be + * scheduled, else the returned activity should be scheduled manually. If + * two different color activities are scheduled for the same node at the + * same time, they will both be applied to the node, but the last one + * scheduled will be applied last on each frame, so it will appear to have + * replaced the original. Generally you will not want to do that. + * + * @param destColor final color value. + * @param duration amount of time that the animation should take + * @return the newly scheduled activity + */ + public PInterpolatingActivity animateToColor(final Color destColor, final long duration) { + if (duration == 0) { + setPaint(destColor); + return null; + } + else { + final PColorActivity.Target t = new PColorActivity.Target() { + public Color getColor() { + return (Color) getPaint(); + } - public void setColor(final Color color) { - setPaint(color); - } - }; + public void setColor(final Color color) { + setPaint(color); + } + }; - final PColorActivity ca = new PColorActivity(duration, - PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destColor); - addActivity(ca); - return ca; - } - } + final PColorActivity ca = new PColorActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destColor); + addActivity(ca); + return ca; + } + } - /** - * Animate this node's transparency from its current value to the new value - * specified. Transparency values must range from zero to one. If this node - * descends from the root then the activity will be scheduled, else the - * returned activity should be scheduled manually. If two different - * transparency activities are scheduled for the same node at the same time, - * they will both be applied to the node, but the last one scheduled will be - * applied last on each frame, so it will appear to have replaced the - * original. Generally you will not want to do that. - * - * @param zeroToOne - * final transparency value. - * @param duration - * amount of time that the animation should take - * @return the newly scheduled activity - */ - public PInterpolatingActivity animateToTransparency(final float zeroToOne, - final long duration) { - if (duration == 0) { - setTransparency(zeroToOne); - return null; - } else { - final float dest = zeroToOne; + /** + * Animate this node's transparency from its current value to the new value + * specified. Transparency values must range from zero to one. If this node + * descends from the root then the activity will be scheduled, else the + * returned activity should be scheduled manually. If two different + * transparency activities are scheduled for the same node at the same time, + * they will both be applied to the node, but the last one scheduled will be + * applied last on each frame, so it will appear to have replaced the + * original. Generally you will not want to do that. + * + * @param zeroToOne final transparency value. + * @param duration amount of time that the animation should take + * @return the newly scheduled activity + */ + public PInterpolatingActivity animateToTransparency(final float zeroToOne, final long duration) { + if (duration == 0) { + setTransparency(zeroToOne); + return null; + } + else { + final float dest = zeroToOne; - final PInterpolatingActivity ta = new PInterpolatingActivity( - duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE) { - private float source; + final PInterpolatingActivity ta = new PInterpolatingActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE) { + private float source; - protected void activityStarted() { - source = getTransparency(); - super.activityStarted(); - } + protected void activityStarted() { + source = getTransparency(); + super.activityStarted(); + } - public void setRelativeTargetValue(final float zeroToOne) { - PNode.this.setTransparency(source + zeroToOne - * (dest - source)); - } - }; + public void setRelativeTargetValue(final float zeroToOne) { + PNode.this.setTransparency(source + zeroToOne * (dest - source)); + } + }; - addActivity(ta); - return ta; - } - } + addActivity(ta); + return ta; + } + } - /** - * Schedule the given activity with the root, note that only scheduled - * activities will be stepped. If the activity is successfully added true is - * returned, else false. - * - * @param activity - * new activity to schedule - * @return true if the activity is successfully scheduled. - */ - public boolean addActivity(final PActivity activity) { - final PRoot r = getRoot(); - if (r != null) { - return r.addActivity(activity); - } - return false; - } + /** + * Schedule the given activity with the root, note that only scheduled + * activities will be stepped. If the activity is successfully added true is + * returned, else false. + * + * @param activity new activity to schedule + * @return true if the activity is successfully scheduled. + */ + public boolean addActivity(final PActivity activity) { + final PRoot r = getRoot(); + if (r != null) { + return r.addActivity(activity); + } + return false; + } - // **************************************************************** - // Client Properties - Methods for managing client properties for - // this node. - // - // Client properties provide a way for programmers to attach - // extra information to a node without having to subclass it and - // add new instance variables. - // **************************************************************** + // **************************************************************** + // Client Properties - Methods for managing client properties for + // this node. + // + // Client properties provide a way for programmers to attach + // extra information to a node without having to subclass it and + // add new instance variables. + // **************************************************************** - /** - * Return mutable attributed set of client properties associated with this - * node. - * - * @return the client properties associated to this node - */ - public MutableAttributeSet getClientProperties() { - if (clientProperties == null) { - clientProperties = new SimpleAttributeSet(); - } - return clientProperties; - } + /** + * Return mutable attributed set of client properties associated with this + * node. + * + * @return the client properties associated to this node + */ + public MutableAttributeSet getClientProperties() { + if (clientProperties == null) { + clientProperties = new SimpleAttributeSet(); + } + return clientProperties; + } - /** - * Returns the value of the client attribute with the specified key. Only - * attributes added with addAttribute will return a non-null - * value. - * - * @param key - * key to use while fetching client attribute - * - * @return the value of this attribute or null - */ - public Object getAttribute(final Object key) { - if (clientProperties == null || key == null) { - return null; - } else { - return clientProperties.getAttribute(key); - } - } + /** + * Returns the value of the client attribute with the specified key. Only + * attributes added with addAttribute will return a non-null + * value. + * + * @param key key to use while fetching client attribute + * + * @return the value of this attribute or null + */ + public Object getAttribute(final Object key) { + if (clientProperties == null || key == null) { + return null; + } + else { + return clientProperties.getAttribute(key); + } + } - /** - * Add an arbitrary key/value to this node. - *

- * The get/add attribute methods provide access to a small - * per-instance attribute set. Callers can use get/add attribute to annotate - * nodes that were created by another module. - *

- * If value is null this method will remove the attribute. - * - * @param key - * to use when adding the attribute - * @param value - * value to associate to the new attribute - */ - public void addAttribute(final Object key, final Object value) { - if (value == null && clientProperties == null) { - return; - } + /** + * Add an arbitrary key/value to this node. + *

+ * The get/add attribute methods provide access to a small + * per-instance attribute set. Callers can use get/add attribute to annotate + * nodes that were created by another module. + *

+ * If value is null this method will remove the attribute. + * + * @param key to use when adding the attribute + * @param value value to associate to the new attribute + */ + public void addAttribute(final Object key, final Object value) { + if (value == null && clientProperties == null) { + return; + } - final Object oldValue = getAttribute(key); + final Object oldValue = getAttribute(key); - if (value != oldValue) { - if (clientProperties == null) { - clientProperties = new SimpleAttributeSet(); - } + if (value != oldValue) { + if (clientProperties == null) { + clientProperties = new SimpleAttributeSet(); + } - if (value == null) { - clientProperties.removeAttribute(key); - } else { - clientProperties.addAttribute(key, value); - } + if (value == null) { + clientProperties.removeAttribute(key); + } + else { + clientProperties.addAttribute(key, value); + } - if (clientProperties.getAttributeCount() == 0 - && clientProperties.getResolveParent() == null) { - clientProperties = null; - } + if (clientProperties.getAttributeCount() == 0 && clientProperties.getResolveParent() == null) { + clientProperties = null; + } - firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES, - PROPERTY_CLIENT_PROPERTIES, null, clientProperties); - firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES, key.toString(), - oldValue, value); - } - } + firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES, PROPERTY_CLIENT_PROPERTIES, null, clientProperties); + firePropertyChange(PROPERTY_CODE_CLIENT_PROPERTIES, key.toString(), oldValue, value); + } + } - /** - * Returns an enumeration of all keys maped to attribute values values. - * - * @return an Enumeration over attribute keys - */ - public Enumeration getClientPropertyKeysEnumeration() { - if (clientProperties == null) { - return PUtil.NULL_ENUMERATION; - } else { - return clientProperties.getAttributeNames(); - } - } + /** + * Returns an enumeration of all keys maped to attribute values values. + * + * @return an Enumeration over attribute keys + */ + public Enumeration getClientPropertyKeysEnumeration() { + if (clientProperties == null) { + return PUtil.NULL_ENUMERATION; + } + else { + return clientProperties.getAttributeNames(); + } + } - // convenience methods for attributes + // convenience methods for attributes - /** - * Fetches the value of the requested attribute, returning defaultValue is - * not found. - * - * @param key - * attribute to search for - * @param defaultValue - * value to return if attribute is not found - * - * @return value of attribute or defaultValue if not found - */ - public Object getAttribute(final Object key, final Object defaultValue) { - final Object value = getAttribute(key); - if (value == null) { - return defaultValue; - } + /** + * Fetches the value of the requested attribute, returning defaultValue is + * not found. + * + * @param key attribute to search for + * @param defaultValue value to return if attribute is not found + * + * @return value of attribute or defaultValue if not found + */ + public Object getAttribute(final Object key, final Object defaultValue) { + final Object value = getAttribute(key); + if (value == null) { + return defaultValue; + } + + return value; + } - return value; - } + /** + * Fetches the boolean value of the requested attribute, returning + * defaultValue is not found. + * + * @param key attribute to search for + * @param defaultValue value to return if attribute is not found + * + * @return value of attribute or defaultValue if not found + */ + public boolean getBooleanAttribute(final Object key, final boolean defaultValue) { + final Boolean value = (Boolean) getAttribute(key); + if (value == null) { + return defaultValue; + } - /** - * Fetches the boolean value of the requested attribute, returning - * defaultValue is not found. - * - * @param key - * attribute to search for - * @param defaultValue - * value to return if attribute is not found - * - * @return value of attribute or defaultValue if not found - */ - public boolean getBooleanAttribute(final Object key, - final boolean defaultValue) { - final Boolean value = (Boolean) getAttribute(key); - if (value == null) { - return defaultValue; - } + return value.booleanValue(); + } - return value.booleanValue(); - } + /** + * Fetches the integer value of the requested attribute, returning + * defaultValue is not found. + * + * @param key attribute to search for + * @param defaultValue value to return if attribute is not found + * + * @return value of attribute or defaultValue if not found + */ + public int getIntegerAttribute(final Object key, final int defaultValue) { + final Number value = (Number) getAttribute(key); + if (value == null) { + return defaultValue; + } - /** - * Fetches the integer value of the requested attribute, returning - * defaultValue is not found. - * - * @param key - * attribute to search for - * @param defaultValue - * value to return if attribute is not found - * - * @return value of attribute or defaultValue if not found - */ - public int getIntegerAttribute(final Object key, final int defaultValue) { - final Number value = (Number) getAttribute(key); - if (value == null) { - return defaultValue; - } + return value.intValue(); + } - return value.intValue(); - } + /** + * Fetches the double value of the requested attribute, returning + * defaultValue is not found. + * + * @param key attribute to search for + * @param defaultValue value to return if attribute is not found + * + * @return value of attribute or defaultValue if not found + */ + public double getDoubleAttribute(final Object key, final double defaultValue) { + final Number value = (Number) getAttribute(key); + if (value == null) { + return defaultValue; + } - /** - * Fetches the double value of the requested attribute, returning - * defaultValue is not found. - * - * @param key - * attribute to search for - * @param defaultValue - * value to return if attribute is not found - * - * @return value of attribute or defaultValue if not found - */ - public double getDoubleAttribute(final Object key, final double defaultValue) { - final Number value = (Number) getAttribute(key); - if (value == null) { - return defaultValue; - } + return value.doubleValue(); + } - return value.doubleValue(); - } + /** + * @deprecated use getAttribute(Object key)instead. + * + * @param key name of property to search for + * @return value of matching client property + */ + public Object getClientProperty(final Object key) { + return getAttribute(key); + } - /** - * @deprecated use getAttribute(Object key)instead. - * - * @param key - * name of property to search for - * @return value of matching client property - */ - public Object getClientProperty(final Object key) { - return getAttribute(key); - } + /** + * @deprecated use addAttribute(Object key, Object value)instead. + * + * @param key name of property to add + * @param value value or new attribute + */ + public void addClientProperty(final Object key, final Object value) { + addAttribute(key, value); + } - /** - * @deprecated use addAttribute(Object key, Object value)instead. - * - * @param key - * name of property to add - * @param value - * value or new attribute - */ - public void addClientProperty(final Object key, final Object value) { - addAttribute(key, value); - } + /** + * @deprecated use getClientPropertyKeysEnumerator() instead. + * + * @return iterator for client property keys + */ + public Iterator getClientPropertyKeysIterator() { + final Enumeration enumeration = getClientPropertyKeysEnumeration(); - /** - * @deprecated use getClientPropertyKeysEnumerator() instead. - * - * @return iterator for client property keys - */ - public Iterator getClientPropertyKeysIterator() { - final Enumeration enumeration = getClientPropertyKeysEnumeration(); + return new ClientPropertyKeyIterator(enumeration); + } - return new ClientPropertyKeyIterator(enumeration); - } + // **************************************************************** + // Copying - Methods for copying this node and its descendants. + // Copying is implemented in terms of serialization. + // **************************************************************** - // **************************************************************** - // Copying - Methods for copying this node and its descendants. - // Copying is implemented in terms of serialization. - // **************************************************************** + /** + * The copy method copies this node and all of its descendants. Note that + * copying is implemented in terms of java serialization. See the + * serialization notes for more information. + * + * @return new copy of this node or null if the node was not serializable + */ + public Object clone() { + try { + final byte[] ser = PObjectOutputStream.toByteArray(this); + return new ObjectInputStream(new ByteArrayInputStream(ser)).readObject(); + } + catch (final IOException e) { + return null; + } + catch (final ClassNotFoundException e) { + return null; + } + } - /** - * The copy method copies this node and all of its descendants. Note that - * copying is implemented in terms of java serialization. See the - * serialization notes for more information. - * - * @return new copy of this node or null if the node was not serializable - */ - public Object clone() { - try { - final byte[] ser = PObjectOutputStream.toByteArray(this); - return new ObjectInputStream(new ByteArrayInputStream(ser)) - .readObject(); - } catch (final IOException e) { - return null; - } catch (final ClassNotFoundException e) { - return null; - } - } + // **************************************************************** + // Coordinate System Conversions - Methods for converting + // geometry between this nodes local coordinates and the other + // major coordinate systems. + // + // Each nodes has an affine transform that it uses to define its + // own coordinate system. For example if you create a new node and + // add it to the canvas it will appear in the upper right corner. Its + // coordinate system matches the coordinate system of its parent + // (the root node) at this point. But if you move this node by calling + // node.translate() the nodes affine transform will be modified and the + // node will appear at a different location on the screen. The node + // coordinate system no longer matches the coordinate system of its + // parent. + // + // This is useful because it means that the node's methods for + // rendering and picking don't need to worry about the fact that + // the node has been moved to another position on the screen, they + // keep working just like they did when it was in the upper right + // hand corner of the screen. + // + // The problem is now that each node defines its own coordinate + // system it is difficult to compare the positions of two node with + // each other. These methods are all meant to help solve that problem. + // + // The terms used in the methods are as follows: + // + // local - The local or base coordinate system of a node. + // parent - The coordinate system of a node's parent + // global - The topmost coordinate system, above the root node. + // + // Normally when comparing the positions of two nodes you will + // convert the local position of each node to the global coordinate + // system, and then compare the positions in that common coordinate + // system. + // *************************************************************** - // **************************************************************** - // Coordinate System Conversions - Methods for converting - // geometry between this nodes local coordinates and the other - // major coordinate systems. - // - // Each nodes has an affine transform that it uses to define its - // own coordinate system. For example if you create a new node and - // add it to the canvas it will appear in the upper right corner. Its - // coordinate system matches the coordinate system of its parent - // (the root node) at this point. But if you move this node by calling - // node.translate() the nodes affine transform will be modified and the - // node will appear at a different location on the screen. The node - // coordinate system no longer matches the coordinate system of its - // parent. - // - // This is useful because it means that the node's methods for - // rendering and picking don't need to worry about the fact that - // the node has been moved to another position on the screen, they - // keep working just like they did when it was in the upper right - // hand corner of the screen. - // - // The problem is now that each node defines its own coordinate - // system it is difficult to compare the positions of two node with - // each other. These methods are all meant to help solve that problem. - // - // The terms used in the methods are as follows: - // - // local - The local or base coordinate system of a node. - // parent - The coordinate system of a node's parent - // global - The topmost coordinate system, above the root node. - // - // Normally when comparing the positions of two nodes you will - // convert the local position of each node to the global coordinate - // system, and then compare the positions in that common coordinate - // system. - // *************************************************************** + /** + * Transform the given point from this node's local coordinate system to its + * parent's local coordinate system. Note that this will modify the point + * parameter. + * + * @param localPoint point in local coordinate system to be transformed. + * @return point in parent's local coordinate system + */ + public Point2D localToParent(final Point2D localPoint) { + if (transform == null) { + return localPoint; + } + return transform.transform(localPoint, localPoint); + } - /** - * Transform the given point from this node's local coordinate system to its - * parent's local coordinate system. Note that this will modify the point - * parameter. - * - * @param localPoint - * point in local coordinate system to be transformed. - * @return point in parent's local coordinate system - */ - public Point2D localToParent(final Point2D localPoint) { - if (transform == null) { - return localPoint; - } - return transform.transform(localPoint, localPoint); - } + /** + * Transform the given dimension from this node's local coordinate system to + * its parent's local coordinate system. Note that this will modify the + * dimension parameter. + * + * @param localDimension dimension in local coordinate system to be + * transformed. + * @return dimension in parent's local coordinate system + */ + public Dimension2D localToParent(final Dimension2D localDimension) { + if (transform == null) { + return localDimension; + } + return transform.transform(localDimension, localDimension); + } - /** - * Transform the given dimension from this node's local coordinate system to - * its parent's local coordinate system. Note that this will modify the - * dimension parameter. - * - * @param localDimension - * dimension in local coordinate system to be transformed. - * @return dimension in parent's local coordinate system - */ - public Dimension2D localToParent(final Dimension2D localDimension) { - if (transform == null) { - return localDimension; - } - return transform.transform(localDimension, localDimension); - } + /** + * Transform the given rectangle from this node's local coordinate system to + * its parent's local coordinate system. Note that this will modify the + * rectangle parameter. + * + * @param localRectangle rectangle in local coordinate system to be + * transformed. + * @return rectangle in parent's local coordinate system + */ + public Rectangle2D localToParent(final Rectangle2D localRectangle) { + if (transform == null) { + return localRectangle; + } + return transform.transform(localRectangle, localRectangle); + } - /** - * Transform the given rectangle from this node's local coordinate system to - * its parent's local coordinate system. Note that this will modify the - * rectangle parameter. - * - * @param localRectangle - * rectangle in local coordinate system to be transformed. - * @return rectangle in parent's local coordinate system - */ - public Rectangle2D localToParent(final Rectangle2D localRectangle) { - if (transform == null) { - return localRectangle; - } - return transform.transform(localRectangle, localRectangle); - } + /** + * Transform the given point from this node's parent's local coordinate + * system to the local coordinate system of this node. Note that this will + * modify the point parameter. + * + * @param parentPoint point in parent's coordinate system to be transformed. + * @return point in this node's local coordinate system + */ + public Point2D parentToLocal(final Point2D parentPoint) { + if (transform == null) { + return parentPoint; + } - /** - * Transform the given point from this node's parent's local coordinate - * system to the local coordinate system of this node. Note that this will - * modify the point parameter. - * - * @param parentPoint - * point in parent's coordinate system to be transformed. - * @return point in this node's local coordinate system - */ - public Point2D parentToLocal(final Point2D parentPoint) { - if (transform == null) { - return parentPoint; - } + return transform.inverseTransform(parentPoint, parentPoint); + } - return transform.inverseTransform(parentPoint, parentPoint); - } + /** + * Transform the given dimension from this node's parent's local coordinate + * system to the local coordinate system of this node. Note that this will + * modify the dimension parameter. + * + * @param parentDimension dimension in parent's coordinate system to be + * transformed. + * @return dimension in this node's local coordinate system + */ + public Dimension2D parentToLocal(final Dimension2D parentDimension) { + if (transform == null) { + return parentDimension; + } + return transform.inverseTransform(parentDimension, parentDimension); + } - /** - * Transform the given dimension from this node's parent's local coordinate - * system to the local coordinate system of this node. Note that this will - * modify the dimension parameter. - * - * @param parentDimension - * dimension in parent's coordinate system to be transformed. - * @return dimension in this node's local coordinate system - */ - public Dimension2D parentToLocal(final Dimension2D parentDimension) { - if (transform == null) { - return parentDimension; - } - return transform.inverseTransform(parentDimension, parentDimension); - } + /** + * Transform the given rectangle from this node's parent's local coordinate + * system to the local coordinate system of this node. Note that this will + * modify the rectangle parameter. + * + * @param parentRectangle rectangle in parent's coordinate system to be + * transformed. + * @return rectangle in this node's local coordinate system + */ + public Rectangle2D parentToLocal(final Rectangle2D parentRectangle) { + if (transform == null) { + return parentRectangle; + } + return transform.inverseTransform(parentRectangle, parentRectangle); + } - /** - * Transform the given rectangle from this node's parent's local coordinate - * system to the local coordinate system of this node. Note that this will - * modify the rectangle parameter. - * - * @param parentRectangle - * rectangle in parent's coordinate system to be transformed. - * @return rectangle in this node's local coordinate system - */ - public Rectangle2D parentToLocal(final Rectangle2D parentRectangle) { - if (transform == null) { - return parentRectangle; - } - return transform.inverseTransform(parentRectangle, parentRectangle); - } + /** + * Transform the given point from this node's local coordinate system to the + * global coordinate system. Note that this will modify the point parameter. + * + * @param localPoint point in local coordinate system to be transformed. + * @return point in global coordinates + */ + public Point2D localToGlobal(final Point2D localPoint) { + PNode n = this; + while (n != null) { + n.localToParent(localPoint); + n = n.parent; + } + return localPoint; + } - /** - * Transform the given point from this node's local coordinate system to the - * global coordinate system. Note that this will modify the point parameter. - * - * @param localPoint - * point in local coordinate system to be transformed. - * @return point in global coordinates - */ - public Point2D localToGlobal(final Point2D localPoint) { - PNode n = this; - while (n != null) { - n.localToParent(localPoint); - n = n.parent; - } - return localPoint; - } + /** + * Transform the given dimension from this node's local coordinate system to + * the global coordinate system. Note that this will modify the dimension + * parameter. + * + * @param localDimension dimension in local coordinate system to be + * transformed. + * @return dimension in global coordinates + */ + public Dimension2D localToGlobal(final Dimension2D localDimension) { + PNode n = this; + while (n != null) { + n.localToParent(localDimension); + n = n.parent; + } + return localDimension; + } - /** - * Transform the given dimension from this node's local coordinate system to - * the global coordinate system. Note that this will modify the dimension - * parameter. - * - * @param localDimension - * dimension in local coordinate system to be transformed. - * @return dimension in global coordinates - */ - public Dimension2D localToGlobal(final Dimension2D localDimension) { - PNode n = this; - while (n != null) { - n.localToParent(localDimension); - n = n.parent; - } - return localDimension; - } + /** + * Transform the given rectangle from this node's local coordinate system to + * the global coordinate system. Note that this will modify the rectangle + * parameter. + * + * @param localRectangle rectangle in local coordinate system to be + * transformed. + * @return rectangle in global coordinates + */ + public Rectangle2D localToGlobal(final Rectangle2D localRectangle) { + PNode n = this; + while (n != null) { + n.localToParent(localRectangle); + n = n.parent; + } + return localRectangle; + } - /** - * Transform the given rectangle from this node's local coordinate system to - * the global coordinate system. Note that this will modify the rectangle - * parameter. - * - * @param localRectangle - * rectangle in local coordinate system to be transformed. - * @return rectangle in global coordinates - */ - public Rectangle2D localToGlobal(final Rectangle2D localRectangle) { - PNode n = this; - while (n != null) { - n.localToParent(localRectangle); - n = n.parent; - } - return localRectangle; - } + /** + * Transform the given point from global coordinates to this node's local + * coordinate system. Note that this will modify the point parameter. + * + * @param globalPoint point in global coordinates to be transformed. + * @return point in this node's local coordinate system. + */ + public Point2D globalToLocal(final Point2D globalPoint) { + final PAffineTransform globalTransform = computeGlobalTransform(this); + return globalTransform.inverseTransform(globalPoint, globalPoint); + } - /** - * Transform the given point from global coordinates to this node's local - * coordinate system. Note that this will modify the point parameter. - * - * @param globalPoint - * point in global coordinates to be transformed. - * @return point in this node's local coordinate system. - */ - public Point2D globalToLocal(final Point2D globalPoint) { - final PAffineTransform globalTransform = computeGlobalTransform(this); - return globalTransform.inverseTransform(globalPoint, globalPoint); - } + private PAffineTransform computeGlobalTransform(final PNode node) { + if (node == null) { + return new PAffineTransform(); + } - private PAffineTransform computeGlobalTransform(final PNode node) { - if (node == null) { - return new PAffineTransform(); - } - - final PAffineTransform parentGlobalTransform = computeGlobalTransform(node.parent); - if (node.transform != null) { - parentGlobalTransform.concatenate(node.transform); - } - return parentGlobalTransform; - } + final PAffineTransform parentGlobalTransform = computeGlobalTransform(node.parent); + if (node.transform != null) { + parentGlobalTransform.concatenate(node.transform); + } + return parentGlobalTransform; + } - /** - * Transform the given dimension from global coordinates to this node's - * local coordinate system. Note that this will modify the dimension - * parameter. - * - * @param globalDimension - * dimension in global coordinates to be transformed. - * @return dimension in this node's local coordinate system. - */ - public Dimension2D globalToLocal(final Dimension2D globalDimension) { - if (parent != null) { - parent.globalToLocal(globalDimension); - } - return parentToLocal(globalDimension); - } + /** + * Transform the given dimension from global coordinates to this node's + * local coordinate system. Note that this will modify the dimension + * parameter. + * + * @param globalDimension dimension in global coordinates to be transformed. + * @return dimension in this node's local coordinate system. + */ + public Dimension2D globalToLocal(final Dimension2D globalDimension) { + if (parent != null) { + parent.globalToLocal(globalDimension); + } + return parentToLocal(globalDimension); + } - /** - * Transform the given rectangle from global coordinates to this node's - * local coordinate system. Note that this will modify the rectangle - * parameter. - * - * @param globalRectangle - * rectangle in global coordinates to be transformed. - * @return rectangle in this node's local coordinate system. - */ - public Rectangle2D globalToLocal(final Rectangle2D globalRectangle) { - if (parent != null) { - parent.globalToLocal(globalRectangle); - } - return parentToLocal(globalRectangle); - } + /** + * Transform the given rectangle from global coordinates to this node's + * local coordinate system. Note that this will modify the rectangle + * parameter. + * + * @param globalRectangle rectangle in global coordinates to be transformed. + * @return rectangle in this node's local coordinate system. + */ + public Rectangle2D globalToLocal(final Rectangle2D globalRectangle) { + if (parent != null) { + parent.globalToLocal(globalRectangle); + } + return parentToLocal(globalRectangle); + } - /** - * Return the transform that converts local coordinates at this node to the - * global coordinate system. - * - * @param dest - * PAffineTransform to transform to global coordinates - * @return The concatenation of transforms from the top node down to this - * node. - */ - public PAffineTransform getLocalToGlobalTransform( - final PAffineTransform dest) { - PAffineTransform result = dest; - if (parent != null) { - result = parent.getLocalToGlobalTransform(result); - if (transform != null) { - result.concatenate(transform); - } - } else if (dest == null) { - result = getTransform(); - } else if (transform != null) { - result.setTransform(transform); - } else { - result.setToIdentity(); - } + /** + * Return the transform that converts local coordinates at this node to the + * global coordinate system. + * + * @param dest PAffineTransform to transform to global coordinates + * @return The concatenation of transforms from the top node down to this + * node. + */ + public PAffineTransform getLocalToGlobalTransform(final PAffineTransform dest) { + PAffineTransform result = dest; + if (parent != null) { + result = parent.getLocalToGlobalTransform(result); + if (transform != null) { + result.concatenate(transform); + } + } + else if (dest == null) { + result = getTransform(); + } + else if (transform != null) { + result.setTransform(transform); + } + else { + result.setToIdentity(); + } - return result; - } + return result; + } - /** - * Return the transform that converts global coordinates to local - * coordinates of this node. - * - * @param dest - * PAffineTransform to transform from global to local - * - * @return The inverse of the concatenation of transforms from the root down - * to this node. - */ - public PAffineTransform getGlobalToLocalTransform( - final PAffineTransform dest) { - PAffineTransform result = getLocalToGlobalTransform(dest); - try { - result.setTransform(result.createInverse()); - } catch (final NoninvertibleTransformException e) { - throw new PAffineTransformException(e, result); - } - return result; - } + /** + * Return the transform that converts global coordinates to local + * coordinates of this node. + * + * @param dest PAffineTransform to transform from global to local + * + * @return The inverse of the concatenation of transforms from the root down + * to this node. + */ + public PAffineTransform getGlobalToLocalTransform(final PAffineTransform dest) { + PAffineTransform result = getLocalToGlobalTransform(dest); + try { + result.setTransform(result.createInverse()); + } + catch (final NoninvertibleTransformException e) { + throw new PAffineTransformException(e, result); + } + return result; + } - // **************************************************************** - // Event Listeners - Methods for adding and removing event listeners - // from a node. - // - // Here methods are provided to add property change listeners and - // input event listeners. The property change listeners are notified - // when certain properties of this node change, and the input event - // listeners are notified when the nodes receives new key and mouse - // events. - // **************************************************************** + // **************************************************************** + // Event Listeners - Methods for adding and removing event listeners + // from a node. + // + // Here methods are provided to add property change listeners and + // input event listeners. The property change listeners are notified + // when certain properties of this node change, and the input event + // listeners are notified when the nodes receives new key and mouse + // events. + // **************************************************************** - /** - * Return the list of event listeners associated with this node. - * - * @return event listener list or null - */ - public EventListenerList getListenerList() { - return listenerList; - } + /** + * Return the list of event listeners associated with this node. + * + * @return event listener list or null + */ + public EventListenerList getListenerList() { + return listenerList; + } - /** - * Adds the specified input event listener to receive input events from this - * node. - * - * @param listener - * the new input listener - */ - public void addInputEventListener(final PInputEventListener listener) { - if (listenerList == null) { - listenerList = new EventListenerList(); - } - getListenerList().add(PInputEventListener.class, listener); - } + /** + * Adds the specified input event listener to receive input events from this + * node. + * + * @param listener the new input listener + */ + public void addInputEventListener(final PInputEventListener listener) { + if (listenerList == null) { + listenerList = new EventListenerList(); + } + getListenerList().add(PInputEventListener.class, listener); + } - /** - * Removes the specified input event listener so that it no longer receives - * input events from this node. - * - * @param listener - * the input listener to remove - */ - public void removeInputEventListener(final PInputEventListener listener) { - if (listenerList == null) { - return; - } - getListenerList().remove(PInputEventListener.class, listener); - if (listenerList.getListenerCount() == 0) { - listenerList = null; - } - } + /** + * Removes the specified input event listener so that it no longer receives + * input events from this node. + * + * @param listener the input listener to remove + */ + public void removeInputEventListener(final PInputEventListener listener) { + if (listenerList == null) { + return; + } + getListenerList().remove(PInputEventListener.class, listener); + if (listenerList.getListenerCount() == 0) { + listenerList = null; + } + } - /** - * Add a PropertyChangeListener to the listener list. The listener is - * registered for all properties. See the fields in PNode and subclasses - * that start with PROPERTY_ to find out which properties exist. - * - * @param listener - * The PropertyChangeListener to be added - */ - public void addPropertyChangeListener(final PropertyChangeListener listener) { - if (changeSupport == null) { - changeSupport = new SwingPropertyChangeSupport(this); - } - changeSupport.addPropertyChangeListener(listener); - } + /** + * Add a PropertyChangeListener to the listener list. The listener is + * registered for all properties. See the fields in PNode and subclasses + * that start with PROPERTY_ to find out which properties exist. + * + * @param listener The PropertyChangeListener to be added + */ + public void addPropertyChangeListener(final PropertyChangeListener listener) { + if (changeSupport == null) { + changeSupport = new SwingPropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(listener); + } - /** - * Add a PropertyChangeListener for a specific property. The listener will - * be invoked only when a call on firePropertyChange names that specific - * property. See the fields in PNode and subclasses that start with - * PROPERTY_ to find out which properties are supported. - * - * @param propertyName - * The name of the property to listen on. - * @param listener - * The PropertyChangeListener to be added - */ - public void addPropertyChangeListener(final String propertyName, - final PropertyChangeListener listener) { - if (listener == null) { - return; - } - if (changeSupport == null) { - changeSupport = new SwingPropertyChangeSupport(this); - } - changeSupport.addPropertyChangeListener(propertyName, listener); - } + /** + * Add a PropertyChangeListener for a specific property. The listener will + * be invoked only when a call on firePropertyChange names that specific + * property. See the fields in PNode and subclasses that start with + * PROPERTY_ to find out which properties are supported. + * + * @param propertyName The name of the property to listen on. + * @param listener The PropertyChangeListener to be added + */ + public void addPropertyChangeListener(final String propertyName, final PropertyChangeListener listener) { + if (listener == null) { + return; + } + if (changeSupport == null) { + changeSupport = new SwingPropertyChangeSupport(this); + } + changeSupport.addPropertyChangeListener(propertyName, listener); + } - /** - * Remove a PropertyChangeListener from the listener list. This removes a - * PropertyChangeListener that was registered for all properties. - * - * @param listener - * The PropertyChangeListener to be removed - */ - public void removePropertyChangeListener( - final PropertyChangeListener listener) { - if (changeSupport != null) { - changeSupport.removePropertyChangeListener(listener); - } - } + /** + * Remove a PropertyChangeListener from the listener list. This removes a + * PropertyChangeListener that was registered for all properties. + * + * @param listener The PropertyChangeListener to be removed + */ + public void removePropertyChangeListener(final PropertyChangeListener listener) { + if (changeSupport != null) { + changeSupport.removePropertyChangeListener(listener); + } + } - /** - * Remove a PropertyChangeListener for a specific property. - * - * @param propertyName - * The name of the property that was listened on. - * @param listener - * The PropertyChangeListener to be removed - */ - public void removePropertyChangeListener(final String propertyName, - final PropertyChangeListener listener) { - if (listener == null) { - return; - } - if (changeSupport == null) { - return; - } - changeSupport.removePropertyChangeListener(propertyName, listener); - } + /** + * Remove a PropertyChangeListener for a specific property. + * + * @param propertyName The name of the property that was listened on. + * @param listener The PropertyChangeListener to be removed + */ + public void removePropertyChangeListener(final String propertyName, final PropertyChangeListener listener) { + if (listener == null) { + return; + } + if (changeSupport == null) { + return; + } + changeSupport.removePropertyChangeListener(propertyName, listener); + } - /** - * Return the propertyChangeParentMask that determines which property change - * events are forwared to this nodes parent so that its property change - * listeners will also be notified. - * - * @return mask used for deciding whether to bubble property changes up to - * parent - */ - public int getPropertyChangeParentMask() { - return propertyChangeParentMask; - } + /** + * Return the propertyChangeParentMask that determines which property change + * events are forwared to this nodes parent so that its property change + * listeners will also be notified. + * + * @return mask used for deciding whether to bubble property changes up to + * parent + */ + public int getPropertyChangeParentMask() { + return propertyChangeParentMask; + } - /** - * Set the propertyChangeParentMask that determines which property change - * events are forwared to this nodes parent so that its property change - * listeners will also be notified. - * - * @param propertyChangeParentMask - * new mask for property change bubble up - */ - public void setPropertyChangeParentMask(final int propertyChangeParentMask) { - this.propertyChangeParentMask = propertyChangeParentMask; - } + /** + * Set the propertyChangeParentMask that determines which property change + * events are forwared to this nodes parent so that its property change + * listeners will also be notified. + * + * @param propertyChangeParentMask new mask for property change bubble up + */ + public void setPropertyChangeParentMask(final int propertyChangeParentMask) { + this.propertyChangeParentMask = propertyChangeParentMask; + } - /** - * Report a bound property update to any registered listeners. No event is - * fired if old and new are equal and non-null. If the propertyCode exists - * in this node's propertyChangeParentMask then a property change event will - * also be fired on this nodes parent. - * - * @param propertyCode - * The code of the property changed. - * @param propertyName - * The name of the property that was changed. - * @param oldValue - * The old value of the property. - * @param newValue - * The new value of the property. - */ - protected void firePropertyChange(final int propertyCode, - final String propertyName, final Object oldValue, - final Object newValue) { - PropertyChangeEvent event = null; + /** + * Report a bound property update to any registered listeners. No event is + * fired if old and new are equal and non-null. If the propertyCode exists + * in this node's propertyChangeParentMask then a property change event will + * also be fired on this nodes parent. + * + * @param propertyCode The code of the property changed. + * @param propertyName The name of the property that was changed. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + */ + protected void firePropertyChange(final int propertyCode, final String propertyName, final Object oldValue, + final Object newValue) { + PropertyChangeEvent event = null; - if (changeSupport != null) { - event = new PropertyChangeEvent(this, propertyName, oldValue, - newValue); - changeSupport.firePropertyChange(event); - } - if (parent != null && (propertyCode & propertyChangeParentMask) != 0) { - if (event == null) { - event = new PropertyChangeEvent(this, propertyName, oldValue, - newValue); - } - parent.fireChildPropertyChange(event, propertyCode); - } - } + if (changeSupport != null) { + event = new PropertyChangeEvent(this, propertyName, oldValue, newValue); + changeSupport.firePropertyChange(event); + } + if (parent != null && (propertyCode & propertyChangeParentMask) != 0) { + if (event == null) { + event = new PropertyChangeEvent(this, propertyName, oldValue, newValue); + } + parent.fireChildPropertyChange(event, propertyCode); + } + } - /** - * Called by child node to forward property change events up the node tree - * so that property change listeners registered with this node will be - * notified of property changes of its children nodes. For performance - * reason only propertyCodes listed in the propertyChangeParentMask are - * forwarded. - * - * @param event - * The property change event containing source node and changed - * values. - * @param propertyCode - * The code of the property changed. - */ - protected void fireChildPropertyChange(final PropertyChangeEvent event, - final int propertyCode) { - if (changeSupport != null) { - changeSupport.firePropertyChange(event); - } - if (parent != null && (propertyCode & propertyChangeParentMask) != 0) { - parent.fireChildPropertyChange(event, propertyCode); - } - } + /** + * Called by child node to forward property change events up the node tree + * so that property change listeners registered with this node will be + * notified of property changes of its children nodes. For performance + * reason only propertyCodes listed in the propertyChangeParentMask are + * forwarded. + * + * @param event The property change event containing source node and changed + * values. + * @param propertyCode The code of the property changed. + */ + protected void fireChildPropertyChange(final PropertyChangeEvent event, final int propertyCode) { + if (changeSupport != null) { + changeSupport.firePropertyChange(event); + } + if (parent != null && (propertyCode & propertyChangeParentMask) != 0) { + parent.fireChildPropertyChange(event, propertyCode); + } + } - // **************************************************************** - // Bounds Geometry - Methods for setting and querying the bounds - // of this node. - // - // The bounds of a node store the node's position and size in - // the nodes local coordinate system. Many node subclasses will need - // to override the setBounds method so that they can update their - // internal state appropriately. See PPath for an example. - // - // Since the bounds are stored in the local coordinate system - // they WILL NOT change if the node is scaled, translated, or rotated. - // - // The bounds may be accessed with either getBounds, or - // getBoundsReference. The former returns a copy of the bounds - // the latter returns a reference to the nodes bounds that should - // normally not be modified. If a node is marked as volatile then - // it may modify its bounds before returning them from getBoundsReference, - // otherwise it may not. - // **************************************************************** + // **************************************************************** + // Bounds Geometry - Methods for setting and querying the bounds + // of this node. + // + // The bounds of a node store the node's position and size in + // the nodes local coordinate system. Many node subclasses will need + // to override the setBounds method so that they can update their + // internal state appropriately. See PPath for an example. + // + // Since the bounds are stored in the local coordinate system + // they WILL NOT change if the node is scaled, translated, or rotated. + // + // The bounds may be accessed with either getBounds, or + // getBoundsReference. The former returns a copy of the bounds + // the latter returns a reference to the nodes bounds that should + // normally not be modified. If a node is marked as volatile then + // it may modify its bounds before returning them from getBoundsReference, + // otherwise it may not. + // **************************************************************** - /** - * Return a copy of this node's bounds. These bounds are stored in the local - * coordinate system of this node and do not include the bounds of any of - * this node's children. - * - * @return copy of this node's local bounds - */ - public PBounds getBounds() { - return (PBounds) getBoundsReference().clone(); - } + /** + * Return a copy of this node's bounds. These bounds are stored in the local + * coordinate system of this node and do not include the bounds of any of + * this node's children. + * + * @return copy of this node's local bounds + */ + public PBounds getBounds() { + return (PBounds) getBoundsReference().clone(); + } - /** - * Return a direct reference to this node's bounds. These bounds are stored - * in the local coordinate system of this node and do not include the bounds - * of any of this node's children. The value returned should not be - * modified. - * - * @return direct reference to local bounds - */ - public PBounds getBoundsReference() { - return bounds; - } + /** + * Return a direct reference to this node's bounds. These bounds are stored + * in the local coordinate system of this node and do not include the bounds + * of any of this node's children. The value returned should not be + * modified. + * + * @return direct reference to local bounds + */ + public PBounds getBoundsReference() { + return bounds; + } - /** - * Notify this node that you will begin to repeatedly call setBounds + /** + * Notify this node that you will begin to repeatedly call setBounds * . When you - * are done call endResizeBounds to let the node know that you - * are done. - */ - public void startResizeBounds() { - } + * are done call endResizeBounds to let the node know that you + * are done. + */ + public void startResizeBounds() { + } - /** - * Notify this node that you have finished a resize bounds sequence. - */ - public void endResizeBounds() { - } + /** + * Notify this node that you have finished a resize bounds sequence. + */ + public void endResizeBounds() { + } - /** - * Set's this node's bounds left position, leaving y, width, and height - * unchanged. - * - * @param x - * new x position of bounds - * - * @return whether the change was successful - */ - public boolean setX(final double x) { - return setBounds(x, getY(), getWidth(), getHeight()); - } + /** + * Set's this node's bounds left position, leaving y, width, and height + * unchanged. + * + * @param x new x position of bounds + * + * @return whether the change was successful + */ + public boolean setX(final double x) { + return setBounds(x, getY(), getWidth(), getHeight()); + } - /** - * Set's this node's bounds top position, leaving x, width, and height - * unchanged. - * - * @param y - * new y position of bounds - * - * @return whether the change was successful - */ - public boolean setY(final double y) { - return setBounds(getX(), y, getWidth(), getHeight()); - } + /** + * Set's this node's bounds top position, leaving x, width, and height + * unchanged. + * + * @param y new y position of bounds + * + * @return whether the change was successful + */ + public boolean setY(final double y) { + return setBounds(getX(), y, getWidth(), getHeight()); + } - /** - * Set's this node's bounds width, leaving x, y, and height unchanged. - * - * @param width - * new width position of bounds - * - * @return whether the change was successful - */ - public boolean setWidth(final double width) { - return setBounds(getX(), getY(), width, getHeight()); - } + /** + * Set's this node's bounds width, leaving x, y, and height unchanged. + * + * @param width new width position of bounds + * + * @return whether the change was successful + */ + public boolean setWidth(final double width) { + return setBounds(getX(), getY(), width, getHeight()); + } - /** - * Set's this node's bounds height, leaving x, y, and width unchanged. - * - * @param height - * new height position of bounds - * - * @return whether the change was successful - */ - public boolean setHeight(final double height) { - return setBounds(getX(), getY(), getWidth(), height); - } + /** + * Set's this node's bounds height, leaving x, y, and width unchanged. + * + * @param height new height position of bounds + * + * @return whether the change was successful + */ + public boolean setHeight(final double height) { + return setBounds(getX(), getY(), getWidth(), height); + } - /** - * Set the bounds of this node to the given value. These bounds are stored - * in the local coordinate system of this node. - * - * @param newBounds - * bounds to apply to this node - * - * @return true if the bounds changed. - */ - public boolean setBounds(final Rectangle2D newBounds) { - return setBounds(newBounds.getX(), newBounds.getY(), newBounds - .getWidth(), newBounds.getHeight()); - } + /** + * Set the bounds of this node to the given value. These bounds are stored + * in the local coordinate system of this node. + * + * @param newBounds bounds to apply to this node + * + * @return true if the bounds changed. + */ + public boolean setBounds(final Rectangle2D newBounds) { + return setBounds(newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight()); + } - /** - * Set the bounds of this node to the given position and size. These bounds - * are stored in the local coordinate system of this node. - * - * If the width or height is less then or equal to zero then the bound's - * empty bit will be set to true. - * - * Subclasses must call the super.setBounds() method. - * - * @param x - * x position of bounds - * @param y - * y position of bounds - * @param width - * width to apply to the bounds - * @param height - * height to apply to the bounds - * - * @return true if the bounds changed. - */ - public boolean setBounds(final double x, final double y, - final double width, final double height) { - if (bounds.x != x || bounds.y != y || bounds.width != width - || bounds.height != height) { - bounds.setRect(x, y, width, height); + /** + * Set the bounds of this node to the given position and size. These bounds + * are stored in the local coordinate system of this node. + * + * If the width or height is less then or equal to zero then the bound's + * empty bit will be set to true. + * + * Subclasses must call the super.setBounds() method. + * + * @param x x position of bounds + * @param y y position of bounds + * @param width width to apply to the bounds + * @param height height to apply to the bounds + * + * @return true if the bounds changed. + */ + public boolean setBounds(final double x, final double y, final double width, final double height) { + if (bounds.x != x || bounds.y != y || bounds.width != width || bounds.height != height) { + bounds.setRect(x, y, width, height); - if (width <= 0 || height <= 0) { - bounds.reset(); - } + if (width <= 0 || height <= 0) { + bounds.reset(); + } - internalUpdateBounds(x, y, width, height); - invalidatePaint(); - signalBoundsChanged(); - return true; - } - // Don't put any invalidating code here or else nodes with volatile - // bounds will - // create a soft infinite loop (calling Swing.invokeLater()) when they - // validate - // their bounds. - return false; - } + internalUpdateBounds(x, y, width, height); + invalidatePaint(); + signalBoundsChanged(); + return true; + } + // Don't put any invalidating code here or else nodes with volatile + // bounds will + // create a soft infinite loop (calling Swing.invokeLater()) when they + // validate + // their bounds. + return false; + } - /** - * Gives nodes a chance to update their internal structure before bounds - * changed notifications are sent. When this message is recived the nodes - * bounds field will contain the new value. - * - * See PPath for an example that uses this method. - * - * @param x - * x position of bounds - * @param y - * y position of bounds - * @param width - * width to apply to the bounds - * @param height - * height to apply to the bounds - */ - protected void internalUpdateBounds(final double x, final double y, - final double width, final double height) { - } + /** + * Gives nodes a chance to update their internal structure before bounds + * changed notifications are sent. When this message is recived the nodes + * bounds field will contain the new value. + * + * See PPath for an example that uses this method. + * + * @param x x position of bounds + * @param y y position of bounds + * @param width width to apply to the bounds + * @param height height to apply to the bounds + */ + protected void internalUpdateBounds(final double x, final double y, final double width, final double height) { + } - /** - * Set the empty bit of this bounds to true. - */ - public void resetBounds() { - setBounds(0, 0, 0, 0); - } + /** + * Set the empty bit of this bounds to true. + */ + public void resetBounds() { + setBounds(0, 0, 0, 0); + } - /** - * Return the x position (in local coords) of this node's bounds. - * - * @return local x position of bounds - */ - public double getX() { - return getBoundsReference().getX(); - } + /** + * Return the x position (in local coords) of this node's bounds. + * + * @return local x position of bounds + */ + public double getX() { + return getBoundsReference().getX(); + } - /** - * Return the y position (in local coords) of this node's bounds. - * - * @return local y position of bounds - */ - public double getY() { - return getBoundsReference().getY(); - } + /** + * Return the y position (in local coords) of this node's bounds. + * + * @return local y position of bounds + */ + public double getY() { + return getBoundsReference().getY(); + } - /** - * Return the width (in local coords) of this node's bounds. - * - * @return local width of bounds - */ - public double getWidth() { - return getBoundsReference().getWidth(); - } + /** + * Return the width (in local coords) of this node's bounds. + * + * @return local width of bounds + */ + public double getWidth() { + return getBoundsReference().getWidth(); + } - /** - * Return the height (in local coords) of this node's bounds. - * - * @return local width of bounds - */ - public double getHeight() { - return getBoundsReference().getHeight(); - } + /** + * Return the height (in local coords) of this node's bounds. + * + * @return local width of bounds + */ + public double getHeight() { + return getBoundsReference().getHeight(); + } - /** - * Return a copy of the bounds of this node in the global coordinate system. - * - * @return the bounds in global coordinate system. - */ - public PBounds getGlobalBounds() { - return (PBounds) localToGlobal(getBounds()); - } + /** + * Return a copy of the bounds of this node in the global coordinate system. + * + * @return the bounds in global coordinate system. + */ + public PBounds getGlobalBounds() { + return (PBounds) localToGlobal(getBounds()); + } - /** - * Center the bounds of this node so that they are centered on the given - * point specified on the local coordinates of this node. Note that this - * method will modify the nodes bounds, while centerFullBoundsOnPoint will - * modify the nodes transform. - * - * @param localX - * x position of point around which to center bounds - * @param localY - * y position of point around which to center bounds - * - * @return true if the bounds changed. - */ - public boolean centerBoundsOnPoint(final double localX, final double localY) { - final double dx = localX - bounds.getCenterX(); - final double dy = localY - bounds.getCenterY(); - return setBounds(bounds.x + dx, bounds.y + dy, bounds.width, - bounds.height); - } + /** + * Center the bounds of this node so that they are centered on the given + * point specified on the local coordinates of this node. Note that this + * method will modify the nodes bounds, while centerFullBoundsOnPoint will + * modify the nodes transform. + * + * @param localX x position of point around which to center bounds + * @param localY y position of point around which to center bounds + * + * @return true if the bounds changed. + */ + public boolean centerBoundsOnPoint(final double localX, final double localY) { + final double dx = localX - bounds.getCenterX(); + final double dy = localY - bounds.getCenterY(); + return setBounds(bounds.x + dx, bounds.y + dy, bounds.width, bounds.height); + } - /** - * Center the full bounds of this node so that they are centered on the - * given point specified on the local coordinates of this nodes parent. Note - * that this method will modify the nodes transform, while - * centerBoundsOnPoint will modify the nodes bounds. - * - * @param parentX - * x position around which to center full bounds - * @param parentY - * y position around which to center full bounds - */ - public void centerFullBoundsOnPoint(final double parentX, - final double parentY) { - final double dx = parentX - getFullBoundsReference().getCenterX(); - final double dy = parentY - getFullBoundsReference().getCenterY(); - offset(dx, dy); - } + /** + * Center the full bounds of this node so that they are centered on the + * given point specified on the local coordinates of this nodes parent. Note + * that this method will modify the nodes transform, while + * centerBoundsOnPoint will modify the nodes bounds. + * + * @param parentX x position around which to center full bounds + * @param parentY y position around which to center full bounds + */ + public void centerFullBoundsOnPoint(final double parentX, final double parentY) { + final double dx = parentX - getFullBoundsReference().getCenterX(); + final double dy = parentY - getFullBoundsReference().getCenterY(); + offset(dx, dy); + } - /** - * Return true if this node intersects the given rectangle specified in - * local bounds. If the geometry of this node is complex this method can - * become expensive, it is therefore recommended that - * fullIntersects is used for quick rejects before calling this - * method. - * - * @param localBounds - * the bounds to test for intersection against - * @return true if the given rectangle intersects this nodes geometry. - */ - public boolean intersects(final Rectangle2D localBounds) { - if (localBounds == null) { - return true; - } - return getBoundsReference().intersects(localBounds); - } + /** + * Return true if this node intersects the given rectangle specified in + * local bounds. If the geometry of this node is complex this method can + * become expensive, it is therefore recommended that + * fullIntersects is used for quick rejects before calling this + * method. + * + * @param localBounds the bounds to test for intersection against + * @return true if the given rectangle intersects this nodes geometry. + */ + public boolean intersects(final Rectangle2D localBounds) { + if (localBounds == null) { + return true; + } + return getBoundsReference().intersects(localBounds); + } - // **************************************************************** - // Full Bounds - Methods for computing and querying the - // full bounds of this node. - // - // The full bounds of a node store the nodes bounds - // together with the union of the bounds of all the - // node's descendants. The full bounds are stored in the parent - // coordinate system of this node, the full bounds DOES change - // when you translate, scale, or rotate this node. - // - // The full bounds may be accessed with either getFullBounds, or - // getFullBoundsReference. The former returns a copy of the full bounds - // the latter returns a reference to the node's full bounds that should - // not be modified. - // **************************************************************** + // **************************************************************** + // Full Bounds - Methods for computing and querying the + // full bounds of this node. + // + // The full bounds of a node store the nodes bounds + // together with the union of the bounds of all the + // node's descendants. The full bounds are stored in the parent + // coordinate system of this node, the full bounds DOES change + // when you translate, scale, or rotate this node. + // + // The full bounds may be accessed with either getFullBounds, or + // getFullBoundsReference. The former returns a copy of the full bounds + // the latter returns a reference to the node's full bounds that should + // not be modified. + // **************************************************************** - /** - * Return a copy of this node's full bounds. These bounds are stored in the - * parent coordinate system of this node and they include the union of this - * node's bounds and all the bounds of it's descendants. - * - * @return a copy of this node's full bounds. - */ - public PBounds getFullBounds() { - return (PBounds) getFullBoundsReference().clone(); - } + /** + * Return a copy of this node's full bounds. These bounds are stored in the + * parent coordinate system of this node and they include the union of this + * node's bounds and all the bounds of it's descendants. + * + * @return a copy of this node's full bounds. + */ + public PBounds getFullBounds() { + return (PBounds) getFullBoundsReference().clone(); + } - /** - * Return a reference to this node's full bounds cache. These bounds are - * stored in the parent coordinate system of this node and they include the - * union of this node's bounds and all the bounds of it's descendants. The - * bounds returned by this method should not be modified. - * - * @return a reference to this node's full bounds cache. - */ - public PBounds getFullBoundsReference() { - validateFullBounds(); - return fullBoundsCache; - } + /** + * Return a reference to this node's full bounds cache. These bounds are + * stored in the parent coordinate system of this node and they include the + * union of this node's bounds and all the bounds of it's descendants. The + * bounds returned by this method should not be modified. + * + * @return a reference to this node's full bounds cache. + */ + public PBounds getFullBoundsReference() { + validateFullBounds(); + return fullBoundsCache; + } - /** - * Compute and return the full bounds of this node. If the dstBounds - * parameter is not null then it will be used to return the results instead - * of creating a new PBounds. - * - * @param dstBounds - * if not null the new bounds will be stored here - * @return the full bounds in the parent coordinate system of this node - */ - public PBounds computeFullBounds(final PBounds dstBounds) { - final PBounds result = getUnionOfChildrenBounds(dstBounds); - result.add(getBoundsReference()); - localToParent(result); - return result; - } + /** + * Compute and return the full bounds of this node. If the dstBounds + * parameter is not null then it will be used to return the results instead + * of creating a new PBounds. + * + * @param dstBounds if not null the new bounds will be stored here + * @return the full bounds in the parent coordinate system of this node + */ + public PBounds computeFullBounds(final PBounds dstBounds) { + final PBounds result = getUnionOfChildrenBounds(dstBounds); + result.add(getBoundsReference()); + localToParent(result); + return result; + } - /** - * Compute and return the union of the full bounds of all the children of - * this node. If the dstBounds parameter is not null then it will be used to - * return the results instead of creating a new PBounds. - * - * @param dstBounds - * if not null the new bounds will be stored here - * @return union of children bounds - */ - public PBounds getUnionOfChildrenBounds(final PBounds dstBounds) { - PBounds resultBounds; - if (dstBounds == null) { - resultBounds = new PBounds(); - } else { - resultBounds = dstBounds; - resultBounds.resetToZero(); - } + /** + * Compute and return the union of the full bounds of all the children of + * this node. If the dstBounds parameter is not null then it will be used to + * return the results instead of creating a new PBounds. + * + * @param dstBounds if not null the new bounds will be stored here + * @return union of children bounds + */ + public PBounds getUnionOfChildrenBounds(final PBounds dstBounds) { + PBounds resultBounds; + if (dstBounds == null) { + resultBounds = new PBounds(); + } + else { + resultBounds = dstBounds; + resultBounds.resetToZero(); + } - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - resultBounds.add(each.getFullBoundsReference()); - } + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + resultBounds.add(each.getFullBoundsReference()); + } - return resultBounds; - } + return resultBounds; + } - /** - * Return a copy of the full bounds of this node in the global coordinate - * system. - * - * @return the full bounds in global coordinate system. - */ - public PBounds getGlobalFullBounds() { - final PBounds b = getFullBounds(); - if (parent != null) { - parent.localToGlobal(b); - } - return b; - } + /** + * Return a copy of the full bounds of this node in the global coordinate + * system. + * + * @return the full bounds in global coordinate system. + */ + public PBounds getGlobalFullBounds() { + final PBounds b = getFullBounds(); + if (parent != null) { + parent.localToGlobal(b); + } + return b; + } - /** - * Return true if the full bounds of this node intersects with the specified - * bounds. - * - * @param parentBounds - * the bounds to test for intersection against (specified in - * parent's coordinate system) - * @return true if this nodes full bounds intersect the given bounds. - */ - public boolean fullIntersects(final Rectangle2D parentBounds) { - if (parentBounds == null) { - return true; - } - return getFullBoundsReference().intersects(parentBounds); - } + /** + * Return true if the full bounds of this node intersects with the specified + * bounds. + * + * @param parentBounds the bounds to test for intersection against + * (specified in parent's coordinate system) + * @return true if this nodes full bounds intersect the given bounds. + */ + public boolean fullIntersects(final Rectangle2D parentBounds) { + if (parentBounds == null) { + return true; + } + return getFullBoundsReference().intersects(parentBounds); + } - // **************************************************************** - // Bounds Damage Management - Methods used to invalidate and validate - // the bounds of nodes. - // **************************************************************** + // **************************************************************** + // Bounds Damage Management - Methods used to invalidate and validate + // the bounds of nodes. + // **************************************************************** - /** - * Return true if this nodes bounds may change at any time. The default - * behavior is to return false, subclasses that override this method to - * return true should also override getBoundsReference() and compute their - * volatile bounds there before returning the reference. - * - * @return true if this node has volatile bounds - */ - protected boolean getBoundsVolatile() { - return false; - } + /** + * Return true if this nodes bounds may change at any time. The default + * behavior is to return false, subclasses that override this method to + * return true should also override getBoundsReference() and compute their + * volatile bounds there before returning the reference. + * + * @return true if this node has volatile bounds + */ + protected boolean getBoundsVolatile() { + return false; + } - /** - * Return true if this node has a child with volatile bounds. - * - * @return true if this node has a child with volatile bounds - */ - protected boolean getChildBoundsVolatile() { - return childBoundsVolatile; - } + /** + * Return true if this node has a child with volatile bounds. + * + * @return true if this node has a child with volatile bounds + */ + protected boolean getChildBoundsVolatile() { + return childBoundsVolatile; + } - /** - * Set if this node has a child with volatile bounds. This should normally - * be managed automatically by the bounds validation process. - * - * @param childBoundsVolatile - * true if this node has a descendant with volatile bounds - */ - protected void setChildBoundsVolatile(final boolean childBoundsVolatile) { - this.childBoundsVolatile = childBoundsVolatile; - } + /** + * Set if this node has a child with volatile bounds. This should normally + * be managed automatically by the bounds validation process. + * + * @param childBoundsVolatile true if this node has a descendant with + * volatile bounds + */ + protected void setChildBoundsVolatile(final boolean childBoundsVolatile) { + this.childBoundsVolatile = childBoundsVolatile; + } - /** - * Return true if this node's bounds have recently changed. This flag will - * be reset on the next call of validateFullBounds. - * - * @return true if this node's bounds have changed. - */ - protected boolean getBoundsChanged() { - return boundsChanged; - } + /** + * Return true if this node's bounds have recently changed. This flag will + * be reset on the next call of validateFullBounds. + * + * @return true if this node's bounds have changed. + */ + protected boolean getBoundsChanged() { + return boundsChanged; + } - /** - * Set the bounds chnaged flag. This flag will be reset on the next call of - * validateFullBounds. - * - * @param boundsChanged - * true if this nodes bounds have changed. - */ - protected void setBoundsChanged(final boolean boundsChanged) { - this.boundsChanged = boundsChanged; - } + /** + * Set the bounds chnaged flag. This flag will be reset on the next call of + * validateFullBounds. + * + * @param boundsChanged true if this nodes bounds have changed. + */ + protected void setBoundsChanged(final boolean boundsChanged) { + this.boundsChanged = boundsChanged; + } - /** - * Return true if the full bounds of this node are invalid. This means that - * the full bounds of this node have changed and need to be recomputed. - * - * @return true if the full bounds of this node are invalid - */ - protected boolean getFullBoundsInvalid() { - return fullBoundsInvalid; - } + /** + * Return true if the full bounds of this node are invalid. This means that + * the full bounds of this node have changed and need to be recomputed. + * + * @return true if the full bounds of this node are invalid + */ + protected boolean getFullBoundsInvalid() { + return fullBoundsInvalid; + } - /** - * Set the full bounds invalid flag. This flag is set when the full bounds - * of this node need to be recomputed as is the case when this node is - * transformed or when one of this node's children changes geometry. - * - * @param fullBoundsInvalid - * true=invalid, false=valid - */ - protected void setFullBoundsInvalid(final boolean fullBoundsInvalid) { - this.fullBoundsInvalid = fullBoundsInvalid; - } + /** + * Set the full bounds invalid flag. This flag is set when the full bounds + * of this node need to be recomputed as is the case when this node is + * transformed or when one of this node's children changes geometry. + * + * @param fullBoundsInvalid true=invalid, false=valid + */ + protected void setFullBoundsInvalid(final boolean fullBoundsInvalid) { + this.fullBoundsInvalid = fullBoundsInvalid; + } - /** - * Return true if one of this node's descendants has invalid bounds. - * - * @return whether child bounds are invalid - */ - protected boolean getChildBoundsInvalid() { - return childBoundsInvalid; - } + /** + * Return true if one of this node's descendants has invalid bounds. + * + * @return whether child bounds are invalid + */ + protected boolean getChildBoundsInvalid() { + return childBoundsInvalid; + } - /** - * Set the flag indicating that one of this node's descendants has invalid - * bounds. - * - * @param childBoundsInvalid - * true=invalid, false=valid - */ - protected void setChildBoundsInvalid(final boolean childBoundsInvalid) { - this.childBoundsInvalid = childBoundsInvalid; - } + /** + * Set the flag indicating that one of this node's descendants has invalid + * bounds. + * + * @param childBoundsInvalid true=invalid, false=valid + */ + protected void setChildBoundsInvalid(final boolean childBoundsInvalid) { + this.childBoundsInvalid = childBoundsInvalid; + } - /** - * This method should be called when the bounds of this node are changed. It - * invalidates the full bounds of this node, and also notifies each of this - * nodes children that their parent's bounds have changed. As a result of - * this method getting called this nodes layoutChildren will be called. - */ - public void signalBoundsChanged() { - invalidateFullBounds(); - setBoundsChanged(true); - firePropertyChange(PROPERTY_CODE_BOUNDS, PROPERTY_BOUNDS, null, bounds); + /** + * This method should be called when the bounds of this node are changed. It + * invalidates the full bounds of this node, and also notifies each of this + * nodes children that their parent's bounds have changed. As a result of + * this method getting called this nodes layoutChildren will be called. + */ + public void signalBoundsChanged() { + invalidateFullBounds(); + setBoundsChanged(true); + firePropertyChange(PROPERTY_CODE_BOUNDS, PROPERTY_BOUNDS, null, bounds); - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - each.parentBoundsChanged(); - } - } + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + each.parentBoundsChanged(); + } + } - /** - * Invalidate this node's layout, so that later layoutChildren will get - * called. - */ - public void invalidateLayout() { - invalidateFullBounds(); - } + /** + * Invalidate this node's layout, so that later layoutChildren will get + * called. + */ + public void invalidateLayout() { + invalidateFullBounds(); + } - /** - * A notification that the bounds of this node's parent have changed. - */ - protected void parentBoundsChanged() { - } + /** + * A notification that the bounds of this node's parent have changed. + */ + protected void parentBoundsChanged() { + } - /** - * Invalidates the full bounds of this node, and sets the child bounds - * invalid flag on each of this node's ancestors. - */ - public void invalidateFullBounds() { - setFullBoundsInvalid(true); + /** + * Invalidates the full bounds of this node, and sets the child bounds + * invalid flag on each of this node's ancestors. + */ + public void invalidateFullBounds() { + setFullBoundsInvalid(true); - PNode n = parent; - while (n != null && !n.getChildBoundsInvalid()) { - n.setChildBoundsInvalid(true); - n = n.parent; - } + PNode n = parent; + while (n != null && !n.getChildBoundsInvalid()) { + n.setChildBoundsInvalid(true); + n = n.parent; + } - if (SCENE_GRAPH_DELEGATE != null) { - SCENE_GRAPH_DELEGATE.nodeFullBoundsInvalidated(this); - } - } + if (SCENE_GRAPH_DELEGATE != null) { + SCENE_GRAPH_DELEGATE.nodeFullBoundsInvalidated(this); + } + } - /** - * This method is called to validate the bounds of this node and all of its - * descendants. It returns true if this nodes bounds or the bounds of any of - * its descendants are marked as volatile. - * - * @return true if this node or any of its descendants have volatile bounds - */ - protected boolean validateFullBounds() { - final boolean boundsVolatile = getBoundsVolatile(); + /** + * This method is called to validate the bounds of this node and all of its + * descendants. It returns true if this nodes bounds or the bounds of any of + * its descendants are marked as volatile. + * + * @return true if this node or any of its descendants have volatile bounds + */ + protected boolean validateFullBounds() { + final boolean boundsVolatile = getBoundsVolatile(); - // 1. Only compute new bounds if invalid flags are set. - if (fullBoundsInvalid || childBoundsInvalid || boundsVolatile - || childBoundsVolatile) { + // 1. Only compute new bounds if invalid flags are set. + if (fullBoundsInvalid || childBoundsInvalid || boundsVolatile || childBoundsVolatile) { - // 2. If my bounds are volatile and they have not been changed then - // signal a change. - // - // For most cases this will do nothing, but if a nodes bounds depend - // on its model, then - // validate bounds has the responsibility of making the bounds match - // the models value. - // For example PPaths validateBounds method makes sure that the - // bounds are equal to the - // bounds of the GeneralPath model. - if (boundsVolatile && !boundsChanged) { - signalBoundsChanged(); - } + // 2. If my bounds are volatile and they have not been changed then + // signal a change. + // + // For most cases this will do nothing, but if a nodes bounds depend + // on its model, then + // validate bounds has the responsibility of making the bounds match + // the models value. + // For example PPaths validateBounds method makes sure that the + // bounds are equal to the + // bounds of the GeneralPath model. + if (boundsVolatile && !boundsChanged) { + signalBoundsChanged(); + } - // 3. If the bounds of on of my decendents are invalidate then - // validate the bounds of all of my children. - if (childBoundsInvalid || childBoundsVolatile) { - childBoundsVolatile = false; - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - childBoundsVolatile |= each.validateFullBounds(); - } - } + // 3. If the bounds of on of my decendents are invalidate then + // validate the bounds of all of my children. + if (childBoundsInvalid || childBoundsVolatile) { + childBoundsVolatile = false; + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + childBoundsVolatile |= each.validateFullBounds(); + } + } - // 4. Now that my children's bounds are valid and my own bounds are - // valid run any layout algorithm here. Note that if you try to - // layout volatile - // children piccolo will most likely start a "soft" infinite loop. - // It won't freeze - // your program, but it will make an infinite number of calls to - // SwingUtilities - // invoke later. You don't want to do that. - layoutChildren(); + // 4. Now that my children's bounds are valid and my own bounds are + // valid run any layout algorithm here. Note that if you try to + // layout volatile + // children piccolo will most likely start a "soft" infinite loop. + // It won't freeze + // your program, but it will make an infinite number of calls to + // SwingUtilities + // invoke later. You don't want to do that. + layoutChildren(); - // 5. If the full bounds cache is invalid then recompute the full - // bounds cache here after our own bounds and the children's bounds - // have been computed above. - if (fullBoundsInvalid) { - final double oldX = fullBoundsCache.x; - final double oldY = fullBoundsCache.y; - final double oldWidth = fullBoundsCache.width; - final double oldHeight = fullBoundsCache.height; - final boolean oldEmpty = fullBoundsCache.isEmpty(); + // 5. If the full bounds cache is invalid then recompute the full + // bounds cache here after our own bounds and the children's bounds + // have been computed above. + if (fullBoundsInvalid) { + final double oldX = fullBoundsCache.x; + final double oldY = fullBoundsCache.y; + final double oldWidth = fullBoundsCache.width; + final double oldHeight = fullBoundsCache.height; + final boolean oldEmpty = fullBoundsCache.isEmpty(); - // 6. This will call getFullBoundsReference on all of the - // children. So if the above - // layoutChildren method changed the bounds of any of the - // children they will be - // validated again here. - fullBoundsCache = computeFullBounds(fullBoundsCache); + // 6. This will call getFullBoundsReference on all of the + // children. So if the above + // layoutChildren method changed the bounds of any of the + // children they will be + // validated again here. + fullBoundsCache = computeFullBounds(fullBoundsCache); - final boolean fullBoundsChanged = fullBoundsCache.x != oldX - || fullBoundsCache.y != oldY - || fullBoundsCache.width != oldWidth - || fullBoundsCache.height != oldHeight - || fullBoundsCache.isEmpty() != oldEmpty; + final boolean fullBoundsChanged = fullBoundsCache.x != oldX || fullBoundsCache.y != oldY + || fullBoundsCache.width != oldWidth || fullBoundsCache.height != oldHeight + || fullBoundsCache.isEmpty() != oldEmpty; - // 7. If the new full bounds cache differs from the previous - // cache then - // tell our parent to invalidate their full bounds. This is how - // bounds changes - // deep in the tree percolate up. - if (fullBoundsChanged) { - if (parent != null) { - parent.invalidateFullBounds(); - } - firePropertyChange(PROPERTY_CODE_FULL_BOUNDS, - PROPERTY_FULL_BOUNDS, null, fullBoundsCache); + // 7. If the new full bounds cache differs from the previous + // cache then + // tell our parent to invalidate their full bounds. This is how + // bounds changes + // deep in the tree percolate up. + if (fullBoundsChanged) { + if (parent != null) { + parent.invalidateFullBounds(); + } + firePropertyChange(PROPERTY_CODE_FULL_BOUNDS, PROPERTY_FULL_BOUNDS, null, fullBoundsCache); - // 8. If our paint was invalid make sure to repaint our old - // full bounds. The - // new bounds will be computed later in the validatePaint - // pass. - if (paintInvalid && !oldEmpty) { - TEMP_REPAINT_BOUNDS.setRect(oldX, oldY, oldWidth, - oldHeight); - repaintFrom(TEMP_REPAINT_BOUNDS, this); - } - } - } + // 8. If our paint was invalid make sure to repaint our old + // full bounds. The + // new bounds will be computed later in the validatePaint + // pass. + if (paintInvalid && !oldEmpty) { + TEMP_REPAINT_BOUNDS.setRect(oldX, oldY, oldWidth, oldHeight); + repaintFrom(TEMP_REPAINT_BOUNDS, this); + } + } + } - // 9. Clear the invalid bounds flags. - boundsChanged = false; - fullBoundsInvalid = false; - childBoundsInvalid = false; - } + // 9. Clear the invalid bounds flags. + boundsChanged = false; + fullBoundsInvalid = false; + childBoundsInvalid = false; + } - return boundsVolatile || childBoundsVolatile; - } + return boundsVolatile || childBoundsVolatile; + } - /** - * Nodes that apply layout constraints to their children should override - * this method and do the layout there. - */ - protected void layoutChildren() { - } + /** + * Nodes that apply layout constraints to their children should override + * this method and do the layout there. + */ + protected void layoutChildren() { + } - // **************************************************************** - // Node Transform - Methods to manipulate the node's transform. - // - // Each node has a transform that is used to define the nodes - // local coordinate system. IE it is applied before picking and - // rendering the node. - // - // The usual way to move nodes about on the canvas is to manipulate - // this transform, as opposed to changing the bounds of the - // node. - // - // Since this transform defines the local coordinate system of this - // node the following methods with affect the global position both - // this node and all of its descendants. - // **************************************************************** + // **************************************************************** + // Node Transform - Methods to manipulate the node's transform. + // + // Each node has a transform that is used to define the nodes + // local coordinate system. IE it is applied before picking and + // rendering the node. + // + // The usual way to move nodes about on the canvas is to manipulate + // this transform, as opposed to changing the bounds of the + // node. + // + // Since this transform defines the local coordinate system of this + // node the following methods with affect the global position both + // this node and all of its descendants. + // **************************************************************** - /** - * Returns the rotation applied by this node's transform in radians. This - * rotation affects this node and all its descendants. The value returned - * will be between 0 and 2pi radians. - * - * @return rotation in radians. - */ - public double getRotation() { - if (transform == null) { - return 0; - } - return transform.getRotation(); - } + /** + * Returns the rotation applied by this node's transform in radians. This + * rotation affects this node and all its descendants. The value returned + * will be between 0 and 2pi radians. + * + * @return rotation in radians. + */ + public double getRotation() { + if (transform == null) { + return 0; + } + return transform.getRotation(); + } - /** - * Sets the rotation of this nodes transform in radians. This will affect - * this node and all its descendents. - * - * @param theta - * rotation in radians - */ - public void setRotation(final double theta) { - rotate(theta - getRotation()); - } + /** + * Sets the rotation of this nodes transform in radians. This will affect + * this node and all its descendents. + * + * @param theta rotation in radians + */ + public void setRotation(final double theta) { + rotate(theta - getRotation()); + } - /** - * Rotates this node by theta (in radians) about the 0,0 point. This will - * affect this node and all its descendants. - * - * @param theta - * the amount to rotate by in radians - */ - public void rotate(final double theta) { - rotateAboutPoint(theta, 0, 0); - } + /** + * Rotates this node by theta (in radians) about the 0,0 point. This will + * affect this node and all its descendants. + * + * @param theta the amount to rotate by in radians + */ + public void rotate(final double theta) { + rotateAboutPoint(theta, 0, 0); + } - /** - * Rotates this node by theta (in radians), and then translates the node so - * that the x, y position of its fullBounds stays constant. - * - * @param theta - * the amount to rotate by in radians - */ - public void rotateInPlace(final double theta) { - PBounds b = getFullBoundsReference(); - final double px = b.x; - final double py = b.y; - rotateAboutPoint(theta, 0, 0); - b = getFullBoundsReference(); - offset(px - b.x, py - b.y); - } + /** + * Rotates this node by theta (in radians), and then translates the node so + * that the x, y position of its fullBounds stays constant. + * + * @param theta the amount to rotate by in radians + */ + public void rotateInPlace(final double theta) { + PBounds b = getFullBoundsReference(); + final double px = b.x; + final double py = b.y; + rotateAboutPoint(theta, 0, 0); + b = getFullBoundsReference(); + offset(px - b.x, py - b.y); + } - /** - * Rotates this node by theta (in radians) about the given point. This will - * affect this node and all its descendants. - * - * @param theta - * the amount to rotate by in radians - * @param point - * the point about which to rotate - */ - public void rotateAboutPoint(final double theta, final Point2D point) { - rotateAboutPoint(theta, point.getX(), point.getY()); - } + /** + * Rotates this node by theta (in radians) about the given point. This will + * affect this node and all its descendants. + * + * @param theta the amount to rotate by in radians + * @param point the point about which to rotate + */ + public void rotateAboutPoint(final double theta, final Point2D point) { + rotateAboutPoint(theta, point.getX(), point.getY()); + } - /** - * Rotates this node by theta (in radians) about the given point. This will - * affect this node and all its descendants. - * - * @param theta - * the amount to rotate by in radians - * @param x - * the x coordinate of the point around which to rotate - * @param y - * the y coordinate of the point around which to rotate - */ - public void rotateAboutPoint(final double theta, final double x, - final double y) { - getTransformReference(true).rotate(theta, x, y); - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - transform); - } + /** + * Rotates this node by theta (in radians) about the given point. This will + * affect this node and all its descendants. + * + * @param theta the amount to rotate by in radians + * @param x the x coordinate of the point around which to rotate + * @param y the y coordinate of the point around which to rotate + */ + public void rotateAboutPoint(final double theta, final double x, final double y) { + getTransformReference(true).rotate(theta, x, y); + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, transform); + } - /** - * Return the total amount of rotation applied to this node by its own - * transform together with the transforms of all its ancestors. The value - * returned will be between 0 and 2pi radians. - * - * @return the total amount of rotation applied to this node in radians - */ - public double getGlobalRotation() { - return getLocalToGlobalTransform(null).getRotation(); - } + /** + * Return the total amount of rotation applied to this node by its own + * transform together with the transforms of all its ancestors. The value + * returned will be between 0 and 2pi radians. + * + * @return the total amount of rotation applied to this node in radians + */ + public double getGlobalRotation() { + return getLocalToGlobalTransform(null).getRotation(); + } - /** - * Set the global rotation (in radians) of this node. This is implemented by - * rotating this nodes transform the required amount so that the nodes - * global rotation is as requested. - * - * @param theta - * the amount to rotate by in radians relative to the global - * coordinate system. - */ - public void setGlobalRotation(final double theta) { - if (parent != null) { - setRotation(theta - parent.getGlobalRotation()); - } else { - setRotation(theta); - } - } + /** + * Set the global rotation (in radians) of this node. This is implemented by + * rotating this nodes transform the required amount so that the nodes + * global rotation is as requested. + * + * @param theta the amount to rotate by in radians relative to the global + * coordinate system. + */ + public void setGlobalRotation(final double theta) { + if (parent != null) { + setRotation(theta - parent.getGlobalRotation()); + } + else { + setRotation(theta); + } + } - /** - * Return the scale applied by this node's transform. The scale is effecting - * this node and all its descendants. - * - * @return scale applied by this nodes transform. - */ - public double getScale() { - if (transform == null) { - return 1; - } - return transform.getScale(); - } + /** + * Return the scale applied by this node's transform. The scale is effecting + * this node and all its descendants. + * + * @return scale applied by this nodes transform. + */ + public double getScale() { + if (transform == null) { + return 1; + } + return transform.getScale(); + } - /** - * Set the scale of this node's transform. The scale will affect this node - * and all its descendants. - * - * @param scale - * the scale to set the transform to - */ - public void setScale(final double scale) { - if (scale == 0) { - throw new RuntimeException("Can't set scale to 0"); - } - scale(scale / getScale()); - } + /** + * Set the scale of this node's transform. The scale will affect this node + * and all its descendants. + * + * @param scale the scale to set the transform to + */ + public void setScale(final double scale) { + if (scale == 0) { + throw new RuntimeException("Can't set scale to 0"); + } + scale(scale / getScale()); + } - /** - * Scale this nodes transform by the given amount. This will affect this - * node and all of its descendants. - * - * @param scale - * the amount to scale by - */ - public void scale(final double scale) { - scaleAboutPoint(scale, 0, 0); - } + /** + * Scale this nodes transform by the given amount. This will affect this + * node and all of its descendants. + * + * @param scale the amount to scale by + */ + public void scale(final double scale) { + scaleAboutPoint(scale, 0, 0); + } - /** - * Scale this nodes transform by the given amount about the specified point. - * This will affect this node and all of its descendants. - * - * @param scale - * the amount to scale by - * @param point - * the point to scale about - */ - public void scaleAboutPoint(final double scale, final Point2D point) { - scaleAboutPoint(scale, point.getX(), point.getY()); - } + /** + * Scale this nodes transform by the given amount about the specified point. + * This will affect this node and all of its descendants. + * + * @param scale the amount to scale by + * @param point the point to scale about + */ + public void scaleAboutPoint(final double scale, final Point2D point) { + scaleAboutPoint(scale, point.getX(), point.getY()); + } - /** - * Scale this nodes transform by the given amount about the specified point. - * This will affect this node and all of its descendants. - * - * @param scale - * the amount to scale by - * @param x - * the x coordinate of the point around which to scale - * @param y - * the y coordinate of the point around which to scale - */ - public void scaleAboutPoint(final double scale, final double x, - final double y) { - getTransformReference(true).scaleAboutPoint(scale, x, y); - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - transform); - } + /** + * Scale this nodes transform by the given amount about the specified point. + * This will affect this node and all of its descendants. + * + * @param scale the amount to scale by + * @param x the x coordinate of the point around which to scale + * @param y the y coordinate of the point around which to scale + */ + public void scaleAboutPoint(final double scale, final double x, final double y) { + getTransformReference(true).scaleAboutPoint(scale, x, y); + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, transform); + } - /** - * Return the global scale that is being applied to this node by its - * transform together with the transforms of all its ancestors. - * - * @return global scale of this node - */ - public double getGlobalScale() { - return getLocalToGlobalTransform(null).getScale(); - } + /** + * Return the global scale that is being applied to this node by its + * transform together with the transforms of all its ancestors. + * + * @return global scale of this node + */ + public double getGlobalScale() { + return getLocalToGlobalTransform(null).getScale(); + } - /** - * Set the global scale of this node. This is implemented by scaling this - * nodes transform the required amount so that the nodes global scale is as - * requested. - * - * @param scale - * the desired global scale - */ - public void setGlobalScale(final double scale) { - if (parent != null) { - setScale(scale / parent.getGlobalScale()); - } else { - setScale(scale); - } - } + /** + * Set the global scale of this node. This is implemented by scaling this + * nodes transform the required amount so that the nodes global scale is as + * requested. + * + * @param scale the desired global scale + */ + public void setGlobalScale(final double scale) { + if (parent != null) { + setScale(scale / parent.getGlobalScale()); + } + else { + setScale(scale); + } + } - /** - * Returns the x offset of this node as applied by its transform. - * - * @return x offset of this node as applied by its transform - */ - public double getXOffset() { - if (transform == null) { - return 0; - } - return transform.getTranslateX(); - } + /** + * Returns the x offset of this node as applied by its transform. + * + * @return x offset of this node as applied by its transform + */ + public double getXOffset() { + if (transform == null) { + return 0; + } + return transform.getTranslateX(); + } - /** - * Returns the y offset of this node as applied by its transform. - * - * @return y offset of this node as applied by its transform - */ - public double getYOffset() { - if (transform == null) { - return 0; - } - return transform.getTranslateY(); - } + /** + * Returns the y offset of this node as applied by its transform. + * + * @return y offset of this node as applied by its transform + */ + public double getYOffset() { + if (transform == null) { + return 0; + } + return transform.getTranslateY(); + } - /** - * Return the offset that is being applied to this node by its transform. - * This offset effects this node and all of its descendants and is specified - * in the parent coordinate system. This returns the values that are in the - * m02 and m12 positions in the affine transform. - * - * @return a point representing the x and y offset - */ - public Point2D getOffset() { - if (transform == null) { - return new Point2D.Double(); - } - return new Point2D.Double(transform.getTranslateX(), transform - .getTranslateY()); - } + /** + * Return the offset that is being applied to this node by its transform. + * This offset effects this node and all of its descendants and is specified + * in the parent coordinate system. This returns the values that are in the + * m02 and m12 positions in the affine transform. + * + * @return a point representing the x and y offset + */ + public Point2D getOffset() { + if (transform == null) { + return new Point2D.Double(); + } + return new Point2D.Double(transform.getTranslateX(), transform.getTranslateY()); + } - /** - * Set the offset that is being applied to this node by its transform. This - * offset effects this node and all of its descendants and is specified in - * the nodes parent coordinate system. This directly sets the values of the - * m02 and m12 positions in the affine transform. Unlike "PNode.translate()" - * it is not effected by the transforms scale. - * - * @param point - * value of new offset - */ - public void setOffset(final Point2D point) { - setOffset(point.getX(), point.getY()); - } + /** + * Set the offset that is being applied to this node by its transform. This + * offset effects this node and all of its descendants and is specified in + * the nodes parent coordinate system. This directly sets the values of the + * m02 and m12 positions in the affine transform. Unlike "PNode.translate()" + * it is not effected by the transforms scale. + * + * @param point value of new offset + */ + public void setOffset(final Point2D point) { + setOffset(point.getX(), point.getY()); + } - /** - * Set the offset that is being applied to this node by its transform. This - * offset effects this node and all of its descendants and is specified in - * the nodes parent coordinate system. This directly sets the values of the - * m02 and m12 positions in the affine transform. Unlike "PNode.translate()" - * it is not effected by the transforms scale. - * - * @param x - * amount of x offset - * @param y - * amount of y offset - */ - public void setOffset(final double x, final double y) { - getTransformReference(true).setOffset(x, y); - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - transform); - } + /** + * Set the offset that is being applied to this node by its transform. This + * offset effects this node and all of its descendants and is specified in + * the nodes parent coordinate system. This directly sets the values of the + * m02 and m12 positions in the affine transform. Unlike "PNode.translate()" + * it is not effected by the transforms scale. + * + * @param x amount of x offset + * @param y amount of y offset + */ + public void setOffset(final double x, final double y) { + getTransformReference(true).setOffset(x, y); + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, transform); + } - /** - * Offset this node relative to the parents coordinate system, and is NOT - * effected by this nodes current scale or rotation. This is implemented by - * directly adding dx to the m02 position and dy to the m12 position in the - * affine transform. - * - * @param dx - * amount to add to this nodes current x Offset - * @param dy - * amount to add to this nodes current y Offset - */ - public void offset(final double dx, final double dy) { - getTransformReference(true); - setOffset(transform.getTranslateX() + dx, transform.getTranslateY() - + dy); - } + /** + * Offset this node relative to the parents coordinate system, and is NOT + * effected by this nodes current scale or rotation. This is implemented by + * directly adding dx to the m02 position and dy to the m12 position in the + * affine transform. + * + * @param dx amount to add to this nodes current x Offset + * @param dy amount to add to this nodes current y Offset + */ + public void offset(final double dx, final double dy) { + getTransformReference(true); + setOffset(transform.getTranslateX() + dx, transform.getTranslateY() + dy); + } - /** - * Translate this node's transform by the given amount, using the standard - * affine transform translate method. This translation effects this node and - * all of its descendants. - * - * @param dx - * amount to add to this nodes current x translation - * @param dy - * amount to add to this nodes current y translation - */ - public void translate(final double dx, final double dy) { - getTransformReference(true).translate(dx, dy); - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - transform); - } + /** + * Translate this node's transform by the given amount, using the standard + * affine transform translate method. This translation effects this node and + * all of its descendants. + * + * @param dx amount to add to this nodes current x translation + * @param dy amount to add to this nodes current y translation + */ + public void translate(final double dx, final double dy) { + getTransformReference(true).translate(dx, dy); + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, transform); + } - /** - * Return the global translation that is being applied to this node by its - * transform together with the transforms of all its ancestors. - * - * @return the global translation applied to this node - */ - public Point2D getGlobalTranslation() { - final Point2D p = getOffset(); - if (parent != null) { - parent.localToGlobal(p); - } - return p; - } + /** + * Return the global translation that is being applied to this node by its + * transform together with the transforms of all its ancestors. + * + * @return the global translation applied to this node + */ + public Point2D getGlobalTranslation() { + final Point2D p = getOffset(); + if (parent != null) { + parent.localToGlobal(p); + } + return p; + } - /** - * Set the global translation of this node. This is implemented by - * translating this nodes transform the required amount so that the nodes - * global scale is as requested. - * - * @param globalPoint - * the desired global translation - */ - public void setGlobalTranslation(final Point2D globalPoint) { - if (parent != null) { - parent.getGlobalToLocalTransform(null).transform(globalPoint, - globalPoint); - } - setOffset(globalPoint); - } + /** + * Set the global translation of this node. This is implemented by + * translating this nodes transform the required amount so that the nodes + * global scale is as requested. + * + * @param globalPoint the desired global translation + */ + public void setGlobalTranslation(final Point2D globalPoint) { + if (parent != null) { + parent.getGlobalToLocalTransform(null).transform(globalPoint, globalPoint); + } + setOffset(globalPoint); + } - /** - * Transform this nodes transform by the given transform. - * - * @param aTransform - * the transform to apply. - */ - public void transformBy(final AffineTransform aTransform) { - getTransformReference(true).concatenate(aTransform); - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - transform); - } + /** + * Transform this nodes transform by the given transform. + * + * @param aTransform the transform to apply. + */ + public void transformBy(final AffineTransform aTransform) { + getTransformReference(true).concatenate(aTransform); + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, transform); + } - /** - * Linearly interpolates between a and b, based on t. Specifically, it - * computes lerp(a, b, t) = a + t*(b - a). This produces a result that - * changes from a (when t = 0) to b (when t = 1). - * - * @param t - * variable 'time' parameter - * @param a - * from point - * @param b - * to Point - * - * @return linear interpolation between and b at time interval t (given as # - * between 0f and 1f) - */ - public static double lerp(final double t, final double a, final double b) { - return a + t * (b - a); - } + /** + * Linearly interpolates between a and b, based on t. Specifically, it + * computes lerp(a, b, t) = a + t*(b - a). This produces a result that + * changes from a (when t = 0) to b (when t = 1). + * + * @param t variable 'time' parameter + * @param a from point + * @param b to Point + * + * @return linear interpolation between and b at time interval t (given as # + * between 0f and 1f) + */ + public static double lerp(final double t, final double a, final double b) { + return a + t * (b - a); + } - /** - * This will calculate the necessary transform in order to make this node - * appear at a particular position relative to the specified bounding box. - * The source point specifies a point in the unit square (0, 0) - (1, 1) - * that represents an anchor point on the corresponding node to this - * transform. The destination point specifies an anchor point on the - * reference node. The position method then computes the transform that - * results in transforming this node so that the source anchor point - * coincides with the reference anchor point. This can be useful for layout - * algorithms as it is straightforward to position one object relative to - * another. - *

- * For example, If you have two nodes, A and B, and you call - * - *

-	 * Point2D srcPt = new Point2D.Double(1.0, 0.0);
-	 * Point2D destPt = new Point2D.Double(0.0, 0.0);
-	 * A.position(srcPt, destPt, B.getGlobalBounds(), 750, null);
-	 * 
- * - * The result is that A will move so that its upper-right corner is at the - * same place as the upper-left corner of B, and the transition will be - * smoothly animated over a period of 750 milliseconds. - * - * @since 1.3 - * @param srcPt - * The anchor point on this transform's node (normalized to a - * unit square) - * @param destPt - * The anchor point on destination bounds (normalized to a unit - * square) - * @param destBounds - * The bounds (in global coordinates) used to calculate this - * transform's node - * @param millis - * Number of milliseconds over which to perform the animation - * - * @return newly scheduled activity or node if activity could not be - * scheduled - */ - public PActivity animateToRelativePosition(final Point2D srcPt, - final Point2D destPt, final Rectangle2D destBounds, final int millis) { - double srcx, srcy; - double destx, desty; - double dx, dy; - Point2D pt1, pt2; + /** + * This will calculate the necessary transform in order to make this node + * appear at a particular position relative to the specified bounding box. + * The source point specifies a point in the unit square (0, 0) - (1, 1) + * that represents an anchor point on the corresponding node to this + * transform. The destination point specifies an anchor point on the + * reference node. The position method then computes the transform that + * results in transforming this node so that the source anchor point + * coincides with the reference anchor point. This can be useful for layout + * algorithms as it is straightforward to position one object relative to + * another. + *

+ * For example, If you have two nodes, A and B, and you call + * + *

+     * Point2D srcPt = new Point2D.Double(1.0, 0.0);
+     * Point2D destPt = new Point2D.Double(0.0, 0.0);
+     * A.position(srcPt, destPt, B.getGlobalBounds(), 750, null);
+     * 
+ * + * The result is that A will move so that its upper-right corner is at the + * same place as the upper-left corner of B, and the transition will be + * smoothly animated over a period of 750 milliseconds. + * + * @since 1.3 + * @param srcPt The anchor point on this transform's node (normalized to a + * unit square) + * @param destPt The anchor point on destination bounds (normalized to a + * unit square) + * @param destBounds The bounds (in global coordinates) used to calculate + * this transform's node + * @param millis Number of milliseconds over which to perform the animation + * + * @return newly scheduled activity or node if activity could not be + * scheduled + */ + public PActivity animateToRelativePosition(final Point2D srcPt, final Point2D destPt, final Rectangle2D destBounds, + final int millis) { + double srcx, srcy; + double destx, desty; + double dx, dy; + Point2D pt1, pt2; - if (parent == null) { - return null; - } else { - // First compute translation amount in global coordinates - final Rectangle2D srcBounds = getGlobalFullBounds(); - srcx = lerp(srcPt.getX(), srcBounds.getX(), srcBounds.getX() - + srcBounds.getWidth()); - srcy = lerp(srcPt.getY(), srcBounds.getY(), srcBounds.getY() - + srcBounds.getHeight()); - destx = lerp(destPt.getX(), destBounds.getX(), destBounds.getX() - + destBounds.getWidth()); - desty = lerp(destPt.getY(), destBounds.getY(), destBounds.getY() - + destBounds.getHeight()); + if (parent == null) { + return null; + } + else { + // First compute translation amount in global coordinates + final Rectangle2D srcBounds = getGlobalFullBounds(); + srcx = lerp(srcPt.getX(), srcBounds.getX(), srcBounds.getX() + srcBounds.getWidth()); + srcy = lerp(srcPt.getY(), srcBounds.getY(), srcBounds.getY() + srcBounds.getHeight()); + destx = lerp(destPt.getX(), destBounds.getX(), destBounds.getX() + destBounds.getWidth()); + desty = lerp(destPt.getY(), destBounds.getY(), destBounds.getY() + destBounds.getHeight()); - // Convert vector to local coordinates - pt1 = new Point2D.Double(srcx, srcy); - globalToLocal(pt1); - pt2 = new Point2D.Double(destx, desty); - globalToLocal(pt2); - dx = pt2.getX() - pt1.getX(); - dy = pt2.getY() - pt1.getY(); + // Convert vector to local coordinates + pt1 = new Point2D.Double(srcx, srcy); + globalToLocal(pt1); + pt2 = new Point2D.Double(destx, desty); + globalToLocal(pt2); + dx = pt2.getX() - pt1.getX(); + dy = pt2.getY() - pt1.getY(); - // Finally, animate change - final PAffineTransform at = new PAffineTransform( - getTransformReference(true)); - at.translate(dx, dy); - return animateToTransform(at, millis); - } - } + // Finally, animate change + final PAffineTransform at = new PAffineTransform(getTransformReference(true)); + at.translate(dx, dy); + return animateToTransform(at, millis); + } + } - /** - * @deprecated in favor of animateToRelativePosition - * - * It will calculate the necessary transform in order to make - * this node appear at a particular position relative to the - * specified bounding box. The source point specifies a point in - * the unit square (0, 0) - (1, 1) that represents an anchor - * point on the corresponding node to this transform. The - * destination point specifies an anchor point on the reference - * node. The position method then computes the transform that - * results in transforming this node so that the source anchor - * point coincides with the reference anchor point. This can be - * useful for layout algorithms as it is straightforward to - * position one object relative to another. - *

- * For example, If you have two nodes, A and B, and you call - * - *

-	 * Point2D srcPt = new Point2D.Double(1.0, 0.0);
-	 * Point2D destPt = new Point2D.Double(0.0, 0.0);
-	 * A.position(srcPt, destPt, B.getGlobalBounds(), 750, null);
-	 * 
- * - * The result is that A will move so that its upper-right corner - * is at the same place as the upper-left corner of B, and the - * transition will be smoothly animated over a period of 750 - * milliseconds. - * - * @param srcPt - * The anchor point on this transform's node (normalized to a - * unit square) - * @param destPt - * The anchor point on destination bounds (normalized to a unit - * square) - * @param destBounds - * The bounds (in global coordinates) used to calculate this - * transform's node - * @param millis - * Number of milliseconds over which to perform the animation - */ - public void position(final Point2D srcPt, final Point2D destPt, - final Rectangle2D destBounds, final int millis) { - animateToRelativePosition(srcPt, destPt, destBounds, millis); - }; + /** + * @deprecated in favor of animateToRelativePosition + * + * It will calculate the necessary transform in order to make + * this node appear at a particular position relative to the + * specified bounding box. The source point specifies a point in + * the unit square (0, 0) - (1, 1) that represents an anchor + * point on the corresponding node to this transform. The + * destination point specifies an anchor point on the reference + * node. The position method then computes the transform that + * results in transforming this node so that the source anchor + * point coincides with the reference anchor point. This can be + * useful for layout algorithms as it is straightforward to + * position one object relative to another. + *

+ * For example, If you have two nodes, A and B, and you call + * + *

+     * Point2D srcPt = new Point2D.Double(1.0, 0.0);
+     * Point2D destPt = new Point2D.Double(0.0, 0.0);
+     * A.position(srcPt, destPt, B.getGlobalBounds(), 750, null);
+     * 
+ * + * The result is that A will move so that its upper-right corner + * is at the same place as the upper-left corner of B, and the + * transition will be smoothly animated over a period of 750 + * milliseconds. + * + * @param srcPt The anchor point on this transform's node (normalized to a + * unit square) + * @param destPt The anchor point on destination bounds (normalized to a + * unit square) + * @param destBounds The bounds (in global coordinates) used to calculate + * this transform's node + * @param millis Number of milliseconds over which to perform the animation + */ + public void position(final Point2D srcPt, final Point2D destPt, final Rectangle2D destBounds, final int millis) { + animateToRelativePosition(srcPt, destPt, destBounds, millis); + }; - /** - * Return a copy of the transform associated with this node. - * - * @return copy of this node's transform - */ - public PAffineTransform getTransform() { - if (transform == null) { - return new PAffineTransform(); - } else { - return (PAffineTransform) transform.clone(); - } - } + /** + * Return a copy of the transform associated with this node. + * + * @return copy of this node's transform + */ + public PAffineTransform getTransform() { + if (transform == null) { + return new PAffineTransform(); + } + else { + return (PAffineTransform) transform.clone(); + } + } - /** - * Return a reference to the transform associated with this node. This - * returned transform should not be modified. PNode transforms are created - * lazily when needed. If you access the transform reference before the - * transform has been created it may return null. The - * createNewTransformIfNull parameter is used to specify that the PNode - * should create a new transform (and assign that transform to the nodes - * local transform variable) instead of returning null. - * - * @param createNewTransformIfNull - * if the transform has not been initialised, should it be? - * - * @return reference to this node's transform - */ - public PAffineTransform getTransformReference( - final boolean createNewTransformIfNull) { - if (transform == null && createNewTransformIfNull) { - transform = new PAffineTransform(); - } - return transform; - } + /** + * Return a reference to the transform associated with this node. This + * returned transform should not be modified. PNode transforms are created + * lazily when needed. If you access the transform reference before the + * transform has been created it may return null. The + * createNewTransformIfNull parameter is used to specify that the PNode + * should create a new transform (and assign that transform to the nodes + * local transform variable) instead of returning null. + * + * @param createNewTransformIfNull if the transform has not been + * initialised, should it be? + * + * @return reference to this node's transform + */ + public PAffineTransform getTransformReference(final boolean createNewTransformIfNull) { + if (transform == null && createNewTransformIfNull) { + transform = new PAffineTransform(); + } + return transform; + } - /** - * Return an inverted copy of the transform associated with this node. - * - * @return inverted copy of this node's transform - */ - public PAffineTransform getInverseTransform() { - if (transform == null) { - return new PAffineTransform(); - } + /** + * Return an inverted copy of the transform associated with this node. + * + * @return inverted copy of this node's transform + */ + public PAffineTransform getInverseTransform() { + if (transform == null) { + return new PAffineTransform(); + } - try { - return new PAffineTransform(transform.createInverse()); - } catch (final NoninvertibleTransformException e) { - throw new PAffineTransformException(e, transform); - } - } + try { + return new PAffineTransform(transform.createInverse()); + } + catch (final NoninvertibleTransformException e) { + throw new PAffineTransformException(e, transform); + } + } - /** - * Set the transform applied to this node. - * - * @param transform - * the new transform value - */ - public void setTransform(final AffineTransform transform) { - if (transform == null) { - this.transform = null; - } else { - getTransformReference(true).setTransform(transform); - } + /** + * Set the transform applied to this node. + * + * @param transform the new transform value + */ + public void setTransform(final AffineTransform transform) { + if (transform == null) { + this.transform = null; + } + else { + getTransformReference(true).setTransform(transform); + } - invalidatePaint(); - invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, - this.transform); - } + invalidatePaint(); + invalidateFullBounds(); + firePropertyChange(PROPERTY_CODE_TRANSFORM, PROPERTY_TRANSFORM, null, this.transform); + } - // **************************************************************** - // Paint Damage Management - Methods used to invalidate the areas of - // the screen that this node appears in so that they will later get - // painted. - // - // Generally you will not need to call these invalidate methods - // when starting out with Piccolo2d because methods such as setPaint - // already automatically call them for you. You will need to call - // them when you start creating your own nodes. - // - // When you do create you own nodes the only method that you will - // normally need to call is invalidatePaint. This method marks the - // nodes as having invalid paint, the root node's UI cycle will then - // later discover this damage and report it to the Java repaint manager. - // - // Repainting is normally done with PNode.invalidatePaint() instead of - // directly calling PNode.repaint() because PNode.repaint() requires - // the nodes bounds to be computed right away. But with invalidatePaint - // the bounds computation can be delayed until the end of the root's UI - // cycle, and this can add up to a bit savings when modifying a - // large number of nodes all at once. - // - // The other methods here will rarely be called except internally - // from the framework. - // **************************************************************** + // **************************************************************** + // Paint Damage Management - Methods used to invalidate the areas of + // the screen that this node appears in so that they will later get + // painted. + // + // Generally you will not need to call these invalidate methods + // when starting out with Piccolo2d because methods such as setPaint + // already automatically call them for you. You will need to call + // them when you start creating your own nodes. + // + // When you do create you own nodes the only method that you will + // normally need to call is invalidatePaint. This method marks the + // nodes as having invalid paint, the root node's UI cycle will then + // later discover this damage and report it to the Java repaint manager. + // + // Repainting is normally done with PNode.invalidatePaint() instead of + // directly calling PNode.repaint() because PNode.repaint() requires + // the nodes bounds to be computed right away. But with invalidatePaint + // the bounds computation can be delayed until the end of the root's UI + // cycle, and this can add up to a bit savings when modifying a + // large number of nodes all at once. + // + // The other methods here will rarely be called except internally + // from the framework. + // **************************************************************** - /** - * Return true if this nodes paint is invalid, in which case the node needs - * to be repainted. - * - * @return true if this node needs to be repainted - */ - public boolean getPaintInvalid() { - return paintInvalid; - } + /** + * Return true if this nodes paint is invalid, in which case the node needs + * to be repainted. + * + * @return true if this node needs to be repainted + */ + public boolean getPaintInvalid() { + return paintInvalid; + } - /** - * Mark this node as having invalid paint. If this is set the node will - * later be repainted. Node this method is most often used internally. - * - * @param paintInvalid - * true if this node should be repainted - */ - public void setPaintInvalid(final boolean paintInvalid) { - this.paintInvalid = paintInvalid; - } + /** + * Mark this node as having invalid paint. If this is set the node will + * later be repainted. Node this method is most often used internally. + * + * @param paintInvalid true if this node should be repainted + */ + public void setPaintInvalid(final boolean paintInvalid) { + this.paintInvalid = paintInvalid; + } - /** - * Return true if this node has a child with invalid paint. - * - * @return true if this node has a child with invalid paint - */ - public boolean getChildPaintInvalid() { - return childPaintInvalid; - } + /** + * Return true if this node has a child with invalid paint. + * + * @return true if this node has a child with invalid paint + */ + public boolean getChildPaintInvalid() { + return childPaintInvalid; + } - /** - * Mark this node as having a child with invalid paint. - * - * @param childPaintInvalid - * true if this node has a child with invalid paint - */ - public void setChildPaintInvalid(final boolean childPaintInvalid) { - this.childPaintInvalid = childPaintInvalid; - } + /** + * Mark this node as having a child with invalid paint. + * + * @param childPaintInvalid true if this node has a child with invalid paint + */ + public void setChildPaintInvalid(final boolean childPaintInvalid) { + this.childPaintInvalid = childPaintInvalid; + } - /** - * Invalidate this node's paint, and mark all of its ancestors as having a - * node with invalid paint. - */ - public void invalidatePaint() { - setPaintInvalid(true); + /** + * Invalidate this node's paint, and mark all of its ancestors as having a + * node with invalid paint. + */ + public void invalidatePaint() { + setPaintInvalid(true); - PNode n = parent; - while (n != null && !n.getChildPaintInvalid()) { - n.setChildPaintInvalid(true); - n = n.parent; - } + PNode n = parent; + while (n != null && !n.getChildPaintInvalid()) { + n.setChildPaintInvalid(true); + n = n.parent; + } - if (SCENE_GRAPH_DELEGATE != null) { - SCENE_GRAPH_DELEGATE.nodePaintInvalidated(this); - } - } + if (SCENE_GRAPH_DELEGATE != null) { + SCENE_GRAPH_DELEGATE.nodePaintInvalidated(this); + } + } - /** - * Repaint this node and any of its descendants if they have invalid paint. - */ - public void validateFullPaint() { - if (getPaintInvalid()) { - repaint(); - setPaintInvalid(false); - } + /** + * Repaint this node and any of its descendants if they have invalid paint. + */ + public void validateFullPaint() { + if (getPaintInvalid()) { + repaint(); + setPaintInvalid(false); + } - if (getChildPaintInvalid()) { - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - each.validateFullPaint(); - } - setChildPaintInvalid(false); - } - } + if (getChildPaintInvalid()) { + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + each.validateFullPaint(); + } + setChildPaintInvalid(false); + } + } - /** - * Mark the area on the screen represented by this nodes full bounds as - * needing a repaint. - */ - public void repaint() { - TEMP_REPAINT_BOUNDS.setRect(getFullBoundsReference()); - repaintFrom(TEMP_REPAINT_BOUNDS, this); - } + /** + * Mark the area on the screen represented by this nodes full bounds as + * needing a repaint. + */ + public void repaint() { + TEMP_REPAINT_BOUNDS.setRect(getFullBoundsReference()); + repaintFrom(TEMP_REPAINT_BOUNDS, this); + } - /** - * Pass the given repaint request up the tree, so that any cameras can - * invalidate that region on their associated canvas. - * - * @param localBounds - * the bounds to repaint - * @param childOrThis - * if childOrThis does not equal this then this nodes transform - * will be applied to the localBounds param - */ - public void repaintFrom(final PBounds localBounds, final PNode childOrThis) { - if (parent != null) { - if (childOrThis != this) { - localToParent(localBounds); - } else if (!getVisible()) { - return; - } - parent.repaintFrom(localBounds, this); - } - } + /** + * Pass the given repaint request up the tree, so that any cameras can + * invalidate that region on their associated canvas. + * + * @param localBounds the bounds to repaint + * @param childOrThis if childOrThis does not equal this then this nodes + * transform will be applied to the localBounds param + */ + public void repaintFrom(final PBounds localBounds, final PNode childOrThis) { + if (parent != null) { + if (childOrThis != this) { + localToParent(localBounds); + } + else if (!getVisible()) { + return; + } + parent.repaintFrom(localBounds, this); + } + } - // **************************************************************** - // Occluding - Methods to support occluding optimisation. Not yet - // complete. - // **************************************************************** + // **************************************************************** + // Occluding - Methods to support occluding optimisation. Not yet + // complete. + // **************************************************************** - /** - * Returns whether this node is Opaque. - * - * @param boundary - * boundary to check and see if this node covers completely. - * - * @return true if opaque - */ - public boolean isOpaque(final Rectangle2D boundary) { - return false; - } + /** + * Returns whether this node is Opaque. + * + * @param boundary boundary to check and see if this node covers completely. + * + * @return true if opaque + */ + public boolean isOpaque(final Rectangle2D boundary) { + return false; + } - /** - * Returns whether this node has been flagged as occluded. - * - * @return true if occluded - */ - public boolean getOccluded() { - return occluded; - } + /** + * Returns whether this node has been flagged as occluded. + * + * @return true if occluded + */ + public boolean getOccluded() { + return occluded; + } - /** - * Flags this node as occluded. - * - * @param occluded - * new value for occluded - */ - public void setOccluded(final boolean occluded) { - this.occluded = occluded; - } + /** + * Flags this node as occluded. + * + * @param occluded new value for occluded + */ + public void setOccluded(final boolean occluded) { + this.occluded = occluded; + } - // **************************************************************** - // Painting - Methods for painting this node and its children - // - // Painting is how a node defines its visual representation on the - // screen, and is done in the local coordinate system of the node. - // - // The default painting behavior is to first paint the node, and - // then paint the node's children on top of the node. If a node - // needs wants specialised painting behavior it can override: - // - // paint() - Painting here will happen before the children - // are painted, so the children will be painted on top of painting done - // here. - // paintAfterChildren() - Painting here will happen after the children - // are painted, so it will paint on top of them. - // - // Note that you should not normally need to override fullPaint(). - // - // The visible flag can be used to make a node invisible so that - // it will never get painted. - // **************************************************************** + // **************************************************************** + // Painting - Methods for painting this node and its children + // + // Painting is how a node defines its visual representation on the + // screen, and is done in the local coordinate system of the node. + // + // The default painting behavior is to first paint the node, and + // then paint the node's children on top of the node. If a node + // needs wants specialised painting behavior it can override: + // + // paint() - Painting here will happen before the children + // are painted, so the children will be painted on top of painting done + // here. + // paintAfterChildren() - Painting here will happen after the children + // are painted, so it will paint on top of them. + // + // Note that you should not normally need to override fullPaint(). + // + // The visible flag can be used to make a node invisible so that + // it will never get painted. + // **************************************************************** - /** - * Return true if this node is visible, that is if it will paint itself and - * descendants. - * - * @return true if this node and its descendants are visible. - */ - public boolean getVisible() { - return visible; - } + /** + * Return true if this node is visible, that is if it will paint itself and + * descendants. + * + * @return true if this node and its descendants are visible. + */ + public boolean getVisible() { + return visible; + } - /** - * Set the visibility of this node and its descendants. - * - * @param isVisible - * true if this node and its descendants are visible - */ - public void setVisible(final boolean isVisible) { - if (getVisible() != isVisible) { - if (!isVisible) { - repaint(); - } - visible = isVisible; - firePropertyChange(PROPERTY_CODE_VISIBLE, PROPERTY_VISIBLE, null, - null); - invalidatePaint(); - } - } + /** + * Set the visibility of this node and its descendants. + * + * @param isVisible true if this node and its descendants are visible + */ + public void setVisible(final boolean isVisible) { + if (getVisible() != isVisible) { + if (!isVisible) { + repaint(); + } + visible = isVisible; + firePropertyChange(PROPERTY_CODE_VISIBLE, PROPERTY_VISIBLE, null, null); + invalidatePaint(); + } + } - /** - * Return the paint used while painting this node. This value may be null. - * - * @return the paint used while painting this node. - */ - public Paint getPaint() { - return paint; - } + /** + * Return the paint used while painting this node. This value may be null. + * + * @return the paint used while painting this node. + */ + public Paint getPaint() { + return paint; + } - /** - * Set the paint used to paint this node, which may be null. - * - * @param newPaint - * paint that this node should use when painting itself. - */ - public void setPaint(final Paint newPaint) { - if (paint == newPaint) { - return; - } + /** + * Set the paint used to paint this node, which may be null. + * + * @param newPaint paint that this node should use when painting itself. + */ + public void setPaint(final Paint newPaint) { + if (paint == newPaint) { + return; + } - final Paint oldPaint = paint; - paint = newPaint; - invalidatePaint(); - firePropertyChange(PROPERTY_CODE_PAINT, PROPERTY_PAINT, oldPaint, paint); - } + final Paint oldPaint = paint; + paint = newPaint; + invalidatePaint(); + firePropertyChange(PROPERTY_CODE_PAINT, PROPERTY_PAINT, oldPaint, paint); + } - /** - * Return the transparency used when painting this node. Note that this - * transparency is also applied to all of the node's descendants. - * - * @return how transparent this node is 0f = completely transparent, 1f = - * completely opaque - */ - public float getTransparency() { - return transparency; - } + /** + * Return the transparency used when painting this node. Note that this + * transparency is also applied to all of the node's descendants. + * + * @return how transparent this node is 0f = completely transparent, 1f = + * completely opaque + */ + public float getTransparency() { + return transparency; + } - /** - * Set the transparency used to paint this node. Note that this transparency - * applies to this node and all of its descendants. - * - * @param newTransparency - * transparency value for this node. 0f = fully transparent, 1f = - * fully opaque - */ - public void setTransparency(final float newTransparency) { - if (Math.abs(transparency - newTransparency) > TRANSPARENCY_RESOLUTION) { - final float oldTransparency = transparency; - transparency = newTransparency; - invalidatePaint(); - firePropertyChange(PROPERTY_CODE_TRANSPARENCY, - PROPERTY_TRANSPARENCY, new Float(oldTransparency), - new Float(newTransparency)); - } - } + /** + * Set the transparency used to paint this node. Note that this transparency + * applies to this node and all of its descendants. + * + * @param newTransparency transparency value for this node. 0f = fully + * transparent, 1f = fully opaque + */ + public void setTransparency(final float newTransparency) { + if (Math.abs(transparency - newTransparency) > TRANSPARENCY_RESOLUTION) { + final float oldTransparency = transparency; + transparency = newTransparency; + invalidatePaint(); + firePropertyChange(PROPERTY_CODE_TRANSPARENCY, PROPERTY_TRANSPARENCY, new Float(oldTransparency), + new Float(newTransparency)); + } + } - /** - * Paint this node behind any of its children nodes. Subclasses that define - * a different appearance should override this method and paint themselves - * there. - * - * @param paintContext - * the paint context to use for painting the node - */ - protected void paint(final PPaintContext paintContext) { - if (paint != null) { - final Graphics2D g2 = paintContext.getGraphics(); - g2.setPaint(paint); - g2.fill(getBoundsReference()); - } - } + /** + * Paint this node behind any of its children nodes. Subclasses that define + * a different appearance should override this method and paint themselves + * there. + * + * @param paintContext the paint context to use for painting the node + */ + protected void paint(final PPaintContext paintContext) { + if (paint != null) { + final Graphics2D g2 = paintContext.getGraphics(); + g2.setPaint(paint); + g2.fill(getBoundsReference()); + } + } - /** - * Paint this node and all of its descendants. Most subclasses do not need - * to override this method, they should override paint or - * paintAfterChildren instead. - * - * @param paintContext - * the paint context to use for painting this node and its - * children - */ - public void fullPaint(final PPaintContext paintContext) { - if (getVisible() && fullIntersects(paintContext.getLocalClip())) { - paintContext.pushTransform(transform); - paintContext.pushTransparency(transparency); + /** + * Paint this node and all of its descendants. Most subclasses do not need + * to override this method, they should override paint or + * paintAfterChildren instead. + * + * @param paintContext the paint context to use for painting this node and + * its children + */ + public void fullPaint(final PPaintContext paintContext) { + if (getVisible() && fullIntersects(paintContext.getLocalClip())) { + paintContext.pushTransform(transform); + paintContext.pushTransparency(transparency); - if (!getOccluded()) { - paint(paintContext); - } + if (!getOccluded()) { + paint(paintContext); + } - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - each.fullPaint(paintContext); - } + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + each.fullPaint(paintContext); + } - paintAfterChildren(paintContext); + paintAfterChildren(paintContext); - paintContext.popTransparency(transparency); - paintContext.popTransform(transform); - } - } + paintContext.popTransparency(transparency); + paintContext.popTransform(transform); + } + } - /** - * Subclasses that wish to do additional painting after their children are - * painted should override this method and do that painting here. - * - * @param paintContext - * the paint context to sue for painting after the children are - * painted - */ - protected void paintAfterChildren(final PPaintContext paintContext) { - } + /** + * Subclasses that wish to do additional painting after their children are + * painted should override this method and do that painting here. + * + * @param paintContext the paint context to sue for painting after the + * children are painted + */ + protected void paintAfterChildren(final PPaintContext paintContext) { + } - /** - * Return a new Image representing this node and all of its children. The - * image size will be equal to the size of this nodes full bounds. - * - * @return a new image representing this node and its descendants - */ - public Image toImage() { - final PBounds b = getFullBoundsReference(); - return toImage((int) Math.ceil(b.getWidth()), (int) Math.ceil(b - .getHeight()), null); - } + /** + * Return a new Image representing this node and all of its children. The + * image size will be equal to the size of this nodes full bounds. + * + * @return a new image representing this node and its descendants + */ + public Image toImage() { + final PBounds b = getFullBoundsReference(); + return toImage((int) Math.ceil(b.getWidth()), (int) Math.ceil(b.getHeight()), null); + } - /** - * Return a new Image of the requested size representing this node and all - * of its children. If backGroundPaint is null the resulting image will have - * transparent regions, otherwise those regions will be filled with the - * backgroundPaint. - * - * @param width - * pixel width of the resulting image - * @param height - * pixel height of the resulting image - * @param backgroundPaint - * paint to fill the image with before drawing this node, may be - * null - * - * @return a new image representing this node and its descendants - */ - public Image toImage(final int width, final int height, - final Paint backgroundPaint) { - BufferedImage result; + /** + * Return a new Image of the requested size representing this node and all + * of its children. If backGroundPaint is null the resulting image will have + * transparent regions, otherwise those regions will be filled with the + * backgroundPaint. + * + * @param width pixel width of the resulting image + * @param height pixel height of the resulting image + * @param backgroundPaint paint to fill the image with before drawing this + * node, may be null + * + * @return a new image representing this node and its descendants + */ + public Image toImage(final int width, final int height, final Paint backgroundPaint) { + BufferedImage result; - if (GraphicsEnvironment.isHeadless()) { - result = new BufferedImage(width, height, - BufferedImage.TYPE_INT_ARGB); - } else { - final GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment - .getLocalGraphicsEnvironment().getDefaultScreenDevice() - .getDefaultConfiguration(); - result = graphicsConfiguration.createCompatibleImage(width, height, - Transparency.TRANSLUCENT); - } + if (GraphicsEnvironment.isHeadless()) { + result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + } + else { + final GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + result = graphicsConfiguration.createCompatibleImage(width, height, Transparency.TRANSLUCENT); + } - return toImage(result, backgroundPaint); - } + return toImage(result, backgroundPaint); + } - /** - * Paint a representation of this node into the specified buffered image. If - * background, paint is null, then the image will not be filled with a color - * prior to rendering - * - * @param image - * Image onto which this node will be painted - * @param backGroundPaint - * will fill background of image with this. May be null. - * @return a rendering of this image and its descendants onto the specified - * image - */ - public Image toImage(final BufferedImage image, final Paint backGroundPaint) { - return toImage(image, backGroundPaint, FILL_STRATEGY_ASPECT_FIT); - } + /** + * Paint a representation of this node into the specified buffered image. If + * background, paint is null, then the image will not be filled with a color + * prior to rendering + * + * @param image Image onto which this node will be painted + * @param backGroundPaint will fill background of image with this. May be + * null. + * @return a rendering of this image and its descendants onto the specified + * image + */ + public Image toImage(final BufferedImage image, final Paint backGroundPaint) { + return toImage(image, backGroundPaint, FILL_STRATEGY_ASPECT_FIT); + } - /** - * Paint a representation of this node into the specified buffered image. If - * background, paint is null, then the image will not be filled with a color - * prior to rendering - * - * @since 1.3 - * @param image - * Image onto which this node will be painted - * @param backGroundPaint - * will fill background of image with this. May be null. - * @param fillStrategy - * strategy to use regarding how node will cover the image - * @return a rendering of this image and its descendants onto the specified - * image - */ - public Image toImage(final BufferedImage image, - final Paint backGroundPaint, final int fillStrategy) { - final int imageWidth = image.getWidth(); - final int imageHeight = image.getHeight(); - final Graphics2D g2 = image.createGraphics(); + /** + * Paint a representation of this node into the specified buffered image. If + * background, paint is null, then the image will not be filled with a color + * prior to rendering + * + * @since 1.3 + * @param image Image onto which this node will be painted + * @param backGroundPaint will fill background of image with this. May be + * null. + * @param fillStrategy strategy to use regarding how node will cover the + * image + * @return a rendering of this image and its descendants onto the specified + * image + */ + public Image toImage(final BufferedImage image, final Paint backGroundPaint, final int fillStrategy) { + final int imageWidth = image.getWidth(); + final int imageHeight = image.getHeight(); + final Graphics2D g2 = image.createGraphics(); - if (backGroundPaint != null) { - g2.setPaint(backGroundPaint); - g2.fillRect(0, 0, imageWidth, imageHeight); - } - g2.setClip(0, 0, imageWidth, imageHeight); + if (backGroundPaint != null) { + g2.setPaint(backGroundPaint); + g2.fillRect(0, 0, imageWidth, imageHeight); + } + g2.setClip(0, 0, imageWidth, imageHeight); - final PBounds nodeBounds = getFullBounds(); - nodeBounds.expandNearestIntegerDimensions(); + final PBounds nodeBounds = getFullBounds(); + nodeBounds.expandNearestIntegerDimensions(); - final double nodeWidth = nodeBounds.getWidth(); - final double nodeHeight = nodeBounds.getHeight(); + final double nodeWidth = nodeBounds.getWidth(); + final double nodeHeight = nodeBounds.getHeight(); - double imageRatio = imageWidth / (imageHeight * 1.0); - double nodeRatio = nodeWidth / nodeHeight; - double scale; - switch (fillStrategy) { - case FILL_STRATEGY_ASPECT_FIT: - // scale the graphics so node's full bounds fit in the imageable - // bounds but aspect ration is retained + double imageRatio = imageWidth / (imageHeight * 1.0); + double nodeRatio = nodeWidth / nodeHeight; + double scale; + switch (fillStrategy) { + case FILL_STRATEGY_ASPECT_FIT: + // scale the graphics so node's full bounds fit in the imageable + // bounds but aspect ration is retained - if (nodeRatio <= imageRatio) { - scale = image.getHeight() / nodeHeight; - } else { - scale = image.getWidth() / nodeWidth; - } - g2.scale(scale, scale); - g2.translate(-nodeBounds.x, -nodeBounds.y); - break; - case FILL_STRATEGY_ASPECT_COVER: - // scale the graphics so node completely covers the imageable - // area, but retains its aspect ratio. - if (nodeRatio <= imageRatio) { - scale = image.getWidth() / nodeWidth; - } else { - scale = image.getHeight() / nodeHeight; - } - g2.scale(scale, scale); - break; - case FILL_STRATEGY_EXACT_FIT: - // scale the node so that it covers then entire image, - // distorting it if necessary. - g2.scale(image.getWidth() / nodeWidth, image.getHeight() - / nodeHeight); - g2.translate(-nodeBounds.x, -nodeBounds.y); - break; - default: - throw new IllegalArgumentException( - "Fill strategy provided is invalid"); - } + if (nodeRatio <= imageRatio) { + scale = image.getHeight() / nodeHeight; + } + else { + scale = image.getWidth() / nodeWidth; + } + g2.scale(scale, scale); + g2.translate(-nodeBounds.x, -nodeBounds.y); + break; + case FILL_STRATEGY_ASPECT_COVER: + // scale the graphics so node completely covers the imageable + // area, but retains its aspect ratio. + if (nodeRatio <= imageRatio) { + scale = image.getWidth() / nodeWidth; + } + else { + scale = image.getHeight() / nodeHeight; + } + g2.scale(scale, scale); + break; + case FILL_STRATEGY_EXACT_FIT: + // scale the node so that it covers then entire image, + // distorting it if necessary. + g2.scale(image.getWidth() / nodeWidth, image.getHeight() / nodeHeight); + g2.translate(-nodeBounds.x, -nodeBounds.y); + break; + default: + throw new IllegalArgumentException("Fill strategy provided is invalid"); + } - final PPaintContext pc = new PPaintContext(g2); - pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); - fullPaint(pc); - return image; - } + final PPaintContext pc = new PPaintContext(g2); + pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + fullPaint(pc); + return image; + } - /** - * Constructs a new PrinterJob, allows the user to select which printer to - * print to, And then prints the node. - */ - public void print() { - final PrinterJob printJob = PrinterJob.getPrinterJob(); - final PageFormat pageFormat = printJob.defaultPage(); - final Book book = new Book(); - book.append(this, pageFormat); - printJob.setPageable(book); + /** + * Constructs a new PrinterJob, allows the user to select which printer to + * print to, And then prints the node. + */ + public void print() { + final PrinterJob printJob = PrinterJob.getPrinterJob(); + final PageFormat pageFormat = printJob.defaultPage(); + final Book book = new Book(); + book.append(this, pageFormat); + printJob.setPageable(book); - if (printJob.printDialog()) { - try { - printJob.print(); - } catch (final PrinterException e) { - throw new RuntimeException("Error Printing", e); - } - } - } + if (printJob.printDialog()) { + try { + printJob.print(); + } + catch (final PrinterException e) { + throw new RuntimeException("Error Printing", e); + } + } + } - /** - * Prints the node into the given Graphics context using the specified - * format. The zero based index of the requested page is specified by - * pageIndex. If the requested page does not exist then this method returns - * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. If the printable object - * aborts the print job then it throws a PrinterException. - * - * @param graphics - * the context into which the node is drawn - * @param pageFormat - * the size and orientation of the page - * @param pageIndex - * the zero based index of the page to be drawn - * - * @return Either NO_SUCH_PAGE or PAGE_EXISTS - */ - public int print(final Graphics graphics, final PageFormat pageFormat, - final int pageIndex) { - if (pageIndex != 0) { - return NO_SUCH_PAGE; - } + /** + * Prints the node into the given Graphics context using the specified + * format. The zero based index of the requested page is specified by + * pageIndex. If the requested page does not exist then this method returns + * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. If the printable object + * aborts the print job then it throws a PrinterException. + * + * @param graphics the context into which the node is drawn + * @param pageFormat the size and orientation of the page + * @param pageIndex the zero based index of the page to be drawn + * + * @return Either NO_SUCH_PAGE or PAGE_EXISTS + */ + public int print(final Graphics graphics, final PageFormat pageFormat, final int pageIndex) { + if (pageIndex != 0) { + return NO_SUCH_PAGE; + } - if (!(graphics instanceof Graphics2D)) { - throw new IllegalArgumentException( - "Provided graphics context is not a Graphics2D object"); - } + if (!(graphics instanceof Graphics2D)) { + throw new IllegalArgumentException("Provided graphics context is not a Graphics2D object"); + } - final Graphics2D g2 = (Graphics2D) graphics; - final PBounds imageBounds = getFullBounds(); + final Graphics2D g2 = (Graphics2D) graphics; + final PBounds imageBounds = getFullBounds(); - imageBounds.expandNearestIntegerDimensions(); + imageBounds.expandNearestIntegerDimensions(); - g2.setClip(0, 0, (int) pageFormat.getWidth(), (int) pageFormat - .getHeight()); - g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + g2.setClip(0, 0, (int) pageFormat.getWidth(), (int) pageFormat.getHeight()); + g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); - // scale the graphics so node's full bounds fit in the imageable bounds. - double scale = pageFormat.getImageableWidth() / imageBounds.getWidth(); - if (pageFormat.getImageableHeight() / imageBounds.getHeight() < scale) { - scale = pageFormat.getImageableHeight() / imageBounds.getHeight(); - } + // scale the graphics so node's full bounds fit in the imageable bounds. + double scale = pageFormat.getImageableWidth() / imageBounds.getWidth(); + if (pageFormat.getImageableHeight() / imageBounds.getHeight() < scale) { + scale = pageFormat.getImageableHeight() / imageBounds.getHeight(); + } - g2.scale(scale, scale); - g2.translate(-imageBounds.x, -imageBounds.y); + g2.scale(scale, scale); + g2.translate(-imageBounds.x, -imageBounds.y); - final PPaintContext pc = new PPaintContext(g2); - pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); - fullPaint(pc); + final PPaintContext pc = new PPaintContext(g2); + pc.setRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + fullPaint(pc); - return PAGE_EXISTS; - } + return PAGE_EXISTS; + } - // **************************************************************** - // Picking - Methods for picking this node and its children. - // - // Picking is used to determine the node that intersects a point or - // rectangle on the screen. It is most frequently used by the - // PInputManager to determine the node that the cursor is over. - // - // The intersects() method is used to determine if a node has - // been picked or not. The default implementation just test to see - // if the pick bounds intersects the bounds of the node. Subclasses - // whose geometry (a circle for example) does not match up exactly with - // the bounds should override the intersects() method. - // - // The default picking behavior is to first try to pick the nodes - // children, and then try to pick the nodes own bounds. If a node - // wants specialized picking behavior it can override: - // - // pick() - Pick nodes here that should be picked before the nodes - // children are picked. - // pickAfterChildren() - Pick nodes here that should be picked after the - // node's children are picked. - // - // Note that fullPick should not normally be overridden. - // - // The pickable and childrenPickable flags can be used to make a - // node or it children not pickable even if their geometry does - // intersect the pick bounds. - // **************************************************************** + // **************************************************************** + // Picking - Methods for picking this node and its children. + // + // Picking is used to determine the node that intersects a point or + // rectangle on the screen. It is most frequently used by the + // PInputManager to determine the node that the cursor is over. + // + // The intersects() method is used to determine if a node has + // been picked or not. The default implementation just test to see + // if the pick bounds intersects the bounds of the node. Subclasses + // whose geometry (a circle for example) does not match up exactly with + // the bounds should override the intersects() method. + // + // The default picking behavior is to first try to pick the nodes + // children, and then try to pick the nodes own bounds. If a node + // wants specialized picking behavior it can override: + // + // pick() - Pick nodes here that should be picked before the nodes + // children are picked. + // pickAfterChildren() - Pick nodes here that should be picked after the + // node's children are picked. + // + // Note that fullPick should not normally be overridden. + // + // The pickable and childrenPickable flags can be used to make a + // node or it children not pickable even if their geometry does + // intersect the pick bounds. + // **************************************************************** - /** - * Return true if this node is pickable. Only pickable nodes can receive - * input events. Nodes are pickable by default. - * - * @return true if this node is pickable - */ - public boolean getPickable() { - return pickable; - } + /** + * Return true if this node is pickable. Only pickable nodes can receive + * input events. Nodes are pickable by default. + * + * @return true if this node is pickable + */ + public boolean getPickable() { + return pickable; + } - /** - * Set the pickable flag for this node. Only pickable nodes can receive - * input events. Nodes are pickable by default. - * - * @param isPickable - * true if this node is pickable - */ - public void setPickable(final boolean isPickable) { - if (getPickable() != isPickable) { - pickable = isPickable; - firePropertyChange(PROPERTY_CODE_PICKABLE, PROPERTY_PICKABLE, null, - null); - } - } + /** + * Set the pickable flag for this node. Only pickable nodes can receive + * input events. Nodes are pickable by default. + * + * @param isPickable true if this node is pickable + */ + public void setPickable(final boolean isPickable) { + if (getPickable() != isPickable) { + pickable = isPickable; + firePropertyChange(PROPERTY_CODE_PICKABLE, PROPERTY_PICKABLE, null, null); + } + } - /** - * Return true if the children of this node should be picked. If this flag - * is false then this node will not try to pick its children. Children are - * pickable by default. - * - * @return true if this node tries to pick its children - */ - public boolean getChildrenPickable() { - return childrenPickable; - } + /** + * Return true if the children of this node should be picked. If this flag + * is false then this node will not try to pick its children. Children are + * pickable by default. + * + * @return true if this node tries to pick its children + */ + public boolean getChildrenPickable() { + return childrenPickable; + } - /** - * Set the children pickable flag. If this flag is false then this node will - * not try to pick its children. Children are pickable by default. - * - * @param areChildrenPickable - * true if this node tries to pick its children - */ - public void setChildrenPickable(final boolean areChildrenPickable) { - if (getChildrenPickable() != areChildrenPickable) { - childrenPickable = areChildrenPickable; - firePropertyChange(PROPERTY_CODE_CHILDREN_PICKABLE, - PROPERTY_CHILDREN_PICKABLE, null, null); - } - } + /** + * Set the children pickable flag. If this flag is false then this node will + * not try to pick its children. Children are pickable by default. + * + * @param areChildrenPickable true if this node tries to pick its children + */ + public void setChildrenPickable(final boolean areChildrenPickable) { + if (getChildrenPickable() != areChildrenPickable) { + childrenPickable = areChildrenPickable; + firePropertyChange(PROPERTY_CODE_CHILDREN_PICKABLE, PROPERTY_CHILDREN_PICKABLE, null, null); + } + } - /** - * Try to pick this node before its children have had a chance to be picked. - * Nodes that paint on top of their children may want to override this - * method to if the pick path intersects that paint. - * - * @param pickPath - * the pick path used for the pick operation - * @return true if this node was picked - */ - protected boolean pick(final PPickPath pickPath) { - return false; - } + /** + * Try to pick this node before its children have had a chance to be picked. + * Nodes that paint on top of their children may want to override this + * method to if the pick path intersects that paint. + * + * @param pickPath the pick path used for the pick operation + * @return true if this node was picked + */ + protected boolean pick(final PPickPath pickPath) { + return false; + } - /** - * Try to pick this node and all of its descendants. Most subclasses should - * not need to override this method. Instead they should override - * pick or pickAfterChildren. - * - * @param pickPath - * the pick path to add the node to if its picked - * @return true if this node or one of its descendants was picked. - */ - public boolean fullPick(final PPickPath pickPath) { - if (getVisible() && (getPickable() || getChildrenPickable()) - && fullIntersects(pickPath.getPickBounds())) { - pickPath.pushNode(this); - pickPath.pushTransform(transform); + /** + * Try to pick this node and all of its descendants. Most subclasses should + * not need to override this method. Instead they should override + * pick or pickAfterChildren. + * + * @param pickPath the pick path to add the node to if its picked + * @return true if this node or one of its descendants was picked. + */ + public boolean fullPick(final PPickPath pickPath) { + if (getVisible() && (getPickable() || getChildrenPickable()) && fullIntersects(pickPath.getPickBounds())) { + pickPath.pushNode(this); + pickPath.pushTransform(transform); - final boolean thisPickable = getPickable() - && pickPath.acceptsNode(this); + final boolean thisPickable = getPickable() && pickPath.acceptsNode(this); - if (thisPickable && pick(pickPath)) { - return true; - } + if (thisPickable && pick(pickPath)) { + return true; + } - if (getChildrenPickable()) { - final int count = getChildrenCount(); - for (int i = count - 1; i >= 0; i--) { - final PNode each = (PNode) children.get(i); - if (each.fullPick(pickPath)) { - return true; - } - } - } + if (getChildrenPickable()) { + final int count = getChildrenCount(); + for (int i = count - 1; i >= 0; i--) { + final PNode each = (PNode) children.get(i); + if (each.fullPick(pickPath)) { + return true; + } + } + } - if (thisPickable && pickAfterChildren(pickPath)) { - return true; - } + if (thisPickable && pickAfterChildren(pickPath)) { + return true; + } - pickPath.popTransform(transform); - pickPath.popNode(this); - } + pickPath.popTransform(transform); + pickPath.popNode(this); + } - return false; - } + return false; + } - /** - * Finds all descendants of this node that intersect with the given bounds - * and adds them to the results array. - * - * @param fullBounds - * bounds to compare against - * @param results - * array into which to add matches - */ - public void findIntersectingNodes(final Rectangle2D fullBounds, - final ArrayList results) { - if (fullIntersects(fullBounds)) { - final Rectangle2D localBounds = parentToLocal((Rectangle2D) fullBounds - .clone()); + /** + * Finds all descendants of this node that intersect with the given bounds + * and adds them to the results array. + * + * @param fullBounds bounds to compare against + * @param results array into which to add matches + */ + public void findIntersectingNodes(final Rectangle2D fullBounds, final ArrayList results) { + if (fullIntersects(fullBounds)) { + final Rectangle2D localBounds = parentToLocal((Rectangle2D) fullBounds.clone()); - if (intersects(localBounds)) { - results.add(this); - } + if (intersects(localBounds)) { + results.add(this); + } - final int count = getChildrenCount(); - for (int i = count - 1; i >= 0; i--) { - final PNode each = (PNode) children.get(i); - each.findIntersectingNodes(localBounds, results); - } - } - } + final int count = getChildrenCount(); + for (int i = count - 1; i >= 0; i--) { + final PNode each = (PNode) children.get(i); + each.findIntersectingNodes(localBounds, results); + } + } + } - /** - * Try to pick this node after its children have had a chance to be picked. - * Most subclasses the define a different geometry will need to override - * this method. - * - * @param pickPath - * the pick path used for the pick operation - * @return true if this node was picked - */ - protected boolean pickAfterChildren(final PPickPath pickPath) { - if (intersects(pickPath.getPickBounds())) { - return true; - } - return false; - } + /** + * Try to pick this node after its children have had a chance to be picked. + * Most subclasses the define a different geometry will need to override + * this method. + * + * @param pickPath the pick path used for the pick operation + * @return true if this node was picked + */ + protected boolean pickAfterChildren(final PPickPath pickPath) { + if (intersects(pickPath.getPickBounds())) { + return true; + } + return false; + } - // **************************************************************** - // Structure - Methods for manipulating and traversing the - // parent child relationship - // - // Most of these methods won't need to be overridden by subclasses - // but you will use them frequently to build up your node structures. - // **************************************************************** + // **************************************************************** + // Structure - Methods for manipulating and traversing the + // parent child relationship + // + // Most of these methods won't need to be overridden by subclasses + // but you will use them frequently to build up your node structures. + // **************************************************************** - /** - * Add a node to be a new child of this node. The new node is added to the - * end of the list of this node's children. If child was previously a child - * of another node, it is removed from that first. - * - * @param child - * the new child to add to this node - */ - public void addChild(final PNode child) { - int insertIndex = getChildrenCount(); - if (child.parent == this) { - insertIndex--; - } - addChild(insertIndex, child); - } + /** + * Add a node to be a new child of this node. The new node is added to the + * end of the list of this node's children. If child was previously a child + * of another node, it is removed from that first. + * + * @param child the new child to add to this node + */ + public void addChild(final PNode child) { + int insertIndex = getChildrenCount(); + if (child.parent == this) { + insertIndex--; + } + addChild(insertIndex, child); + } - /** - * Add a node to be a new child of this node at the specified index. If - * child was previously a child of another node, it is removed from that - * node first. - * - * @param index - * where in the children list to insert the child - * @param child - * the new child to add to this node - */ - public void addChild(final int index, final PNode child) { - final PNode oldParent = child.getParent(); + /** + * Add a node to be a new child of this node at the specified index. If + * child was previously a child of another node, it is removed from that + * node first. + * + * @param index where in the children list to insert the child + * @param child the new child to add to this node + */ + public void addChild(final int index, final PNode child) { + final PNode oldParent = child.getParent(); - if (oldParent != null) { - oldParent.removeChild(child); - } + if (oldParent != null) { + oldParent.removeChild(child); + } - child.setParent(this); - getChildrenReference().add(index, child); - child.invalidatePaint(); - invalidateFullBounds(); + child.setParent(this); + getChildrenReference().add(index, child); + child.invalidatePaint(); + invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, - children); - } + firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, children); + } - /** - * Add a collection of nodes to be children of this node. If these nodes - * already have parents they will first be removed from those parents. - * - * @param nodes - * a collection of nodes to be added to this node - */ - public void addChildren(final Collection nodes) { - final Iterator i = nodes.iterator(); - while (i.hasNext()) { - final PNode each = (PNode) i.next(); - addChild(each); - } - } + /** + * Add a collection of nodes to be children of this node. If these nodes + * already have parents they will first be removed from those parents. + * + * @param nodes a collection of nodes to be added to this node + */ + public void addChildren(final Collection nodes) { + final Iterator i = nodes.iterator(); + while (i.hasNext()) { + final PNode each = (PNode) i.next(); + addChild(each); + } + } - /** - * Return true if this node is an ancestor of the parameter node. - * - * @param node - * a possible descendant node - * @return true if this node is an ancestor of the given node - */ - public boolean isAncestorOf(final PNode node) { - PNode p = node.parent; - while (p != null) { - if (p == this) { - return true; - } - p = p.parent; - } - return false; - } + /** + * Return true if this node is an ancestor of the parameter node. + * + * @param node a possible descendant node + * @return true if this node is an ancestor of the given node + */ + public boolean isAncestorOf(final PNode node) { + PNode p = node.parent; + while (p != null) { + if (p == this) { + return true; + } + p = p.parent; + } + return false; + } - /** - * Return true if this node is a descendant of the parameter node. - * - * @param node - * a possible ancestor node - * @return true if this nodes descends from the given node - */ - public boolean isDescendentOf(final PNode node) { - PNode p = parent; - while (p != null) { - if (p == node) { - return true; - } - p = p.parent; - } - return false; - } + /** + * Return true if this node is a descendant of the parameter node. + * + * @param node a possible ancestor node + * @return true if this nodes descends from the given node + */ + public boolean isDescendentOf(final PNode node) { + PNode p = parent; + while (p != null) { + if (p == node) { + return true; + } + p = p.parent; + } + return false; + } - /** - * Return true if this node descends from the root. - * - * @return whether this node descends from root node - */ - public boolean isDescendentOfRoot() { - return getRoot() != null; - } + /** + * Return true if this node descends from the root. + * + * @return whether this node descends from root node + */ + public boolean isDescendentOfRoot() { + return getRoot() != null; + } - /** - * Change the order of this node in its parent's children list so that it - * will draw in back of all of its other sibling nodes. - */ - public void moveToBack() { - final PNode p = parent; - if (p != null) { - p.removeChild(this); - p.addChild(0, this); - } - } + /** + * Change the order of this node in its parent's children list so that it + * will draw in back of all of its other sibling nodes. + */ + public void moveToBack() { + final PNode p = parent; + if (p != null) { + p.removeChild(this); + p.addChild(0, this); + } + } - /** - * Change the order of this node in its parent's children list so that it - * will draw in front of all of its other sibling nodes. - * - * @param sibling - * sibling in back of which this nodes should be moved. - */ - public void moveInBackOf(final PNode sibling) { - final PNode p = parent; - if (p != null && p == sibling.getParent()) { - p.removeChild(this); - final int index = p.indexOfChild(sibling); - p.addChild(index, this); - } - } + /** + * Change the order of this node in its parent's children list so that it + * will draw in front of all of its other sibling nodes. + * + * @param sibling sibling in back of which this nodes should be moved. + */ + public void moveInBackOf(final PNode sibling) { + final PNode p = parent; + if (p != null && p == sibling.getParent()) { + p.removeChild(this); + final int index = p.indexOfChild(sibling); + p.addChild(index, this); + } + } - /** - * Change the order of this node in its parent's children list so that it - * will draw after the given sibling node. - */ - public void moveToFront() { - final PNode p = parent; - if (p != null) { - p.removeChild(this); - p.addChild(this); - } - } + /** + * Change the order of this node in its parent's children list so that it + * will draw after the given sibling node. + */ + public void moveToFront() { + final PNode p = parent; + if (p != null) { + p.removeChild(this); + p.addChild(this); + } + } - /** - * Change the order of this node in its parent's children list so that it - * will draw before the given sibling node. - * - * @param sibling - * sibling in front of which this nodes should be moved. - */ - public void moveInFrontOf(final PNode sibling) { - final PNode p = parent; - if (p != null && p == sibling.getParent()) { - p.removeChild(this); - final int index = p.indexOfChild(sibling); - p.addChild(index + 1, this); - } - } + /** + * Change the order of this node in its parent's children list so that it + * will draw before the given sibling node. + * + * @param sibling sibling in front of which this nodes should be moved. + */ + public void moveInFrontOf(final PNode sibling) { + final PNode p = parent; + if (p != null && p == sibling.getParent()) { + p.removeChild(this); + final int index = p.indexOfChild(sibling); + p.addChild(index + 1, this); + } + } - /** - * Return the parent of this node. This will be null if this node has not - * been added to a parent yet. - * - * @return this nodes parent or null - */ - public PNode getParent() { - return parent; - } + /** + * Return the parent of this node. This will be null if this node has not + * been added to a parent yet. + * + * @return this nodes parent or null + */ + public PNode getParent() { + return parent; + } - /** - * Set the parent of this node. Note this is set automatically when adding - * and removing children. - * - * @param newParent - * the parent to which this node should be added - */ - public void setParent(final PNode newParent) { - final PNode old = parent; - parent = newParent; - firePropertyChange(PROPERTY_CODE_PARENT, PROPERTY_PARENT, old, parent); - } + /** + * Set the parent of this node. Note this is set automatically when adding + * and removing children. + * + * @param newParent the parent to which this node should be added + */ + public void setParent(final PNode newParent) { + final PNode old = parent; + parent = newParent; + firePropertyChange(PROPERTY_CODE_PARENT, PROPERTY_PARENT, old, parent); + } - /** - * Return the index where the given child is stored. - * - * @param child - * child so search for - * @return index of child or -1 if not found - */ - public int indexOfChild(final PNode child) { - if (children == null) { - return -1; - } - return children.indexOf(child); - } + /** + * Return the index where the given child is stored. + * + * @param child child so search for + * @return index of child or -1 if not found + */ + public int indexOfChild(final PNode child) { + if (children == null) { + return -1; + } + return children.indexOf(child); + } - /** - * Remove the given child from this node's children list. Any subsequent - * children are shifted to the left (one is subtracted from their indices). - * The removed child's parent is set to null. - * - * @param child - * the child to remove - * @return the removed child - */ - public PNode removeChild(final PNode child) { - final int index = indexOfChild(child); - if (index == -1) { - return null; - } - return removeChild(index); - } + /** + * Remove the given child from this node's children list. Any subsequent + * children are shifted to the left (one is subtracted from their indices). + * The removed child's parent is set to null. + * + * @param child the child to remove + * @return the removed child + */ + public PNode removeChild(final PNode child) { + final int index = indexOfChild(child); + if (index == -1) { + return null; + } + return removeChild(index); + } - /** - * Remove the child at the specified position of this group node's children. - * Any subsequent children are shifted to the left (one is subtracted from - * their indices). The removed child's parent is set to null. - * - * @param index - * the index of the child to remove - * @return the removed child - */ - public PNode removeChild(final int index) { - if (children == null) { - return null; - } - final PNode child = (PNode) children.remove(index); + /** + * Remove the child at the specified position of this group node's children. + * Any subsequent children are shifted to the left (one is subtracted from + * their indices). The removed child's parent is set to null. + * + * @param index the index of the child to remove + * @return the removed child + */ + public PNode removeChild(final int index) { + if (children == null) { + return null; + } + final PNode child = (PNode) children.remove(index); - if (children.size() == 0) { - children = null; - } + if (children.size() == 0) { + children = null; + } - child.repaint(); - child.setParent(null); - invalidateFullBounds(); + child.repaint(); + child.setParent(null); + invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, - children); + firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, children); - return child; - } + return child; + } - /** - * Remove all the children in the given collection from this node's list of - * children. All removed nodes will have their parent set to null. - * - * @param childrenNodes - * the collection of children to remove - */ - public void removeChildren(final Collection childrenNodes) { - final Iterator i = childrenNodes.iterator(); - while (i.hasNext()) { - final PNode each = (PNode) i.next(); - removeChild(each); - } - } + /** + * Remove all the children in the given collection from this node's list of + * children. All removed nodes will have their parent set to null. + * + * @param childrenNodes the collection of children to remove + */ + public void removeChildren(final Collection childrenNodes) { + final Iterator i = childrenNodes.iterator(); + while (i.hasNext()) { + final PNode each = (PNode) i.next(); + removeChild(each); + } + } - /** - * Remove all the children from this node. Node this method is more - * efficient then removing each child individually. - */ - public void removeAllChildren() { - if (children != null) { - final int count = children.size(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - each.setParent(null); - } - children = null; - invalidatePaint(); - invalidateFullBounds(); + /** + * Remove all the children from this node. Node this method is more + * efficient then removing each child individually. + */ + public void removeAllChildren() { + if (children != null) { + final int count = children.size(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + each.setParent(null); + } + children = null; + invalidatePaint(); + invalidateFullBounds(); - firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, - children); - } - } + firePropertyChange(PROPERTY_CODE_CHILDREN, PROPERTY_CHILDREN, null, children); + } + } - /** - * Delete this node by removing it from its parent's list of children. - */ - public void removeFromParent() { - if (parent != null) { - parent.removeChild(this); - } - } + /** + * Delete this node by removing it from its parent's list of children. + */ + public void removeFromParent() { + if (parent != null) { + parent.removeChild(this); + } + } - /** - * Set the parent of this node, and transform the node in such a way that it - * doesn't move in global coordinates. - * - * @param newParent - * The new parent of this node. - */ - public void reparent(final PNode newParent) { - final AffineTransform originalTransform = getLocalToGlobalTransform(null); - final AffineTransform newTransform = newParent - .getGlobalToLocalTransform(null); - newTransform.concatenate(originalTransform); + /** + * Set the parent of this node, and transform the node in such a way that it + * doesn't move in global coordinates. + * + * @param newParent The new parent of this node. + */ + public void reparent(final PNode newParent) { + final AffineTransform originalTransform = getLocalToGlobalTransform(null); + final AffineTransform newTransform = newParent.getGlobalToLocalTransform(null); + newTransform.concatenate(originalTransform); - removeFromParent(); - setTransform(newTransform); - newParent.addChild(this); - computeFullBounds(fullBoundsCache); - } + removeFromParent(); + setTransform(newTransform); + newParent.addChild(this); + computeFullBounds(fullBoundsCache); + } - /** - * Swaps this node out of the scene graph tree, and replaces it with the - * specified replacement node. This node is left dangling, and it is up to - * the caller to manage it. The replacement node will be added to this - * node's parent in the same position as this was. That is, if this was the - * 3rd child of its parent, then after calling replaceWith(), the - * replacement node will also be the 3rd child of its parent. If this node - * has no parent when replace is called, then nothing will be done at all. - * - * @param replacementNode - * the new node that replaces the current node in the scene graph - * tree. - */ - public void replaceWith(final PNode replacementNode) { - if (parent != null) { - final PNode p = parent; - final int index = p.getChildrenReference().indexOf(this); - p.removeChild(this); - p.addChild(index, replacementNode); - } - } + /** + * Swaps this node out of the scene graph tree, and replaces it with the + * specified replacement node. This node is left dangling, and it is up to + * the caller to manage it. The replacement node will be added to this + * node's parent in the same position as this was. That is, if this was the + * 3rd child of its parent, then after calling replaceWith(), the + * replacement node will also be the 3rd child of its parent. If this node + * has no parent when replace is called, then nothing will be done at all. + * + * @param replacementNode the new node that replaces the current node in the + * scene graph tree. + */ + public void replaceWith(final PNode replacementNode) { + if (parent != null) { + final PNode p = parent; + final int index = p.getChildrenReference().indexOf(this); + p.removeChild(this); + p.addChild(index, replacementNode); + } + } - /** - * Sets the name of this null, may be null. - * - * @since 1.3 - * @param name - * new name for this node - */ - public void setName(final String name) { - this.name = name; - } + /** + * Sets the name of this null, may be null. + * + * @since 1.3 + * @param name new name for this node + */ + public void setName(final String name) { + this.name = name; + } - /** - * Returns the name given to this node. - * - * @since 1.3 - * @return name given to this node, may be null - */ - public String getName() { - return name; - } + /** + * Returns the name given to this node. + * + * @since 1.3 + * @return name given to this node, may be null + */ + public String getName() { + return name; + } - /** - * Return the number of children that this node has. - * - * @return the number of children - */ - public int getChildrenCount() { - if (children == null) { - return 0; - } - return children.size(); - } + /** + * Return the number of children that this node has. + * + * @return the number of children + */ + public int getChildrenCount() { + if (children == null) { + return 0; + } + return children.size(); + } - /** - * Return the child node at the specified index. - * - * @param index - * a child index - * @return the child node at the specified index - */ - public PNode getChild(final int index) { - return (PNode) children.get(index); - } + /** + * Return the child node at the specified index. + * + * @param index a child index + * @return the child node at the specified index + */ + public PNode getChild(final int index) { + return (PNode) children.get(index); + } - /** - * Return a reference to the list used to manage this node's children. This - * list should not be modified. - * - * @return reference to the children list - */ - public List getChildrenReference() { - if (children == null) { - children = new ArrayList(); - } - return children; - } + /** + * Return a reference to the list used to manage this node's children. This + * list should not be modified. + * + * @return reference to the children list + */ + public List getChildrenReference() { + if (children == null) { + children = new ArrayList(); + } + return children; + } - /** - * Return an iterator over this node's direct descendant children. - * - * @return iterator over this nodes children - */ - public ListIterator getChildrenIterator() { - if (children == null) { - return Collections.EMPTY_LIST.listIterator(); - } - return Collections.unmodifiableList(children).listIterator(); - } + /** + * Return an iterator over this node's direct descendant children. + * + * @return iterator over this nodes children + */ + public ListIterator getChildrenIterator() { + if (children == null) { + return Collections.EMPTY_LIST.listIterator(); + } + return Collections.unmodifiableList(children).listIterator(); + } - /** - * Return the root node (instance of PRoot). If this node does not descend - * from a PRoot then null will be returned. - * - * @return root element of this node, or null if this node does not descend - * from a PRoot - */ - public PRoot getRoot() { - if (parent != null) { - return parent.getRoot(); - } - return null; - } + /** + * Return the root node (instance of PRoot). If this node does not descend + * from a PRoot then null will be returned. + * + * @return root element of this node, or null if this node does not descend + * from a PRoot + */ + public PRoot getRoot() { + if (parent != null) { + return parent.getRoot(); + } + return null; + } - /** - * Return a collection containing this node and all of its descendant nodes. - * - * @return a new collection containing this node and all descendants - */ - public Collection getAllNodes() { - return getAllNodes(null, null); - } + /** + * Return a collection containing this node and all of its descendant nodes. + * + * @return a new collection containing this node and all descendants + */ + public Collection getAllNodes() { + return getAllNodes(null, null); + } - /** - * Return a collection containing the subset of this node and all of its - * descendant nodes that are accepted by the given node filter. If the - * filter is null then all nodes will be accepted. If the results parameter - * is not null then it will be used to collect this subset instead of - * creating a new collection. - * - * @param filter - * the filter used to determine the subset - * @param resultantNodes - * where matching nodes should be added - * @return a collection containing this node and all descendants - */ - public Collection getAllNodes(final PNodeFilter filter, - final Collection resultantNodes) { - Collection results; - if (resultantNodes == null) { - results = new ArrayList(); - } else { - results = resultantNodes; - } + /** + * Return a collection containing the subset of this node and all of its + * descendant nodes that are accepted by the given node filter. If the + * filter is null then all nodes will be accepted. If the results parameter + * is not null then it will be used to collect this subset instead of + * creating a new collection. + * + * @param filter the filter used to determine the subset + * @param resultantNodes where matching nodes should be added + * @return a collection containing this node and all descendants + */ + public Collection getAllNodes(final PNodeFilter filter, final Collection resultantNodes) { + Collection results; + if (resultantNodes == null) { + results = new ArrayList(); + } + else { + results = resultantNodes; + } - if (filter == null || filter.accept(this)) { - results.add(this); - } + if (filter == null || filter.accept(this)) { + results.add(this); + } - if (filter == null || filter.acceptChildrenOf(this)) { - final int count = getChildrenCount(); - for (int i = 0; i < count; i++) { - final PNode each = (PNode) children.get(i); - each.getAllNodes(filter, results); - } - } + if (filter == null || filter.acceptChildrenOf(this)) { + final int count = getChildrenCount(); + for (int i = 0; i < count; i++) { + final PNode each = (PNode) children.get(i); + each.getAllNodes(filter, results); + } + } - return results; - } + return results; + } - // **************************************************************** - // Serialization - Nodes conditionally serialize their parent. - // This means that only the parents that were unconditionally - // (using writeObject) serialized by someone else will be restored - // when the node is unserialized. - // **************************************************************** + // **************************************************************** + // Serialization - Nodes conditionally serialize their parent. + // This means that only the parents that were unconditionally + // (using writeObject) serialized by someone else will be restored + // when the node is unserialized. + // **************************************************************** - /** - * Write this node and all of its descendant nodes to the given outputsteam. - * This stream must be an instance of PObjectOutputStream or serialization - * will fail. This nodes parent is written out conditionally, that is it - * will only be written out if someone else writes it out unconditionally. - * - * @param out - * the output stream to write to, must be an instance of - * PObjectOutputStream - * @throws IOException - * when an error occurs speaking to underlying - * ObjectOutputStream - */ - private void writeObject(final ObjectOutputStream out) throws IOException { - if (!(out instanceof PObjectOutputStream)) { - throw new IllegalArgumentException( - "PNode.writeObject may only be used with PObjectOutputStreams"); - } - out.defaultWriteObject(); - ((PObjectOutputStream) out).writeConditionalObject(parent); - } + /** + * Write this node and all of its descendant nodes to the given outputsteam. + * This stream must be an instance of PObjectOutputStream or serialization + * will fail. This nodes parent is written out conditionally, that is it + * will only be written out if someone else writes it out unconditionally. + * + * @param out the output stream to write to, must be an instance of + * PObjectOutputStream + * @throws IOException when an error occurs speaking to underlying + * ObjectOutputStream + */ + private void writeObject(final ObjectOutputStream out) throws IOException { + if (!(out instanceof PObjectOutputStream)) { + throw new IllegalArgumentException("PNode.writeObject may only be used with PObjectOutputStreams"); + } + out.defaultWriteObject(); + ((PObjectOutputStream) out).writeConditionalObject(parent); + } - /** - * Read this node and all of its descendants in from the given input stream. - * - * @param in - * the stream to read from - * - * @throws IOException - * when an error occurs speaking to underlying - * ObjectOutputStream - * @throws ClassNotFoundException - * when a class is deserialized that no longer exists. This can - * happen if it's renamed or deleted. - */ - private void readObject(final ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - parent = (PNode) in.readObject(); - } + /** + * Read this node and all of its descendants in from the given input stream. + * + * @param in the stream to read from + * + * @throws IOException when an error occurs speaking to underlying + * ObjectOutputStream + * @throws ClassNotFoundException when a class is deserialized that no + * longer exists. This can happen if it's renamed or deleted. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + parent = (PNode) in.readObject(); + } - /** - * @deprecated see http://code.google.com/p/piccolo2d/issues/detail?id=99 - * - * @return a string representation of this node's state - */ - protected String paramString() { - return ""; - } + /** + * @deprecated see http://code.google.com/p/piccolo2d/issues/detail?id=99 + * + * @return a string representation of this node's state + */ + protected String paramString() { + return ""; + } - /** - * Returns an array of input event listeners that are attached to this node. - * - * @since 1.3 - * @return event listeners attached to this node - */ - public PInputEventListener[] getInputEventListeners() { - if (listenerList == null || listenerList.getListenerCount() == 0) { - return new PInputEventListener[] {}; - } + /** + * Returns an array of input event listeners that are attached to this node. + * + * @since 1.3 + * @return event listeners attached to this node + */ + public PInputEventListener[] getInputEventListeners() { + if (listenerList == null || listenerList.getListenerCount() == 0) { + return new PInputEventListener[] {}; + } - final EventListener[] listeners = listenerList - .getListeners(PInputEventListener.class); + final EventListener[] listeners = listenerList.getListeners(PInputEventListener.class); - final PInputEventListener[] result = new PInputEventListener[listeners.length]; - for (int i = 0; i < listeners.length; i++) { - result[i] = (PInputEventListener) listeners[i]; - } - return result; - } + final PInputEventListener[] result = new PInputEventListener[listeners.length]; + for (int i = 0; i < listeners.length; i++) { + result[i] = (PInputEventListener) listeners[i]; + } + return result; + } - private static final class ClientPropertyKeyIterator implements Iterator { - private final Enumeration enumeration; + private static final class ClientPropertyKeyIterator implements Iterator { + private final Enumeration enumeration; - private ClientPropertyKeyIterator(final Enumeration enumeration) { - this.enumeration = enumeration; - } + private ClientPropertyKeyIterator(final Enumeration enumeration) { + this.enumeration = enumeration; + } - public boolean hasNext() { - return enumeration.hasMoreElements(); - } + public boolean hasNext() { + return enumeration.hasMoreElements(); + } - public Object next() { - return enumeration.nextElement(); - } + public Object next() { + return enumeration.nextElement(); + } - public void remove() { - throw new UnsupportedOperationException(); - } - } + public void remove() { + throw new UnsupportedOperationException(); + } + } - /** - * PSceneGraphDelegate is an interface to receive low level node - * events. It together with PNode.SCENE_GRAPH_DELEGATE gives Piccolo2d users - * an efficient way to learn about low level changes in Piccolo's scene - * graph. Most users will not need to use this. - */ - public interface PSceneGraphDelegate { - /** - * Called to notify delegate that the node needs repainting. - * - * @param node - * node needing repaint - */ - void nodePaintInvalidated(PNode node); + /** + * PSceneGraphDelegate is an interface to receive low level node + * events. It together with PNode.SCENE_GRAPH_DELEGATE gives Piccolo2d users + * an efficient way to learn about low level changes in Piccolo's scene + * graph. Most users will not need to use this. + */ + public interface PSceneGraphDelegate { + /** + * Called to notify delegate that the node needs repainting. + * + * @param node node needing repaint + */ + void nodePaintInvalidated(PNode node); - /** - * Called to notify delegate that the node and all it's children need - * repainting. - * - * @param node - * node needing repaint - */ - void nodeFullBoundsInvalidated(PNode node); - } + /** + * Called to notify delegate that the node and all it's children need + * repainting. + * + * @param node node needing repaint + */ + void nodeFullBoundsInvalidated(PNode node); + } }