From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/java/awt/Component.java | 7099 +++++++++++++++++++++++++++++ 1 file changed, 7099 insertions(+) create mode 100644 libjava/classpath/java/awt/Component.java (limited to 'libjava/classpath/java/awt/Component.java') diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java new file mode 100644 index 000000000..d2878a9fd --- /dev/null +++ b/libjava/classpath/java/awt/Component.java @@ -0,0 +1,7099 @@ +/* Component.java -- a graphics component + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.awt; + +//import gnu.java.awt.dnd.peer.gtk.GtkDropTargetContextPeer; + +import gnu.java.awt.ComponentReshapeEvent; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.AdjustmentEvent; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.awt.image.BufferStrategy; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.accessibility.AccessibleStateSet; + +/** + * The root of all evil. All graphical representations are subclasses of this + * giant class, which is designed for screen display and user interaction. + * This class can be extended directly to build a lightweight component (one + * not associated with a native window); lightweight components must reside + * inside a heavyweight window. + * + *

This class is Serializable, which has some big implications. A user can + * save the state of all graphical components in one VM, and reload them in + * another. Note that this class will only save Serializable listeners, and + * ignore the rest, without causing any serialization exceptions. However, by + * making a listener serializable, and adding it to another element, you link + * in that entire element to the state of this component. To get around this, + * use the idiom shown in the example below - make listeners non-serializable + * in inner classes, rather than using this object itself as the listener, if + * external objects do not need to save the state of this object. + * + *

+ * import java.awt.*;
+ * import java.awt.event.*;
+ * import java.io.Serializable;
+ * class MyApp implements Serializable
+ * {
+ *   BigObjectThatShouldNotBeSerializedWithAButton bigOne;
+ *   // Serializing aButton will not suck in an instance of MyApp, with its
+ *   // accompanying field bigOne.
+ *   Button aButton = new Button();
+ *   class MyActionListener implements ActionListener
+ *   {
+ *     public void actionPerformed(ActionEvent e)
+ *     {
+ *       System.out.println("Hello There");
+ *     }
+ *   }
+ *   MyApp()
+ *   {
+ *     aButton.addActionListener(new MyActionListener());
+ *   }
+ * }
+ * 
+ * + *

Status: Incomplete. The event dispatch mechanism is implemented. All + * other methods defined in the J2SE 1.3 API javadoc exist, but are mostly + * incomplete or only stubs; except for methods relating to the Drag and + * Drop, Input Method, and Accessibility frameworks: These methods are + * present but commented out. + * + * @author original author unknown + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 support + */ +public abstract class Component + implements ImageObserver, MenuContainer, Serializable +{ + // Word to the wise - this file is huge. Search for '\f' (^L) for logical + // sectioning by fields, public API, private API, and nested classes. + + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7644114512714619750L; + + /** + * Constant returned by the getAlignmentY method to indicate + * that the component wishes to be aligned to the top relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float TOP_ALIGNMENT = 0; + + /** + * Constant returned by the getAlignmentY and + * getAlignmentX methods to indicate + * that the component wishes to be aligned to the centdisper relative to + * other components. + * + * @see #getAlignmentX() + * @see #getAlignmentY() + */ + public static final float CENTER_ALIGNMENT = 0.5f; + + /** + * Constant returned by the getAlignmentY method to indicate + * that the component wishes to be aligned to the bottom relative to + * other components. + * + * @see #getAlignmentY() + */ + public static final float BOTTOM_ALIGNMENT = 1; + + /** + * Constant returned by the getAlignmentX method to indicate + * that the component wishes to be aligned to the right relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float RIGHT_ALIGNMENT = 1; + + /** + * Constant returned by the getAlignmentX method to indicate + * that the component wishes to be aligned to the left relative to + * other components. + * + * @see #getAlignmentX() + */ + public static final float LEFT_ALIGNMENT = 0; + + /** + * Make the treelock a String so that it can easily be identified + * in debug dumps. We clone the String in order to avoid a conflict in + * the unlikely event that some other package uses exactly the same string + * as a lock object. + */ + static final Object treeLock = new String("AWT_TREE_LOCK"); + + /** + * The default maximum size. + */ + private static final Dimension DEFAULT_MAX_SIZE + = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + + // Serialized fields from the serialization spec. + + /** + * The x position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the x position + */ + int x; + + /** + * The y position of the component in the parent's coordinate system. + * + * @see #getLocation() + * @serial the y position + */ + int y; + + /** + * The component width. + * + * @see #getSize() + * @serial the width + */ + int width; + + /** + * The component height. + * + * @see #getSize() + * @serial the height + */ + int height; + + /** + * The foreground color for the component. This may be null. + * + * @see #getForeground() + * @see #setForeground(Color) + * @serial the foreground color + */ + Color foreground; + + /** + * The background color for the component. This may be null. + * + * @see #getBackground() + * @see #setBackground(Color) + * @serial the background color + */ + Color background; + + /** + * The default font used in the component. This may be null. + * + * @see #getFont() + * @see #setFont(Font) + * @serial the font + */ + Font font; + + /** + * The font in use by the peer, or null if there is no peer. + * + * @serial the peer's font + */ + Font peerFont; + + /** + * The cursor displayed when the pointer is over this component. This may + * be null. + * + * @see #getCursor() + * @see #setCursor(Cursor) + */ + Cursor cursor; + + /** + * The locale for the component. + * + * @see #getLocale() + * @see #setLocale(Locale) + */ + Locale locale = Locale.getDefault (); + + /** + * True if the object should ignore repaint events (usually because it is + * not showing). + * + * @see #getIgnoreRepaint() + * @see #setIgnoreRepaint(boolean) + * @serial true to ignore repaints + * @since 1.4 + */ + boolean ignoreRepaint; + + /** + * True when the object is visible (although it is only showing if all + * ancestors are likewise visible). For component, this defaults to true. + * + * @see #isVisible() + * @see #setVisible(boolean) + * @serial true if visible + */ + boolean visible = true; + + /** + * True if the object is enabled, meaning it can interact with the user. + * For component, this defaults to true. + * + * @see #isEnabled() + * @see #setEnabled(boolean) + * @serial true if enabled + */ + boolean enabled = true; + + /** + * True if the object is valid. This is set to false any time a size + * adjustment means the component need to be layed out again. + * + * @see #isValid() + * @see #validate() + * @see #invalidate() + * @serial true if layout is valid + */ + boolean valid; + + /** + * The DropTarget for drag-and-drop operations. + * + * @see #getDropTarget() + * @see #setDropTarget(DropTarget) + * @serial the drop target, or null + * @since 1.2 + */ + DropTarget dropTarget; + + /** + * The list of popup menus for this component. + * + * @see #add(PopupMenu) + * @serial the list of popups + */ + Vector popups; + + /** + * The component's name. May be null, in which case a default name is + * generated on the first use. + * + * @see #getName() + * @see #setName(String) + * @serial the name + */ + String name; + + /** + * True once the user has set the name. Note that the user may set the name + * to null. + * + * @see #name + * @see #getName() + * @see #setName(String) + * @serial true if the name has been explicitly set + */ + boolean nameExplicitlySet; + + /** + * Indicates if the object can be focused. Defaults to true for components. + * + * @see #isFocusable() + * @see #setFocusable(boolean) + * @since 1.4 + */ + boolean focusable = true; + + /** + * Tracks whether this component's {@link #isFocusTraversable} + * method has been overridden. + * + * @since 1.4 + */ + int isFocusTraversableOverridden; + + /** + * The focus traversal keys, if not inherited from the parent or + * default keyboard focus manager. These sets will contain only + * AWTKeyStrokes that represent press and release events to use as + * focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + Set[] focusTraversalKeys; + + /** + * True if focus traversal keys are enabled. This defaults to true for + * Component. If this is true, keystrokes in focusTraversalKeys are trapped + * and processed automatically rather than being passed on to the component. + * + * @see #getFocusTraversalKeysEnabled() + * @see #setFocusTraversalKeysEnabled(boolean) + * @since 1.4 + */ + boolean focusTraversalKeysEnabled = true; + + /** + * Cached information on the minimum size. Should have been transient. + * + * @serial ignore + */ + Dimension minSize; + + /** + * Flag indicating whether the minimum size for the component has been set + * by a call to {@link #setMinimumSize(Dimension)} with a non-null value. + */ + boolean minSizeSet; + + /** + * The maximum size for the component. + * @see #setMaximumSize(Dimension) + */ + Dimension maxSize; + + /** + * A flag indicating whether the maximum size for the component has been set + * by a call to {@link #setMaximumSize(Dimension)} with a non-null value. + */ + boolean maxSizeSet; + + /** + * Cached information on the preferred size. Should have been transient. + * + * @serial ignore + */ + Dimension prefSize; + + /** + * Flag indicating whether the preferred size for the component has been set + * by a call to {@link #setPreferredSize(Dimension)} with a non-null value. + */ + boolean prefSizeSet; + + /** + * Set to true if an event is to be handled by this component, false if + * it is to be passed up the hierarcy. + * + * @see #dispatchEvent(AWTEvent) + * @serial true to process event locally + */ + boolean newEventsOnly; + + /** + * Set by subclasses to enable event handling of particular events, and + * left alone when modifying listeners. For component, this defaults to + * enabling only input methods. + * + * @see #enableInputMethods(boolean) + * @see AWTEvent + * @serial the mask of events to process + */ + long eventMask = AWTEvent.INPUT_ENABLED_EVENT_MASK; + + /** + * Describes all registered PropertyChangeListeners. + * + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #firePropertyChange(String, Object, Object) + * @serial the property change listeners + * @since 1.2 + */ + PropertyChangeSupport changeSupport; + + /** + * True if the component has been packed (layed out). + * + * @serial true if this is packed + */ + boolean isPacked; + + /** + * The serialization version for this class. Currently at version 4. + * + * XXX How do we handle prior versions? + * + * @serial the serialization version + */ + int componentSerializedDataVersion = 4; + + /** + * The accessible context associated with this component. This is only set + * by subclasses. + * + * @see #getAccessibleContext() + * @serial the accessibility context + * @since 1.2 + */ + AccessibleContext accessibleContext; + + + // Guess what - listeners are special cased in serialization. See + // readObject and writeObject. + + /** Component listener chain. */ + transient ComponentListener componentListener; + + /** Focus listener chain. */ + transient FocusListener focusListener; + + /** Key listener chain. */ + transient KeyListener keyListener; + + /** Mouse listener chain. */ + transient MouseListener mouseListener; + + /** Mouse motion listener chain. */ + transient MouseMotionListener mouseMotionListener; + + /** + * Mouse wheel listener chain. + * + * @since 1.4 + */ + transient MouseWheelListener mouseWheelListener; + + /** + * Input method listener chain. + * + * @since 1.2 + */ + transient InputMethodListener inputMethodListener; + + /** + * Hierarcy listener chain. + * + * @since 1.3 + */ + transient HierarchyListener hierarchyListener; + + /** + * Hierarcy bounds listener chain. + * + * @since 1.3 + */ + transient HierarchyBoundsListener hierarchyBoundsListener; + + // Anything else is non-serializable, and should be declared "transient". + + /** The parent. */ + transient Container parent; + + /** The associated native peer. */ + transient ComponentPeer peer; + + /** The preferred component orientation. */ + transient ComponentOrientation componentOrientation = ComponentOrientation.UNKNOWN; + + /** + * The associated graphics configuration. + * + * @since 1.4 + */ + transient GraphicsConfiguration graphicsConfig; + + /** + * The buffer strategy for repainting. + * + * @since 1.4 + */ + transient BufferStrategy bufferStrategy; + + /** + * The number of hierarchy listeners of this container plus all of its + * children. This is needed for efficient handling of HierarchyEvents. + * These must be propagated to all child components with HierarchyListeners + * attached. To avoid traversal of the whole subtree, we keep track of + * the number of HierarchyListeners here and only walk the paths that + * actually have listeners. + */ + int numHierarchyListeners; + int numHierarchyBoundsListeners; + + /** + * true if requestFocus was called on this component when its + * top-level ancestor was not focusable. + */ + private transient FocusEvent pendingFocusRequest = null; + + /** + * The system properties that affect image updating. + */ + private static transient boolean incrementalDraw; + private static transient Long redrawRate; + + static + { + incrementalDraw = Boolean.getBoolean ("awt.image.incrementalDraw"); + redrawRate = Long.getLong ("awt.image.redrawrate"); + } + + // Public and protected API. + + /** + * Default constructor for subclasses. When Component is extended directly, + * it forms a lightweight component that must be hosted in an opaque native + * container higher in the tree. + */ + protected Component() + { + // Nothing to do here. + } + + /** + * Returns the name of this component. + * + * @return the name of this component + * @see #setName(String) + * @since 1.1 + */ + public String getName() + { + if (name == null && ! nameExplicitlySet) + name = generateName(); + return name; + } + + /** + * Sets the name of this component to the specified name (this is a bound + * property with the name 'name'). + * + * @param name the new name (null permitted). + * @see #getName() + * @since 1.1 + */ + public void setName(String name) + { + nameExplicitlySet = true; + String old = this.name; + this.name = name; + firePropertyChange("name", old, name); + } + + /** + * Returns the parent of this component. + * + * @return the parent of this component + */ + public Container getParent() + { + return parent; + } + + /** + * Returns the native windowing system peer for this component. Only the + * platform specific implementation code should call this method. + * + * @return the peer for this component + * @deprecated user programs should not directly manipulate peers; use + * {@link #isDisplayable()} instead + */ + // Classpath's Gtk peers rely on this. + public ComponentPeer getPeer() + { + return peer; + } + + /** + * Set the associated drag-and-drop target, which receives events when this + * is enabled. + * + * @param dt the new drop target + * @see #isEnabled() + */ + public void setDropTarget(DropTarget dt) + { + this.dropTarget = dt; + + if (peer != null) + dropTarget.addNotify(peer); + } + + /** + * Gets the associated drag-and-drop target, if there is one. + * + * @return the drop target + */ + public DropTarget getDropTarget() + { + return dropTarget; + } + + /** + * Returns the graphics configuration of this component, if there is one. + * If it has not been set, it is inherited from the parent. + * + * @return the graphics configuration, or null + * @since 1.3 + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + GraphicsConfiguration conf = null; + synchronized (getTreeLock()) + { + if (graphicsConfig != null) + { + conf = graphicsConfig; + } + else + { + Component par = getParent(); + if (par != null) + { + conf = parent.getGraphicsConfiguration(); + } + } + } + return conf; + } + + /** + * Returns the object used for synchronization locks on this component + * when performing tree and layout functions. + * + * @return the synchronization lock for this component + */ + public final Object getTreeLock() + { + return treeLock; + } + + /** + * Returns the toolkit in use for this component. The toolkit is associated + * with the frame this component belongs to. + * + * @return the toolkit for this component + */ + public Toolkit getToolkit() + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + Toolkit tk = null; + if (p != null) + { + tk = peer.getToolkit(); + } + if (tk == null) + tk = Toolkit.getDefaultToolkit(); + return tk; + } + + /** + * Tests whether or not this component is valid. A invalid component needs + * to have its layout redone. + * + * @return true if this component is valid + * @see #validate() + * @see #invalidate() + */ + public boolean isValid() + { + // Tests show that components are invalid as long as they are not showing, even after validate() + // has been called on them. + return peer != null && valid; + } + + /** + * Tests if the component is displayable. It must be connected to a native + * screen resource. This reduces to checking that peer is not null. A + * containment hierarchy is made displayable when a window is packed or + * made visible. + * + * @return true if the component is displayable + * @see Container#add(Component) + * @see Container#remove(Component) + * @see Window#pack() + * @see Window#show() + * @see Window#dispose() + * @since 1.2 + */ + public boolean isDisplayable() + { + return peer != null; + } + + /** + * Tests whether or not this component is visible. Except for top-level + * frames, components are initially visible. + * + * @return true if the component is visible + * @see #setVisible(boolean) + */ + public boolean isVisible() + { + return visible; + } + + /** + * Tests whether or not this component is actually being shown on + * the screen. This will be true if and only if it this component is + * visible and its parent components are all visible. + * + * @return true if the component is showing on the screen + * @see #setVisible(boolean) + */ + public boolean isShowing() + { + Component par = parent; + return visible && peer != null && (par == null || par.isShowing()); + } + + /** + * Tests whether or not this component is enabled. Components are enabled + * by default, and must be enabled to receive user input or generate events. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Enables or disables this component. The component must be enabled to + * receive events (except that lightweight components always receive mouse + * events). + * + * @param enabled true to enable this component + * + * @see #isEnabled() + * @see #isLightweight() + * + * @since 1.1 + */ + public void setEnabled(boolean enabled) + { + enable(enabled); + } + + /** + * Enables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable() + { + if (! enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = true; + ComponentPeer p = peer; + if (p != null) + p.enable(); + } + } + } + + /** + * Enables or disables this component. + * + * @param enabled true to enable this component + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void enable(boolean enabled) + { + if (enabled) + enable(); + else + disable(); + } + + /** + * Disables this component. + * + * @deprecated use {@link #setEnabled(boolean)} instead + */ + public void disable() + { + if (enabled) + { + // Need to lock the tree here, because the peers are involved. + synchronized (getTreeLock()) + { + enabled = false; + ComponentPeer p = peer; + if (p != null) + p.disable(); + } + } + } + + /** + * Checks if this image is painted to an offscreen image buffer that is + * later copied to screen (double buffering reduces flicker). This version + * returns false, so subclasses must override it if they provide double + * buffering. + * + * @return true if this is double buffered; defaults to false + */ + public boolean isDoubleBuffered() + { + return false; + } + + /** + * Enables or disables input method support for this component. By default, + * components have this enabled. Input methods are given the opportunity + * to process key events before this component and its listeners. + * + * @param enable true to enable input method processing + * @see #processKeyEvent(KeyEvent) + * @since 1.2 + */ + public void enableInputMethods(boolean enable) + { + if (enable) + eventMask |= AWTEvent.INPUT_ENABLED_EVENT_MASK; + else + eventMask &= ~AWTEvent.INPUT_ENABLED_EVENT_MASK; + } + + /** + * Makes this component visible or invisible. Note that it wtill might + * not show the component, if a parent is invisible. + * + * @param visible true to make this component visible + * + * @see #isVisible() + * + * @since 1.1 + */ + public void setVisible(boolean visible) + { + // Inspection by subclassing shows that Sun's implementation calls + // show(boolean) which then calls show() or hide(). It is the show() + // method that is overriden in subclasses like Window. + show(visible); + } + + /** + * Makes this component visible on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show() + { + // We must set visible before showing the peer. Otherwise the + // peer could post paint events before visible is true, in which + // case lightweight components are not initially painted -- + // Container.paint first calls isShowing () before painting itself + // and its children. + if(! visible) + { + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = true; + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer = peer; + if (currentPeer != null) + { + currentPeer.show(); + + // Fire HierarchyEvent. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + + // The JDK repaints the component before invalidating the parent. + // So do we. + if (peer instanceof LightweightPeer) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_SHOWN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + // Invalidate the parent if we have one. The component itself must + // not be invalidated. We also avoid NullPointerException with + // a local reference here. + Container currentParent = parent; + if (currentParent != null) + currentParent.invalidate(); + + } + } + + /** + * Makes this component visible or invisible. + * + * @param visible true to make this component visible + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void show(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * Hides this component so that it is no longer shown on the screen. + * + * @deprecated use {@link #setVisible(boolean)} instead + */ + public void hide() + { + if (visible) + { + // Need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + visible = false; + + // Avoid NullPointerExceptions by creating a local reference. + ComponentPeer currentPeer = peer; + if (currentPeer != null) + { + currentPeer.hide(); + + // Fire hierarchy event. + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, + this, parent, + HierarchyEvent.SHOWING_CHANGED); + // The JDK repaints the component before invalidating the + // parent. So do we. This only applies for lightweights. + if (peer instanceof LightweightPeer) + repaint(); + } + + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + ComponentEvent ce = + new ComponentEvent(this,ComponentEvent.COMPONENT_HIDDEN); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + + // Invalidate the parent if we have one. The component itself need + // not be invalidated. We also avoid NullPointerException with + // a local reference here. + Container currentParent = parent; + if (currentParent != null) + currentParent.invalidate(); + + } + } + + /** + * Returns this component's foreground color. If not set, this is inherited + * from the parent. + * + * @return this component's foreground color, or null + * @see #setForeground(Color) + */ + public Color getForeground() + { + if (foreground != null) + return foreground; + return parent == null ? null : parent.getForeground(); + } + + /** + * Sets this component's foreground color to the specified color. This is a + * bound property. + * + * @param c the new foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + if (peer != null) + peer.setForeground(c); + + Color previous = foreground; + foreground = c; + firePropertyChange("foreground", previous, c); + } + + /** + * Tests if the foreground was explicitly set, or just inherited from the + * parent. + * + * @return true if the foreground has been set + * @since 1.4 + */ + public boolean isForegroundSet() + { + return foreground != null; + } + + /** + * Returns this component's background color. If not set, this is inherited + * from the parent. + * + * @return the background color of the component, or null + * @see #setBackground(Color) + */ + public Color getBackground() + { + if (background != null) + return background; + return parent == null ? null : parent.getBackground(); + } + + /** + * Sets this component's background color to the specified color. The parts + * of the component affected by the background color may by system dependent. + * This is a bound property. + * + * @param c the new background color + * @see #getBackground() + */ + public void setBackground(Color c) + { + // return if the background is already set to that color. + if ((c != null) && c.equals(background)) + return; + + Color previous = background; + background = c; + if (peer != null && c != null) + peer.setBackground(c); + firePropertyChange("background", previous, c); + } + + /** + * Tests if the background was explicitly set, or just inherited from the + * parent. + * + * @return true if the background has been set + * @since 1.4 + */ + public boolean isBackgroundSet() + { + return background != null; + } + + /** + * Returns the font in use for this component. If not set, this is inherited + * from the parent. + * + * @return the font for this component + * @see #setFont(Font) + */ + public Font getFont() + { + return getFontImpl(); + } + + /** + * Implementation of getFont(). This is pulled out of getFont() to prevent + * client programs from overriding this. + * + * @return the font of this component + */ + private final Font getFontImpl() + { + Font f = font; + if (f == null) + { + Component p = parent; + if (p != null) + f = p.getFontImpl(); + else + { + // It is important to return null here and not some kind of default + // font, otherwise the Swing UI would not install its fonts because + // it keeps non-UIResource fonts. + f = null; + } + } + return f; + } + + /** + * Sets the font for this component to the specified font. This is a bound + * property. + * + * @param f the new font for this component + * + * @see #getFont() + */ + public void setFont(Font f) + { + Font oldFont; + Font newFont; + // Synchronize on the tree because getFontImpl() relies on the hierarchy + // not beeing changed. + synchronized (getTreeLock()) + { + // Synchronize on this here to guarantee thread safety wrt to the + // property values. + synchronized (this) + { + oldFont = font; + font = f; + newFont = f; + } + // Create local variable here for thread safety. + ComponentPeer p = peer; + if (p != null) + { + // The peer receives the real font setting, which can depend on + // the parent font when this component's font has been set to null. + f = getFont(); + if (f != null) + { + p.setFont(f); + peerFont = f; + } + } + } + + // Fire property change event. + firePropertyChange("font", oldFont, newFont); + + // Invalidate when necessary as font changes can change the size of the + // component. + if (valid) + invalidate(); + } + + /** + * Tests if the font was explicitly set, or just inherited from the parent. + * + * @return true if the font has been set + * @since 1.4 + */ + public boolean isFontSet() + { + return font != null; + } + + /** + * Returns the locale for this component. If this component does not + * have a locale, the locale of the parent component is returned. + * + * @return the locale for this component + * @throws IllegalComponentStateException if it has no locale or parent + * @see #setLocale(Locale) + * @since 1.1 + */ + public Locale getLocale() + { + if (locale != null) + return locale; + if (parent == null) + throw new IllegalComponentStateException + ("Component has no parent: can't determine Locale"); + return parent.getLocale(); + } + + /** + * Sets the locale for this component to the specified locale. This is a + * bound property. + * + * @param newLocale the new locale for this component + */ + public void setLocale(Locale newLocale) + { + if (locale == newLocale) + return; + + Locale oldLocale = locale; + locale = newLocale; + firePropertyChange("locale", oldLocale, newLocale); + // New writing/layout direction or more/less room for localized labels. + invalidate(); + } + + /** + * Returns the color model of the device this componet is displayed on. + * + * @return this object's color model + * @see Toolkit#getColorModel() + */ + public ColorModel getColorModel() + { + GraphicsConfiguration config = getGraphicsConfiguration(); + return config != null ? config.getColorModel() + : getToolkit().getColorModel(); + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. This may be outdated, so for synchronous behavior, + * you should use a component listner. + * + * @return the location of this component + * @see #setLocation(int, int) + * @see #getLocationOnScreen() + * @since 1.1 + */ + public Point getLocation() + { + return location (); + } + + /** + * Returns the location of this component's top left corner in screen + * coordinates. + * + * @return the location of this component in screen coordinates + * @throws IllegalComponentStateException if the component is not showing + */ + public Point getLocationOnScreen() + { + if (! isShowing()) + throw new IllegalComponentStateException("component " + + getClass().getName() + + " not showing"); + + // Need to lock the tree here. We get crazy races and explosions when + // the tree changes while we are trying to find the location of this + // component. + synchronized (getTreeLock()) + { + // Only a heavyweight peer can answer the question for the screen + // location. So we are going through the hierarchy until we find + // one and add up the offsets while doing so. + int offsX = 0; + int offsY = 0; + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + offsX += comp.x; + offsY += comp.y; + comp = comp.parent; + p = comp == null ? null: comp.peer; + } + // Now we have a heavyweight component. + assert ! (p instanceof LightweightPeer); + Point loc = p.getLocationOnScreen(); + loc.x += offsX; + loc.y += offsY; + return loc; + } + } + + /** + * Returns the location of this component's top left corner relative to + * its parent component. + * + * @return the location of this component + * @deprecated use {@link #getLocation()} instead + */ + public Point location() + { + return new Point (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @see #getLocation() + * @see #setBounds(int, int, int, int) + */ + public void setLocation(int x, int y) + { + move (x, y); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param x the new X coordinate of this component + * @param y the new Y coordinate of this component + * @deprecated use {@link #setLocation(int, int)} instead + */ + public void move(int x, int y) + { + setBounds(x, y, this.width, this.height); + } + + /** + * Moves this component to the specified location, relative to the parent's + * coordinates. The coordinates are the new upper left corner of this + * component. + * + * @param p new coordinates for this component + * @throws NullPointerException if p is null + * @see #getLocation() + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setLocation(Point p) + { + setLocation(p.x, p.y); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @see #setSize(int, int) + * @since 1.1 + */ + public Dimension getSize() + { + return size (); + } + + /** + * Returns the size of this object. + * + * @return the size of this object + * @deprecated use {@link #getSize()} instead + */ + public Dimension size() + { + return new Dimension (width, height); + } + + /** + * Sets the size of this component to the specified width and height. + * + * @param width the new width of this component + * @param height the new height of this component + * @see #getSize() + * @see #setBounds(int, int, int, int) + */ + public void setSize(int width, int height) + { + resize (width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param width the new width of the component + * @param height the new height of the component + * @deprecated use {@link #setSize(int, int)} instead + */ + public void resize(int width, int height) + { + setBounds(this.x, this.y, width, height); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @see #setSize(int, int) + * @see #setBounds(int, int, int, int) + * @since 1.1 + */ + public void setSize(Dimension d) + { + resize (d); + } + + /** + * Sets the size of this component to the specified value. + * + * @param d the new size of this component + * @throws NullPointerException if d is null + * @deprecated use {@link #setSize(Dimension)} instead + */ + public void resize(Dimension d) + { + resize (d.width, d.height); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @see #setBounds(int, int, int, int) + * @see #getLocation() + * @see #getSize() + */ + public Rectangle getBounds() + { + return bounds (); + } + + /** + * Returns a bounding rectangle for this component. Note that the + * returned rectange is relative to this component's parent, not to + * the screen. + * + * @return the bounding rectangle for this component + * @deprecated use {@link #getBounds()} instead + */ + public Rectangle bounds() + { + return new Rectangle (x, y, width, height); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @see #getBounds() + * @see #setLocation(int, int) + * @see #setLocation(Point) + * @see #setSize(int, int) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(int x, int y, int w, int h) + { + reshape (x, y, w, h); + } + + /** + * Sets the bounding rectangle for this component to the specified values. + * Note that these coordinates are relative to the parent, not to the screen. + * + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @deprecated use {@link #setBounds(int, int, int, int)} instead + */ + public void reshape(int x, int y, int width, int height) + { + // We need to lock the tree here, otherwise we risk races and + // inconsistencies. + synchronized (getTreeLock()) + { + int oldx = this.x; + int oldy = this.y; + int oldwidth = this.width; + int oldheight = this.height; + + boolean resized = oldwidth != width || oldheight != height; + boolean moved = oldx != x || oldy != y; + + if (resized || moved) + { + // Update the fields. + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + if (peer != null) + { + peer.setBounds (x, y, width, height); + if (resized) + invalidate(); + if (parent != null && parent.valid) + parent.invalidate(); + } + + // Send some events to interested listeners. + notifyReshape(resized, moved); + + // Repaint this component and the parent if appropriate. + if (parent != null && peer instanceof LightweightPeer + && isShowing()) + { + // The parent repaints the area that we occupied before. + parent.repaint(oldx, oldy, oldwidth, oldheight); + // This component repaints the area that we occupy now. + repaint(); + } + } + } + } + + /** + * Sends notification to interested listeners about resizing and/or moving + * the component. If this component has interested + * component listeners or the corresponding event mask enabled, then + * COMPONENT_MOVED and/or COMPONENT_RESIZED events are posted to the event + * queue. + * + * @param resized true if the component has been resized, false otherwise + * @param moved true if the component has been moved, false otherwise + */ + void notifyReshape(boolean resized, boolean moved) + { + // Only post an event if this component actually has a listener + // or has this event explicitly enabled. + if (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0) + { + // Fire component event on this component. + if (moved) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_MOVED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + if (resized) + { + ComponentEvent ce = new ComponentEvent(this, + ComponentEvent.COMPONENT_RESIZED); + getToolkit().getSystemEventQueue().postEvent(ce); + } + } + } + + /** + * Sets the bounding rectangle for this component to the specified + * rectangle. Note that these coordinates are relative to the parent, not + * to the screen. + * + * @param r the new bounding rectangle + * @throws NullPointerException if r is null + * @see #getBounds() + * @see #setLocation(Point) + * @see #setSize(Dimension) + * @since 1.1 + */ + public void setBounds(Rectangle r) + { + setBounds (r.x, r.y, r.width, r.height); + } + + /** + * Gets the x coordinate of the upper left corner. This is more efficient + * than getBounds().x or getLocation().x. + * + * @return the current x coordinate + * @since 1.2 + */ + public int getX() + { + return x; + } + + /** + * Gets the y coordinate of the upper left corner. This is more efficient + * than getBounds().y or getLocation().y. + * + * @return the current y coordinate + * @since 1.2 + */ + public int getY() + { + return y; + } + + /** + * Gets the width of the component. This is more efficient than + * getBounds().width or getSize().width. + * + * @return the current width + * @since 1.2 + */ + public int getWidth() + { + return width; + } + + /** + * Gets the height of the component. This is more efficient than + * getBounds().height or getSize().height. + * + * @return the current width + * @since 1.2 + */ + public int getHeight() + { + return height; + } + + /** + * Returns the bounds of this component. This allows reuse of an existing + * rectangle, if r is non-null. + * + * @param r the rectangle to use, or null + * @return the bounds + */ + public Rectangle getBounds(Rectangle r) + { + if (r == null) + r = new Rectangle(); + r.x = x; + r.y = y; + r.width = width; + r.height = height; + return r; + } + + /** + * Returns the size of this component. This allows reuse of an existing + * dimension, if d is non-null. + * + * @param d the dimension to use, or null + * @return the size + */ + public Dimension getSize(Dimension d) + { + if (d == null) + d = new Dimension(); + d.width = width; + d.height = height; + return d; + } + + /** + * Returns the location of this component. This allows reuse of an existing + * point, if p is non-null. + * + * @param p the point to use, or null + * @return the location + */ + public Point getLocation(Point p) + { + if (p == null) + p = new Point(); + p.x = x; + p.y = y; + return p; + } + + /** + * Tests if this component is opaque. All "heavyweight" (natively-drawn) + * components are opaque. A component is opaque if it draws all pixels in + * the bounds; a lightweight component is partially transparent if it lets + * pixels underneath show through. Subclasses that guarantee that all pixels + * will be drawn should override this. + * + * @return true if this is opaque + * @see #isLightweight() + * @since 1.2 + */ + public boolean isOpaque() + { + return ! isLightweight(); + } + + /** + * Return whether the component is lightweight. That means the component has + * no native peer, but is displayable. This applies to subclasses of + * Component not in this package, such as javax.swing. + * + * @return true if the component has a lightweight peer + * @see #isDisplayable() + * @since 1.2 + */ + public boolean isLightweight() + { + return peer instanceof LightweightPeer; + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @see #getMinimumSize() + * @see #setPreferredSize(Dimension) + * @see LayoutManager + */ + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /** + * Sets the preferred size that will be returned by + * {@link #getPreferredSize()} always, and sends a + * {@link PropertyChangeEvent} (with the property name 'preferredSize') to + * all registered listeners. + * + * @param size the preferred size (null permitted). + * + * @since 1.5 + * + * @see #getPreferredSize() + */ + public void setPreferredSize(Dimension size) + { + Dimension old = prefSizeSet ? prefSize : null; + prefSize = size; + prefSizeSet = (size != null); + firePropertyChange("preferredSize", old, size); + } + + /** + * Returns true if the current preferred size is not + * null and was set by a call to + * {@link #setPreferredSize(Dimension)}, otherwise returns false. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isPreferredSizeSet() + { + return prefSizeSet; + } + + /** + * Returns the component's preferred size. + * + * @return the component's preferred size + * @deprecated use {@link #getPreferredSize()} instead + */ + public Dimension preferredSize() + { + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(preferredSizeImpl()); + } + + /** + * The actual calculation is pulled out of preferredSize() so that + * we can call it from Container.preferredSize() and avoid creating a + * new intermediate Dimension object. + * + * @return the preferredSize of the component + */ + Dimension preferredSizeImpl() + { + Dimension size = prefSize; + // Try to use a cached value. + if (size == null || !(valid || prefSizeSet)) + { + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.preferredSize(); + else + size = minimumSizeImpl(); + } + } + return size; + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @see #getPreferredSize() + * @see #setMinimumSize(Dimension) + * @see LayoutManager + */ + public Dimension getMinimumSize() + { + return minimumSize(); + } + + /** + * Sets the minimum size that will be returned by {@link #getMinimumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'minimumSize') to all registered listeners. + * + * @param size the minimum size (null permitted). + * + * @since 1.5 + * + * @see #getMinimumSize() + */ + public void setMinimumSize(Dimension size) + { + Dimension old = minSizeSet ? minSize : null; + minSize = size; + minSizeSet = (size != null); + firePropertyChange("minimumSize", old, size); + } + + /** + * Returns true if the current minimum size is not + * null and was set by a call to + * {@link #setMinimumSize(Dimension)}, otherwise returns false. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMinimumSizeSet() + { + return minSizeSet; + } + + /** + * Returns the component's minimum size. + * + * @return the component's minimum size + * @deprecated use {@link #getMinimumSize()} instead + */ + public Dimension minimumSize() + { + // Create a new Dimension object, so that the application doesn't mess + // with the actual values. + return new Dimension(minimumSizeImpl()); + } + + /** + * The actual calculation is pulled out of minimumSize() so that + * we can call it from Container.preferredSize() and + * Component.preferredSizeImpl and avoid creating a + * new intermediate Dimension object. + * + * @return the minimum size of the component + */ + Dimension minimumSizeImpl() + { + Dimension size = minSize; + if (size == null || !(valid || minSizeSet)) + { + // We need to lock here, because the calculation depends on the + // component structure not changing. + synchronized (getTreeLock()) + { + ComponentPeer p = peer; + if (p != null) + size = peer.minimumSize(); + else + size = size(); + } + } + return size; + } + + /** + * Returns the component's maximum size. + * + * @return the component's maximum size + * @see #getMinimumSize() + * @see #setMaximumSize(Dimension) + * @see #getPreferredSize() + * @see LayoutManager + */ + public Dimension getMaximumSize() + { + return new Dimension(maximumSizeImpl()); + } + + /** + * This is pulled out from getMaximumSize(), so that we can access it + * from Container.getMaximumSize() without creating an additional + * intermediate Dimension object. + * + * @return the maximum size of the component + */ + Dimension maximumSizeImpl() + { + Dimension size; + if (maxSizeSet) + size = maxSize; + else + size = DEFAULT_MAX_SIZE; + return size; + } + + /** + * Sets the maximum size that will be returned by {@link #getMaximumSize()} + * always, and sends a {@link PropertyChangeEvent} (with the property name + * 'maximumSize') to all registered listeners. + * + * @param size the maximum size (null permitted). + * + * @since 1.5 + * + * @see #getMaximumSize() + */ + public void setMaximumSize(Dimension size) + { + Dimension old = maxSizeSet ? maxSize : null; + maxSize = size; + maxSizeSet = (size != null); + firePropertyChange("maximumSize", old, size); + } + + /** + * Returns true if the current maximum size is not + * null and was set by a call to + * {@link #setMaximumSize(Dimension)}, otherwise returns false. + * + * @return A boolean. + * + * @since 1.5 + */ + public boolean isMaximumSizeSet() + { + return maxSizeSet; + } + + /** + * Returns the preferred horizontal alignment of this component. The value + * returned will be between {@link #LEFT_ALIGNMENT} and + * {@link #RIGHT_ALIGNMENT}, inclusive. + * + * @return the preferred horizontal alignment of this component + */ + public float getAlignmentX() + { + return CENTER_ALIGNMENT; + } + + /** + * Returns the preferred vertical alignment of this component. The value + * returned will be between {@link #TOP_ALIGNMENT} and + * {@link #BOTTOM_ALIGNMENT}, inclusive. + * + * @return the preferred vertical alignment of this component + */ + public float getAlignmentY() + { + return CENTER_ALIGNMENT; + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @see #validate() + * @see LayoutManager + */ + public void doLayout() + { + layout (); + } + + /** + * Calls the layout manager to re-layout the component. This is called + * during validation of a container in most cases. + * + * @deprecated use {@link #doLayout()} instead + */ + public void layout() + { + // Nothing to do unless we're a container. + } + + /** + * Called to ensure that the layout for this component is valid. This is + * usually called on containers. + * + * @see #invalidate() + * @see #doLayout() + * @see LayoutManager + * @see Container#validate() + */ + public void validate() + { + if (! valid) + { + // Synchronize on the tree here as this might change the layout + // of the hierarchy. + synchronized (getTreeLock()) + { + // Create local variables for thread safety. + ComponentPeer p = peer; + if (p != null) + { + // Possibly update the peer's font. + Font newFont = getFont(); + Font oldFont = peerFont; + // Only update when the font really changed. + if (newFont != oldFont + && (oldFont == null || ! oldFont.equals(newFont))) + { + p.setFont(newFont); + peerFont = newFont; + } + // Let the peer perform any layout. + p.layout(); + } + } + valid = true; + } + } + + /** + * Invalidates this component and all of its parent components. This will + * cause them to have their layout redone. This is called frequently, so + * make it fast. + */ + public void invalidate() + { + // Need to lock here, to avoid races and other ugly stuff when doing + // layout or structure changes in other threads. + synchronized (getTreeLock()) + { + // Invalidate. + valid = false; + + // Throw away cached layout information. + if (! minSizeSet) + minSize = null; + if (! prefSizeSet) + prefSize = null; + if (! maxSizeSet) + maxSize = null; + + // Also invalidate the parent, if it hasn't already been invalidated. + if (parent != null && parent.isValid()) + parent.invalidate(); + } + } + + /** + * Returns a graphics object for this component. Returns null + * if this component is not currently displayed on the screen. + * + * @return a graphics object for this component + * @see #paint(Graphics) + */ + public Graphics getGraphics() + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Graphics g = null; + if (p instanceof LightweightPeer) + { + if (parent != null) + { + g = parent.getGraphics(); + if (g != null) + { + g.translate(x, y); + g.setClip(0, 0, width, height); + g.setFont(getFont()); + } + } + } + else + { + if (p != null) + g = p.getGraphics(); + } + return g; + } + + /** + * Returns the font metrics for the specified font in this component. + * + * @param font the font to retrieve metrics for + * @return the font metrics for the specified font + * @throws NullPointerException if font is null + * @see #getFont() + * @see Toolkit#getFontMetrics(Font) + */ + public FontMetrics getFontMetrics(Font font) + { + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + return p == null ? getToolkit().getFontMetrics(font) + : p.getFontMetrics(font); + } + + /** + * Sets the cursor for this component to the specified cursor. The cursor + * is displayed when the point is contained by the component, and the + * component is visible, displayable, and enabled. This is inherited by + * subcomponents unless they set their own cursor. + * + * @param cursor the new cursor for this component + * @see #isEnabled() + * @see #isShowing() + * @see #getCursor() + * @see #contains(int, int) + * @see Toolkit#createCustomCursor(Image, Point, String) + */ + public void setCursor(Cursor cursor) + { + this.cursor = cursor; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setCursor(cursor); + } + + /** + * Returns the cursor for this component. If not set, this is inherited + * from the parent, or from Cursor.getDefaultCursor(). + * + * @return the cursor for this component + */ + public Cursor getCursor() + { + if (cursor != null) + return cursor; + return parent != null ? parent.getCursor() : Cursor.getDefaultCursor(); + } + + /** + * Tests if the cursor was explicitly set, or just inherited from the parent. + * + * @return true if the cursor has been set + * @since 1.4 + */ + public boolean isCursorSet() + { + return cursor != null; + } + + /** + * Paints this component on the screen. The clipping region in the graphics + * context will indicate the region that requires painting. This is called + * whenever the component first shows, or needs to be repaired because + * something was temporarily drawn on top. It is not necessary for + * subclasses to call super.paint(g). Components with no area + * are not painted. + * + * @param g the graphics context for this paint job + * @see #update(Graphics) + */ + public void paint(Graphics g) + { + // This is a callback method and is meant to be overridden by subclasses + // that want to perform custom painting. + } + + /** + * Updates this component. This is called for heavyweight components in + * response to {@link #repaint()}. The default implementation simply forwards + * to {@link #paint(Graphics)}. The coordinates of the graphics are + * relative to this component. Subclasses should call either + * super.update(g) or paint(g). + * + * @param g the graphics context for this update + * + * @see #paint(Graphics) + * @see #repaint() + */ + public void update(Graphics g) + { + // Note 1: We used to clear the background here for lightweights and + // toplevel components. Tests show that this is not what the JDK does + // here. Note that there is some special handling and background + // clearing code in Container.update(Graphics). + + // Note 2 (for peer implementors): The JDK doesn't seem call update() for + // toplevel components, even when an UPDATE event is sent (as a result + // of repaint). + paint(g); + } + + /** + * Paints this entire component, including any sub-components. + * + * @param g the graphics context for this paint job + * + * @see #paint(Graphics) + */ + public void paintAll(Graphics g) + { + if (isShowing()) + { + validate(); + if (peer instanceof LightweightPeer) + paint(g); + else + peer.paint(g); + } + } + + /** + * Repaint this entire component. The update() method + * on this component will be called as soon as possible. + * + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint() + { + repaint(0, 0, 0, width, height); + } + + /** + * Repaint this entire component. The update() method on this + * component will be called in approximate the specified number of + * milliseconds. + * + * @param tm milliseconds before this component should be repainted + * @see #paint(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(long tm) + { + repaint(tm, 0, 0, width, height); + } + + /** + * Repaints the specified rectangular region within this component. The + * update method on this component will be called as soon as + * possible. The coordinates are relative to this component. + * + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param w the width of the region to repaint + * @param h the height of the region to repaint + * @see #update(Graphics) + * @see #repaint(long, int, int, int, int) + */ + public void repaint(int x, int y, int w, int h) + { + repaint(0, x, y, w, h); + } + + /** + * Repaints the specified rectangular region within this component. The + * update method on this component will be called in + * approximately the specified number of milliseconds. The coordinates + * are relative to this component. + * + * @param tm milliseconds before this component should be repainted + * @param x the X coordinate of the upper left of the region to repaint + * @param y the Y coordinate of the upper left of the region to repaint + * @param width the width of the region to repaint + * @param height the height of the region to repaint + * @see #update(Graphics) + */ + public void repaint(long tm, int x, int y, int width, int height) + { + // The repaint() call has previously been delegated to + // {@link ComponentPeer.repaint()}. Testing on the JDK using some + // dummy peers show that this methods is never called. I think it makes + // sense to actually perform the tasks below here, since it's pretty + // much peer independent anyway, and makes sure only heavyweights are + // bothered by this. + ComponentPeer p = peer; + + // Let the nearest heavyweight parent handle repainting for lightweight + // components. + // We need to recursivly call repaint() on the parent here, since + // a (lightweight) parent component might have overridden repaint() + // to perform additional custom tasks. + + if (p instanceof LightweightPeer) + { + // We perform some boundary checking to restrict the paint + // region to this component. + if (parent != null) + { + int px = this.x + Math.max(0, x); + int py = this.y + Math.max(0, y); + int pw = Math.min(this.width, width); + int ph = Math.min(this.height, height); + parent.repaint(tm, px, py, pw, ph); + } + } + else + { + // Now send an UPDATE event to the heavyweight component that we've found. + if (isVisible() && p != null && width > 0 && height > 0) + { + PaintEvent pe = new PaintEvent(this, PaintEvent.UPDATE, + new Rectangle(x, y, width, height)); + getToolkit().getSystemEventQueue().postEvent(pe); + } + } + } + + /** + * Prints this component. This method is provided so that printing can be + * done in a different manner from painting. However, the implementation + * in this class simply calls the paint() method. + * + * @param g the graphics context of the print device + * + * @see #paint(Graphics) + */ + public void print(Graphics g) + { + paint(g); + } + + /** + * Prints this component, including all sub-components. + * + * @param g the graphics context of the print device + * + * @see #paintAll(Graphics) + */ + public void printAll(Graphics g) + { + if( peer != null ) + peer.print( g ); + paintAll( g ); + } + + /** + * Called when an image has changed so that this component is repainted. + * This incrementally draws an image as more bits are available, when + * possible. Incremental drawing is enabled if the system property + * awt.image.incrementalDraw is not present or is true, in which + * case the redraw rate is set to 100ms or the value of the system property + * awt.image.redrawrate. + * + *

The coordinate system used depends on the particular flags. + * + * @param img the image that has been updated + * @param flags tlags as specified in ImageObserver + * @param x the X coordinate + * @param y the Y coordinate + * @param w the width + * @param h the height + * @return false if the image is completely loaded, loading has been + * aborted, or an error has occurred. true if more updates are + * required. + * @see ImageObserver + * @see Graphics#drawImage(Image, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, Color, ImageObserver) + * @see Graphics#drawImage(Image, int, int, int, int, ImageObserver) + * @see ImageObserver#imageUpdate(Image, int, int, int, int, int) + */ + public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h) + { + if ((flags & (FRAMEBITS | ALLBITS)) != 0) + repaint(); + else if ((flags & SOMEBITS) != 0) + { + if (incrementalDraw) + { + if (redrawRate != null) + { + long tm = redrawRate.longValue(); + if (tm < 0) + tm = 0; + repaint(tm); + } + else + repaint(100); + } + } + return (flags & (ALLBITS | ABORT | ERROR)) == 0; + } + + /** + * Creates an image from the specified producer. + * + * @param producer the image procedure to create the image from + * @return the resulting image + */ + public Image createImage(ImageProducer producer) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + // Sun allows producer to be null. + Image im; + if (p != null) + im = p.createImage(producer); + else + im = getToolkit().createImage(producer); + return im; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + */ + public Image createImage (int width, int height) + { + Image returnValue = null; + if (!GraphicsEnvironment.isHeadless ()) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + returnValue = p.createImage(width, height); + } + return returnValue; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. + * + * @param width the width of the image + * @param height the height of the image + * @return the requested image, or null if it is not supported + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height) + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = p.createVolatileImage(width, height); + return im; + } + + /** + * Creates an image with the specified width and height for use in + * double buffering. Headless environments do not support images. The image + * will support the specified capabilities. + * + * @param width the width of the image + * @param height the height of the image + * @param caps the requested capabilities + * @return the requested image, or null if it is not supported + * @throws AWTException if a buffer with the capabilities cannot be created + * @since 1.4 + */ + public VolatileImage createVolatileImage(int width, int height, + ImageCapabilities caps) + throws AWTException + { + // Only heavyweight peers can handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + VolatileImage im = null; + if (p != null) + im = peer.createVolatileImage(width, height); + return im; + } + + /** + * Prepares the specified image for rendering on this component. + * + * @param image the image to prepare for rendering + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + * @throws NullPointerException if image is null + */ + public boolean prepareImage(Image image, ImageObserver observer) + { + return prepareImage(image, image.getWidth(observer), + image.getHeight(observer), observer); + } + + /** + * Prepares the specified image for rendering on this component at the + * specified scaled width and height + * + * @param image the image to prepare for rendering + * @param width the scaled width of the image + * @param height the scaled height of the image + * @param observer the observer to notify of image preparation status + * @return true if the image is already fully prepared + */ + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + boolean retval; + if (p != null) + retval = p.prepareImage(image, width, height, observer); + else + retval = getToolkit().prepareImage(image, width, height, observer); + return retval; + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in ImageObserver. + * + * @param image the image to check on + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + * @throws NullPointerException if image is null + */ + public int checkImage(Image image, ImageObserver observer) + { + return checkImage(image, -1, -1, observer); + } + + /** + * Returns the status of the loading of the specified image. The value + * returned will be those flags defined in ImageObserver. + * + * @param image the image to check on + * @param width the scaled image width + * @param height the scaled image height + * @param observer the observer to notify of image loading progress + * @return the image observer flags indicating the status of the load + * @see #prepareImage(Image, int, int, ImageObserver) + * @see Toolkit#checkImage(Image, int, int, ImageObserver) + */ + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + int retval; + if (p != null) + retval = p.checkImage(image, width, height, observer); + else + retval = getToolkit().checkImage(image, width, height, observer); + return retval; + } + + /** + * Sets whether paint messages delivered by the operating system should be + * ignored. This does not affect messages from AWT, except for those + * triggered by OS messages. Setting this to true can allow faster + * performance in full-screen mode or page-flipping. + * + * @param ignoreRepaint the new setting for ignoring repaint events + * @see #getIgnoreRepaint() + * @see BufferStrategy + * @see GraphicsDevice#setFullScreenWindow(Window) + * @since 1.4 + */ + public void setIgnoreRepaint(boolean ignoreRepaint) + { + this.ignoreRepaint = ignoreRepaint; + } + + /** + * Test whether paint events from the operating system are ignored. + * + * @return the status of ignoring paint events + * @see #setIgnoreRepaint(boolean) + * @since 1.4 + */ + public boolean getIgnoreRepaint() + { + return ignoreRepaint; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @see #getComponentAt(int, int) + */ + public boolean contains(int x, int y) + { + return inside (x, y); + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param x the X coordinate of the point to test + * @param y the Y coordinate of the point to test + * @return true if the point is within this component + * @deprecated use {@link #contains(int, int)} instead + */ + public boolean inside(int x, int y) + { + return x >= 0 && y >= 0 && x < width && y < height; + } + + /** + * Tests whether or not the specified point is contained within this + * component. Coordinates are relative to this component. + * + * @param p the point to test + * @return true if the point is within this component + * @throws NullPointerException if p is null + * @see #getComponentAt(Point) + * @since 1.1 + */ + public boolean contains(Point p) + { + return contains (p.x, p.y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @see #contains(int, int) + */ + public Component getComponentAt(int x, int y) + { + return locate (x, y); + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param x the X coordinate to search for components at + * @param y the Y coordinate to search for components at + * @return the component at the specified location, or null + * @deprecated use {@link #getComponentAt(int, int)} instead + */ + public Component locate(int x, int y) + { + return contains (x, y) ? this : null; + } + + /** + * Returns the component occupying the position (x,y). This will either + * be this component, an immediate child component, or null + * if neither of the first two occupies the specified location. + * + * @param p the point to search for components at + * @return the component at the specified location, or null + * @throws NullPointerException if p is null + * @see #contains(Point) + * @since 1.1 + */ + public Component getComponentAt(Point p) + { + return getComponentAt (p.x, p.y); + } + + /** + * AWT 1.0 event delivery. + * + * Deliver an AWT 1.0 event to this Component. This method simply + * calls {@link #postEvent}. + * + * @param e the event to deliver + * @deprecated use {@link #dispatchEvent (AWTEvent)} instead + */ + public void deliverEvent (Event e) + { + postEvent (e); + } + + /** + * Forwards AWT events to processEvent() if:

+ * + * @param e the event to dispatch + */ + public final void dispatchEvent(AWTEvent e) + { + // Some subclasses in the AWT package need to override this behavior, + // hence the use of dispatchEventImpl(). + dispatchEventImpl(e); + } + + /** + * By default, no old mouse events should be ignored. + * This can be overridden by subclasses. + * + * @return false, no mouse events are ignored. + */ + static boolean ignoreOldMouseEvents() + { + return false; + } + + /** + * AWT 1.0 event handler. + * + * This method simply calls handleEvent and returns the result. + * + * @param e the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #dispatchEvent(AWTEvent)} instead + */ + public boolean postEvent (Event e) + { + boolean handled = handleEvent (e); + + if (!handled && getParent() != null) + // FIXME: need to translate event coordinates to parent's + // coordinate space. + handled = getParent ().postEvent (e); + + return handled; + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see ComponentEvent + * @see #removeComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void addComponentListener(ComponentListener listener) + { + if (listener != null) + { + componentListener = AWTEventMulticaster.add(componentListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see ComponentEvent + * @see #addComponentListener(ComponentListener) + * @see #getComponentListeners() + * @since 1.1 + */ + public synchronized void removeComponentListener(ComponentListener listener) + { + componentListener = AWTEventMulticaster.remove(componentListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addComponentListener(ComponentListener) + * @see #removeComponentListener(ComponentListener) + * @since 1.4 + */ + public synchronized ComponentListener[] getComponentListeners() + { + return (ComponentListener[]) + AWTEventMulticaster.getListeners(componentListener, + ComponentListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see FocusEvent + * @see #removeFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void addFocusListener(FocusListener listener) + { + if (listener != null) + { + focusListener = AWTEventMulticaster.add(focusListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see FocusEvent + * @see #addFocusListener(FocusListener) + * @see #getFocusListeners() + * @since 1.1 + */ + public synchronized void removeFocusListener(FocusListener listener) + { + focusListener = AWTEventMulticaster.remove(focusListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addFocusListener(FocusListener) + * @see #removeFocusListener(FocusListener) + * @since 1.4 + */ + public synchronized FocusListener[] getFocusListeners() + { + return (FocusListener[]) + AWTEventMulticaster.getListeners(focusListener, FocusListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void addHierarchyListener(HierarchyListener listener) + { + if (listener != null) + { + hierarchyListener = AWTEventMulticaster.add(hierarchyListener, + listener); + newEventsOnly = true; + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + 1); + } + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyListener(HierarchyListener) + * @see #getHierarchyListeners() + * @since 1.3 + */ + public synchronized void removeHierarchyListener(HierarchyListener listener) + { + hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount(AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyListener(HierarchyListener) + * @see #removeHierarchyListener(HierarchyListener) + * @since 1.4 + */ + public synchronized HierarchyListener[] getHierarchyListeners() + { + return (HierarchyListener[]) + AWTEventMulticaster.getListeners(hierarchyListener, + HierarchyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see HierarchyEvent + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + addHierarchyBoundsListener(HierarchyBoundsListener listener) + { + if (listener != null) + { + hierarchyBoundsListener = + AWTEventMulticaster.add(hierarchyBoundsListener, listener); + newEventsOnly = true; + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1); + } + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see HierarchyEvent + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #getHierarchyBoundsListeners() + * @since 1.3 + */ + public synchronized void + removeHierarchyBoundsListener(HierarchyBoundsListener listener) + { + hierarchyBoundsListener = + AWTEventMulticaster.remove(hierarchyBoundsListener, listener); + + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #removeHierarchyBoundsListener(HierarchyBoundsListener) + * @since 1.4 + */ + public synchronized HierarchyBoundsListener[] getHierarchyBoundsListeners() + { + return (HierarchyBoundsListener[]) + AWTEventMulticaster.getListeners(hierarchyBoundsListener, + HierarchyBoundsListener.class); + } + + /** + * Fires a HierarchyEvent or HierarchyChangeEvent on this component. + * + * @param id the event id + * @param changed the changed component + * @param parent the parent + * @param flags the event flags + */ + void fireHierarchyEvent(int id, Component changed, Container parent, + long flags) + { + boolean enabled = false; + switch (id) + { + case HierarchyEvent.HIERARCHY_CHANGED: + enabled = hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0; + break; + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + enabled = hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0; + break; + default: + assert false : "Should not reach here"; + } + if (enabled) + { + HierarchyEvent ev = new HierarchyEvent(this, id, changed, parent, + flags); + dispatchEvent(ev); + } + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see KeyEvent + * @see #removeKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void addKeyListener(KeyListener listener) + { + if (listener != null) + { + keyListener = AWTEventMulticaster.add(keyListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see KeyEvent + * @see #addKeyListener(KeyListener) + * @see #getKeyListeners() + * @since 1.1 + */ + public synchronized void removeKeyListener(KeyListener listener) + { + keyListener = AWTEventMulticaster.remove(keyListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addKeyListener(KeyListener) + * @see #removeKeyListener(KeyListener) + * @since 1.4 + */ + public synchronized KeyListener[] getKeyListeners() + { + return (KeyListener[]) + AWTEventMulticaster.getListeners(keyListener, KeyListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void addMouseListener(MouseListener listener) + { + if (listener != null) + { + mouseListener = AWTEventMulticaster.add(mouseListener, listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseListener(MouseListener) + * @see #getMouseListeners() + * @since 1.1 + */ + public synchronized void removeMouseListener(MouseListener listener) + { + mouseListener = AWTEventMulticaster.remove(mouseListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseListener(MouseListener) + * @see #removeMouseListener(MouseListener) + * @since 1.4 + */ + public synchronized MouseListener[] getMouseListeners() + { + return (MouseListener[]) + AWTEventMulticaster.getListeners(mouseListener, MouseListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see #removeMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void addMouseMotionListener(MouseMotionListener listener) + { + if (listener != null) + { + mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see #addMouseMotionListener(MouseMotionListener) + * @see #getMouseMotionListeners() + * @since 1.1 + */ + public synchronized void removeMouseMotionListener(MouseMotionListener listener) + { + mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseMotionListener(MouseMotionListener) + * @see #removeMouseMotionListener(MouseMotionListener) + * @since 1.4 + */ + public synchronized MouseMotionListener[] getMouseMotionListeners() + { + return (MouseMotionListener[]) + AWTEventMulticaster.getListeners(mouseMotionListener, + MouseMotionListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see MouseEvent + * @see MouseWheelEvent + * @see #removeMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void addMouseWheelListener(MouseWheelListener listener) + { + if (listener != null) + { + mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see MouseEvent + * @see MouseWheelEvent + * @see #addMouseWheelListener(MouseWheelListener) + * @see #getMouseWheelListeners() + * @since 1.4 + */ + public synchronized void removeMouseWheelListener(MouseWheelListener listener) + { + mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addMouseWheelListener(MouseWheelListener) + * @see #removeMouseWheelListener(MouseWheelListener) + * @since 1.4 + */ + public synchronized MouseWheelListener[] getMouseWheelListeners() + { + return (MouseWheelListener[]) + AWTEventMulticaster.getListeners(mouseWheelListener, + MouseWheelListener.class); + } + + /** + * Adds the specified listener to this component. This is harmless if the + * listener is null, but if the listener has already been registered, it + * will now be registered twice. + * + * @param listener the new listener to add + * @see InputMethodEvent + * @see #removeInputMethodListener(InputMethodListener) + * @see #getInputMethodListeners() + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void addInputMethodListener(InputMethodListener listener) + { + if (listener != null) + { + inputMethodListener = AWTEventMulticaster.add(inputMethodListener, + listener); + newEventsOnly = true; + } + } + + /** + * Removes the specified listener from the component. This is harmless if + * the listener was not previously registered. + * + * @param listener the listener to remove + * @see InputMethodEvent + * @see #addInputMethodListener(InputMethodListener) + * @see #getInputMethodRequests() + * @since 1.2 + */ + public synchronized void removeInputMethodListener(InputMethodListener listener) + { + inputMethodListener = AWTEventMulticaster.remove(inputMethodListener, listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addInputMethodListener(InputMethodListener) + * @see #removeInputMethodListener(InputMethodListener) + * @since 1.4 + */ + public synchronized InputMethodListener[] getInputMethodListeners() + { + return (InputMethodListener[]) + AWTEventMulticaster.getListeners(inputMethodListener, + InputMethodListener.class); + } + + /** + * Returns all registered {@link EventListener}s of the given + * listenerType. + * + * @param listenerType the class of listeners to filter (null + * not permitted). + * + * @return An array of registered listeners. + * + * @throws ClassCastException if listenerType does not implement + * the {@link EventListener} interface. + * @throws NullPointerException if listenerType is + * null. + * + * @see #getComponentListeners() + * @see #getFocusListeners() + * @see #getHierarchyListeners() + * @see #getHierarchyBoundsListeners() + * @see #getKeyListeners() + * @see #getMouseListeners() + * @see #getMouseMotionListeners() + * @see #getMouseWheelListeners() + * @see #getInputMethodListeners() + * @see #getPropertyChangeListeners() + * @since 1.3 + */ + public T[] getListeners(Class listenerType) + { + if (listenerType == ComponentListener.class) + return (T[]) getComponentListeners(); + if (listenerType == FocusListener.class) + return (T[]) getFocusListeners(); + if (listenerType == HierarchyListener.class) + return (T[]) getHierarchyListeners(); + if (listenerType == HierarchyBoundsListener.class) + return (T[]) getHierarchyBoundsListeners(); + if (listenerType == KeyListener.class) + return (T[]) getKeyListeners(); + if (listenerType == MouseListener.class) + return (T[]) getMouseListeners(); + if (listenerType == MouseMotionListener.class) + return (T[]) getMouseMotionListeners(); + if (listenerType == MouseWheelListener.class) + return (T[]) getMouseWheelListeners(); + if (listenerType == InputMethodListener.class) + return (T[]) getInputMethodListeners(); + if (listenerType == PropertyChangeListener.class) + return (T[]) getPropertyChangeListeners(); + return (T[]) Array.newInstance(listenerType, 0); + } + + /** + * Returns the input method request handler, for subclasses which support + * on-the-spot text input. By default, input methods are handled by AWT, + * and this returns null. + * + * @return the input method handler, null by default + * @since 1.2 + */ + public InputMethodRequests getInputMethodRequests() + { + return null; + } + + /** + * Gets the input context of this component, which is inherited from the + * parent unless this is overridden. + * + * @return the text input context + * @since 1.2 + */ + public InputContext getInputContext() + { + return parent == null ? null : parent.getInputContext(); + } + + /** + * Enables the specified events. The events to enable are specified + * by OR-ing together the desired masks from AWTEvent. + * + *

Events are enabled by default when a listener is attached to the + * component for that event type. This method can be used by subclasses + * to ensure the delivery of a specified event regardless of whether + * or not a listener is attached. + * + * @param eventsToEnable the desired events to enable + * @see #processEvent(AWTEvent) + * @see #disableEvents(long) + * @see AWTEvent + * @since 1.1 + */ + protected final void enableEvents(long eventsToEnable) + { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToEnable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + 1); + } + } + if ((eventsToEnable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners++; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + 1); + } + } + + eventMask |= eventsToEnable; + newEventsOnly = true; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + + } + + /** + * Disables the specified events. The events to disable are specified + * by OR-ing together the desired masks from AWTEvent. + * + * @param eventsToDisable the desired events to disable + * @see #enableEvents(long) + * @since 1.1 + */ + protected final void disableEvents(long eventsToDisable) + { + // Update the counter for hierarchy (bounds) listeners. + if ((eventsToDisable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_EVENT_MASK, + -1); + } + } + if ((eventsToDisable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 + && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) + { + // Need to lock the tree, otherwise we might end up inconsistent. + synchronized (getTreeLock()) + { + numHierarchyBoundsListeners--; + if (parent != null) + parent.updateHierarchyListenerCount + (AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, + -1); + } + } + + eventMask &= ~eventsToDisable; + + // Only heavyweight peers handle this. + ComponentPeer p = peer; + Component comp = this; + while (p instanceof LightweightPeer) + { + comp = comp.parent; + p = comp == null ? null : comp.peer; + } + + if (p != null) + p.setEventMask(eventMask); + + } + + /** + * This is called by the EventQueue if two events with the same event id + * and owner component are queued. Returns a new combined event, or null if + * no combining is done. The coelesced events are currently mouse moves + * (intermediate ones are discarded) and paint events (a merged paint is + * created in place of the two events). + * + * @param existingEvent the event on the queue + * @param newEvent the new event that might be entered on the queue + * @return null if both events are kept, or the replacement coelesced event + */ + protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) + { + AWTEvent coalesced = null; + switch (existingEvent.id) + { + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + // Just drop the old (intermediate) event and return the new one. + MouseEvent me1 = (MouseEvent) existingEvent; + MouseEvent me2 = (MouseEvent) newEvent; + if (me1.getModifiers() == me2.getModifiers()) + coalesced = newEvent; + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + // For heavyweights the EventQueue should ask the peer. + if (peer == null || peer instanceof LightweightPeer) + { + PaintEvent pe1 = (PaintEvent) existingEvent; + PaintEvent pe2 = (PaintEvent) newEvent; + Rectangle r1 = pe1.getUpdateRect(); + Rectangle r2 = pe2.getUpdateRect(); + if (r1.contains(r2)) + coalesced = existingEvent; + else if (r2.contains(r1)) + coalesced = newEvent; + } + else + { + // Replace the event and let the heavyweight figure out the expanding + // of the repaint area. + coalesced = newEvent; + } + break; + default: + coalesced = null; + } + return coalesced; + } + + /** + * Processes the specified event. In this class, this method simply + * calls one of the more specific event handlers. + * + * @param e the event to process + * @throws NullPointerException if e is null + * @see #processComponentEvent(ComponentEvent) + * @see #processFocusEvent(FocusEvent) + * @see #processKeyEvent(KeyEvent) + * @see #processMouseEvent(MouseEvent) + * @see #processMouseMotionEvent(MouseEvent) + * @see #processInputMethodEvent(InputMethodEvent) + * @see #processHierarchyEvent(HierarchyEvent) + * @see #processMouseWheelEvent(MouseWheelEvent) + * @since 1.1 + */ + protected void processEvent(AWTEvent e) + { + /* Note: the order of these if statements are + important. Subclasses must be checked first. Eg. MouseEvent + must be checked before ComponentEvent, since a MouseEvent + object is also an instance of a ComponentEvent. */ + + if (e instanceof FocusEvent) + processFocusEvent((FocusEvent) e); + else if (e instanceof MouseWheelEvent) + processMouseWheelEvent((MouseWheelEvent) e); + else if (e instanceof MouseEvent) + { + if (e.id == MouseEvent.MOUSE_MOVED + || e.id == MouseEvent.MOUSE_DRAGGED) + processMouseMotionEvent((MouseEvent) e); + else + processMouseEvent((MouseEvent) e); + } + else if (e instanceof KeyEvent) + processKeyEvent((KeyEvent) e); + else if (e instanceof InputMethodEvent) + processInputMethodEvent((InputMethodEvent) e); + else if (e instanceof ComponentEvent) + processComponentEvent((ComponentEvent) e); + else if (e instanceof HierarchyEvent) + { + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + processHierarchyEvent((HierarchyEvent) e); + else + processHierarchyBoundsEvent((HierarchyEvent) e); + } + } + + /** + * Called when a component event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the ComponentEvent to process + * @throws NullPointerException if e is null + * @see ComponentListener + * @see #addComponentListener(ComponentListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processComponentEvent(ComponentEvent e) + { + if (componentListener == null) + return; + switch (e.id) + { + case ComponentEvent.COMPONENT_HIDDEN: + componentListener.componentHidden(e); + break; + case ComponentEvent.COMPONENT_MOVED: + componentListener.componentMoved(e); + break; + case ComponentEvent.COMPONENT_RESIZED: + componentListener.componentResized(e); + break; + case ComponentEvent.COMPONENT_SHOWN: + componentListener.componentShown(e); + break; + } + } + + /** + * Called when a focus event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the FocusEvent to process + * @throws NullPointerException if e is null + * @see FocusListener + * @see #addFocusListener(FocusListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processFocusEvent(FocusEvent e) + { + if (focusListener == null) + return; + + switch (e.id) + { + case FocusEvent.FOCUS_GAINED: + focusListener.focusGained(e); + break; + case FocusEvent.FOCUS_LOST: + focusListener.focusLost(e); + break; + } + } + + /** + * Called when a key event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the KeyEvent to process + * @throws NullPointerException if e is null + * @see KeyListener + * @see #addKeyListener(KeyListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processKeyEvent(KeyEvent e) + { + if (keyListener == null) + return; + switch (e.id) + { + case KeyEvent.KEY_PRESSED: + keyListener.keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + keyListener.keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + keyListener.keyTyped(e); + break; + } + } + + /** + * Called when a regular mouse event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the MouseEvent to process + * @throws NullPointerException if e is null + * @see MouseListener + * @see #addMouseListener(MouseListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseEvent(MouseEvent e) + { + if (mouseListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_CLICKED: + mouseListener.mouseClicked(e); + break; + case MouseEvent.MOUSE_ENTERED: + if( isLightweight() ) + setCursor( getCursor() ); + mouseListener.mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + mouseListener.mouseExited(e); + break; + case MouseEvent.MOUSE_PRESSED: + mouseListener.mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + mouseListener.mouseReleased(e); + break; + } + } + + /** + * Called when a mouse motion event is dispatched and component events are + * enabled. This method passes the event along to any listeners + * that are attached. + * + * @param e the MouseMotionEvent to process + * @throws NullPointerException if e is null + * @see MouseMotionListener + * @see #addMouseMotionListener(MouseMotionListener) + * @see #enableEvents(long) + * @since 1.1 + */ + protected void processMouseMotionEvent(MouseEvent e) + { + if (mouseMotionListener == null) + return; + switch (e.id) + { + case MouseEvent.MOUSE_DRAGGED: + mouseMotionListener.mouseDragged(e); + break; + case MouseEvent.MOUSE_MOVED: + mouseMotionListener.mouseMoved(e); + break; + } + e.consume(); + } + + /** + * Called when a mouse wheel event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the MouseWheelEvent to process + * @throws NullPointerException if e is null + * @see MouseWheelListener + * @see #addMouseWheelListener(MouseWheelListener) + * @see #enableEvents(long) + * @since 1.4 + */ + protected void processMouseWheelEvent(MouseWheelEvent e) + { + if (mouseWheelListener != null + && e.id == MouseEvent.MOUSE_WHEEL) + { + mouseWheelListener.mouseWheelMoved(e); + e.consume(); + } + } + + /** + * Called when an input method event is dispatched and component events are + * enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the InputMethodEvent to process + * @throws NullPointerException if e is null + * @see InputMethodListener + * @see #addInputMethodListener(InputMethodListener) + * @see #enableEvents(long) + * @since 1.2 + */ + protected void processInputMethodEvent(InputMethodEvent e) + { + if (inputMethodListener == null) + return; + switch (e.id) + { + case InputMethodEvent.CARET_POSITION_CHANGED: + inputMethodListener.caretPositionChanged(e); + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + inputMethodListener.inputMethodTextChanged(e); + break; + } + } + + /** + * Called when a hierarchy change event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the HierarchyEvent to process + * @throws NullPointerException if e is null + * @see HierarchyListener + * @see #addHierarchyListener(HierarchyListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyEvent(HierarchyEvent e) + { + if (hierarchyListener == null) + return; + if (e.id == HierarchyEvent.HIERARCHY_CHANGED) + hierarchyListener.hierarchyChanged(e); + } + + /** + * Called when a hierarchy bounds event is dispatched and component events + * are enabled. This method passes the event along to any listeners that are + * attached. + * + * @param e the HierarchyEvent to process + * @throws NullPointerException if e is null + * @see HierarchyBoundsListener + * @see #addHierarchyBoundsListener(HierarchyBoundsListener) + * @see #enableEvents(long) + * @since 1.3 + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e) + { + if (hierarchyBoundsListener == null) + return; + switch (e.id) + { + case HierarchyEvent.ANCESTOR_MOVED: + hierarchyBoundsListener.ancestorMoved(e); + break; + case HierarchyEvent.ANCESTOR_RESIZED: + hierarchyBoundsListener.ancestorResized(e); + break; + } + } + + /** + * AWT 1.0 event handler. + * + * This method calls one of the event-specific handler methods. For + * example for key events, either {@link #keyDown(Event,int)} + * or {@link #keyUp(Event,int)} is called. A derived + * component can override one of these event-specific methods if it + * only needs to handle certain event types. Otherwise it can + * override handleEvent itself and handle any event. + * + * @param evt the event to handle + * @return true if the event was handled, false otherwise + * @deprecated use {@link #processEvent(AWTEvent)} instead + */ + public boolean handleEvent (Event evt) + { + switch (evt.id) + { + // Handle key events. + case Event.KEY_ACTION: + case Event.KEY_PRESS: + return keyDown (evt, evt.key); + case Event.KEY_ACTION_RELEASE: + case Event.KEY_RELEASE: + return keyUp (evt, evt.key); + + // Handle mouse events. + case Event.MOUSE_DOWN: + return mouseDown (evt, evt.x, evt.y); + case Event.MOUSE_UP: + return mouseUp (evt, evt.x, evt.y); + case Event.MOUSE_MOVE: + return mouseMove (evt, evt.x, evt.y); + case Event.MOUSE_DRAG: + return mouseDrag (evt, evt.x, evt.y); + case Event.MOUSE_ENTER: + return mouseEnter (evt, evt.x, evt.y); + case Event.MOUSE_EXIT: + return mouseExit (evt, evt.x, evt.y); + + // Handle focus events. + case Event.GOT_FOCUS: + return gotFocus (evt, evt.arg); + case Event.LOST_FOCUS: + return lostFocus (evt, evt.arg); + + // Handle action event. + case Event.ACTION_EVENT: + return action (evt, evt.arg); + } + // Unknown event. + return false; + } + + /** + * AWT 1.0 MOUSE_DOWN event handler. This method is meant to be + * overridden by components providing their own MOUSE_DOWN handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseDown(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_DRAG event handler. This method is meant to be + * overridden by components providing their own MOUSE_DRAG handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseDrag(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_UP event handler. This method is meant to be + * overridden by components providing their own MOUSE_UP handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseUp(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_MOVE event handler. This method is meant to be + * overridden by components providing their own MOUSE_MOVE handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseMotionEvent(MouseEvent)} instead + */ + public boolean mouseMove(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_ENTER event handler. This method is meant to be + * overridden by components providing their own MOUSE_ENTER handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseEnter(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 MOUSE_EXIT event handler. This method is meant to be + * overridden by components providing their own MOUSE_EXIT handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param x the x coordinate, ignored + * @param y the y coordinate, ignored + * @return false + * @deprecated use {@link #processMouseEvent(MouseEvent)} instead + */ + public boolean mouseExit(Event evt, int x, int y) + { + return false; + } + + /** + * AWT 1.0 KEY_PRESS and KEY_ACTION event handler. This method is + * meant to be overridden by components providing their own key + * press handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyDown(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 KEY_RELEASE and KEY_ACTION_RELEASE event handler. This + * method is meant to be overridden by components providing their + * own key release handler. The default implementation simply + * returns false. + * + * @param evt the event to handle + * @param key the key pressed, ignored + * @return false + * @deprecated use {@link #processKeyEvent(KeyEvent)} instead + */ + public boolean keyUp(Event evt, int key) + { + return false; + } + + /** + * AWT 1.0 ACTION_EVENT event handler. This method is meant to be + * overridden by components providing their own action event + * handler. The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the object acted on, ignored + * @return false + * @deprecated in classes which support actions, use + * processActionEvent(ActionEvent) instead + */ + public boolean action(Event evt, Object what) + { + return false; + } + + /** + * Called when the parent of this Component is made visible or when + * the Component is added to an already visible Container and needs + * to be shown. A native peer - if any - is created at this + * time. This method is called automatically by the AWT system and + * should not be called by user level code. + * + * @see #isDisplayable() + * @see #removeNotify() + */ + public void addNotify() + { + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + if (peer == null) + peer = getToolkit().createComponent(this); + else if (parent != null && parent.isLightweight()) + new HeavyweightInLightweightListener(parent); + // Now that all the children has gotten their peers, we should + // have the event mask needed for this component and its + //lightweight subcomponents. + peer.setEventMask(eventMask); + + // We used to leave the invalidate() to the peer. However, I put it + // back here for 2 reasons: 1) The RI does call invalidate() from + // addNotify(); 2) The peer shouldn't be bother with validation too + // much. + invalidate(); + + if (dropTarget != null) + dropTarget.addNotify(peer); + + // Fetch the peerFont for later installation in validate(). + peerFont = getFont(); + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); + } + } + + /** + * Called to inform this component is has been removed from its + * container. Its native peer - if any - is destroyed at this time. + * This method is called automatically by the AWT system and should + * not be called by user level code. + * + * @see #isDisplayable() + * @see #addNotify() + */ + public void removeNotify() + { + // We need to lock the tree here to avoid races and inconsistencies. + synchronized (getTreeLock()) + { + // We null our peer field before disposing of it, such that if we're + // not the event dispatch thread and the dispatch thread is awoken by + // the dispose call, there will be no race checking the peer's null + // status. + + ComponentPeer tmp = peer; + peer = null; + peerFont = null; + if (tmp != null) + { + tmp.hide(); + tmp.dispose(); + } + + // Notify hierarchy listeners. + long flags = HierarchyEvent.DISPLAYABILITY_CHANGED; + if (isHierarchyVisible()) + flags |= HierarchyEvent.SHOWING_CHANGED; + fireHierarchyEvent(HierarchyEvent.HIERARCHY_CHANGED, this, parent, + flags); + } + } + + /** + * AWT 1.0 GOT_FOCUS event handler. This method is meant to be + * overridden by components providing their own GOT_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean gotFocus(Event evt, Object what) + { + return false; + } + + /** + * AWT 1.0 LOST_FOCUS event handler. This method is meant to be + * overridden by components providing their own LOST_FOCUS handler. + * The default implementation simply returns false. + * + * @param evt the event to handle + * @param what the Object focused, ignored + * @return false + * @deprecated use {@link #processFocusEvent(FocusEvent)} instead + */ + public boolean lostFocus(Event evt, Object what) + { + return false; + } + + /** + * Tests whether or not this component is in the group that can be + * traversed using the keyboard traversal mechanism (such as the TAB key). + * + * @return true if the component is traversed via the TAB key + * @see #setFocusable(boolean) + * @since 1.1 + * @deprecated use {@link #isFocusable()} instead + */ + public boolean isFocusTraversable() + { + return enabled && visible && (peer == null || isLightweight() || peer.isFocusTraversable()); + } + + /** + * Tests if this component can receive focus. + * + * @return true if this component can receive focus + * @since 1.4 + */ + public boolean isFocusable() + { + return focusable; + } + + /** + * Specify whether this component can receive focus. This method also + * sets the {@link #isFocusTraversableOverridden} field to 1, which + * appears to be the undocumented way {@link + * DefaultFocusTraversalPolicy#accept(Component)} determines whether to + * respect the {@link #isFocusable()} method of the component. + * + * @param focusable the new focusable status + * @since 1.4 + */ + public void setFocusable(boolean focusable) + { + firePropertyChange("focusable", this.focusable, focusable); + this.focusable = focusable; + this.isFocusTraversableOverridden = 1; + } + + /** + * Sets the focus traversal keys for one of the three focus + * traversal directions supported by Components: + * {@link KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS}, + * {@link KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS}, or + * {@link KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS}. Normally, the + * default values should match the operating system's native + * choices. To disable a given traversal, use + * Collections.EMPTY_SET. The event dispatcher will + * consume PRESSED, RELEASED, and TYPED events for the specified + * key, although focus can only transfer on PRESSED or RELEASED. + * + *

The defaults are: + * + * + * + * + * + * + * + * + * + * + *
IdentifierMeaningDefault
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYSNormal forward traversalTAB on KEY_PRESSED, Ctrl-TAB on KEY_PRESSED
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYSNormal backward traversalShift-TAB on KEY_PRESSED, Ctrl-Shift-TAB on KEY_PRESSED
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYSGo up a traversal cycleNone
+ * + * If keystrokes is null, this component's focus traversal key set + * is inherited from one of its ancestors. If none of its ancestors + * has its own set of focus traversal keys, the focus traversal keys + * are set to the defaults retrieved from the current + * KeyboardFocusManager. If not null, the set must contain only + * AWTKeyStrokes that are not already focus keys and are not + * KEY_TYPED events. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or + * UP_CYCLE_TRAVERSAL_KEYS + * @param keystrokes a set of keys, or null + * @throws IllegalArgumentException if id or keystrokes is invalid + * @see #getFocusTraversalKeys(int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public void setFocusTraversalKeys(int id, + Set keystrokes) + { + if (keystrokes == null) + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[3]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; + } + + /** + * Returns the set of keys for a given focus traversal action, as + * defined in setFocusTraversalKeys. If not set, this + * is inherited from the parent component, which may have gotten it + * from the KeyboardFocusManager. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * + * @return set of traversal keys + * + * @throws IllegalArgumentException if id is invalid + * + * @see #setFocusTraversalKeys (int, Set) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * + * @since 1.4 + */ + public Set getFocusTraversalKeys (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException(); + + Set s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; + } + + /** + * Tests whether the focus traversal keys for a given action are explicitly + * set or inherited. + * + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS + * @return true if that set is explicitly specified + * @throws IllegalArgumentException if id is invalid + * @see #getFocusTraversalKeys (int) + * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS + * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS + * @since 1.4 + */ + public boolean areFocusTraversalKeysSet (int id) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + + return focusTraversalKeys != null && focusTraversalKeys[id] != null; + } + + /** + * Enable or disable focus traversal keys on this Component. If + * they are, then the keyboard focus manager consumes and acts on + * key press and release events that trigger focus traversal, and + * discards the corresponding key typed events. If focus traversal + * keys are disabled, then all key events that would otherwise + * trigger focus traversal are sent to this Component. + * + * @param focusTraversalKeysEnabled the new value of the flag + * @see #getFocusTraversalKeysEnabled () + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled) + { + firePropertyChange ("focusTraversalKeysEnabled", + this.focusTraversalKeysEnabled, + focusTraversalKeysEnabled); + this.focusTraversalKeysEnabled = focusTraversalKeysEnabled; + } + + /** + * Check whether or not focus traversal keys are enabled on this + * Component. If they are, then the keyboard focus manager consumes + * and acts on key press and release events that trigger focus + * traversal, and discards the corresponding key typed events. If + * focus traversal keys are disabled, then all key events that would + * otherwise trigger focus traversal are sent to this Component. + * + * @return true if focus traversal keys are enabled + * @see #setFocusTraversalKeysEnabled (boolean) + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) + * @since 1.4 + */ + public boolean getFocusTraversalKeysEnabled () + { + return focusTraversalKeysEnabled; + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + */ + public void requestFocus () + { + requestFocusImpl(false, true); + } + + /** + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow()} should be used instead. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocusInWindow () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocus (boolean temporary) + { + return requestFocusImpl(temporary, true); + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * FOCUS_GAINED event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. + * + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + public boolean requestFocusInWindow () + { + return requestFocusImpl(false, false); + } + + /** + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * FOCUS_GAINED event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. + * + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. + * + * @param temporary true if the focus request is temporary + * @return true if the request has a chance of success + * @see #requestFocus () + * @see FocusEvent + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () + * @since 1.4 + */ + protected boolean requestFocusInWindow (boolean temporary) + { + return requestFocusImpl(temporary, false); + } + + /** + * Helper method for all 4 requestFocus variants. + * + * @param temporary indicates if the focus change is temporary + * @param focusWindow indicates if the window focus may be changed + * + * @return false if the request has been definitely denied, + * true otherwise + */ + private boolean requestFocusImpl(boolean temporary, boolean focusWindow) + { + boolean retval = false; + + // Don't try to focus non-focusable and non-visible components. + if (isFocusable() && isVisible()) + { + ComponentPeer myPeer = peer; + if (peer != null) + { + // Find Window ancestor and find out if we're showing while + // doing this. + boolean showing = true; + Component window = this; + while (! (window instanceof Window)) + { + if (! window.isVisible()) + showing = false; + window = window.parent; + } + // Don't allow focus when there is no window or the window + // is not focusable. + if (window != null && ((Window) window).isFocusableWindow() + && showing) + { + // Search for nearest heavy ancestor (including this + // component). + Component heavyweightParent = this; + while (heavyweightParent.peer instanceof LightweightPeer) + heavyweightParent = heavyweightParent.parent; + + // Don't allow focus on lightweight components without + // visible heavyweight ancestor + if (heavyweightParent != null && heavyweightParent.isVisible()) + { + // Don't allow focus when heavyweightParent has no peer. + myPeer = heavyweightParent.peer; + if (myPeer != null) + { + // Register lightweight focus request. + if (heavyweightParent != this) + { + KeyboardFocusManager + .addLightweightFocusRequest(heavyweightParent, + this); + } + + // Try to focus the component. + long time = EventQueue.getMostRecentEventTime(); + boolean success = myPeer.requestFocus(this, temporary, + focusWindow, + time); + if (! success) + { + // Dequeue key events if focus request failed. + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + kfm.dequeueKeyEvents(time, this); + } + retval = success; + } + } + } + } + } + return retval; + } + + /** + * Transfers focus to the next component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus() + * @since 1.1 + */ + public void transferFocus () + { + nextFocus (); + } + + /** + * Returns the root container that owns the focus cycle where this + * component resides. A focus cycle root is in two cycles, one as + * the ancestor, and one as the focusable element; this call always + * returns the ancestor. + * + * @return the ancestor container that owns the focus cycle + * @since 1.4 + */ + public Container getFocusCycleRootAncestor () + { + Container parent = getParent (); + + while (parent != null && !parent.isFocusCycleRoot()) + parent = parent.getParent (); + + return parent; + } + + /** + * Tests if the container is the ancestor of the focus cycle that + * this component belongs to. + * + * @param c the container to test + * @return true if c is the focus cycle root + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) + { + return c == getFocusCycleRootAncestor (); + } + + /** + * AWT 1.0 focus event processor. Transfers focus to the next + * component in the focus traversal order, as though this were the + * current focus owner. + * + * @deprecated use {@link #transferFocus ()} instead + */ + public void nextFocus () + { + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentAfter(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); + + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } + } + + /** + * Transfers focus to the previous component in the focus traversal + * order, as though this were the current focus owner. + * + * @see #requestFocus () + * @since 1.4 + */ + public void transferFocusBackward () + { + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentBefore(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); + + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } + } + + /** + * Transfers focus to the focus cycle root of this component. + * However, if this is a Window, the default focus owner in the + * window in the current focus cycle is focused instead. + * + * @see #requestFocus() + * @see #isFocusCycleRoot(Container) + * @since 1.4 + */ + public void transferFocusUpCycle () + { + // Find the nearest focus cycle root ancestor that is itself + // focusable, showing and enabled. + Container focusCycleRoot = getFocusCycleRootAncestor(); + while (focusCycleRoot != null && + ! (focusCycleRoot.isShowing() && focusCycleRoot.isFocusable() + && focusCycleRoot.isEnabled())) + { + focusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor(); + } + + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + + if (focusCycleRoot != null) + { + // If we found a focus cycle root, then we make this the new + // focused component, and make it's focus cycle root the new + // global focus cycle root. If the found root has no focus cycle + // root ancestor itself, then the component will be both the focused + // component and the new global focus cycle root. + Container focusCycleAncestor = + focusCycleRoot.getFocusCycleRootAncestor(); + Container globalFocusCycleRoot; + if (focusCycleAncestor == null) + globalFocusCycleRoot = focusCycleRoot; + else + globalFocusCycleRoot = focusCycleAncestor; + + fm.setGlobalCurrentFocusCycleRoot(globalFocusCycleRoot); + focusCycleRoot.requestFocus(); + } + else + { + // If this component has no applicable focus cycle root, we try + // find the nearest window and set this as the new global focus cycle + // root and the default focus component of this window the new focused + // component. + Container cont; + if (this instanceof Container) + cont = (Container) this; + else + cont = getParent(); + + while (cont != null && !(cont instanceof Window)) + cont = cont.getParent(); + + if (cont != null) + { + FocusTraversalPolicy policy = cont.getFocusTraversalPolicy(); + Component focusComp = policy.getDefaultComponent(cont); + if (focusComp != null) + { + fm.setGlobalCurrentFocusCycleRoot(cont); + focusComp.requestFocus(); + } + } + } + } + + /** + * Tests if this component is the focus owner. Use {@link + * #isFocusOwner ()} instead. + * + * @return true if this component owns focus + * @since 1.2 + */ + public boolean hasFocus () + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Component focusOwner = manager.getFocusOwner (); + + return this == focusOwner; + } + + /** + * Tests if this component is the focus owner. + * + * @return true if this component owns focus + * @since 1.4 + */ + public boolean isFocusOwner() + { + return hasFocus (); + } + + /** + * Adds the specified popup menu to this component. + * + * @param popup the popup menu to be added + * + * @see #remove(MenuComponent) + * + * @since 1.1 + */ + public synchronized void add(PopupMenu popup) + { + if (popups == null) + popups = new Vector(); + popups.add(popup); + + if (popup.parent != null) + popup.parent.remove(popup); + popup.parent = this; + if (peer != null) + popup.addNotify(); + } + + /** + * Removes the specified popup menu from this component. + * + * @param popup the popup menu to remove + * @see #add(PopupMenu) + * @since 1.1 + */ + public synchronized void remove(MenuComponent popup) + { + if (popups != null) + popups.remove(popup); + } + + /** + * Returns a debugging string representing this component. The string may + * be empty but not null. + * + * @return a string representing this component + */ + protected String paramString() + { + CPStringBuilder param = new CPStringBuilder(); + String name = getName(); + if (name != null) + param.append(name).append(","); + param.append(x).append(",").append(y).append(",").append(width) + .append("x").append(height); + if (! isValid()) + param.append(",invalid"); + if (! isVisible()) + param.append(",invisible"); + if (! isEnabled()) + param.append(",disabled"); + if (! isOpaque()) + param.append(",translucent"); + if (isDoubleBuffered()) + param.append(",doublebuffered"); + if (parent == null) + param.append(",parent=null"); + else + param.append(",parent=").append(parent.getName()); + return param.toString(); + } + + /** + * Returns a string representation of this component. This is implemented + * as getClass().getName() + '[' + paramString() + ']'. + * + * @return a string representation of this component + */ + public String toString() + { + return getClass().getName() + '[' + paramString() + ']'; + } + + /** + * Prints a listing of this component to System.out. + * + * @see #list(PrintStream) + */ + public void list() + { + list(System.out, 0); + } + + /** + * Prints a listing of this component to the specified print stream. + * + * @param out the PrintStream to print to + */ + public void list(PrintStream out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print stream, + * starting at the specified indentation point. + * + * @param out the PrintStream to print to + * @param indent the indentation point + */ + public void list(PrintStream out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Prints a listing of this component to the specified print writer. + * + * @param out the PrintWrinter to print to + * @since 1.1 + */ + public void list(PrintWriter out) + { + list(out, 0); + } + + /** + * Prints a listing of this component to the specified print writer, + * starting at the specified indentation point. + * + * @param out the PrintWriter to print to + * @param indent the indentation point + * @since 1.1 + */ + public void list(PrintWriter out, int indent) + { + for (int i = 0; i < indent; ++i) + out.print(' '); + out.println(toString()); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. Recognized properties include:
+ *

    + *
  • the font ("font")
  • + *
  • the background color ("background")
  • + *
  • the foreground color ("foreground")
  • + *
  • the focusability ("focusable")
  • + *
  • the focus key traversal enabled state + * ("focusTraversalKeysEnabled")
  • + *
  • the set of forward traversal keys + * ("forwardFocusTraversalKeys")
  • + *
  • the set of backward traversal keys + * ("backwardFocusTraversalKeys")
  • + *
  • the set of up-cycle traversal keys + * ("upCycleFocusTraversalKeys")
  • + *
+ * + * @param listener the new listener to add + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes the specified property listener from the component. This is + * harmless if the listener was not previously registered. + * + * @param listener the listener to remove + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns an array of all specified listeners registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(PropertyChangeListener) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(); + } + + /** + * Adds the specified property listener to this component. This is harmless + * if the listener is null, but if the listener has already been registered, + * it will now be registered twice. The property listener ignores inherited + * properties. The listener is keyed to a single property. Recognized + * properties include:
+ *
    + *
  • the font ("font")
  • + *
  • the background color ("background")
  • + *
  • the foreground color ("foreground")
  • + *
  • the focusability ("focusable")
  • + *
  • the focus key traversal enabled state + * ("focusTraversalKeysEnabled")
  • + *
  • the set of forward traversal keys + * ("forwardFocusTraversalKeys")
  • +p *
  • the set of backward traversal keys + * ("backwardFocusTraversalKeys")
  • + *
  • the set of up-cycle traversal keys + * ("upCycleFocusTraversalKeys")
  • + *
+ * + * @param propertyName the property name to filter on + * @param listener the new listener to add + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #addPropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new PropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(propertyName, listener); + } + + /** + * Removes the specified property listener on a particular property from + * the component. This is harmless if the listener was not previously + * registered. + * + * @param propertyName the property name to filter on + * @param listener the listener to remove + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners(String) + * @see #removePropertyChangeListener(PropertyChangeListener) + * @since 1.1 + */ + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(propertyName, listener); + } + + /** + * Returns an array of all specified listeners on the named property that + * are registered on this component. + * + * @return an array of listeners + * @see #addPropertyChangeListener(String, PropertyChangeListener) + * @see #removePropertyChangeListener(String, PropertyChangeListener) + * @see #getPropertyChangeListeners() + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners(String property) + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(property); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + */ + protected void firePropertyChange(String propertyName, int oldValue, + int newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, byte oldValue, + byte newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Byte(oldValue), + new Byte(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, char oldValue, + char newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Character(oldValue), + new Character(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, short oldValue, + short newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Short(oldValue), + new Short(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, long oldValue, + long newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Long(oldValue), + new Long(newValue)); + } + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, float oldValue, + float newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Float(oldValue), + new Float(newValue)); + } + + + /** + * Report a change in a bound property to any registered property listeners. + * + * @param propertyName the property that changed + * @param oldValue the old property value + * @param newValue the new property value + * + * @since 1.5 + */ + public void firePropertyChange(String propertyName, double oldValue, + double newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Double(oldValue), + new Double(newValue)); + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects only + * the current component, while + * {@link #applyComponentOrientation(ComponentOrientation)} affects the + * entire hierarchy. + * + * @param o the new orientation (null is accepted) + * @see #getComponentOrientation() + */ + public void setComponentOrientation(ComponentOrientation o) + { + + ComponentOrientation oldOrientation = componentOrientation; + componentOrientation = o; + firePropertyChange("componentOrientation", oldOrientation, o); + } + + /** + * Determines the text layout orientation used by this component. + * + * @return the component orientation (this can be null) + * @see #setComponentOrientation(ComponentOrientation) + */ + public ComponentOrientation getComponentOrientation() + { + return componentOrientation; + } + + /** + * Sets the text layout orientation of this component. New components default + * to UNKNOWN (which behaves like LEFT_TO_RIGHT). This method affects the + * entire hierarchy, while + * {@link #setComponentOrientation(ComponentOrientation)} affects only the + * current component. + * + * @param o the new orientation + * @throws NullPointerException if o is null + * @see #getComponentOrientation() + * @since 1.4 + */ + public void applyComponentOrientation(ComponentOrientation o) + { + setComponentOrientation(o); + } + + /** + * Returns the accessibility framework context of this class. Component is + * not accessible, so the default implementation returns null. Subclasses + * must override this behavior, and return an appropriate subclass of + * {@link AccessibleAWTComponent}. + * + * @return the accessibility context + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + + // Helper methods; some are package visible for use by subclasses. + + /** + * Subclasses should override this to return unique component names like + * "menuitem0". + * + * @return the generated name for this component + */ + String generateName() + { + // Component is abstract. + return null; + } + + /** + * Sets the peer for this component. + * + * @param peer the new peer + */ + final void setPeer(ComponentPeer peer) + { + this.peer = peer; + } + + /** + * Translate an AWT 1.1 event ({@link AWTEvent}) into an AWT 1.0 + * event ({@link Event}). + * + * @param e an AWT 1.1 event to translate + * + * @return an AWT 1.0 event representing e + */ + static Event translateEvent (AWTEvent e) + { + Object target = e.getSource (); + Event translated = null; + + if (e instanceof WindowEvent) + { + WindowEvent we = (WindowEvent) e; + int id = we.id; + int newId = 0; + + switch (id) + { + case WindowEvent.WINDOW_DEICONIFIED: + newId = Event.WINDOW_DEICONIFY; + break; + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_CLOSING: + newId = Event.WINDOW_DESTROY; + break; + case WindowEvent.WINDOW_ICONIFIED: + newId = Event.WINDOW_ICONIFY; + break; + case WindowEvent.WINDOW_GAINED_FOCUS: + newId = Event.GOT_FOCUS; + break; + case WindowEvent.WINDOW_LOST_FOCUS: + newId = Event.LOST_FOCUS; + break; + default: + return null; + } + + translated = new Event(target, 0, newId, 0, 0, 0, 0); + } + else if (e instanceof InputEvent) + { + InputEvent ie = (InputEvent) e; + long when = ie.getWhen (); + + int oldID = 0; + int id = e.getID (); + + int oldMods = 0; + int mods = ie.getModifiersEx (); + + if ((mods & InputEvent.BUTTON2_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + else if ((mods & InputEvent.BUTTON3_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if ((mods & InputEvent.SHIFT_DOWN_MASK) != 0) + oldMods |= Event.SHIFT_MASK; + + if ((mods & InputEvent.CTRL_DOWN_MASK) != 0) + oldMods |= Event.CTRL_MASK; + + if ((mods & InputEvent.META_DOWN_MASK) != 0) + oldMods |= Event.META_MASK; + + if ((mods & InputEvent.ALT_DOWN_MASK) != 0) + oldMods |= Event.ALT_MASK; + + if (e instanceof MouseEvent && !ignoreOldMouseEvents()) + { + if (id == MouseEvent.MOUSE_PRESSED) + oldID = Event.MOUSE_DOWN; + else if (id == MouseEvent.MOUSE_RELEASED) + oldID = Event.MOUSE_UP; + else if (id == MouseEvent.MOUSE_MOVED) + oldID = Event.MOUSE_MOVE; + else if (id == MouseEvent.MOUSE_DRAGGED) + oldID = Event.MOUSE_DRAG; + else if (id == MouseEvent.MOUSE_ENTERED) + oldID = Event.MOUSE_ENTER; + else if (id == MouseEvent.MOUSE_EXITED) + oldID = Event.MOUSE_EXIT; + else + // No analogous AWT 1.0 mouse event. + return null; + + MouseEvent me = (MouseEvent) e; + + translated = new Event (target, when, oldID, + me.getX (), me.getY (), 0, oldMods); + } + else if (e instanceof KeyEvent) + { + if (id == KeyEvent.KEY_PRESSED) + oldID = Event.KEY_PRESS; + else if (e.getID () == KeyEvent.KEY_RELEASED) + oldID = Event.KEY_RELEASE; + else + // No analogous AWT 1.0 key event. + return null; + + int oldKey = 0; + int newKey = ((KeyEvent) e).getKeyCode (); + switch (newKey) + { + case KeyEvent.VK_BACK_SPACE: + oldKey = Event.BACK_SPACE; + break; + case KeyEvent.VK_CAPS_LOCK: + oldKey = Event.CAPS_LOCK; + break; + case KeyEvent.VK_DELETE: + oldKey = Event.DELETE; + break; + case KeyEvent.VK_DOWN: + case KeyEvent.VK_KP_DOWN: + oldKey = Event.DOWN; + break; + case KeyEvent.VK_END: + oldKey = Event.END; + break; + case KeyEvent.VK_ENTER: + oldKey = Event.ENTER; + break; + case KeyEvent.VK_ESCAPE: + oldKey = Event.ESCAPE; + break; + case KeyEvent.VK_F1: + oldKey = Event.F1; + break; + case KeyEvent.VK_F10: + oldKey = Event.F10; + break; + case KeyEvent.VK_F11: + oldKey = Event.F11; + break; + case KeyEvent.VK_F12: + oldKey = Event.F12; + break; + case KeyEvent.VK_F2: + oldKey = Event.F2; + break; + case KeyEvent.VK_F3: + oldKey = Event.F3; + break; + case KeyEvent.VK_F4: + oldKey = Event.F4; + break; + case KeyEvent.VK_F5: + oldKey = Event.F5; + break; + case KeyEvent.VK_F6: + oldKey = Event.F6; + break; + case KeyEvent.VK_F7: + oldKey = Event.F7; + break; + case KeyEvent.VK_F8: + oldKey = Event.F8; + break; + case KeyEvent.VK_F9: + oldKey = Event.F9; + break; + case KeyEvent.VK_HOME: + oldKey = Event.HOME; + break; + case KeyEvent.VK_INSERT: + oldKey = Event.INSERT; + break; + case KeyEvent.VK_LEFT: + case KeyEvent.VK_KP_LEFT: + oldKey = Event.LEFT; + break; + case KeyEvent.VK_NUM_LOCK: + oldKey = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + oldKey = Event.PAUSE; + break; + case KeyEvent.VK_PAGE_DOWN: + oldKey = Event.PGDN; + break; + case KeyEvent.VK_PAGE_UP: + oldKey = Event.PGUP; + break; + case KeyEvent.VK_PRINTSCREEN: + oldKey = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_KP_RIGHT: + oldKey = Event.RIGHT; + break; + case KeyEvent.VK_SCROLL_LOCK: + oldKey = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_TAB: + oldKey = Event.TAB; + break; + case KeyEvent.VK_UP: + case KeyEvent.VK_KP_UP: + oldKey = Event.UP; + break; + default: + oldKey = ((KeyEvent) e).getKeyChar(); + } + + translated = new Event (target, when, oldID, + 0, 0, oldKey, oldMods); + } + } + else if (e instanceof AdjustmentEvent) + { + AdjustmentEvent ae = (AdjustmentEvent) e; + int type = ae.getAdjustmentType(); + int oldType; + if (type == AdjustmentEvent.BLOCK_DECREMENT) + oldType = Event.SCROLL_PAGE_UP; + else if (type == AdjustmentEvent.BLOCK_INCREMENT) + oldType = Event.SCROLL_PAGE_DOWN; + else if (type == AdjustmentEvent.TRACK) + oldType = Event.SCROLL_ABSOLUTE; + else if (type == AdjustmentEvent.UNIT_DECREMENT) + oldType = Event.SCROLL_LINE_UP; + else if (type == AdjustmentEvent.UNIT_INCREMENT) + oldType = Event.SCROLL_LINE_DOWN; + else + oldType = type; + translated = new Event(target, oldType, new Integer(ae.getValue())); + } + else if (e instanceof ActionEvent) + translated = new Event (target, Event.ACTION_EVENT, + ((ActionEvent) e).getActionCommand ()); + + return translated; + } + + /** + * Implementation of dispatchEvent. Allows trusted package classes + * to dispatch additional events first. This implementation first + * translates e to an AWT 1.0 event and sends the + * result to {@link #postEvent}. If the AWT 1.0 event is not + * handled, and events of type e are enabled for this + * component, e is passed on to {@link #processEvent}. + * + * @param e the event to dispatch + */ + void dispatchEventImpl(AWTEvent e) + { + // Update the component's knowledge about the size. + // Important: Please look at the big comment in ComponentReshapeEvent + // to learn why we did it this way. If you change this code, make + // sure that the peer->AWT bounds update still works. + // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 ) + if (e instanceof ComponentReshapeEvent) + { + ComponentReshapeEvent reshape = (ComponentReshapeEvent) e; + x = reshape.x; + y = reshape.y; + width = reshape.width; + height = reshape.height; + return; + } + + // Retarget focus events before dispatching it to the KeyboardFocusManager + // in order to handle lightweight components properly. + boolean dispatched = false; + if (! e.isFocusManagerEvent) + { + e = KeyboardFocusManager.retargetFocusEvent(e); + dispatched = KeyboardFocusManager.getCurrentKeyboardFocusManager() + .dispatchEvent(e); + } + + if (! dispatched) + { + // Give toolkit a chance to dispatch the event + // to globally registered listeners. + Toolkit.getDefaultToolkit().globalDispatchEvent(e); + + if (newEventsOnly) + { + if (eventTypeEnabled(e.id)) + processEvent(e); + } + else + { + Event oldEvent = translateEvent(e); + if (oldEvent != null) + postEvent (oldEvent); + } + if (peer != null) + peer.handleEvent(e); + } + } + + /** + * Tells whether or not an event type is enabled. + */ + boolean eventTypeEnabled (int type) + { + if (type > AWTEvent.RESERVED_ID_MAX) + return true; + + switch (type) + { + case HierarchyEvent.HIERARCHY_CHANGED: + return (hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0); + + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + return (hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0); + + case ComponentEvent.COMPONENT_HIDDEN: + case ComponentEvent.COMPONENT_MOVED: + case ComponentEvent.COMPONENT_RESIZED: + case ComponentEvent.COMPONENT_SHOWN: + return (componentListener != null + || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0); + + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + return (keyListener != null + || (eventMask & AWTEvent.KEY_EVENT_MASK) != 0); + + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + return (mouseListener != null + || (eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0); + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + return (mouseMotionListener != null + || (eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0); + case MouseEvent.MOUSE_WHEEL: + return (mouseWheelListener != null + || (eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0); + + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + return (focusListener != null + || (eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0); + + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + case InputMethodEvent.CARET_POSITION_CHANGED: + return (inputMethodListener != null + || (eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0); + + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + return (eventMask & AWTEvent.PAINT_EVENT_MASK) != 0; + + default: + return false; + } + } + + /** + * Returns true when this component and all of its ancestors + * are visible, false otherwise. + * + * @return true when this component and all of its ancestors + * are visible, false otherwise + */ + boolean isHierarchyVisible() + { + boolean visible = isVisible(); + Component comp = parent; + while (comp != null && visible) + { + comp = comp.parent; + if (comp != null) + visible = visible && comp.isVisible(); + } + return visible; + } + + /** + * Returns the mouse pointer position relative to this Component's + * top-left corner. + * + * @return relative mouse pointer position + * + * @throws HeadlessException if in a headless environment + */ + public Point getMousePosition() throws HeadlessException + { + return getMousePositionHelper(true); + } + + Point getMousePositionHelper(boolean allowChildren) throws HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException("can't get mouse position" + + " in headless environment"); + if (!isShowing()) + return null; + + Component parent = this; + int windowRelativeXOffset = 0; + int windowRelativeYOffset = 0; + while (parent != null && !(parent instanceof Window)) + { + windowRelativeXOffset += parent.getX(); + windowRelativeYOffset += parent.getY(); + parent = parent.getParent(); + } + if (parent == null) + return null; + + Window window = (Window) parent; + if (!Toolkit.getDefaultToolkit() + .getMouseInfoPeer().isWindowUnderMouse(window)) + return null; + + PointerInfo info = MouseInfo.getPointerInfo(); + Point mouseLocation = info.getLocation(); + Point windowLocation = window.getLocationOnScreen(); + + int x = mouseLocation.x - windowLocation.x; + int y = mouseLocation.y - windowLocation.y; + + if (!mouseOverComponent(window.getComponentAt(x, y), allowChildren)) + return null; + + return new Point(x - windowRelativeXOffset, y - windowRelativeYOffset); + } + + boolean mouseOverComponent(Component component, boolean allowChildren) + { + return component == this; + } + + /** + * This method is used to implement transferFocus(). CHILD is the child + * making the request. This is overridden by Container; when called for an + * ordinary component there is no child and so we always return null. + * + * FIXME: is this still needed, in light of focus traversal policies? + * + * @param child the component making the request + * @return the next component to focus on + */ + Component findNextFocusComponent(Component child) + { + return null; + } + + /** + * Deserializes this component. This regenerates all serializable listeners + * which were registered originally. + * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject(); + String key = (String) s.readObject(); + while (key != null) + { + Object listener = s.readObject(); + if ("componentL".equals(key)) + addComponentListener((ComponentListener) listener); + else if ("focusL".equals(key)) + addFocusListener((FocusListener) listener); + else if ("keyL".equals(key)) + addKeyListener((KeyListener) listener); + else if ("mouseL".equals(key)) + addMouseListener((MouseListener) listener); + else if ("mouseMotionL".equals(key)) + addMouseMotionListener((MouseMotionListener) listener); + else if ("inputMethodL".equals(key)) + addInputMethodListener((InputMethodListener) listener); + else if ("hierarchyL".equals(key)) + addHierarchyListener((HierarchyListener) listener); + else if ("hierarchyBoundsL".equals(key)) + addHierarchyBoundsListener((HierarchyBoundsListener) listener); + else if ("mouseWheelL".equals(key)) + addMouseWheelListener((MouseWheelListener) listener); + key = (String) s.readObject(); + } + } + + /** + * Serializes this component. This ignores all listeners which do not + * implement Serializable, but includes those that do. + * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + AWTEventMulticaster.save(s, "componentL", componentListener); + AWTEventMulticaster.save(s, "focusL", focusListener); + AWTEventMulticaster.save(s, "keyL", keyListener); + AWTEventMulticaster.save(s, "mouseL", mouseListener); + AWTEventMulticaster.save(s, "mouseMotionL", mouseMotionListener); + AWTEventMulticaster.save(s, "inputMethodL", inputMethodListener); + AWTEventMulticaster.save(s, "hierarchyL", hierarchyListener); + AWTEventMulticaster.save(s, "hierarchyBoundsL", hierarchyBoundsListener); + AWTEventMulticaster.save(s, "mouseWheelL", mouseWheelListener); + s.writeObject(null); + } + + + // Nested classes. + + /** + * This class fixes the bounds for a Heavyweight component that + * is placed inside a Lightweight container. When the lightweight is + * moved or resized, setBounds for the lightweight peer does nothing. + * Therefore, it was never moved on the screen. This class is + * attached to the lightweight, and it adjusts the position and size + * of the peer when notified. + * This is the same for show and hide. + */ + class HeavyweightInLightweightListener + implements ComponentListener + { + + /** + * Constructor. Adds component listener to lightweight parent. + * + * @param parent - the lightweight container. + */ + public HeavyweightInLightweightListener(Container parent) + { + parent.addComponentListener(this); + } + + /** + * This method is called when the component is resized. + * + * @param event the ComponentEvent indicating the resize + */ + public void componentResized(ComponentEvent event) + { + // Nothing to do here, componentMoved will be called. + } + + /** + * This method is called when the component is moved. + * + * @param event the ComponentEvent indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (peer != null) + peer.setBounds(x, y, width, height); + } + + /** + * This method is called when the component is made visible. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (isShowing()) + peer.show(); + } + + /** + * This method is called when the component is hidden. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (isShowing()) + peer.hide(); + } + } + + /** + * This class provides accessibility support for subclasses of container. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected abstract class AccessibleAWTComponent extends AccessibleContext + implements Serializable, AccessibleComponent + { + /** + * Compatible with JDK 1.3+. + */ + private static final long serialVersionUID = 642321655757800191L; + + /** + * Converts show/hide events to PropertyChange events, and is registered + * as a component listener on this component. + * + * @serial the component handler + */ + protected ComponentListener accessibleAWTComponentHandler + = new AccessibleAWTComponentHandler(); + + /** + * Converts focus events to PropertyChange events, and is registered + * as a focus listener on this component. + * + * @serial the focus handler + */ + protected FocusListener accessibleAWTFocusHandler + = new AccessibleAWTFocusHandler(); + + /** + * The default constructor. + */ + protected AccessibleAWTComponent() + { + Component.this.addComponentListener(accessibleAWTComponentHandler); + Component.this.addFocusListener(accessibleAWTFocusHandler); + } + + /** + * Adds a global property change listener to the accessible component. + * + * @param l the listener to add + * @see #ACCESSIBLE_NAME_PROPERTY + * @see #ACCESSIBLE_DESCRIPTION_PROPERTY + * @see #ACCESSIBLE_STATE_PROPERTY + * @see #ACCESSIBLE_VALUE_PROPERTY + * @see #ACCESSIBLE_SELECTION_PROPERTY + * @see #ACCESSIBLE_TEXT_PROPERTY + * @see #ACCESSIBLE_VISIBLE_DATA_PROPERTY + */ + public void addPropertyChangeListener(PropertyChangeListener l) + { + Component.this.addPropertyChangeListener(l); + super.addPropertyChangeListener(l); + } + + /** + * Removes a global property change listener from this accessible + * component. + * + * @param l the listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener l) + { + Component.this.removePropertyChangeListener(l); + super.removePropertyChangeListener(l); + } + + /** + * Returns the accessible name of this component. It is almost always + * wrong to return getName(), since it is not localized. In fact, for + * things like buttons, this should be the text of the button, not the + * name of the object. The tooltip text might also be appropriate. + * + * @return the name + * @see #setAccessibleName(String) + */ + public String getAccessibleName() + { + return accessibleName; + } + + /** + * Returns a brief description of this accessible context. This should + * be localized. + * + * @return a description of this component + * @see #setAccessibleDescription(String) + */ + public String getAccessibleDescription() + { + return accessibleDescription; + } + + /** + * Returns the role of this component. + * + * @return the accessible role + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.AWT_COMPONENT; + } + + /** + * Returns a state set describing this component's state. + * + * @return a new state set + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() + { + AccessibleStateSet s = new AccessibleStateSet(); + if (Component.this.isEnabled()) + s.add(AccessibleState.ENABLED); + if (isFocusable()) + s.add(AccessibleState.FOCUSABLE); + if (isFocusOwner()) + s.add(AccessibleState.FOCUSED); + // Note: While the java.awt.Component has an 'opaque' property, it + // seems that it is not added to the accessible state set here, even + // if this property is true. However, it is handled for + // javax.swing.JComponent, so we add it there. + if (Component.this.isShowing()) + s.add(AccessibleState.SHOWING); + if (Component.this.isVisible()) + s.add(AccessibleState.VISIBLE); + return s; + } + + /** + * Returns the parent of this component, if it is accessible. + * + * @return the accessible parent + */ + public Accessible getAccessibleParent() + { + if (accessibleParent == null) + { + Container parent = getParent(); + accessibleParent = parent instanceof Accessible + ? (Accessible) parent : null; + } + return accessibleParent; + } + + /** + * Returns the index of this component in its accessible parent. + * + * @return the index, or -1 if the parent is not accessible + * @see #getAccessibleParent() + */ + public int getAccessibleIndexInParent() + { + if (getAccessibleParent() == null) + return -1; + AccessibleContext context + = ((Component) accessibleParent).getAccessibleContext(); + if (context == null) + return -1; + for (int i = context.getAccessibleChildrenCount(); --i >= 0; ) + if (context.getAccessibleChild(i) == Component.this) + return i; + return -1; + } + + /** + * Returns the number of children of this component which implement + * Accessible. Subclasses must override this if they can have children. + * + * @return the number of accessible children, default 0 + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Returns the ith accessible child. Subclasses must override this if + * they can have children. + * + * @return the ith accessible child, or null + * @see #getAccessibleChildrenCount() + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * Returns the locale of this component. + * + * @return the locale + * @throws IllegalComponentStateException if the locale is unknown + */ + public Locale getLocale() + { + return Component.this.getLocale(); + } + + /** + * Returns this, since it is an accessible component. + * + * @return the accessible component + */ + public AccessibleComponent getAccessibleComponent() + { + return this; + } + + /** + * Gets the background color. + * + * @return the background color + * @see #setBackground(Color) + */ + public Color getBackground() + { + return Component.this.getBackground(); + } + + /** + * Sets the background color. + * + * @param c the background color + * @see #getBackground() + * @see #isOpaque() + */ + public void setBackground(Color c) + { + Component.this.setBackground(c); + } + + /** + * Gets the foreground color. + * + * @return the foreground color + * @see #setForeground(Color) + */ + public Color getForeground() + { + return Component.this.getForeground(); + } + + /** + * Sets the foreground color. + * + * @param c the foreground color + * @see #getForeground() + */ + public void setForeground(Color c) + { + Component.this.setForeground(c); + } + + /** + * Gets the cursor. + * + * @return the cursor + * @see #setCursor(Cursor) + */ + public Cursor getCursor() + { + return Component.this.getCursor(); + } + + /** + * Sets the cursor. + * + * @param cursor the cursor + * @see #getCursor() + */ + public void setCursor(Cursor cursor) + { + Component.this.setCursor(cursor); + } + + /** + * Gets the font. + * + * @return the font + * @see #setFont(Font) + */ + public Font getFont() + { + return Component.this.getFont(); + } + + /** + * Sets the font. + * + * @param f the font + * @see #getFont() + */ + public void setFont(Font f) + { + Component.this.setFont(f); + } + + /** + * Gets the font metrics for a font. + * + * @param f the font to look up + * @return its metrics + * @throws NullPointerException if f is null + * @see #getFont() + */ + public FontMetrics getFontMetrics(Font f) + { + return Component.this.getFontMetrics(f); + } + + /** + * Tests if the component is enabled. + * + * @return true if the component is enabled + * @see #setEnabled(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#ENABLED + */ + public boolean isEnabled() + { + return Component.this.isEnabled(); + } + + /** + * Set whether the component is enabled. + * + * @param b the new enabled status + * @see #isEnabled() + */ + public void setEnabled(boolean b) + { + Component.this.setEnabled(b); + } + + /** + * Test whether the component is visible (not necesarily showing). + * + * @return true if it is visible + * @see #setVisible(boolean) + * @see #getAccessibleStateSet() + * @see AccessibleState#VISIBLE + */ + public boolean isVisible() + { + return Component.this.isVisible(); + } + + /** + * Sets the visibility of this component. + * + * @param b the desired visibility + * @see #isVisible() + */ + public void setVisible(boolean b) + { + Component.this.setVisible(b); + } + + /** + * Tests if the component is showing. + * + * @return true if this is showing + */ + public boolean isShowing() + { + return Component.this.isShowing(); + } + + /** + * Tests if the point is contained in this component. + * + * @param p the point to check + * @return true if it is contained + * @throws NullPointerException if p is null + */ + public boolean contains(Point p) + { + return Component.this.contains(p.x, p.y); + } + + /** + * Returns the location of this object on the screen, or null if it is + * not showing. + * + * @return the location relative to screen coordinates, if showing + * @see #getBounds() + * @see #getLocation() + */ + public Point getLocationOnScreen() + { + return Component.this.isShowing() ? Component.this.getLocationOnScreen() + : null; + } + + /** + * Returns the location of this object relative to its parent's coordinate + * system, or null if it is not showing. + * + * @return the location + * @see #getBounds() + * @see #getLocationOnScreen() + */ + public Point getLocation() + { + return Component.this.getLocation(); + } + + /** + * Sets the location of this relative to its parent's coordinate system. + * + * @param p the location + * @throws NullPointerException if p is null + * @see #getLocation() + */ + public void setLocation(Point p) + { + Component.this.setLocation(p.x, p.y); + } + + /** + * Gets the bounds of this component, or null if it is not on screen. + * + * @return the bounds + * @see #contains(Point) + * @see #setBounds(Rectangle) + */ + public Rectangle getBounds() + { + return Component.this.getBounds(); + } + + /** + * Sets the bounds of this component. + * + * @param r the bounds + * @throws NullPointerException if r is null + * @see #getBounds() + */ + public void setBounds(Rectangle r) + { + Component.this.setBounds(r.x, r.y, r.width, r.height); + } + + /** + * Gets the size of this component, or null if it is not showing. + * + * @return the size + * @see #setSize(Dimension) + */ + public Dimension getSize() + { + return Component.this.getSize(); + } + + /** + * Sets the size of this component. + * + * @param d the size + * @throws NullPointerException if d is null + * @see #getSize() + */ + public void setSize(Dimension d) + { + Component.this.setSize(d.width, d.height); + } + + /** + * Returns the Accessible child at a point relative to the coordinate + * system of this component, if one exists, or null. Since components + * have no children, subclasses must override this to get anything besides + * null. + * + * @param p the point to check + * @return the accessible child at that point + * @throws NullPointerException if p is null + */ + public Accessible getAccessibleAt(Point p) + { + return null; + } + + /** + * Tests whether this component can accept focus. + * + * @return true if this is focus traversable + * @see #getAccessibleStateSet () + * @see AccessibleState#FOCUSABLE + * @see AccessibleState#FOCUSED + */ + public boolean isFocusTraversable () + { + return Component.this.isFocusTraversable (); + } + + /** + * Requests focus for this component. + * + * @see #isFocusTraversable () + */ + public void requestFocus () + { + Component.this.requestFocus (); + } + + /** + * Adds a focus listener. + * + * @param l the listener to add + */ + public void addFocusListener(FocusListener l) + { + Component.this.addFocusListener(l); + } + + /** + * Removes a focus listener. + * + * @param l the listener to remove + */ + public void removeFocusListener(FocusListener l) + { + Component.this.removeFocusListener(l); + } + + /** + * Converts component changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTComponentHandler implements ComponentListener + { + /** + * Default constructor. + */ + protected AccessibleAWTComponentHandler() + { + // Nothing to do here. + } + + /** + * Convert a component hidden to a property change. + * + * @param e the event to convert + */ + public void componentHidden(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.VISIBLE, null); + } + + /** + * Convert a component shown to a property change. + * + * @param e the event to convert + */ + public void componentShown(ComponentEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.VISIBLE); + } + + /** + * Moving a component does not affect properties. + * + * @param e ignored + */ + public void componentMoved(ComponentEvent e) + { + // Nothing to do here. + } + + /** + * Resizing a component does not affect properties. + * + * @param e ignored + */ + public void componentResized(ComponentEvent e) + { + // Nothing to do here. + } + } // class AccessibleAWTComponentHandler + + /** + * Converts focus changes into property changes. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.3 + * @status updated to 1.4 + */ + protected class AccessibleAWTFocusHandler implements FocusListener + { + /** + * Default constructor. + */ + protected AccessibleAWTFocusHandler() + { + // Nothing to do here. + } + + /** + * Convert a focus gained to a property change. + * + * @param e the event to convert + */ + public void focusGained(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.FOCUSED); + } + + /** + * Convert a focus lost to a property change. + * + * @param e the event to convert + */ + public void focusLost(FocusEvent e) + { + AccessibleAWTComponent.this.firePropertyChange + (ACCESSIBLE_STATE_PROPERTY, AccessibleState.FOCUSED, null); + } + } // class AccessibleAWTComponentHandler + } // class AccessibleAWTComponent + + /** + * This class provides support for blitting offscreen surfaces to a + * component. + * + * @see BufferStrategy + * + * @since 1.4 + */ + protected class BltBufferStrategy extends BufferStrategy + { + /** + * The capabilities of the image buffer. + */ + protected BufferCapabilities caps; + + /** + * The back buffers used in this strategy. + */ + protected VolatileImage[] backBuffers; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffers. + */ + protected int width; + + /** + * The height of the back buffers. + */ + protected int height; + + /** + * The front buffer. + */ + private VolatileImage frontBuffer; + + /** + * Creates a blitting buffer strategy. + * + * @param numBuffers the number of buffers, including the front + * buffer + * @param caps the capabilities of this strategy + */ + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + { + this.caps = caps; + createBackBuffers(numBuffers - 1); + width = getWidth(); + height = getHeight(); + } + + /** + * Initializes the backBuffers field with an array of numBuffers + * VolatileImages. + * + * @param numBuffers the number of backbuffers to create + */ + protected void createBackBuffers(int numBuffers) + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + backBuffers = new VolatileImage[numBuffers]; + + for (int i = 0; i < numBuffers; i++) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + // Return the backmost buffer's graphics. + return backBuffers[0].getGraphics(); + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + // draw the front buffer. + getGraphics().drawImage(backBuffers[backBuffers.length - 1], + width, height, null); + + BufferCapabilities.FlipContents f = getCapabilities().getFlipContents(); + + // blit the back buffers. + for (int i = backBuffers.length - 1; i > 0 ; i--) + backBuffers[i] = backBuffers[i - 1]; + + // create new backmost buffer. + if (f == BufferCapabilities.FlipContents.UNDEFINED) + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + + // create new backmost buffer and clear it to the background + // color. + if (f == BufferCapabilities.FlipContents.BACKGROUND) + { + backBuffers[0] = c.createCompatibleVolatileImage(width, height); + backBuffers[0].getGraphics().clearRect(0, 0, width, height); + } + + // FIXME: set the backmost buffer to the prior contents of the + // front buffer. How do we retrieve the contents of the front + // buffer? + // + // if (f == BufferCapabilities.FlipContents.PRIOR) + + // set the backmost buffer to a copy of the new front buffer. + if (f == BufferCapabilities.FlipContents.COPIED) + backBuffers[0] = backBuffers[backBuffers.length - 1]; + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_INCOMPATIBLE) + backBuffers[i] = c.createCompatibleVolatileImage(width, height); + } + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + for (int i = 0; i < backBuffers.length; i++) + { + if (backBuffers[i].contentsLost()) + { + validatedContents = false; + return true; + } + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + boolean imageRestored = false; + + for (int i = 0; i < backBuffers.length; i++) + { + int result = backBuffers[i].validate(c); + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + } + + /** + * This class provides support for flipping component buffers. It + * can only be used on Canvases and Windows. + * + * @since 1.4 + */ + protected class FlipBufferStrategy extends BufferStrategy + { + /** + * The number of buffers. + */ + protected int numBuffers; + + /** + * The capabilities of this buffering strategy. + */ + protected BufferCapabilities caps; + + /** + * An Image reference to the drawing buffer. + */ + protected Image drawBuffer; + + /** + * A VolatileImage reference to the drawing buffer. + */ + protected VolatileImage drawVBuffer; + + /** + * Whether or not the image buffer resources are allocated and + * ready to be drawn into. + */ + protected boolean validatedContents; + + /** + * The width of the back buffer. + */ + private int width; + + /** + * The height of the back buffer. + */ + private int height; + + /** + * Creates a flipping buffer strategy. The only supported + * strategy for FlipBufferStrategy itself is a double-buffer page + * flipping strategy. It forms the basis for more complex derived + * strategies. + * + * @param numBuffers the number of buffers + * @param caps the capabilities of this buffering strategy + * + * @throws AWTException if the requested + * number-of-buffers/capabilities combination is not supported + */ + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) + throws AWTException + { + this.caps = caps; + width = getWidth(); + height = getHeight(); + + if (numBuffers > 1) + createBuffers(numBuffers, caps); + else + { + drawVBuffer = peer.createVolatileImage(width, height); + drawBuffer = drawVBuffer; + } + } + + /** + * Creates a multi-buffer flipping strategy. The number of + * buffers must be greater than one and the buffer capabilities + * must specify page flipping. + * + * @param numBuffers the number of flipping buffers; must be + * greater than one + * @param caps the buffering capabilities; caps.isPageFlipping() + * must return true + * + * @throws IllegalArgumentException if numBuffers is not greater + * than one or if the page flipping capability is not requested + * + * @throws AWTException if the requested flipping strategy is not + * supported + */ + protected void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException + { + if (numBuffers <= 1) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " numBuffers must be greater than" + + " one."); + + if (!caps.isPageFlipping()) + throw new IllegalArgumentException("FlipBufferStrategy.createBuffers:" + + " flipping must be a specified" + + " capability."); + + peer.createBuffers(numBuffers, caps); + } + + /** + * Return a direct reference to the back buffer image. + * + * @return a direct reference to the back buffer image. + */ + protected Image getBackBuffer() + { + return peer.getBackBuffer(); + } + + /** + * Perform a flip operation to transfer the contents of the back + * buffer to the front buffer. + */ + protected void flip(BufferCapabilities.FlipContents flipAction) + { + peer.flip(flipAction); + } + + /** + * Release the back buffer's resources. + */ + protected void destroyBuffers() + { + peer.destroyBuffers(); + } + + /** + * Retrieves the capabilities of this buffer strategy. + * + * @return the capabilities of this buffer strategy + */ + public BufferCapabilities getCapabilities() + { + return caps; + } + + /** + * Retrieves a graphics object that can be used to draw into this + * strategy's image buffer. + * + * @return a graphics object + */ + public Graphics getDrawGraphics() + { + return drawVBuffer.getGraphics(); + } + + /** + * Re-create the image buffer resources if they've been lost. + */ + protected void revalidate() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + if (drawVBuffer.validate(c) == VolatileImage.IMAGE_INCOMPATIBLE) + drawVBuffer = peer.createVolatileImage(width, height); + validatedContents = true; + } + + /** + * Returns whether or not the image buffer resources have been + * lost. + * + * @return true if the resources have been lost, false otherwise + */ + public boolean contentsLost() + { + if (drawVBuffer.contentsLost()) + { + validatedContents = false; + return true; + } + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return false; + } + + /** + * Returns whether or not the image buffer resources have been + * restored. + * + * @return true if the resources have been restored, false + * otherwise + */ + public boolean contentsRestored() + { + GraphicsConfiguration c = + GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + int result = drawVBuffer.validate(c); + + boolean imageRestored = false; + + if (result == VolatileImage.IMAGE_RESTORED) + imageRestored = true; + else if (result == VolatileImage.IMAGE_INCOMPATIBLE) + return false; + + // we know that the buffer resources are valid now because we + // just checked them + validatedContents = true; + return imageRestored; + } + + /** + * Bring the contents of the back buffer to the front buffer. + */ + public void show() + { + flip(caps.getFlipContents()); + } + } +} -- cgit v1.2.3