blob: 5ced6989fe782e71be6cb07db1870c63b2e9678e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.draw2d;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Translatable;
import org.eclipse.swt.SWT;
/**
* The base implementation for graphical figures.
*/
public class Figure implements IFigure {
private static final Rectangle PRIVATE_RECT = new Rectangle();
private static final Point PRIVATE_POINT = new Point();
private static final int FLAG_VALID = new Integer(1).intValue(),
FLAG_OPAQUE = new Integer(1 << 1).intValue(),
FLAG_VISIBLE = new Integer(1 << 2).intValue(),
FLAG_FOCUSABLE = new Integer(1 << 3).intValue(),
FLAG_ENABLED = new Integer(1 << 4).intValue(),
FLAG_FOCUS_TRAVERSABLE = new Integer(1 << 5).intValue();
static final int FLAG_REALIZED = 1 << 31;
/**
* The largest flag defined in this class. If subclasses define flags, they
* should declare them as larger than this value and redefine MAX_FLAG to be
* their largest flag value.
* <P>
* This constant is evaluated at runtime and will not be inlined by the
* compiler.
*/
protected static int MAX_FLAG = FLAG_FOCUS_TRAVERSABLE;
/**
* The rectangular area that this Figure occupies.
*/
protected Rectangle bounds = new Rectangle(0, 0, 0, 0);
private LayoutManager layoutManager;
/**
* The flags for this Figure.
*/
protected int flags = FLAG_VISIBLE | FLAG_ENABLED;
private IFigure parent;
private IClippingStrategy clippingStrategy = null;
private Cursor cursor;
private PropertyChangeSupport propertyListeners;
private EventListenerList eventListeners = new EventListenerList();
private List children = Collections.EMPTY_LIST;
/**
* This Figure's preferred size.
*/
protected Dimension prefSize;
/**
* This Figure's minimum size.
*/
protected Dimension minSize;
/**
* This Figure's maximum size.
*/
protected Dimension maxSize;
/**
* @deprecated access using {@link #getLocalFont()}
*/
protected Font font;
/**
* @deprecated access using {@link #getLocalBackgroundColor()}.
*/
protected Color bgColor;
/**
* @deprecated access using {@link #getLocalForegroundColor()}.
*/
protected Color fgColor;
/**
* @deprecated access using {@link #getBorder()}
*/
protected Border border;
/**
* @deprecated access using {@link #getToolTip()}
*/
protected IFigure toolTip;
private AncestorHelper ancestorHelper;
/**
* Calls {@link #add(IFigure, Object, int)} with -1 as the index.
*
* @see IFigure#add(IFigure, Object)
*/
public final void add(IFigure figure, Object constraint) {
add(figure, constraint, -1);
}
/**
* @see IFigure#add(IFigure, Object, int)
*/
public void add(IFigure figure, Object constraint, int index) {
if (children == Collections.EMPTY_LIST)
children = new ArrayList(2);
if (index < -1 || index > children.size())
throw new IndexOutOfBoundsException("Index does not exist"); //$NON-NLS-1$
// Check for Cycle in hierarchy
for (IFigure f = this; f != null; f = f.getParent())
if (figure == f)
throw new IllegalArgumentException(
"Figure being added introduces cycle"); //$NON-NLS-1$
// Detach the child from previous parent
if (figure.getParent() != null)
figure.getParent().remove(figure);
if (index == -1)
children.add(figure);
else
children.add(index, figure);
figure.setParent(this);
if (layoutManager != null)
layoutManager.setConstraint(figure, constraint);
revalidate();
if (getFlag(FLAG_REALIZED))
figure.addNotify();
figure.repaint();
}
/**
* Calls {@link #add(IFigure, Object, int)} with <code>null</code> as the
* constraint and -1 as the index.
*
* @see IFigure#add(IFigure)
*/
public final void add(IFigure figure) {
add(figure, null, -1);
}
/**
* Calls {@link #add(IFigure, Object, int)} with <code>null</code> as the
* constraint.
*
* @see IFigure#add(IFigure, int)
*/
public final void add(IFigure figure, int index) {
add(figure, null, index);
}
/**
* @see IFigure#addAncestorListener(AncestorListener)
*/
public void addAncestorListener(AncestorListener ancestorListener) {
if (ancestorHelper == null)
ancestorHelper = new AncestorHelper(this);
ancestorHelper.addAncestorListener(ancestorListener);
}
/**
* @see IFigure#addCoordinateListener(CoordinateListener)
*/
public void addCoordinateListener(CoordinateListener listener) {
eventListeners.addListener(CoordinateListener.class, listener);
}
/**
* @see IFigure#addFigureListener(FigureListener)
*/
public void addFigureListener(FigureListener listener) {
eventListeners.addListener(FigureListener.class, listener);
}
/**
* @see IFigure#addFocusListener(FocusListener)
*/
public void addFocusListener(FocusListener listener) {
eventListeners.addListener(FocusListener.class, listener);
}
/**
* @see IFigure#addKeyListener(KeyListener)
*/
public void addKeyListener(KeyListener listener) {
eventListeners.addListener(KeyListener.class, listener);
}
/**
* Appends the given layout listener to the list of layout listeners.
*
* @since 3.1
* @param listener
* the listener being added
*/
public void addLayoutListener(LayoutListener listener) {
if (layoutManager instanceof LayoutNotifier) {
LayoutNotifier notifier = (LayoutNotifier) layoutManager;
notifier.listeners.add(listener);
} else
layoutManager = new LayoutNotifier(layoutManager, listener);
}
/**
* Adds a listener of type <i>clazz</i> to this Figure's list of event
* listeners.
*
* @param clazz
* The listener type
* @param listener
* The listener
*/
protected void addListener(Class clazz, Object listener) {
eventListeners.addListener(clazz, listener);
}
/**
* @see IFigure#addMouseListener(MouseListener)
*/
public void addMouseListener(MouseListener listener) {
eventListeners.addListener(MouseListener.class, listener);
}
/**
* @see IFigure#addMouseMotionListener(MouseMotionListener)
*/
public void addMouseMotionListener(MouseMotionListener listener) {
eventListeners.addListener(MouseMotionListener.class, listener);
}
/**
* Called after the receiver's parent has been set and it has been added to
* its parent.
*
* @since 2.0
*/
public void addNotify() {
if (getFlag(FLAG_REALIZED))
throw new RuntimeException(
"addNotify() should not be called multiple times"); //$NON-NLS-1$
setFlag(FLAG_REALIZED, true);
for (int i = 0; i < children.size(); i++)
((IFigure) children.get(i)).addNotify();
}
/**
* @see IFigure#addPropertyChangeListener(String, PropertyChangeListener)
*/
public void addPropertyChangeListener(String property,
PropertyChangeListener listener) {
if (propertyListeners == null)
propertyListeners = new PropertyChangeSupport(this);
propertyListeners.addPropertyChangeListener(property, listener);
}
/**
* @see IFigure#addPropertyChangeListener(PropertyChangeListener)
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (propertyListeners == null)
propertyListeners = new PropertyChangeSupport(this);
propertyListeners.addPropertyChangeListener(listener);
}
/**
* This method is final. Override {@link #containsPoint(int, int)} if
* needed.
*
* @see IFigure#containsPoint(Point)
* @since 2.0
*/
public final boolean containsPoint(Point p) {
return containsPoint(p.x, p.y);
}
/**
* @see IFigure#containsPoint(int, int)
*/
public boolean containsPoint(int x, int y) {
return getBounds().contains(x, y);
}
/**
* @see IFigure#erase()
*/
public void erase() {
if (getParent() == null || !isVisible())
return;
Rectangle r = new Rectangle(getBounds());
getParent().translateToParent(r);
getParent().repaint(r.x, r.y, r.width, r.height);
}
/**
* Returns a descendant of this Figure such that the Figure returned
* contains the point (x, y), and is accepted by the given TreeSearch.
* Returns <code>null</code> if none found.
*
* @param x
* The X coordinate
* @param y
* The Y coordinate
* @param search
* the TreeSearch
* @return The descendant Figure at (x,y)
*/
protected IFigure findDescendantAtExcluding(int x, int y, TreeSearch search) {
PRIVATE_POINT.setLocation(x, y);
translateFromParent(PRIVATE_POINT);
if (!getClientArea(Rectangle.SINGLETON).contains(PRIVATE_POINT))
return null;
x = PRIVATE_POINT.x;
y = PRIVATE_POINT.y;
IFigure fig;
for (int i = children.size(); i > 0;) {
i--;
fig = (IFigure) children.get(i);
if (fig.isVisible()) {
fig = fig.findFigureAt(x, y, search);
if (fig != null)
return fig;
}
}
// No descendants were found
return null;
}
/**
* @see IFigure#findFigureAt(Point)
*/
public final IFigure findFigureAt(Point pt) {
return findFigureAtExcluding(pt.x, pt.y, Collections.EMPTY_LIST);
}
/**
* @see IFigure#findFigureAt(int, int)
*/
public final IFigure findFigureAt(int x, int y) {
return findFigureAt(x, y, IdentitySearch.INSTANCE);
}
/**
* @see IFigure#findFigureAt(int, int, TreeSearch)
*/
public IFigure findFigureAt(int x, int y, TreeSearch search) {
if (!containsPoint(x, y))
return null;
if (search.prune(this))
return null;
IFigure child = findDescendantAtExcluding(x, y, search);
if (child != null)
return child;
if (search.accept(this))
return this;
return null;
}
/**
* @see IFigure#findFigureAtExcluding(int, int, Collection)
*/
public final IFigure findFigureAtExcluding(int x, int y, Collection c) {
return findFigureAt(x, y, new ExclusionSearch(c));
}
/**
* Returns the deepest descendant for which {@link #isMouseEventTarget()}
* returns <code>true</code> or <code>null</code> if none found. The
* Parameters <i>x</i> and <i>y</i> are absolute locations. Any Graphics
* transformations applied by this Figure to its children during
* {@link #paintChildren(Graphics)} (thus causing the children to appear
* transformed to the user) should be applied inversely to the points
* <i>x</i> and <i>y</i> when called on the children.
*
* @param x
* The X coordinate
* @param y
* The Y coordinate
* @return The deepest descendant for which isMouseEventTarget() returns
* true
*/
public IFigure findMouseEventTargetAt(int x, int y) {
if (!containsPoint(x, y))
return null;
IFigure f = findMouseEventTargetInDescendantsAt(x, y);
if (f != null)
return f;
if (isMouseEventTarget())
return this;
return null;
}
/**
* Searches this Figure's children for the deepest descendant for which
* {@link #isMouseEventTarget()} returns <code>true</code> and returns that
* descendant or <code>null</code> if none found.
*
* @see #findMouseEventTargetAt(int, int)
* @param x
* The X coordinate
* @param y
* The Y coordinate
* @return The deepest descendant for which isMouseEventTarget() returns
* true
*/
protected IFigure findMouseEventTargetInDescendantsAt(int x, int y) {
PRIVATE_POINT.setLocation(x, y);
translateFromParent(PRIVATE_POINT);
if (!getClientArea(Rectangle.SINGLETON).contains(PRIVATE_POINT))
return null;
IFigure fig;
for (int i = children.size(); i > 0;) {
i--;
fig = (IFigure) children.get(i);
if (fig.isVisible() && fig.isEnabled()) {
if (fig.containsPoint(PRIVATE_POINT.x, PRIVATE_POINT.y)) {
fig = fig.findMouseEventTargetAt(PRIVATE_POINT.x,
PRIVATE_POINT.y);
return fig;
}
}
}
return null;
}
/**
* Notifies to all {@link CoordinateListener}s that this figure's local
* coordinate system has changed in a way which affects the absolute bounds
* of figures contained within.
*
* @since 3.1
*/
protected void fireCoordinateSystemChanged() {
if (!eventListeners.containsListener(CoordinateListener.class))
return;
Iterator figureListeners = eventListeners
.getListeners(CoordinateListener.class);
while (figureListeners.hasNext())
((CoordinateListener) figureListeners.next())
.coordinateSystemChanged(this);
}
/**
* Notifies to all {@link FigureListener}s that this figure has moved. Moved
* means that the bounds have changed in some way, location and/or size.
*
* @since 3.1
*/
protected void fireFigureMoved() {
if (!eventListeners.containsListener(FigureListener.class))
return;
Iterator figureListeners = eventListeners
.getListeners(FigureListener.class);
while (figureListeners.hasNext())
((FigureListener) figureListeners.next()).figureMoved(this);
}
/**
* Fires both figuremoved and coordinate system changed. This method exists
* for compatibility. Some listeners which used to listen for figureMoved
* now listen for coordinates changed. So to be sure that those new
* listeners are notified, any client code which used called this method
* will also result in notification of coordinate changes.
*
* @since 2.0
* @deprecated call fireFigureMoved() or fireCoordinateSystemChanged() as
* appropriate
*/
protected void fireMoved() {
fireFigureMoved();
fireCoordinateSystemChanged();
}
/**
* Notifies any {@link PropertyChangeListener PropertyChangeListeners}
* listening to this Figure that the boolean property with id
* <i>property</i> has changed.
*
* @param property
* The id of the property that changed
* @param old
* The old value of the changed property
* @param current
* The current value of the changed property
* @since 2.0
*/
protected void firePropertyChange(String property, boolean old,
boolean current) {
if (propertyListeners == null)
return;
propertyListeners.firePropertyChange(property, old, current);
}
/**
* Notifies any {@link PropertyChangeListener PropertyChangeListeners}
* listening to this figure that the Object property with id <i>property</i>
* has changed.
*
* @param property
* The id of the property that changed
* @param old
* The old value of the changed property
* @param current
* The current value of the changed property
* @since 2.0
*/
protected void firePropertyChange(String property, Object old,
Object current) {
if (propertyListeners == null)
return;
propertyListeners.firePropertyChange(property, old, current);
}
/**
* Notifies any {@link PropertyChangeListener PropertyChangeListeners}
* listening to this figure that the integer property with id
* <code>property</code> has changed.
*
* @param property
* The id of the property that changed
* @param old
* The old value of the changed property
* @param current
* The current value of the changed property
* @since 2.0
*/
protected void firePropertyChange(String property, int old, int current) {
if (propertyListeners == null)
return;
propertyListeners.firePropertyChange(property, old, current);
}
/**
* Returns this Figure's background color. If this Figure's background color
* is <code>null</code> and its parent is not <code>null</code>, the
* background color is inherited from the parent.
*
* @see IFigure#getBackgroundColor()
*/
public Color getBackgroundColor() {
if (bgColor == null && getParent() != null)
return getParent().getBackgroundColor();
return bgColor;
}
/**
* @see IFigure#getBorder()
*/
public Border getBorder() {
return border;
}
/**
* Returns the smallest rectangle completely enclosing the figure.
* Implementors may return the Rectangle by reference. For this reason,
* callers of this method must not modify the returned Rectangle.
*
* @return The bounds of this Figure
*/
public Rectangle getBounds() {
return bounds;
}
/**
* @see IFigure#getChildren()
*/
public List getChildren() {
return children;
}
/**
* @see IFigure#getClientArea(Rectangle)
*/
public Rectangle getClientArea(Rectangle rect) {
rect.setBounds(getBounds());
rect.crop(getInsets());
if (useLocalCoordinates())
rect.setLocation(0, 0);
return rect;
}
/**
* @see IFigure#getClientArea()
*/
public final Rectangle getClientArea() {
return getClientArea(new Rectangle());
}
/**
* Returns the IClippingStrategy used by this figure to clip its children
*
* @return the IClipppingStrategy used to clip this figure's children.
* @since 3.6
*/
public IClippingStrategy getClippingStrategy() {
return clippingStrategy;
}
/**
* @see IFigure#getCursor()
*/
public Cursor getCursor() {
if (cursor == null && getParent() != null)
return getParent().getCursor();
return cursor;
}
/**
* Returns the value of the given flag.
*
* @param flag
* The flag to get
* @return The value of the given flag
*/
protected boolean getFlag(int flag) {
return (flags & flag) != 0;
}
/**
* @see IFigure#getFont()
*/
public Font getFont() {
if (font != null)
return font;
if (getParent() != null)
return getParent().getFont();
return null;
}
/**
* @see IFigure#getForegroundColor()
*/
public Color getForegroundColor() {
if (fgColor == null && getParent() != null)
return getParent().getForegroundColor();
return fgColor;
}
/**
* Returns the border's Insets if the border is set. Otherwise returns
* NO_INSETS, an instance of Insets with all 0s. Returns Insets by
* reference. DO NOT Modify returned value. Cannot return null.
*
* @return This Figure's Insets
*/
public Insets getInsets() {
if (getBorder() != null)
return getBorder().getInsets(this);
return NO_INSETS;
}
/**
* @see IFigure#getLayoutManager()
*/
public LayoutManager getLayoutManager() {
if (layoutManager instanceof LayoutNotifier)
return ((LayoutNotifier) layoutManager).realLayout;
return layoutManager;
}
/**
* Returns an Iterator over the listeners of type <i>clazz</i> that are
* listening to this Figure. If there are no listeners of type <i>clazz</i>,
* an empty iterator is returned.
*
* @param clazz
* The type of listeners to get
* @return An Iterator over the requested listeners
* @since 2.0
*/
protected Iterator getListeners(Class clazz) {
if (eventListeners == null)
return Collections.EMPTY_LIST.iterator();
return eventListeners.getListeners(clazz);
}
/**
* Returns <code>null</code> or the local background Color of this Figure.
* Does not inherit this Color from the parent.
*
* @return bgColor <code>null</code> or the local background Color
*/
public Color getLocalBackgroundColor() {
return bgColor;
}
/**
* Returns <code>null</code> or the local font setting for this figure. Does
* not return values inherited from the parent figure.
*
* @return <code>null</code> or the local font
* @since 3.1
*/
protected Font getLocalFont() {
return font;
}
/**
* Returns <code>null</code> or the local foreground Color of this Figure.
* Does not inherit this Color from the parent.
*
* @return fgColor <code>null</code> or the local foreground Color
*/
public Color getLocalForegroundColor() {
return fgColor;
}
/**
* Returns the top-left corner of this Figure's bounds.
*
* @return The top-left corner of this Figure's bounds
* @since 2.0
*/
public final Point getLocation() {
return getBounds().getLocation();
}
/**
* @see IFigure#getMaximumSize()
*/
public Dimension getMaximumSize() {
if (maxSize != null)
return maxSize;
return MAX_DIMENSION;
}
/**
* @see IFigure#getMinimumSize()
*/
public final Dimension getMinimumSize() {
return getMinimumSize(-1, -1);
}
/**
* @see IFigure#getMinimumSize(int, int)
*/
public Dimension getMinimumSize(int wHint, int hHint) {
if (minSize != null)
return minSize;
if (getLayoutManager() != null) {
Dimension d = getLayoutManager().getMinimumSize(this, wHint, hHint);
if (d != null)
return d;
}
return getPreferredSize(wHint, hHint);
}
/**
* @see IFigure#getParent()
*/
public IFigure getParent() {
return parent;
}
/**
* @see IFigure#getPreferredSize()
*/
public final Dimension getPreferredSize() {
return getPreferredSize(-1, -1);
}
/**
* @see IFigure#getPreferredSize(int, int)
*/
public Dimension getPreferredSize(int wHint, int hHint) {
if (prefSize != null)
return prefSize;
if (getLayoutManager() != null) {
Dimension d = getLayoutManager().getPreferredSize(this, wHint,
hHint);
if (d != null)
return d;
}
return getSize();
}
/**
* @see IFigure#getSize()
*/
public final Dimension getSize() {
return getBounds().getSize();
}
/**
* @see IFigure#getToolTip()
*/
public IFigure getToolTip() {
return toolTip;
}
/**
* @see IFigure#getUpdateManager()
*/
public UpdateManager getUpdateManager() {
if (getParent() != null)
return getParent().getUpdateManager();
// Only happens when the figure has not been realized
return NO_MANAGER;
}
/**
* @see IFigure#handleFocusGained(FocusEvent)
*/
public void handleFocusGained(FocusEvent event) {
Iterator iter = eventListeners.getListeners(FocusListener.class);
while (iter.hasNext())
((FocusListener) iter.next()).focusGained(event);
}
/**
* @see IFigure#handleFocusLost(FocusEvent)
*/
public void handleFocusLost(FocusEvent event) {
Iterator iter = eventListeners.getListeners(FocusListener.class);
while (iter.hasNext())
((FocusListener) iter.next()).focusLost(event);
}
/**
* @see IFigure#handleKeyPressed(KeyEvent)
*/
public void handleKeyPressed(KeyEvent event) {
Iterator iter = eventListeners.getListeners(KeyListener.class);
while (!event.isConsumed() && iter.hasNext())
((KeyListener) iter.next()).keyPressed(event);
}
/**
* @see IFigure#handleKeyReleased(KeyEvent)
*/
public void handleKeyReleased(KeyEvent event) {
Iterator iter = eventListeners.getListeners(KeyListener.class);
while (!event.isConsumed() && iter.hasNext())
((KeyListener) iter.next()).keyReleased(event);
}
/**
* @see IFigure#handleMouseDoubleClicked(MouseEvent)
*/
public void handleMouseDoubleClicked(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseListener) iter.next()).mouseDoubleClicked(event);
}
/**
* @see IFigure#handleMouseDragged(MouseEvent)
*/
public void handleMouseDragged(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseMotionListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseMotionListener) iter.next()).mouseDragged(event);
}
/**
* @see IFigure#handleMouseEntered(MouseEvent)
*/
public void handleMouseEntered(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseMotionListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseMotionListener) iter.next()).mouseEntered(event);
}
/**
* @see IFigure#handleMouseExited(MouseEvent)
*/
public void handleMouseExited(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseMotionListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseMotionListener) iter.next()).mouseExited(event);
}
/**
* @see IFigure#handleMouseHover(MouseEvent)
*/
public void handleMouseHover(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseMotionListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseMotionListener) iter.next()).mouseHover(event);
}
/**
* @see IFigure#handleMouseMoved(MouseEvent)
*/
public void handleMouseMoved(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseMotionListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseMotionListener) iter.next()).mouseMoved(event);
}
/**
* @see IFigure#handleMousePressed(MouseEvent)
*/
public void handleMousePressed(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseListener) iter.next()).mousePressed(event);
}
/**
* @see IFigure#handleMouseReleased(MouseEvent)
*/
public void handleMouseReleased(MouseEvent event) {
Iterator iter = eventListeners.getListeners(MouseListener.class);
while (!event.isConsumed() && iter.hasNext())
((MouseListener) iter.next()).mouseReleased(event);
}
/**
* @see IFigure#hasFocus()
*/
public boolean hasFocus() {
EventDispatcher dispatcher = internalGetEventDispatcher();
if (dispatcher == null)
return false;
return dispatcher.getFocusOwner() == this;
}
/**
* @see IFigure#internalGetEventDispatcher()
*/
public EventDispatcher internalGetEventDispatcher() {
if (getParent() != null)
return getParent().internalGetEventDispatcher();
return null;
}
/**
* @see IFigure#intersects(Rectangle)
*/
public boolean intersects(Rectangle rect) {
return getBounds().intersects(rect);
}
/**
* @see IFigure#invalidate()
*/
public void invalidate() {
if (layoutManager != null)
layoutManager.invalidate();
setValid(false);
}
/**
* @see IFigure#invalidateTree()
*/
public void invalidateTree() {
invalidate();
for (Iterator iter = children.iterator(); iter.hasNext();) {
IFigure child = (IFigure) iter.next();
child.invalidateTree();
}
}
/**
* @see IFigure#isCoordinateSystem()
*/
public boolean isCoordinateSystem() {
return useLocalCoordinates();
}
/**
* @see IFigure#isEnabled()
*/
public boolean isEnabled() {
return (flags & FLAG_ENABLED) != 0;
}
/**
* @see IFigure#isFocusTraversable()
*/
public boolean isFocusTraversable() {
return (flags & FLAG_FOCUS_TRAVERSABLE) != 0;
}
/**
* Returns <code>true</code> if this Figure can receive {@link MouseEvent
* MouseEvents}.
*
* @return <code>true</code> if this Figure can receive {@link MouseEvent
* MouseEvents}
* @since 2.0
*/
protected boolean isMouseEventTarget() {
return (eventListeners.containsListener(MouseListener.class) || eventListeners
.containsListener(MouseMotionListener.class));
}
/**
* @see org.eclipse.draw2d.IFigure#isMirrored()
*/
public boolean isMirrored() {
if (getParent() != null)
return getParent().isMirrored();
return false;
}
/**
* @see IFigure#isOpaque()
*/
public boolean isOpaque() {
return (flags & FLAG_OPAQUE) != 0;
}
/**
* @see IFigure#isRequestFocusEnabled()
*/
public boolean isRequestFocusEnabled() {
return (flags & FLAG_FOCUSABLE) != 0;
}
/**
* @see IFigure#isShowing()
*/
public boolean isShowing() {
return isVisible() && (getParent() == null || getParent().isShowing());
}
/**
* Returns <code>true</code> if this Figure is valid.
*
* @return <code>true</code> if this Figure is valid
* @since 2.0
*/
protected boolean isValid() {
return (flags & FLAG_VALID) != 0;
}
/**
* Returns <code>true</code> if revalidating this Figure does not require
* revalidating its parent.
*
* @return <code>true</code> if revalidating this Figure doesn't require
* revalidating its parent.
* @since 2.0
*/
protected boolean isValidationRoot() {
return false;
}
/**
* @see IFigure#isVisible()
*/
public boolean isVisible() {
return getFlag(FLAG_VISIBLE);
}
/**
* Lays out this Figure using its {@link LayoutManager}.
*
* @since 2.0
*/
protected void layout() {
if (layoutManager != null)
layoutManager.layout(this);
}
/**
* Paints this Figure and its children.
*
* @param graphics
* The Graphics object used for painting
* @see #paintFigure(Graphics)
* @see #paintClientArea(Graphics)
* @see #paintBorder(Graphics)
*/
public void paint(Graphics graphics) {
if (getLocalBackgroundColor() != null)
graphics.setBackgroundColor(getLocalBackgroundColor());
if (getLocalForegroundColor() != null)
graphics.setForegroundColor(getLocalForegroundColor());
if (font != null)
graphics.setFont(font);
graphics.pushState();
try {
paintFigure(graphics);
graphics.restoreState();
paintClientArea(graphics);
paintBorder(graphics);
} finally {
graphics.popState();
}
}
/**
* Paints the border associated with this Figure, if one exists.
*
* @param graphics
* The Graphics used to paint
* @see Border#paint(IFigure, Graphics, Insets)
* @since 2.0
*/
protected void paintBorder(Graphics graphics) {
if (getBorder() != null)
getBorder().paint(this, graphics, NO_INSETS);
}
/**
* Paints this Figure's children. The caller must save the state of the
* graphics prior to calling this method, such that
* <code>graphics.restoreState()</code> may be called safely, and doing so
* will return the graphics to its original state when the method was
* entered.
* <P>
* This method must leave the Graphics in its original state upon return.
*
* @param graphics
* the graphics used to paint
* @since 2.0
*/
protected void paintChildren(Graphics graphics) {
for (int i = 0; i < children.size(); i++) {
IFigure child = (IFigure) children.get(i);
if (child.isVisible()) {
// determine clipping areas for child
Rectangle[] clipping = null;
if (clippingStrategy != null) {
clipping = clippingStrategy.getClip(child);
} else {
// default clipping behaviour is to clip at bounds
clipping = new Rectangle[] { child.getBounds() };
}
// child may now paint inside the clipping areas
for (int j = 0; j < clipping.length; j++) {
if (clipping[j].intersects(graphics
.getClip(Rectangle.SINGLETON))) {
graphics.clipRect(clipping[j]);
child.paint(graphics);
graphics.restoreState();
}
}
}
}
}
/**
* Paints this Figure's client area. The client area is typically defined as
* the anything inside the Figure's {@link Border} or {@link Insets}, and by
* default includes the children of this Figure. On return, this method must
* leave the given Graphics in its initial state.
*
* @param graphics
* The Graphics used to paint
* @since 2.0
*/
protected void paintClientArea(Graphics graphics) {
if (children.isEmpty())
return;
boolean optimizeClip = getBorder() == null || getBorder().isOpaque();
if (useLocalCoordinates()) {
graphics.translate(getBounds().x + getInsets().left, getBounds().y
+ getInsets().top);
if (!optimizeClip)
graphics.clipRect(getClientArea(PRIVATE_RECT));
graphics.pushState();
paintChildren(graphics);
graphics.popState();
graphics.restoreState();
} else {
if (optimizeClip)
paintChildren(graphics);
else {
graphics.clipRect(getClientArea(PRIVATE_RECT));
graphics.pushState();
paintChildren(graphics);
graphics.popState();
graphics.restoreState();
}
}
}
/**
* Paints this Figure's primary representation, or background. Changes made
* to the graphics to the graphics current state will not affect the
* subsequent calls to {@link #paintClientArea(Graphics)} and
* {@link #paintBorder(Graphics)}. Furthermore, it is safe to call
* <code>graphics.restoreState()</code> within this method, and doing so
* will restore the graphics to its original state upon entry.
*
* @param graphics
* The Graphics used to paint
* @since 2.0
*/
protected void paintFigure(Graphics graphics) {
if (isOpaque())
graphics.fillRectangle(getBounds());
if (getBorder() instanceof AbstractBackground)
((AbstractBackground) getBorder()).paintBackground(this, graphics,
NO_INSETS);
}
/**
* Translates this Figure's bounds, without firing a move.
*
* @param dx
* The amount to translate horizontally
* @param dy
* The amount to translate vertically
* @see #translate(int, int)
* @since 2.0
*/
protected void primTranslate(int dx, int dy) {
bounds.x += dx;
bounds.y += dy;
if (useLocalCoordinates()) {
fireCoordinateSystemChanged();
return;
}
for (int i = 0; i < children.size(); i++)
((IFigure) children.get(i)).translate(dx, dy);
}
/**
* Removes the given child Figure from this Figure's hierarchy and
* revalidates this Figure. The child Figure's {@link #removeNotify()}
* method is also called.
*
* @param figure
* The Figure to remove
*/
public void remove(IFigure figure) {
if ((figure.getParent() != this))
throw new IllegalArgumentException("Figure is not a child"); //$NON-NLS-1$
if (getFlag(FLAG_REALIZED))
figure.removeNotify();
if (layoutManager != null)
layoutManager.remove(figure);
// The updates in the UpdateManager *have* to be
// done asynchronously, else will result in
// incorrect dirty region corrections.
figure.erase();
figure.setParent(null);
children.remove(figure);
revalidate();
}
/**
* Removes all children from this Figure.
*
* @see #remove(IFigure)
* @since 2.0
*/
public void removeAll() {
List list = new ArrayList(getChildren());
for (int i = 0; i < list.size(); i++) {
remove((IFigure) list.get(i));
}
}
/**
* @see IFigure#removeAncestorListener(AncestorListener)
*/
public void removeAncestorListener(AncestorListener listener) {
if (ancestorHelper != null) {
ancestorHelper.removeAncestorListener(listener);
if (ancestorHelper.isEmpty()) {
ancestorHelper.dispose();
ancestorHelper = null;
}
}
}
/**
* @see IFigure#removeCoordinateListener(CoordinateListener)
*/
public void removeCoordinateListener(CoordinateListener listener) {
eventListeners.removeListener(CoordinateListener.class, listener);
}
/**
* @see IFigure#removeFigureListener(FigureListener)
*/
public void removeFigureListener(FigureListener listener) {
eventListeners.removeListener(FigureListener.class, listener);
}
/**
* @see IFigure#removeFocusListener(FocusListener)
*/
public void removeFocusListener(FocusListener listener) {
eventListeners.removeListener(FocusListener.class, listener);
}
/**
* @see IFigure#removeKeyListener(KeyListener)
*/
public void removeKeyListener(KeyListener listener) {
eventListeners.removeListener(KeyListener.class, listener);
}
/**
* Removes the first occurence of the given listener.
*
* @since 3.1
* @param listener
* the listener being removed
*/
public void removeLayoutListener(LayoutListener listener) {
if (layoutManager instanceof LayoutNotifier) {
LayoutNotifier notifier = (LayoutNotifier) layoutManager;
notifier.listeners.remove(listener);
if (notifier.listeners.isEmpty())
layoutManager = notifier.realLayout;
}
}
/**
* Removes <i>listener</i> of type <i>clazz</i> from this Figure's list of
* listeners.
*
* @param clazz
* The type of listener
* @param listener
* The listener to remove
* @since 2.0
*/
protected void removeListener(Class clazz, Object listener) {
if (eventListeners == null)
return;
eventListeners.removeListener(clazz, listener);
}
/**
* @see IFigure#removeMouseListener(MouseListener)
*/
public void removeMouseListener(MouseListener listener) {
eventListeners.removeListener(MouseListener.class, listener);
}
/**
* @see IFigure#removeMouseMotionListener(MouseMotionListener)
*/
public void removeMouseMotionListener(MouseMotionListener listener) {
eventListeners.removeListener(MouseMotionListener.class, listener);
}
/**
* Called prior to this figure's removal from its parent
*/
public void removeNotify() {
for (int i = 0; i < children.size(); i++)
((IFigure) children.get(i)).removeNotify();
if (internalGetEventDispatcher() != null)
internalGetEventDispatcher().requestRemoveFocus(this);
setFlag(FLAG_REALIZED, false);
}
/**
* @see IFigure#removePropertyChangeListener(PropertyChangeListener)
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (propertyListeners == null)
return;
propertyListeners.removePropertyChangeListener(listener);
}
/**
* @see IFigure#removePropertyChangeListener(String, PropertyChangeListener)
*/
public void removePropertyChangeListener(String property,
PropertyChangeListener listener) {
if (propertyListeners == null)
return;
propertyListeners.removePropertyChangeListener(property, listener);
}
/**
* @see IFigure#repaint(Rectangle)
*/
public final void repaint(Rectangle rect) {
repaint(rect.x, rect.y, rect.width, rect.height);
}
/**
* @see IFigure#repaint(int, int, int, int)
*/
public void repaint(int x, int y, int w, int h) {
if (isVisible())
getUpdateManager().addDirtyRegion(this, x, y, w, h);
}
/**
* @see IFigure#repaint()
*/
public void repaint() {
repaint(getBounds());
}
/**
* @see IFigure#requestFocus()
*/
public final void requestFocus() {
if (!isRequestFocusEnabled() || hasFocus())
return;
EventDispatcher dispatcher = internalGetEventDispatcher();
if (dispatcher == null)
return;
dispatcher.requestFocus(this);
}
/**
* @see IFigure#revalidate()
*/
public void revalidate() {
invalidate();
if (getParent() == null || isValidationRoot())
getUpdateManager().addInvalidFigure(this);
else
getParent().revalidate();
}
/**
* @see IFigure#setBackgroundColor(Color)
*/
public void setBackgroundColor(Color bg) {
// Set background color to bg unless in high contrast mode.
// In that case, get the color from system
if (bgColor != null && bgColor.equals(bg))
return;
Display display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
Color highContrastClr = null;
try {
if (display.getHighContrast()) {
highContrastClr = display
.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
} catch (SWTException e) {
highContrastClr = null;
}
bgColor = highContrastClr == null ? bg : highContrastClr;
repaint();
}
/**
* @see IFigure#setBorder(Border)
*/
public void setBorder(Border border) {
this.border = border;
revalidate();
repaint();
}
/**
* Sets the bounds of this Figure to the Rectangle <i>rect</i>. Note that
* <i>rect</i> is compared to the Figure's current bounds to determine what
* needs to be repainted and/or exposed and if validation is required. Since
* {@link #getBounds()} may return the current bounds by reference, it is
* not safe to modify that Rectangle and then call setBounds() after making
* modifications. The figure would assume that the bounds are unchanged, and
* no layout or paint would occur. For proper behavior, always use a copy.
*
* @param rect
* The new bounds
* @since 2.0
*/
public void setBounds(Rectangle rect) {
int x = bounds.x, y = bounds.y;
boolean resize = (rect.width != bounds.width)
|| (rect.height != bounds.height), translate = (rect.x != x)
|| (rect.y != y);
if ((resize || translate) && isVisible())
erase();
if (translate) {
int dx = rect.x - x;
int dy = rect.y - y;
primTranslate(dx, dy);
}
bounds.width = rect.width;
bounds.height = rect.height;
if (translate || resize) {
if (resize)
invalidate();
fireFigureMoved();
repaint();
}
}
/**
* Sets the direction of any {@link Orientable} children. Allowable values
* for <code>dir</code> are found in {@link PositionConstants}.
*
* @param direction
* The direction
* @see Orientable#setDirection(int)
* @since 2.0
*/
protected void setChildrenDirection(int direction) {
FigureIterator iterator = new FigureIterator(this);
IFigure child;
while (iterator.hasNext()) {
child = iterator.nextFigure();
if (child instanceof Orientable)
((Orientable) child).setDirection(direction);
}
}
/**
* Sets all childrens' enabled property to <i>value</i>.
*
* @param value
* The enable value
* @see #setEnabled(boolean)
* @since 2.0
*/
protected void setChildrenEnabled(boolean value) {
FigureIterator iterator = new FigureIterator(this);
while (iterator.hasNext())
iterator.nextFigure().setEnabled(value);
}
/**
* Sets the orientation of any {@link Orientable} children. Allowable values
* for <i>orientation</i> are found in {@link PositionConstants}.
*
* @param orientation
* The Orientation
* @see Orientable#setOrientation(int)
* @since 2.0
*/
protected void setChildrenOrientation(int orientation) {
FigureIterator iterator = new FigureIterator(this);
IFigure child;
while (iterator.hasNext()) {
child = iterator.nextFigure();
if (child instanceof Orientable)
((Orientable) child).setOrientation(orientation);
}
}
/**
* @see IFigure#setConstraint(IFigure, Object)
*/
public void setConstraint(IFigure child, Object constraint) {
if (child.getParent() != this)
throw new IllegalArgumentException("Figure must be a child"); //$NON-NLS-1$
if (layoutManager != null)
layoutManager.setConstraint(child, constraint);
revalidate();
}
/**
* Registers a clipping strategy to specify how clipping is performed for
* child figures.
*
* @param clippingStrategy
* @since 3.6
*/
public void setClippingStrategy(IClippingStrategy clippingStrategy) {
this.clippingStrategy = clippingStrategy;
}
/**
* @see IFigure#setCursor(Cursor)
*/
public void setCursor(Cursor cursor) {
if (this.cursor == cursor)
return;
this.cursor = cursor;
EventDispatcher dispatcher = internalGetEventDispatcher();
if (dispatcher != null)
dispatcher.updateCursor();
}
/**
* @see IFigure#setEnabled(boolean)
*/
public void setEnabled(boolean value) {
if (isEnabled() == value)
return;
setFlag(FLAG_ENABLED, value);
}
/**
* Sets the given flag to the given value.
*
* @param flag
* The flag to set
* @param value
* The value
* @since 2.0
*/
protected final void setFlag(int flag, boolean value) {
if (value)
flags |= flag;
else
flags &= ~flag;
}
/**
* @see IFigure#setFocusTraversable(boolean)
*/
public void setFocusTraversable(boolean focusTraversable) {
if (isFocusTraversable() == focusTraversable)
return;
setFlag(FLAG_FOCUS_TRAVERSABLE, focusTraversable);
}
/**
* @see IFigure#setFont(Font)
*/
public void setFont(Font f) {
if (font != f) {
font = f;
revalidate();
repaint();
}
}
/**
* @see IFigure#setForegroundColor(Color)
*/
public void setForegroundColor(Color fg) {
// Set foreground color to fg unless in high contrast mode.
// In that case, get the color from system
if (fgColor != null && fgColor.equals(fg))
return;
Display display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
Color highContrastClr = null;
try {
if (display.getHighContrast()) {
highContrastClr = display
.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND);
}
} catch (SWTException e) {
highContrastClr = null;
}
fgColor = highContrastClr == null ? fg : highContrastClr;
repaint();
}
/**
* @see IFigure#setLayoutManager(LayoutManager)
*/
public void setLayoutManager(LayoutManager manager) {
if (layoutManager instanceof LayoutNotifier)
((LayoutNotifier) layoutManager).realLayout = manager;
else
layoutManager = manager;
revalidate();
}
/**
* @see IFigure#setLocation(Point)
*/
public void setLocation(Point p) {
if (getLocation().equals(p))
return;
Rectangle r = new Rectangle(getBounds());
r.setLocation(p);
setBounds(r);
}
/**
* @see IFigure#setMaximumSize(Dimension)
*/
public void setMaximumSize(Dimension d) {
if (maxSize != null && maxSize.equals(d))
return;
maxSize = d;
revalidate();
}
/**
* @see IFigure#setMinimumSize(Dimension)
*/
public void setMinimumSize(Dimension d) {
if (minSize != null && minSize.equals(d))
return;
minSize = d;
revalidate();
}
/**
* @see IFigure#setOpaque(boolean)
*/
public void setOpaque(boolean opaque) {
if (isOpaque() == opaque)
return;
setFlag(FLAG_OPAQUE, opaque);
repaint();
}
/**
* @see IFigure#setParent(IFigure)
*/
public void setParent(IFigure p) {
IFigure oldParent = parent;
parent = p;
firePropertyChange("parent", oldParent, p);//$NON-NLS-1$
}
/**
* @see IFigure#setPreferredSize(Dimension)
*/
public void setPreferredSize(Dimension size) {
if (prefSize != null && prefSize.equals(size))
return;
prefSize = size;
revalidate();
}
/**
* Sets the preferred size of this figure.
*
* @param w
* The new preferred width
* @param h
* The new preferred height
* @see #setPreferredSize(Dimension)
* @since 2.0
*/
public final void setPreferredSize(int w, int h) {
setPreferredSize(new Dimension(w, h));
}
/**
* @see IFigure#setRequestFocusEnabled(boolean)
*/
public void setRequestFocusEnabled(boolean requestFocusEnabled) {
if (isRequestFocusEnabled() == requestFocusEnabled)
return;
setFlag(FLAG_FOCUSABLE, requestFocusEnabled);
}
/**
* @see IFigure#setSize(Dimension)
*/
public final void setSize(Dimension d) {
setSize(d.width, d.height);
}
/**
* @see IFigure#setSize(int, int)
*/
public void setSize(int w, int h) {
Rectangle bounds = getBounds();
if (bounds.width == w && bounds.height == h)
return;
Rectangle r = new Rectangle(getBounds());
r.setSize(w, h);
setBounds(r);
}
/**
* @see IFigure#setToolTip(IFigure)
*/
public void setToolTip(IFigure f) {
if (toolTip == f)
return;
toolTip = f;
}
/**
* Sets this figure to be valid if <i>value</i> is <code>true</code> and
* invalid otherwise.
*
* @param value
* The valid value
* @since 2.0
*/
public void setValid(boolean value) {
setFlag(FLAG_VALID, value);
}
/**
* @see IFigure#setVisible(boolean)
*/
public void setVisible(boolean visible) {
boolean currentVisibility = isVisible();
if (visible == currentVisibility)
return;
if (currentVisibility)
erase();
setFlag(FLAG_VISIBLE, visible);
if (visible)
repaint();
revalidate();
}
/**
* @see IFigure#translate(int, int)
*/
public final void translate(int x, int y) {
primTranslate(x, y);
fireFigureMoved();
}
/**
* @see IFigure#translateFromParent(Translatable)
*/
public void translateFromParent(Translatable t) {
if (useLocalCoordinates())
t.performTranslate(-getBounds().x - getInsets().left,
-getBounds().y - getInsets().top);
}
/**
* @see IFigure#translateToAbsolute(Translatable)
*/
public final void translateToAbsolute(Translatable t) {
if (getParent() != null) {
getParent().translateToParent(t);
getParent().translateToAbsolute(t);
}
}
/**
* @see IFigure#translateToParent(Translatable)
*/
public void translateToParent(Translatable t) {
if (useLocalCoordinates())
t.performTranslate(getBounds().x + getInsets().left, getBounds().y
+ getInsets().top);
}
/**
* @see IFigure#translateToRelative(Translatable)
*/
public final void translateToRelative(Translatable t) {
if (getParent() != null) {
getParent().translateToRelative(t);
getParent().translateFromParent(t);
}
}
/**
* Returns <code>true</code> if this Figure uses local coordinates. This
* means its children are placed relative to this Figure's top-left corner.
*
* @return <code>true</code> if this Figure uses local coordinates
* @since 2.0
*/
protected boolean useLocalCoordinates() {
return false;
}
/**
* @see IFigure#validate()
*/
public void validate() {
if (isValid())
return;
setValid(true);
layout();
for (int i = 0; i < children.size(); i++)
((IFigure) children.get(i)).validate();
}
/**
* A search which does not filter any figures. since 3.0
*/
protected static final class IdentitySearch implements TreeSearch {
/**
* The singleton instance.
*/
public static final TreeSearch INSTANCE = new IdentitySearch();
private IdentitySearch() {
}
/**
* Always returns <code>true</code>.
*
* @see TreeSearch#accept(IFigure)
*/
public boolean accept(IFigure f) {
return true;
}
/**
* Always returns <code>false</code>.
*
* @see TreeSearch#prune(IFigure)
*/
public boolean prune(IFigure f) {
return false;
}
}
final class LayoutNotifier implements LayoutManager {
LayoutManager realLayout;
List listeners = new ArrayList(1);
LayoutNotifier(LayoutManager layout, LayoutListener listener) {
realLayout = layout;
listeners.add(listener);
}
public Object getConstraint(IFigure child) {
if (realLayout != null)
return realLayout.getConstraint(child);
return null;
}
public Dimension getMinimumSize(IFigure container, int wHint, int hHint) {
if (realLayout != null)
return realLayout.getMinimumSize(container, wHint, hHint);
return null;
}
public Dimension getPreferredSize(IFigure container, int wHint,
int hHint) {
if (realLayout != null)
return realLayout.getPreferredSize(container, wHint, hHint);
return null;
}
public void invalidate() {
for (int i = 0; i < listeners.size(); i++)
((LayoutListener) listeners.get(i)).invalidate(Figure.this);
if (realLayout != null)
realLayout.invalidate();
}
public void layout(IFigure container) {
boolean consumed = false;
for (int i = 0; i < listeners.size(); i++)
consumed |= ((LayoutListener) listeners.get(i))
.layout(container);
if (realLayout != null && !consumed)
realLayout.layout(container);
for (int i = 0; i < listeners.size(); i++)
((LayoutListener) listeners.get(i)).postLayout(container);
}
public void remove(IFigure child) {
for (int i = 0; i < listeners.size(); i++)
((LayoutListener) listeners.get(i)).remove(child);
if (realLayout != null)
realLayout.remove(child);
}
public void setConstraint(IFigure child, Object constraint) {
for (int i = 0; i < listeners.size(); i++)
((LayoutListener) listeners.get(i)).setConstraint(child,
constraint);
if (realLayout != null)
realLayout.setConstraint(child, constraint);
}
}
/**
* Iterates over a Figure's children.
*/
public static class FigureIterator {
private List list;
private int index;
/**
* Constructs a new FigureIterator for the given Figure.
*
* @param figure
* The Figure whose children to iterate over
*/
public FigureIterator(IFigure figure) {
list = figure.getChildren();
index = list.size();
}
/**
* Returns the next Figure.
*
* @return The next Figure
*/
public IFigure nextFigure() {
return (IFigure) list.get(--index);
}
/**
* Returns <code>true</code> if there's another Figure to iterate over.
*
* @return <code>true</code> if there's another Figure to iterate over
*/
public boolean hasNext() {
return index > 0;
}
}
/**
* An UpdateManager that does nothing.
*/
protected static final UpdateManager NO_MANAGER = new UpdateManager() {
public void addDirtyRegion(IFigure figure, int x, int y, int w, int h) {
}
public void addInvalidFigure(IFigure f) {
}
public void performUpdate() {
}
public void performUpdate(Rectangle region) {
}
public void setRoot(IFigure root) {
}
public void setGraphicsSource(GraphicsSource gs) {
}
};
}