Package diva.canvas

Class FigureLayer

  • All Implemented Interfaces:
    CanvasComponent, EventAcceptor, FigureContainer, FigureSet, VisibleComponent

    public class FigureLayer
    extends CanvasLayer
    implements FigureContainer, EventAcceptor
    A figure layer is a layer on which Figures can be drawn. It contains a z-list in which all the contained figures are held, and implements wrappers for most of the z-list methods to provide flexible access to the contained figures. Figures are also stored at contiguous integer indexes, with index zero being the "topmost" figure and the highest index being the "lowest" figure.

    FigureLayer responds to events on figures themselves by forwarding the events to interactors attached to a hit figure. It does not support events on the layer itself (see EventLayer for that).

    Version:
    $Id$
    Author:
    John Reekie
    Pt.AcceptedRating:
    Yellow
    • Constructor Summary

      Constructors 
      Constructor Description
      FigureLayer()
      Create a new figure layer that is not in a pane.
      FigureLayer​(CanvasPane pane)
      Create a new figure layer within the given pane.
      FigureLayer​(CanvasPane pane, ZList zlist)
      Create a new figure layer within the given pane and with the given ZList to hold the figures it contains.
      FigureLayer​(ZList zlist)
      Create a new figure layer with the given ZList to hold its figures.
    • Constructor Detail

      • FigureLayer

        public FigureLayer()
        Create a new figure layer that is not in a pane. The layer will not be displayed, and its coordinate transformation will be as though it were a one-to-one mapping. Use of this constructor is strongly discouraged, as many of the geometry-related methods expect to see a pane.
      • FigureLayer

        public FigureLayer​(CanvasPane pane)
        Create a new figure layer within the given pane.
        Parameters:
        pane - The given pane.
      • FigureLayer

        public FigureLayer​(CanvasPane pane,
                           ZList zlist)
        Create a new figure layer within the given pane and with the given ZList to hold the figures it contains.
        Parameters:
        pane - The given pane.
        zlist - The given zlist.
      • FigureLayer

        public FigureLayer​(ZList zlist)
        Create a new figure layer with the given ZList to hold its figures. This can be used to create a more efficient z-list than the default, which is an instance of BasicZList.
        Parameters:
        zlist - The given zlist.
    • Method Detail

      • add

        public void add​(Figure f)
        Add a figure to the layer. The figure is added to the ZList, and the figure's layer and parent fields set appropriately. The figure will be painted over the top of all existing figures. It does not check whether the figure is already in the layer -- clients clients are therefore responsible for being bug-free.
        Specified by:
        add in interface FigureContainer
        Parameters:
        f - The figure to be added
      • add

        public void add​(int index,
                        Figure f)
        Insert a figure into the layer at the given position. To insert the figure just in front of some other figure, use getIndex() to get the other figure's index, and pass index as the first argument. To insert the figure just behind some other figure, pass index+1 as the first argument. To insert so the figure displays over the top of other figures, insert at zero.

        Clients should assume that an implementation of this method does not check if the figure is already contained -- clients are therefore responsible for being bug-free.

        Parameters:
        index - The index
        f - The figure to be added.
      • clear

        public void clear()
        Removes all of the figures from this layer.
      • contains

        public boolean contains​(Figure f)
        Test if the layer contains the given figure. Note that, in general, a much better way of making this same test is to check if the parent of the figure is the same object as this layer.
        Specified by:
        contains in interface FigureContainer
        Specified by:
        contains in interface FigureSet
        Parameters:
        f - The figure to be checked.
        Returns:
        true if the figure is contained.
      • decorate

        public void decorate​(Figure child,
                             FigureDecorator decorator)
        Decorate a child figure, replacing the child figure with the decorator.
        Specified by:
        decorate in interface FigureContainer
        Parameters:
        child - The child figure.
        decorator - The decorator.
      • dispatchEvent

        public void dispatchEvent​(java.awt.AWTEvent event)
        Dispatch an AWT event on this layer. If the layer is not enabled, return immediately. Otherwise process the event according to its type. If the event represents a mouse click, drag, or release, call the protected method processLayerEvent; if it represents a mouse movement, call the protected method processLayerMotionEvent. Currently other events types are not handled.
        Specified by:
        dispatchEvent in interface EventAcceptor
        Parameters:
        event - the event.
      • figures

        public java.util.Iterator figures()
        Return an iteration of the figures in this container. The order in which figures are iterated is undefined.
        Specified by:
        figures in interface FigureSet
        Returns:
        The iterator.
      • figuresFromBack

        public java.util.Iterator figuresFromBack()
        Return an iteration of the figures in this container, from back to front. This is the order in which figures should normally be painted.
        Specified by:
        figuresFromBack in interface FigureSet
        Returns:
        The iterator
      • figuresFromFront

        public java.util.Iterator figuresFromFront()
        Return an iteration of the figures in this container, from front to back. This is the order in which events should normally be intercepted.
        Specified by:
        figuresFromFront in interface FigureSet
        Returns:
        The iterator
      • get

        public Figure get​(int index)
        Get the figure at the given index. Indexes are contiguous from zero to getFigureCount()-1, with figures at lower indexes being displayed "on top of" figures with higher indexes.
        Parameters:
        index - The given index
        Returns:
        The figure at the given index
      • getFigureCount

        public int getFigureCount()
        Return the number of figures in this layer.
        Specified by:
        getFigureCount in interface FigureContainer
        Returns:
        The number of figures.
      • getCurrentFigure

        public Figure getCurrentFigure()
        Return the figure that the mouse pointer is currently over, or null if none.
        Returns:
        The figure the mouse is currently over.
      • getFigures

        public ZList getFigures()
        Get the internal z-list. Clients must not modify the z-list, but can use it for making queries on its contents.
        Returns:
        The internal z-list.
      • getLayerBounds

        public java.awt.geom.Rectangle2D getLayerBounds()
        Get the bounds of the shapes draw in this layer. In this class, we return the bounds of all the figures in the z-list.
        Overrides:
        getLayerBounds in class CanvasLayer
        Returns:
        The bounds of this layer.
      • getPickHalo

        public final double getPickHalo()
        Get the "pick halo". This is the distance in either axis that an object can be from the mouse to be considered hit.
        Returns:
        the pick halo.
        See Also:
        setPickHalo(double)
      • grabPointer

        public void grabPointer​(LayerEvent e,
                                Figure f)
        "Grab" the pointer. Typically, this method will be called from an Interactor class in response to a mousePressed() event. The effect of calling this method is to make the series of mouse events up to and including the mouseReleased() event appear to be originating from the figure f rather than the actual figure that was clicked on. For example, if clicking and dragging on a graph node creates and the drags a new edge, this method will be called after constructing the edge to make the edge itself handle the mouse drag events instead of the node.
        Parameters:
        e - The LayerEvent
        f - The figure
      • getToolTipText

        public java.lang.String getToolTipText​(LayerEvent e)
        Get the toolTipText for the point in the given LayerEvent. This method starts with the figure that is set by the mouse motion events when the pointer moves over a figure. Starting with that figure, it walks up the tree until it finds a figure that returns a tool tip, or until it reaches a root figure. If it finds a tool tip, it returns it, otherwise it returns null.
        Overrides:
        getToolTipText in class CanvasLayer
        Parameters:
        e - The layer event, ignored in this class.
        Returns:
        This method always returns null.
      • indexOf

        public int indexOf​(Figure f)
        Return the index of the given figure. Figures with a higher index are drawn behind figures with a lower index.
        Parameters:
        f - The figure
        Returns:
        The index of the given figure
      • isEnabled

        public final boolean isEnabled()
        Test the enabled flag of this layer. Note that this flag does not indicate whether the layer is actually enabled, as its pane or one if its ancestors may not be enabled.
        Specified by:
        isEnabled in interface EventAcceptor
        Returns:
        true if the object is prepared to handle events with processEvent()
      • isVisible

        public final boolean isVisible()
        Test the visibility flag of this layer. Note that this flag does not indicate whether the layer is actually visible on the screen, as its pane or one if its ancestors may not be visible.
        Specified by:
        isVisible in interface VisibleComponent
        Returns:
        true if the object is visible.
      • paint

        public void paint​(java.awt.Graphics2D g)
        Paint this layer onto a 2D graphics object. If the layer is not visible, return immediately. Otherwise paint all figures from back to front.
        Specified by:
        paint in interface VisibleComponent
        Parameters:
        g - The 2D graphics object that this object it to be painted upon.
      • paint

        public void paint​(java.awt.Graphics2D g,
                          java.awt.geom.Rectangle2D region)
        Paint this layer onto a 2D graphics object, within the given region. If the layer is not visible, return immediately. Otherwise paint all figures that overlap the given region, from back to front.
        Specified by:
        paint in interface VisibleComponent
        Parameters:
        g - The 2D graphics object that this object it to be painted upon.
        region - The region.
      • pick

        public Figure pick​(java.awt.geom.Rectangle2D region)
        Get the picked figure. This method recursively traverses the tree until it finds a figure that is "hit" by the region. Note that a region is given instead of a point so that "hysteresis" can be implemented. If no figure is picked, return null. The region should not have zero size, or no figure will be hit.
        Specified by:
        pick in interface FigureContainer
        Parameters:
        region - The rectangle
        Returns:
        The figure
      • pick

        public Figure pick​(java.awt.geom.Rectangle2D region,
                           Filter filter)
        Get the picked figure. This method recursively traverses the tree until it finds a figure that is "hit" by the region. Note that a region is given instead of a point so that "hysteresis" can be implemented. If no figure is picked, return null. The region should not have zero size, or no figure will be hit.
        Specified by:
        pick in interface FigureContainer
        Parameters:
        region - The rectangle
        filter - The filter
        Returns:
        the Figure or null.
      • remove

        public void remove​(Figure f)
        Remove the given figure from this layer. The figure's layer is set to null.
        Specified by:
        remove in interface FigureContainer
        Parameters:
        f - The figure to be removed
      • remove

        public void remove​(int index)
        Remove the figure at the given position in the list. The figure's layer is set to null.
        Parameters:
        index - The given position.
      • repaint

        public void repaint​(java.awt.geom.Rectangle2D region)
        Repaint all figures that intersect the given rectangle.
        Parameters:
        region - The given rectangle
      • setEnabled

        public final void setEnabled​(boolean flag)
        Set the enabled flag of this layer. If the flag is false, then the layer will not respond to user input events.
        Specified by:
        setEnabled in interface EventAcceptor
        Parameters:
        flag - True if the object is prepared to handle events with processEvent();
      • setPickHalo

        public final void setPickHalo​(double halo)
        Set the "pick halo". This is the distance a figure can be from the mouse in either axis to be considered hit by the mouse. By default, it it set to 0.5, meaning that the hit detection rectangle is 1.0 along each side.
        Parameters:
        halo - The pick halo
        See Also:
        getPickHalo()
      • setIndex

        public void setIndex​(int index,
                             Figure f)
        Set the index of the given figure. That is, move it in the display list to the given position. To move the figure to just in front of some other figure, use getIndex() to get the other figure's index, and pass index as the first argument. To move the figure to just behind some other figure, pass index+1 as the first argument. (Other figures will have their indexes changed accordingly.)

        Note that this method does not check if the figure is already contained -- clients are therefore responsible for being bug-free.

        Parameters:
        index - The index to be set
        f - The figure
        Throws:
        java.lang.IndexOutOfBoundsException - The new index is out of range.
      • setVisible

        public final void setVisible​(boolean flag)
        Set the visibility flag of this layer. If the flag is false, then the layer will not be drawn on the screen.
        Specified by:
        setVisible in interface VisibleComponent
        Parameters:
        flag - True if this object is to be visible.
      • undecorate

        public void undecorate​(FigureDecorator decorator)
        Remove a figure from the given decorator and add it back into this container.
        Specified by:
        undecorate in interface FigureContainer
        Parameters:
        decorator - The decorator
      • getFigure

        protected final Figure getFigure​(LayerEvent e)
        Return the figure pointed to by the given LayerEvent. If there is no figure, then return null.
        Parameters:
        e - The given LayerEvent
        Returns:
        The figure or null
      • processLayerEvent

        protected void processLayerEvent​(LayerEvent e)
        Process a layer event. The behaviour of this method depends on the action type. If it is MOUSE_PRESSED, then it recurses down the figure tree searching for the top-most figure under the cursor. (If a figure has been hit on its transparent part, then it will not be considered to be above another figure -- the method Figure.hits() determines whether a figure gets the event.) When it finds it, it remembers it, and then proceeds back up the tree, passing the event to the event dispatcher of any figures that have one. After each such call, if the event has been consumed, then the upwards-traversal stops. Finally, if this layer is reached, and the event has not been consumed, then any registered LayerListeners are called. (Or should they be notified in any case?)

        If the event type is MOUSE_DRAGGED or MOUSE_RELEASED, then the downwards recursion is skipped, and the upwards propagation is begun from the figure remembered from the MOUSE_PRESSED processing. Again, the propagation stops when the event is consumed.

        Note: the above strategy will not work with more than one input device. Is there anything in MouseEvent that allows us to identify the input device?

        Parameters:
        e - The LayerEvent
      • processLayerMotionEvent

        protected void processLayerMotionEvent​(LayerEvent e)
        Process a layer motion event. The behavior of this method depends on the action type. If the action is MOUSE_ENTERED. then the figure tree is scanned to find if the mouse is now over a figure, and the event is dispatched to that figure if so. If the action is MOUSE_MOVED, then the tree is scanned again to find the figure currently under the mouse; if it is different, then leave and enter events are generated on the previous and current figures (either may not exist); otherwise a motion event is generated on the current figure. If the action is MOUSE_EXITED, then the current figure, if there is one, has an exit event sent to it. In all of these cases the event is propagated from the current figure up the hierarchy until consumed.
        Parameters:
        e - The LayerEvent