| /******************************************************************************* |
| * 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.draw2d.rap.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 |
| 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) { |
| } |
| }; |
| |
| } |