001    /* JComponent.java -- Every component in swing inherits from this class.
002       Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import gnu.java.lang.CPStringBuilder;
042    
043    import java.applet.Applet;
044    import java.awt.AWTEvent;
045    import java.awt.Color;
046    import java.awt.Component;
047    import java.awt.Container;
048    import java.awt.Dimension;
049    import java.awt.EventQueue;
050    import java.awt.FocusTraversalPolicy;
051    import java.awt.Font;
052    import java.awt.Graphics;
053    import java.awt.Image;
054    import java.awt.Insets;
055    import java.awt.Point;
056    import java.awt.Rectangle;
057    import java.awt.Window;
058    import java.awt.dnd.DropTarget;
059    import java.awt.event.ActionEvent;
060    import java.awt.event.ActionListener;
061    import java.awt.event.ContainerEvent;
062    import java.awt.event.ContainerListener;
063    import java.awt.event.FocusEvent;
064    import java.awt.event.FocusListener;
065    import java.awt.event.KeyEvent;
066    import java.awt.event.MouseEvent;
067    import java.awt.peer.LightweightPeer;
068    import java.beans.PropertyChangeEvent;
069    import java.beans.PropertyChangeListener;
070    import java.beans.PropertyVetoException;
071    import java.beans.VetoableChangeListener;
072    import java.beans.VetoableChangeSupport;
073    import java.io.Serializable;
074    import java.util.ArrayList;
075    import java.util.EventListener;
076    import java.util.Hashtable;
077    import java.util.Locale;
078    import java.util.Set;
079    
080    import javax.accessibility.Accessible;
081    import javax.accessibility.AccessibleContext;
082    import javax.accessibility.AccessibleExtendedComponent;
083    import javax.accessibility.AccessibleKeyBinding;
084    import javax.accessibility.AccessibleRole;
085    import javax.accessibility.AccessibleState;
086    import javax.accessibility.AccessibleStateSet;
087    import javax.swing.border.Border;
088    import javax.swing.border.CompoundBorder;
089    import javax.swing.border.TitledBorder;
090    import javax.swing.event.AncestorEvent;
091    import javax.swing.event.AncestorListener;
092    import javax.swing.event.EventListenerList;
093    import javax.swing.plaf.ComponentUI;
094    
095    /**
096     * The base class of all Swing components.
097     * It contains generic methods to manage events, properties and sizes. Actual
098     * drawing of the component is channeled to a look-and-feel class that is
099     * implemented elsewhere.
100     *
101     * @author Ronald Veldema (rveldema&064;cs.vu.nl)
102     * @author Graydon Hoare (graydon&064;redhat.com)
103     */
104    public abstract class JComponent extends Container implements Serializable
105    {
106      private static final long serialVersionUID = -7908749299918704233L;
107    
108      /** 
109       * The accessible context of this <code>JComponent</code>.
110       */
111      protected AccessibleContext accessibleContext;
112    
113      /**
114       * Basic accessibility support for <code>JComponent</code> derived
115       * widgets.
116       */
117      public abstract class AccessibleJComponent 
118        extends AccessibleAWTContainer
119        implements AccessibleExtendedComponent
120      {
121        /**
122         * Receives notification if the focus on the JComponent changes and
123         * fires appropriate PropertyChangeEvents to listeners registered with
124         * the AccessibleJComponent.
125         */
126        protected class AccessibleFocusHandler 
127          implements FocusListener
128        {
129          /**
130           * Creates a new AccessibleFocusHandler.
131           */
132          protected AccessibleFocusHandler()
133          {
134            // Nothing to do here.
135          }
136    
137          /**
138           * Receives notification when the JComponent gained focus and fires
139           * a PropertyChangeEvent to listeners registered on the
140           * AccessibleJComponent with a property name of
141           * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and a new value
142           * of {@link AccessibleState#FOCUSED}.
143           */
144          public void focusGained(FocusEvent event)
145          {
146            AccessibleJComponent.this.firePropertyChange
147              (AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null,
148               AccessibleState.FOCUSED);
149          }
150    
151          /**
152           * Receives notification when the JComponent lost focus and fires
153           * a PropertyChangeEvent to listeners registered on the
154           * AccessibleJComponent with a property name of
155           * {@link AccessibleContext#ACCESSIBLE_STATE_PROPERTY} and an old value
156           * of {@link AccessibleState#FOCUSED}.
157           */
158          public void focusLost(FocusEvent valevent)
159          {
160            AccessibleJComponent.this.firePropertyChange
161              (AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
162               AccessibleState.FOCUSED, null);
163          }
164        }
165    
166        /**
167         * Receives notification if there are child components are added or removed
168         * from the JComponent and fires appropriate PropertyChangeEvents to
169         * interested listeners on the AccessibleJComponent.
170         */
171        protected class AccessibleContainerHandler 
172          implements ContainerListener
173        {
174          /**
175           * Creates a new AccessibleContainerHandler.
176           */
177          protected AccessibleContainerHandler()
178          {
179            // Nothing to do here.
180          }
181    
182          /**
183           * Receives notification when a child component is added to the
184           * JComponent and fires a PropertyChangeEvent on listeners registered
185           * with the AccessibleJComponent with a property name of
186           * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}.
187           *
188           * @param event the container event
189           */
190          public void componentAdded(ContainerEvent event)
191          {
192            Component c = event.getChild();
193            if (c != null && c instanceof Accessible)
194              {
195                AccessibleContext childCtx = c.getAccessibleContext();
196                AccessibleJComponent.this.firePropertyChange
197                  (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, null, childCtx);
198              }
199          }
200    
201          /**
202           * Receives notification when a child component is removed from the
203           * JComponent and fires a PropertyChangeEvent on listeners registered
204           * with the AccessibleJComponent with a property name of
205           * {@link AccessibleContext#ACCESSIBLE_CHILD_PROPERTY}.
206           *
207           * @param event the container event
208           */
209          public void componentRemoved(ContainerEvent event)
210          {
211            Component c = event.getChild();
212            if (c != null && c instanceof Accessible)
213              {
214                AccessibleContext childCtx = c.getAccessibleContext();
215                AccessibleJComponent.this.firePropertyChange
216                  (AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, childCtx, null);
217              }
218          }
219        }
220    
221        private static final long serialVersionUID = -7047089700479897799L;
222    
223        /**
224         * Receives notification when a child component is added to the
225         * JComponent and fires a PropertyChangeEvent on listeners registered
226         * with the AccessibleJComponent.
227         *
228         * @specnote AccessibleAWTContainer has a protected field with the same
229         *           name. Looks like a bug or nasty misdesign to me.
230         */
231        protected ContainerListener accessibleContainerHandler;
232    
233        /**
234         * Receives notification if the focus on the JComponent changes and
235         * fires appropriate PropertyChangeEvents to listeners registered with
236         * the AccessibleJComponent.
237         *
238         * @specnote AccessibleAWTComponent has a protected field
239         *           accessibleAWTFocusHandler. Looks like a bug or nasty misdesign
240         *           to me.
241         */
242        protected FocusListener accessibleFocusHandler;
243    
244        /**
245         * Creates a new AccessibleJComponent.
246         */
247        protected AccessibleJComponent()
248        {
249          // Nothing to do here.
250        }
251    
252        /**
253         * Adds a property change listener to the list of registered listeners.
254         *
255         * This sets up the {@link #accessibleContainerHandler} and
256         * {@link #accessibleFocusHandler} fields and calls
257         * <code>super.addPropertyChangeListener(listener)</code>.
258         *
259         * @param listener the listener to add
260         */
261        public void addPropertyChangeListener(PropertyChangeListener listener)
262        {
263          // Tests seem to indicate that this method also sets up the other two
264          // handlers.
265          if (accessibleContainerHandler == null)
266            {
267              accessibleContainerHandler = new AccessibleContainerHandler();
268              addContainerListener(accessibleContainerHandler);
269            }
270          if (accessibleFocusHandler == null)
271            {
272              accessibleFocusHandler = new AccessibleFocusHandler();
273              addFocusListener(accessibleFocusHandler);
274            }
275          super.addPropertyChangeListener(listener);
276        }
277    
278        /**
279         * Removes a property change listener from the list of registered listeners.
280         *
281         * This uninstalls the {@link #accessibleContainerHandler} and
282         * {@link #accessibleFocusHandler} fields and calls
283         * <code>super.removePropertyChangeListener(listener)</code>.
284         *
285         * @param listener the listener to remove
286         */
287        public void removePropertyChangeListener(PropertyChangeListener listener)
288        {
289          // Tests seem to indicate that this method also resets the other two
290          // handlers.
291          if (accessibleContainerHandler != null)
292            {
293              removeContainerListener(accessibleContainerHandler);
294              accessibleContainerHandler = null;
295            }
296          if (accessibleFocusHandler != null)
297            {
298              removeFocusListener(accessibleFocusHandler);
299              accessibleFocusHandler = null;
300            }
301          super.removePropertyChangeListener(listener);
302        }
303    
304        /**
305         * Returns the number of accessible children of this object.
306         *
307         * @return  the number of accessible children of this object
308         */
309        public int getAccessibleChildrenCount()
310        {
311          // TODO: The functionality should be performed in the superclass.
312          // Find out why this is overridden. However, it is very well possible
313          // that this is left over from times when there was no such superclass
314          // method.
315          return super.getAccessibleChildrenCount();
316        }
317    
318        /**
319         * Returns the accessible child component at index <code>i</code>.
320         *
321         * @param i the index of the accessible child to return
322         *
323         * @return the accessible child component at index <code>i</code>
324         */
325        public Accessible getAccessibleChild(int i)
326        {
327          // TODO: The functionality should be performed in the superclass.
328          // Find out why this is overridden. However, it is very well possible
329          // that this is left over from times when there was no such superclass
330          // method.
331          return super.getAccessibleChild(i);
332        }
333    
334        /**
335         * Returns the accessible state set of this component.
336         *
337         * @return the accessible state set of this component
338         */
339        public AccessibleStateSet getAccessibleStateSet()
340        {
341          // Note: While the java.awt.Component has an 'opaque' property, it
342          // seems that it is not added to the accessible state set there, even
343          // if this property is true. However, it is handled for JComponent, so
344          // we add it here.
345          AccessibleStateSet state = super.getAccessibleStateSet();
346          if (isOpaque())
347            state.add(AccessibleState.OPAQUE);
348          return state;
349        }
350    
351        /**
352         * Returns the localized name for this object. Generally this should
353         * almost never return {@link Component#getName()} since that is not
354         * a localized name. If the object is some kind of text component (like
355         * a menu item), then the value of the object may be returned. Also, if
356         * the object has a tooltip, the value of the tooltip may also be
357         * appropriate.
358         *
359         * @return the localized name for this object or <code>null</code> if this
360         *         object has no name
361         */
362        public String getAccessibleName()
363        {
364          String name = super.getAccessibleName();
365    
366          // There are two fallbacks provided by the JComponent in the case the
367          // superclass returns null:
368          // - If the component is inside a titled border, then it inherits the
369          //   name from the border title.
370          // - If the component is not inside a titled border but has a label
371          //   (via JLabel.setLabelFor()), then it gets the name from the label's
372          //   accessible context.
373    
374          if (name == null)
375            {
376              name = getTitledBorderText();
377            }
378    
379          if (name == null)
380            {
381              Object l = getClientProperty(JLabel.LABEL_PROPERTY);
382              if (l instanceof Accessible)
383                {
384                  AccessibleContext labelCtx =
385                    ((Accessible) l).getAccessibleContext();
386                  name = labelCtx.getAccessibleName();
387                }
388            }
389    
390          return name;
391        }
392    
393        /**
394         * Returns the localized description of this object.
395         *
396         * @return the localized description of this object or <code>null</code>
397         *         if this object has no description
398         */
399        public String getAccessibleDescription()
400        {
401          // There are two fallbacks provided by the JComponent in the case the
402          // superclass returns null:
403          // - If the component has a tooltip, then inherit the description from
404          //   the tooltip.
405          // - If the component is not inside a titled border but has a label
406          //   (via JLabel.setLabelFor()), then it gets the name from the label's
407          //   accessible context.
408          String descr = super.getAccessibleDescription();
409    
410          if (descr == null)
411            {
412              descr = getToolTipText();
413            }
414    
415          if (descr == null)
416            {
417              Object l = getClientProperty(JLabel.LABEL_PROPERTY);
418              if (l instanceof Accessible)
419                {
420                  AccessibleContext labelCtx =
421                    ((Accessible) l).getAccessibleContext();
422                  descr = labelCtx.getAccessibleName();
423                }
424            }
425    
426          return descr;
427        }
428    
429        /**
430         * Returns the accessible role of this component.
431         *
432         * @return the accessible role of this component
433         *
434         * @see AccessibleRole
435         */
436        public AccessibleRole getAccessibleRole()
437        {
438          return AccessibleRole.SWING_COMPONENT;
439        }
440    
441        /**
442         * Recursivly searches a border hierarchy (starting at <code>border) for
443         * a titled border and returns the title if one is found, <code>null</code>
444         * otherwise.
445         *
446         * @param border the border to start search from
447         *
448         * @return the border title of a possibly found titled border
449         */
450        protected String getBorderTitle(Border border)
451        {
452          String title = null;
453          if (border instanceof CompoundBorder)
454            {
455              CompoundBorder compound = (CompoundBorder) border;
456              Border inner = compound.getInsideBorder();
457              title = getBorderTitle(inner);
458              if (title == null)
459                {
460                  Border outer = compound.getOutsideBorder();
461                  title = getBorderTitle(outer);
462                }
463            }
464          else if (border instanceof TitledBorder)
465            {
466              TitledBorder titled = (TitledBorder) border;
467              title = titled.getTitle(); 
468            }
469          return title;
470        }
471    
472        /**
473         * Returns the tooltip text for this accessible component.
474         *
475         * @return the tooltip text for this accessible component
476         */
477        public String getToolTipText()
478        {
479          return JComponent.this.getToolTipText();
480        }
481    
482        /**
483         * Returns the title of the border of this accessible component if
484         * this component has a titled border, otherwise returns <code>null</code>.
485         *
486         * @return the title of the border of this accessible component if
487         *         this component has a titled border, otherwise returns
488         *         <code>null</code>
489         */
490        public String getTitledBorderText()
491        {
492          return getBorderTitle(getBorder()); 
493        }
494    
495        /**
496         * Returns the keybindings associated with this accessible component or
497         * <code>null</code> if the component does not support key bindings.
498         *
499         * @return the keybindings associated with this accessible component
500         */
501        public AccessibleKeyBinding getAccessibleKeyBinding()
502        {
503          // The reference implementation seems to always return null here,
504          // independent of the key bindings of the JComponent. So do we.
505          return null;
506        }
507      }
508    
509      /**
510       * A value between 0.0 and 1.0 indicating the preferred horizontal
511       * alignment of the component, relative to its siblings. The values
512       * {@link #LEFT_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link
513       * #RIGHT_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>,
514       * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout
515       * managers use this property.
516       *
517       * @see #getAlignmentX
518       * @see #setAlignmentX
519       * @see javax.swing.OverlayLayout
520       * @see javax.swing.BoxLayout
521       */
522      float alignmentX = -1.0F;
523    
524      /**
525       * A value between 0.0 and 1.0 indicating the preferred vertical
526       * alignment of the component, relative to its siblings. The values
527       * {@link #TOP_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link
528       * #BOTTOM_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>,
529       * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout
530       * managers use this property.
531       *
532       * @see #getAlignmentY
533       * @see #setAlignmentY
534       * @see javax.swing.OverlayLayout
535       * @see javax.swing.BoxLayout
536       */
537      float alignmentY = -1.0F;
538    
539      /** 
540       * The border painted around this component.
541       * 
542       * @see #paintBorder
543       */
544      Border border;
545    
546      /**
547       * The popup menu for the component.
548       * 
549       * @see #getComponentPopupMenu()
550       * @see #setComponentPopupMenu(JPopupMenu)
551       */
552      JPopupMenu componentPopupMenu;
553       
554      /**
555       * A flag that controls whether the {@link #getComponentPopupMenu()} method
556       * looks to the component's parent when the <code>componentPopupMenu</code>
557       * field is <code>null</code>.
558       */
559      boolean inheritsPopupMenu;
560      
561      /** 
562       * <p>Whether to double buffer this component when painting. This flag
563       * should generally be <code>true</code>, to ensure good painting
564       * performance.</p>
565       *
566       * <p>All children of a double buffered component are painted into the
567       * double buffer automatically, so only the top widget in a window needs
568       * to be double buffered.</p>
569       *
570       * @see #setDoubleBuffered
571       * @see #isDoubleBuffered
572       * @see #paint
573       */
574      boolean doubleBuffered = true;
575    
576      /**
577       * A set of flags indicating which debugging graphics facilities should
578       * be enabled on this component. The values should be a combination of
579       * {@link DebugGraphics#NONE_OPTION}, {@link DebugGraphics#LOG_OPTION},
580       * {@link DebugGraphics#FLASH_OPTION}, or {@link
581       * DebugGraphics#BUFFERED_OPTION}.
582       *
583       * @see #setDebugGraphicsOptions
584       * @see #getDebugGraphicsOptions
585       * @see DebugGraphics
586       * @see #getComponentGraphics
587       */
588      int debugGraphicsOptions;
589    
590      /** 
591       * <p>This property controls two independent behaviors simultaneously.</p>
592       *
593       * <p>First, it controls whether to fill the background of this widget
594       * when painting its body. This affects calls to {@link
595       * JComponent#paintComponent}, which in turn calls {@link
596       * ComponentUI#update} on the component's {@link #ui} property. If the
597       * component is opaque during this call, the background will be filled
598       * before calling {@link ComponentUI#paint}. This happens merely as a
599       * convenience; you may fill the component's background yourself too,
600       * but there is no need to do so if you will be filling with the same
601       * color.</p>
602       *
603       * <p>Second, it the opaque property informs swing's repaint system
604       * whether it will be necessary to paint the components "underneath" this
605       * component, in Z-order. If the component is opaque, it is considered to
606       * completely occlude components "underneath" it, so they will not be
607       * repainted along with the opaque component.</p>
608       *
609       * <p>The default value for this property is <code>false</code>, but most
610       * components will want to set it to <code>true</code> when installing UI
611       * defaults in {@link ComponentUI#installUI}.</p>
612       *
613       * @see #setOpaque
614       * @see #isOpaque
615       * @see #paintComponent
616       */
617      boolean opaque = false;
618    
619      /** 
620       * The user interface delegate for this component. Event delivery and
621       * repainting of the component are usually delegated to this object. 
622       *
623       * @see #setUI
624       * @see #getUIClassID
625       * @see #updateUI
626       */
627      protected ComponentUI ui;
628    
629      /**
630       * A hint to the focus system that this component should or should not
631       * get focus. If this is <code>false</code>, swing will not try to
632       * request focus on this component; if <code>true</code>, swing might
633       * try to request focus, but the request might fail. Thus it is only 
634       * a hint guiding swing's behavior.
635       *
636       * @see #requestFocus()
637       * @see #isRequestFocusEnabled
638       * @see #setRequestFocusEnabled
639       */
640      boolean requestFocusEnabled;
641    
642      /**
643       * Flag indicating behavior of this component when the mouse is dragged
644       * outside the component and the mouse <em>stops moving</em>. If
645       * <code>true</code>, synthetic mouse events will be delivered on regular
646       * timed intervals, continuing off in the direction the mouse exited the
647       * component, until the mouse is released or re-enters the component.
648       *
649       * @see #setAutoscrolls
650       * @see #getAutoscrolls
651       */
652      boolean autoscrolls = false;
653    
654      /**
655       * Indicates whether the current paint call is already double buffered or
656       * not. 
657       */
658      static boolean paintingDoubleBuffered = false;
659    
660      /**
661       * Indicates whether we are calling paintDoubleBuffered() from
662       * paintImmadiately (RepaintManager) or from paint() (AWT refresh).
663       */
664      static boolean isRepainting = false;
665    
666      /**
667       * Listeners for events other than {@link PropertyChangeEvent} are
668       * handled by this listener list. PropertyChangeEvents are handled in
669       * {@link #changeSupport}.
670       */
671      protected EventListenerList listenerList = new EventListenerList();
672    
673      /**
674       * Handles VetoableChangeEvents.
675       */
676      private VetoableChangeSupport vetoableChangeSupport;
677    
678      /** 
679       * Storage for "client properties", which are key/value pairs associated
680       * with this component by a "client", such as a user application or a
681       * layout manager. This is lazily constructed when the component gets its
682       * first client property.
683       */
684      private Hashtable clientProperties;
685      
686      private InputMap inputMap_whenFocused;
687      private InputMap inputMap_whenAncestorOfFocused;
688      private ComponentInputMap inputMap_whenInFocusedWindow;
689      private ActionMap actionMap;
690      /** @since 1.3 */
691      private boolean verifyInputWhenFocusTarget = true;
692      private InputVerifier inputVerifier;
693    
694      private TransferHandler transferHandler;
695    
696      /**
697       * Indicates if this component is currently painting a tile or not.
698       */
699      private boolean paintingTile;
700    
701      /**
702       * A temporary buffer used for fast dragging of components.
703       */
704      private Image dragBuffer;
705    
706      /**
707       * Indicates if the dragBuffer is already initialized.
708       */
709      private boolean dragBufferInitialized;
710    
711      /**
712       * A cached Rectangle object to be reused. Be careful when you use that,
713       * so that it doesn't get modified in another context within the same
714       * method call chain.
715       */
716      private static transient Rectangle rectCache;
717    
718      /**
719       * The default locale of the component.
720       * 
721       * @see #getDefaultLocale
722       * @see #setDefaultLocale
723       */
724      private static Locale defaultLocale;
725      
726      public static final String TOOL_TIP_TEXT_KEY = "ToolTipText";
727    
728      /**
729       * Constant used to indicate that no condition has been assigned to a
730       * particular action.
731       *
732       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
733       */
734      public static final int UNDEFINED_CONDITION = -1;
735    
736      /**
737       * Constant used to indicate that an action should be performed only when 
738       * the component has focus.
739       *
740       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
741       */
742      public static final int WHEN_FOCUSED = 0;
743    
744      /**
745       * Constant used to indicate that an action should be performed only when 
746       * the component is an ancestor of the component which has focus.
747       *
748       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
749       */
750      public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;
751    
752      /**
753       * Constant used to indicate that an action should be performed only when 
754       * the component is in the window which has focus.
755       *
756       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
757       */
758      public static final int WHEN_IN_FOCUSED_WINDOW = 2;
759    
760    
761      /**
762       * Used to optimize painting. This is set in paintImmediately2() to specify
763       * the exact component path to be painted by paintChildren.
764       */
765      Component paintChild;
766    
767      /**
768       * Indicates if the opaque property has been set by a client program or by
769       * the UI.
770       *
771       * @see #setUIProperty(String, Object)
772       * @see LookAndFeel#installProperty(JComponent, String, Object)
773       */
774      private boolean clientOpaqueSet = false;
775    
776      /**
777       * Indicates if the autoscrolls property has been set by a client program or
778       * by the UI.
779       *
780       * @see #setUIProperty(String, Object)
781       * @see LookAndFeel#installProperty(JComponent, String, Object)
782       */
783      private boolean clientAutoscrollsSet = false;
784    
785      /**
786       * Creates a new <code>JComponent</code> instance.
787       */
788      public JComponent()
789      {
790        super();
791        setDropTarget(new DropTarget());
792        setLocale(getDefaultLocale());
793        debugGraphicsOptions = DebugGraphics.NONE_OPTION;
794        setRequestFocusEnabled(true);
795      }
796    
797      /**
798       * Helper to lazily construct and return the client properties table.
799       * 
800       * @return The current client properties table
801       *
802       * @see #clientProperties
803       * @see #getClientProperty
804       * @see #putClientProperty
805       */
806      private Hashtable getClientProperties()
807      {
808        if (clientProperties == null)
809          clientProperties = new Hashtable();
810        return clientProperties;
811      }
812    
813      /**
814       * Get a client property associated with this component and a particular
815       * key.
816       *
817       * @param key The key with which to look up the client property
818       *
819       * @return A client property associated with this object and key
820       *
821       * @see #clientProperties
822       * @see #getClientProperties
823       * @see #putClientProperty
824       */
825      public final Object getClientProperty(Object key)
826      {
827        return getClientProperties().get(key);
828      }
829    
830      /**
831       * Add a client property <code>value</code> to this component, associated
832       * with <code>key</code>. If there is an existing client property
833       * associated with <code>key</code>, it will be replaced.  A
834       * {@link PropertyChangeEvent} is sent to registered listeners (with the
835       * name of the property being <code>key.toString()</code>).
836       *
837       * @param key The key of the client property association to add
838       * @param value The value of the client property association to add
839       *
840       * @see #clientProperties
841       * @see #getClientProperties
842       * @see #getClientProperty
843       */
844      public final void putClientProperty(Object key, Object value)
845      {
846        Hashtable t = getClientProperties();
847        Object old = t.get(key);
848        if (value != null)
849          t.put(key, value);
850        else
851          t.remove(key);
852    
853        // When both old and new value are null, no event is fired. This is
854        // different from what firePropertyChange() normally does, so we add this
855        // check here.
856        if (old != null || value != null)
857          firePropertyChange(key.toString(), old, value);
858      }
859    
860      /**
861       * Unregister an <code>AncestorListener</code>.
862       *
863       * @param listener The listener to unregister
864       * 
865       * @see #addAncestorListener
866       */
867      public void removeAncestorListener(AncestorListener listener)
868      {
869        listenerList.remove(AncestorListener.class, listener);
870      }
871    
872      /**
873       * Unregister a <code>VetoableChangeChangeListener</code>.
874       *
875       * @param listener The listener to unregister
876       *
877       * @see #addVetoableChangeListener
878       */
879      public void removeVetoableChangeListener(VetoableChangeListener listener)
880      {
881        if (vetoableChangeSupport != null)
882          vetoableChangeSupport.removeVetoableChangeListener(listener);
883      }
884    
885      /**
886       * Register an <code>AncestorListener</code>.
887       *
888       * @param listener The listener to register
889       *
890       * @see #removeVetoableChangeListener
891       */
892      public void addAncestorListener(AncestorListener listener)
893      {
894        listenerList.add(AncestorListener.class, listener);
895      }
896    
897      /**
898       * Register a <code>VetoableChangeListener</code>.
899       *
900       * @param listener The listener to register
901       *
902       * @see #removeVetoableChangeListener
903       * @see #listenerList
904       */
905      public void addVetoableChangeListener(VetoableChangeListener listener)
906      {
907        // Lazily instantiate this, it's rarely needed.
908        if (vetoableChangeSupport == null)
909          vetoableChangeSupport = new VetoableChangeSupport(this);
910        vetoableChangeSupport.addVetoableChangeListener(listener);
911      }
912    
913      /**
914       * Returns all registered {@link EventListener}s of the given 
915       * <code>listenerType</code>.
916       *
917       * @param listenerType the class of listeners to filter (<code>null</code> 
918       *                     not permitted).
919       *                     
920       * @return An array of registered listeners.
921       * 
922       * @throws ClassCastException if <code>listenerType</code> does not implement
923       *                            the {@link EventListener} interface.
924       * @throws NullPointerException if <code>listenerType</code> is 
925       *                              <code>null</code>.
926       *                            
927       * @see #getAncestorListeners()
928       * @see #listenerList
929       * 
930       * @since 1.3
931       */
932      public <T extends EventListener> T[] getListeners(Class<T> listenerType)
933      {
934        if (listenerType == PropertyChangeListener.class)
935          return (T[]) getPropertyChangeListeners();
936        else if (listenerType == VetoableChangeListener.class)
937          return (T[]) getVetoableChangeListeners();
938        else
939          return listenerList.getListeners(listenerType);
940      }
941    
942      /**
943       * Return all registered <code>AncestorListener</code> objects.
944       *
945       * @return The set of <code>AncestorListener</code> objects in {@link
946       * #listenerList}
947       */
948      public AncestorListener[] getAncestorListeners()
949      {
950        return (AncestorListener[]) getListeners(AncestorListener.class);
951      }
952    
953      /**
954       * Return all registered <code>VetoableChangeListener</code> objects.
955       *
956       * @return An array of the <code>VetoableChangeListener</code> objects 
957       *     registered with this component (possibly empty but never 
958       *     <code>null</code>).
959       * 
960       * @since 1.4
961       */
962      public VetoableChangeListener[] getVetoableChangeListeners()
963      {    
964        return vetoableChangeSupport == null ? new VetoableChangeListener[0]
965            : vetoableChangeSupport.getVetoableChangeListeners();
966      }
967    
968      /**
969       * Call {@link VetoableChangeListener#vetoableChange} on all listeners
970       * registered to listen to a given property. Any method which changes
971       * the specified property of this component should call this method.
972       *
973       * @param propertyName The property which changed
974       * @param oldValue The old value of the property
975       * @param newValue The new value of the property
976       *
977       * @throws PropertyVetoException if the change was vetoed by a listener
978       *
979       * @see #addVetoableChangeListener
980       * @see #removeVetoableChangeListener
981       */
982      protected void fireVetoableChange(String propertyName, Object oldValue,
983                                        Object newValue)
984        throws PropertyVetoException
985      {
986        if (vetoableChangeSupport != null)
987          vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue);
988      }
989    
990    
991      /**
992       * Fires a property change for a primitive integer property.
993       *
994       * @param property the name of the property
995       * @param oldValue the old value of the property
996       * @param newValue the new value of the property
997       *
998       * @specnote This method is implemented in
999       *           {@link Component#firePropertyChange(String, int, int)}. It is
1000       *           only here because it is specified to be public, whereas the
1001       *           Component method is protected.
1002       */
1003      public void firePropertyChange(String property, int oldValue, int newValue)
1004      {
1005        super.firePropertyChange(property, oldValue, newValue);
1006      }
1007      
1008      /**
1009       * Fires a property change for a primitive boolean property.
1010       *
1011       * @param property the name of the property
1012       * @param oldValue the old value of the property
1013       * @param newValue the new value of the property
1014       *
1015       * @specnote This method is implemented in
1016       *           {@link Component#firePropertyChange(String, boolean, boolean)}.
1017       *           It is only here because it is specified to be public, whereas
1018       *           the Component method is protected.
1019       */
1020      public void firePropertyChange(String property, boolean oldValue,
1021                                     boolean newValue)
1022      {
1023        super.firePropertyChange(property, oldValue, newValue);
1024      }
1025    
1026      /**
1027       * Get the value of the accessibleContext property for this component.
1028       *
1029       * @return the current value of the property
1030       */
1031      public AccessibleContext getAccessibleContext()
1032      {
1033        return null;
1034      }
1035    
1036      /**
1037       * Get the value of the {@link #alignmentX} property.
1038       *
1039       * @return The current value of the property.
1040       *
1041       * @see #setAlignmentX
1042       * @see #alignmentY
1043       */
1044      public float getAlignmentX()
1045      {
1046        float ret = alignmentX;
1047        if (alignmentX < 0)
1048          // alignment has not been set explicitly.
1049          ret = super.getAlignmentX();
1050    
1051        return ret;
1052      }
1053    
1054      /**
1055       * Get the value of the {@link #alignmentY} property.
1056       *
1057       * @return The current value of the property.
1058       *
1059       * @see #setAlignmentY
1060       * @see #alignmentX
1061       */
1062      public float getAlignmentY()
1063      {
1064        float ret = alignmentY;
1065        if (alignmentY < 0)
1066          // alignment has not been set explicitly.
1067          ret = super.getAlignmentY();
1068    
1069        return ret;
1070      }
1071    
1072      /**
1073       * Get the current value of the {@link #autoscrolls} property.
1074       *
1075       * @return The current value of the property
1076       */
1077      public boolean getAutoscrolls()
1078      {
1079        return autoscrolls;
1080      }
1081    
1082      /**
1083       * Set the value of the {@link #border} property.
1084       *   
1085       * @param newBorder The new value of the property
1086       *
1087       * @see #getBorder
1088       */
1089      public void setBorder(Border newBorder)
1090      {
1091        Border oldBorder = getBorder();
1092        if (oldBorder == newBorder)
1093          return;
1094    
1095        border = newBorder;
1096        firePropertyChange("border", oldBorder, newBorder);
1097        repaint();
1098      }
1099    
1100      /**
1101       * Get the value of the {@link #border} property.
1102       *
1103       * @return The property's current value
1104       *
1105       * @see #setBorder
1106       */
1107      public Border getBorder()
1108      {
1109        return border;
1110      }
1111    
1112      /**
1113       * Get the component's current bounding box. If a rectangle is provided,
1114       * use this as the return value (adjusting its fields in place);
1115       * otherwise (of <code>null</code> is provided) return a new {@link
1116       * Rectangle}.
1117       *
1118       * @param rv Optional return value to use
1119       *
1120       * @return A rectangle bounding the component
1121       */
1122      public Rectangle getBounds(Rectangle rv)
1123      {
1124        if (rv == null)
1125          return new Rectangle(getX(), getY(), getWidth(), getHeight());
1126        else
1127          {
1128            rv.setBounds(getX(), getY(), getWidth(), getHeight());
1129            return rv;
1130          }
1131      }
1132    
1133      /**
1134       * Prepares a graphics context for painting this object. If {@link
1135       * #debugGraphicsOptions} is not equal to {@link
1136       * DebugGraphics#NONE_OPTION}, produce a new {@link DebugGraphics} object
1137       * wrapping the parameter. Otherwise configure the parameter with this
1138       * component's foreground color and font.
1139       *
1140       * @param g The graphics context to wrap or configure
1141       *
1142       * @return A graphics context to paint this object with
1143       *
1144       * @see #debugGraphicsOptions
1145       * @see #paint
1146       */
1147      protected Graphics getComponentGraphics(Graphics g)
1148      {
1149        Graphics g2 = g;
1150        int options = getDebugGraphicsOptions();
1151        if (options != DebugGraphics.NONE_OPTION)
1152          {
1153            if (!(g2 instanceof DebugGraphics))
1154              g2 = new DebugGraphics(g);
1155            DebugGraphics dg = (DebugGraphics) g2;
1156            dg.setDebugOptions(dg.getDebugOptions() | options);
1157          }
1158        g2.setFont(this.getFont());
1159        g2.setColor(this.getForeground());
1160        return g2;
1161      }
1162    
1163      /**
1164       * Get the value of the {@link #debugGraphicsOptions} property.
1165       *
1166       * @return The current value of the property.
1167       *
1168       * @see #setDebugGraphicsOptions
1169       * @see #debugGraphicsOptions
1170       */
1171      public int getDebugGraphicsOptions()
1172      {
1173        String option = System.getProperty("gnu.javax.swing.DebugGraphics");
1174        int options = debugGraphicsOptions;
1175        if (option != null && option.length() != 0)
1176          {
1177            if (options < 0)
1178              options = 0;
1179    
1180            if (option.equals("LOG"))
1181              options |= DebugGraphics.LOG_OPTION;
1182            else if (option.equals("FLASH"))
1183              options |= DebugGraphics.FLASH_OPTION;
1184          }
1185        return options;
1186      }
1187    
1188      /**
1189       * Get the component's insets, which are calculated from
1190       * the {@link #border} property. If the border is <code>null</code>,
1191       * calls {@link Container#getInsets}.
1192       *
1193       * @return The component's current insets
1194       */
1195      public Insets getInsets()
1196      {
1197        if (border == null)
1198          return super.getInsets();
1199        return getBorder().getBorderInsets(this);
1200      }
1201    
1202      /**
1203       * Get the component's insets, which are calculated from the {@link
1204       * #border} property. If the border is <code>null</code>, calls {@link
1205       * Container#getInsets}. The passed-in {@link Insets} value will be
1206       * used as the return value, if possible.
1207       *
1208       * @param insets Return value object to reuse, if possible
1209       *
1210       * @return The component's current insets
1211       */
1212      public Insets getInsets(Insets insets)
1213      {
1214        Insets t = getInsets();
1215    
1216        if (insets == null)
1217          return t;
1218    
1219        insets.left = t.left;
1220        insets.right = t.right;
1221        insets.top = t.top;
1222        insets.bottom = t.bottom;
1223        return insets;
1224      }
1225    
1226      /**
1227       * Get the component's location. The passed-in {@link Point} value
1228       * will be used as the return value, if possible.
1229       *
1230       * @param rv Return value object to reuse, if possible
1231       *
1232       * @return The component's current location
1233       */
1234      public Point getLocation(Point rv)
1235      {
1236        if (rv == null)
1237          return new Point(getX(), getY());
1238    
1239        rv.setLocation(getX(), getY());
1240        return rv;
1241      }
1242    
1243      /**
1244       * Get the component's maximum size. If the <code>maximumSize</code> property
1245       * has been explicitly set, it is returned. If the <code>maximumSize</code>
1246       * property has not been set but the {@link #ui} property has been, the
1247       * result of {@link ComponentUI#getMaximumSize} is returned. If neither
1248       * property has been set, the result of {@link Container#getMaximumSize}
1249       * is returned.
1250       *
1251       * @return the maximum size of the component
1252       *
1253       * @see Component#setMaximumSize
1254       * @see Component#getMaximumSize()
1255       * @see Component#isMaximumSizeSet()
1256       * @see ComponentUI#getMaximumSize(JComponent)
1257       */
1258      public Dimension getMaximumSize()
1259      {
1260        Dimension size = null; 
1261        if (isMaximumSizeSet())
1262          size = super.getMaximumSize();
1263        else
1264          {
1265            if (ui != null)
1266              size = ui.getMaximumSize(this);
1267            if (size == null)
1268              size = super.getMaximumSize();
1269          }
1270        return size;
1271      }
1272    
1273      /**
1274       * Get the component's minimum size. If the <code>minimumSize</code> property
1275       * has been explicitly set, it is returned. If the <code>minimumSize</code>
1276       * property has not been set but the {@link #ui} property has been, the
1277       * result of {@link ComponentUI#getMinimumSize} is returned. If neither
1278       * property has been set, the result of {@link Container#getMinimumSize}
1279       * is returned.
1280       *
1281       * @return The minimum size of the component
1282       *
1283       * @see Component#setMinimumSize
1284       * @see Component#getMinimumSize()
1285       * @see Component#isMinimumSizeSet()
1286       * @see ComponentUI#getMinimumSize(JComponent)
1287       */
1288      public Dimension getMinimumSize()
1289      {
1290        Dimension size = null; 
1291        if (isMinimumSizeSet())
1292          size = super.getMinimumSize();
1293        else
1294          {
1295            if (ui != null)
1296              size = ui.getMinimumSize(this);
1297            if (size == null)
1298              size = super.getMinimumSize();
1299          }
1300        return size;
1301      }
1302    
1303      /**
1304       * Get the component's preferred size. If the <code>preferredSize</code>
1305       * property has been explicitly set, it is returned. If the
1306       * <code>preferredSize</code> property has not been set but the {@link #ui}
1307       * property has been, the result of {@link ComponentUI#getPreferredSize} is
1308       * returned. If neither property has been set, the result of {@link
1309       * Container#getPreferredSize} is returned.
1310       *
1311       * @return The preferred size of the component
1312       *
1313       * @see Component#setPreferredSize
1314       * @see Component#getPreferredSize()
1315       * @see Component#isPreferredSizeSet()
1316       * @see ComponentUI#getPreferredSize(JComponent)
1317       */
1318      public Dimension getPreferredSize()
1319      {
1320        Dimension size = null; 
1321        if (isPreferredSizeSet())
1322          size = super.getPreferredSize();
1323        else
1324          {
1325            if (ui != null)
1326              size = ui.getPreferredSize(this);
1327            if (size == null)
1328              size = super.getPreferredSize();
1329          }
1330        return size;
1331      }
1332    
1333      /**
1334       * Return the value of the <code>nextFocusableComponent</code> property.
1335       *
1336       * @return The current value of the property, or <code>null</code>
1337       * if none has been set.
1338       * 
1339       * @deprecated See {@link java.awt.FocusTraversalPolicy}
1340       */
1341      public Component getNextFocusableComponent()
1342      {
1343        Container focusRoot = this;
1344        if (! this.isFocusCycleRoot())
1345          focusRoot = getFocusCycleRootAncestor();
1346    
1347        FocusTraversalPolicy policy  = focusRoot.getFocusTraversalPolicy();
1348        return policy.getComponentAfter(focusRoot, this);
1349      }
1350    
1351      /**
1352       * Return the set of {@link KeyStroke} objects which are registered
1353       * to initiate actions on this component.
1354       *
1355       * @return An array of the registered keystrokes (possibly empty but never
1356       *     <code>null</code>).
1357       */
1358      public KeyStroke[] getRegisteredKeyStrokes()
1359      {
1360        KeyStroke[] ks0;
1361        KeyStroke[] ks1;
1362        KeyStroke[] ks2;
1363        if (inputMap_whenFocused != null)
1364          ks0 = inputMap_whenFocused.keys();
1365        else 
1366          ks0 = new KeyStroke[0];
1367        if (inputMap_whenAncestorOfFocused != null)
1368          ks1 = inputMap_whenAncestorOfFocused.keys();
1369        else 
1370          ks1 = new KeyStroke[0];
1371        if (inputMap_whenInFocusedWindow != null)
1372          ks2 = inputMap_whenInFocusedWindow.keys();
1373        else
1374          ks2 = new KeyStroke[0];
1375        int count = ks0.length + ks1.length + ks2.length;
1376        KeyStroke[] result = new KeyStroke[count];
1377        System.arraycopy(ks0, 0, result, 0, ks0.length);
1378        System.arraycopy(ks1, 0, result, ks0.length, ks1.length);
1379        System.arraycopy(ks2, 0, result, ks0.length + ks1.length, ks2.length);
1380        return result;
1381      }
1382    
1383      /**
1384       * Returns the first ancestor of this component which is a {@link JRootPane}.
1385       * Equivalent to calling <code>SwingUtilities.getRootPane(this);</code>.
1386       *
1387       * @return An ancestral JRootPane, or <code>null</code> if none exists.
1388       */
1389      public JRootPane getRootPane()
1390      {
1391        JRootPane p = SwingUtilities.getRootPane(this);
1392        return p;
1393      }
1394    
1395      /**
1396       * Get the component's size. The passed-in {@link Dimension} value
1397       * will be used as the return value, if possible.
1398       *
1399       * @param rv Return value object to reuse, if possible
1400       *
1401       * @return The component's current size
1402       */
1403      public Dimension getSize(Dimension rv)
1404      {
1405        if (rv == null)
1406          return new Dimension(getWidth(), getHeight());
1407        else
1408          {
1409            rv.setSize(getWidth(), getHeight());
1410            return rv;
1411          }
1412      }
1413    
1414      /**
1415       * Return the <code>toolTip</code> property of this component, creating it and
1416       * setting it if it is currently <code>null</code>. This method can be
1417       * overridden in subclasses which wish to control the exact form of
1418       * tooltip created.
1419       *
1420       * @return The current toolTip
1421       */
1422      public JToolTip createToolTip()
1423      {
1424        JToolTip toolTip = new JToolTip();
1425        toolTip.setComponent(this);
1426        return toolTip;
1427      }
1428    
1429      /**
1430       * Return the location at which the <code>toolTipText</code> property should
1431       * be displayed, when triggered by a particular mouse event. 
1432       *
1433       * @param event The event the tooltip is being presented in response to
1434       *
1435       * @return The point at which to display a tooltip, or <code>null</code>
1436       *     if swing is to choose a default location.
1437       */
1438      public Point getToolTipLocation(MouseEvent event)
1439      {
1440        return null;
1441      }
1442    
1443      /**
1444       * Set the tooltip text for this component. If a non-<code>null</code>
1445       * value is set, this component is registered in the
1446       * <code>ToolTipManager</code> in order to turn on tooltips for this
1447       * component. If a <code>null</code> value is set, tooltips are turne off
1448       * for this component.
1449       *
1450       * @param text the tooltip text for this component
1451       *
1452       * @see #getToolTipText()
1453       * @see #getToolTipText(MouseEvent)
1454       */
1455      public void setToolTipText(String text)
1456      {
1457        String old = getToolTipText();
1458        putClientProperty(TOOL_TIP_TEXT_KEY, text);
1459        ToolTipManager ttm = ToolTipManager.sharedInstance();
1460        if (text == null)
1461          ttm.unregisterComponent(this);
1462        else if (old == null)
1463          ttm.registerComponent(this);
1464      }
1465    
1466      /**
1467       * Returns the current tooltip text for this component, or <code>null</code>
1468       * if none has been set.
1469       *
1470       * @return the current tooltip text for this component, or <code>null</code>
1471       *         if none has been set
1472       *
1473       * @see #setToolTipText
1474       * @see #getToolTipText(MouseEvent)
1475       */
1476      public String getToolTipText()
1477      {
1478        return (String) getClientProperty(TOOL_TIP_TEXT_KEY);
1479      }
1480    
1481      /**
1482       * Returns the tooltip text for this component for a particular mouse
1483       * event. This can be used to support context sensitive tooltips that can
1484       * change with the mouse location. By default this returns the static
1485       * tooltip text returned by {@link #getToolTipText()}.
1486       *
1487       * @param event the mouse event which triggered the tooltip
1488       *
1489       * @return the tooltip text for this component for a particular mouse
1490       *         event
1491       *
1492       * @see #setToolTipText
1493       * @see #getToolTipText()
1494       */
1495      public String getToolTipText(MouseEvent event)
1496      {
1497        return getToolTipText();
1498      }
1499      
1500      /**
1501       * Returns the flag that controls whether or not the component inherits its
1502       * parent's popup menu when no popup menu is specified for this component.
1503       * 
1504       * @return A boolean.
1505       * 
1506       * @since 1.5
1507       * 
1508       * @see #setInheritsPopupMenu(boolean)
1509       */
1510      public boolean getInheritsPopupMenu()
1511      {
1512        return inheritsPopupMenu; 
1513      }
1514      
1515      /**
1516       * Sets the flag that controls whether or not the component inherits its
1517       * parent's popup menu when no popup menu is specified for this component.
1518       * This is a bound property with the property name 'inheritsPopupMenu'.
1519       * 
1520       * @param inherit  the new flag value.
1521       * 
1522       * @since 1.5
1523       * 
1524       * @see #getInheritsPopupMenu()
1525       */
1526      public void setInheritsPopupMenu(boolean inherit)
1527      {
1528        if (inheritsPopupMenu != inherit)
1529          {
1530            inheritsPopupMenu = inherit;
1531            this.firePropertyChange("inheritsPopupMenu", ! inherit, inherit);
1532          }
1533      }
1534      
1535      /**
1536       * Returns the popup menu for this component.  If the popup menu is 
1537       * <code>null</code> AND the {@link #getInheritsPopupMenu()} method returns
1538       * <code>true</code>, this method will return the parent's popup menu (if it
1539       * has one).
1540       * 
1541       * @return The popup menu (possibly <code>null</code>.
1542       * 
1543       * @since 1.5
1544       * 
1545       * @see #setComponentPopupMenu(JPopupMenu)
1546       * @see #getInheritsPopupMenu()
1547       */
1548      public JPopupMenu getComponentPopupMenu()
1549      {
1550        if (componentPopupMenu == null && getInheritsPopupMenu())
1551          {
1552            Container parent = getParent(); 
1553            if (parent instanceof JComponent)
1554              return ((JComponent) parent).getComponentPopupMenu();
1555            else
1556              return null;
1557          }
1558        else
1559          return componentPopupMenu;
1560      }
1561    
1562      /**
1563       * Sets the popup menu for this component (this is a bound property with 
1564       * the property name 'componentPopupMenu').
1565       * 
1566       * @param popup  the popup menu (<code>null</code> permitted).
1567       *
1568       * @since 1.5
1569       * 
1570       * @see #getComponentPopupMenu()
1571       */
1572      public void setComponentPopupMenu(JPopupMenu popup)
1573      {
1574        if (componentPopupMenu != popup)
1575          {
1576            JPopupMenu old = componentPopupMenu;
1577            componentPopupMenu = popup;
1578            firePropertyChange("componentPopupMenu", old, popup);
1579          }
1580      }
1581      
1582      /**
1583       * Return the top level ancestral container (usually a {@link
1584       * java.awt.Window} or {@link java.applet.Applet}) which this component is
1585       * contained within, or <code>null</code> if no ancestors exist.
1586       *
1587       * @return The top level container, if it exists
1588       */
1589      public Container getTopLevelAncestor()
1590      {
1591        Container c = getParent();
1592        for (Container peek = c; peek != null; peek = peek.getParent())
1593          c = peek;
1594        return c;
1595      }
1596    
1597      /**
1598       * Compute the component's visible rectangle, which is defined
1599       * recursively as either the component's bounds, if it has no parent, or
1600       * the intersection of the component's bounds with the visible rectangle
1601       * of its parent.
1602       *
1603       * @param rect The return value slot to place the visible rectangle in
1604       */
1605      public void computeVisibleRect(Rectangle rect)
1606      {
1607        Component c = getParent();
1608        if (c != null && c instanceof JComponent)
1609          {
1610            ((JComponent) c).computeVisibleRect(rect);
1611            rect.translate(-getX(), -getY());
1612            rect = SwingUtilities.computeIntersection(0, 0, getWidth(),
1613                                                      getHeight(), rect);
1614          }
1615        else
1616          rect.setRect(0, 0, getWidth(), getHeight());
1617      }
1618    
1619      /**
1620       * Return the component's visible rectangle in a new {@link Rectangle},
1621       * rather than via a return slot.
1622       *
1623       * @return the component's visible rectangle
1624       *
1625       * @see #computeVisibleRect(Rectangle)
1626       */
1627      public Rectangle getVisibleRect()
1628      {
1629        Rectangle r = new Rectangle();
1630        computeVisibleRect(r);
1631        return r;
1632      }
1633    
1634      /**
1635       * <p>Requests that this component receive input focus, giving window
1636       * focus to the top level ancestor of this component. Only works on
1637       * displayable, focusable, visible components.</p>
1638       *
1639       * <p>This method should not be called by clients; it is intended for
1640       * focus implementations. Use {@link Component#requestFocus()} instead.</p>
1641       *
1642       * @see Component#requestFocus()
1643       */
1644      public void grabFocus()
1645      {
1646        requestFocus();
1647      }
1648    
1649      /**
1650       * Get the value of the {@link #doubleBuffered} property.
1651       *
1652       * @return The property's current value
1653       */
1654      public boolean isDoubleBuffered()
1655      {
1656        return doubleBuffered;
1657      }
1658    
1659      /**
1660       * Return <code>true</code> if the provided component has no native peer;
1661       * in other words, if it is a "lightweight component".
1662       *
1663       * @param c The component to test for lightweight-ness
1664       *
1665       * @return Whether or not the component is lightweight
1666       */
1667      public static boolean isLightweightComponent(Component c)
1668      {
1669        return c.getPeer() instanceof LightweightPeer;
1670      }
1671    
1672      /**
1673       * Return <code>true</code> if you wish this component to manage its own
1674       * focus. In particular: if you want this component to be sent
1675       * <code>TAB</code> and <code>SHIFT+TAB</code> key events, and to not
1676       * have its children considered as focus transfer targets. If
1677       * <code>true</code>, focus traversal around this component changes to
1678       * <code>CTRL+TAB</code> and <code>CTRL+SHIFT+TAB</code>.
1679       *
1680       * @return <code>true</code> if you want this component to manage its own
1681       *     focus, otherwise (by default) <code>false</code>
1682       *
1683       * @deprecated 1.4 Use {@link Component#setFocusTraversalKeys(int, Set)} and
1684       *     {@link Container#setFocusCycleRoot(boolean)} instead
1685       */
1686      public boolean isManagingFocus()
1687      {
1688        return false;
1689      }
1690    
1691      /**
1692       * Return the current value of the {@link #opaque} property. 
1693       *
1694       * @return The current property value
1695       */
1696      public boolean isOpaque()
1697      {
1698        return opaque;
1699      }
1700    
1701      /**
1702       * Return <code>true</code> if the component can guarantee that none of its
1703       * children will overlap in Z-order. This is a hint to the painting system.
1704       * The default is to return <code>true</code>, but some components such as
1705       * {@link JLayeredPane} should override this to return <code>false</code>.
1706       *
1707       * @return Whether the component tiles its children
1708       */
1709      public boolean isOptimizedDrawingEnabled()
1710      {
1711        return true;
1712      }
1713    
1714      /**
1715       * Return <code>true</code> if this component is currently painting a tile,
1716       * this means that paint() is called again on another child component. This
1717       * method returns <code>false</code> if this component does not paint a tile
1718       * or if the last tile is currently painted.
1719       *
1720       * @return whether the component is painting a tile
1721       */
1722      public boolean isPaintingTile()
1723      {
1724        return paintingTile;
1725      }
1726    
1727      /**
1728       * Get the value of the {@link #requestFocusEnabled} property.
1729       *
1730       * @return The current value of the property
1731       */
1732      public boolean isRequestFocusEnabled()
1733      {
1734        return requestFocusEnabled;
1735      }
1736    
1737      /**
1738       * Return <code>true</code> if this component is a validation root; this
1739       * will cause calls to {@link #invalidate()} in this component's children
1740       * to be "captured" at this component, and not propagate to its parents.
1741       * For most components this should return <code>false</code>, but some
1742       * components such as {@link JViewport} will want to return
1743       * <code>true</code>.
1744       *
1745       * @return Whether this component is a validation root
1746       */
1747      public boolean isValidateRoot()
1748      {
1749        return false;
1750      }
1751    
1752      /**
1753       * <p>Paint the component. This is a delicate process, and should only be
1754       * called from the repaint thread, under control of the {@link
1755       * RepaintManager}. Client code should usually call {@link #repaint()} to
1756       * trigger painting.</p>
1757       *
1758       * <p>The body of the <code>paint</code> call involves calling {@link
1759       * #paintComponent}, {@link #paintBorder}, and {@link #paintChildren} in
1760       * order. If you want to customize painting behavior, you should override
1761       * one of these methods rather than <code>paint</code>.</p>
1762       *
1763       * <p>For more details on the painting sequence, see <a
1764       * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">
1765       * this article</a>.</p>
1766       *
1767       * @param g The graphics context to paint with
1768       *
1769       * @see #paintImmediately(Rectangle)
1770       */
1771      public void paint(Graphics g)
1772      {
1773        RepaintManager rm = RepaintManager.currentManager(this);
1774        // We do a little stunt act here to switch on double buffering if it's
1775        // not already on. If we are not already doublebuffered, then we jump
1776        // into the method paintDoubleBuffered, which turns on the double buffer
1777        // and then calls paint(g) again. In the second call we go into the else
1778        // branch of this if statement and actually paint things to the double
1779        // buffer. When this method completes, the call stack unwinds back to
1780        // paintDoubleBuffered, where the buffer contents is finally drawn to the
1781        // screen.
1782        if (!paintingDoubleBuffered && isDoubleBuffered()
1783            && rm.isDoubleBufferingEnabled())
1784          {
1785            Rectangle clip = g.getClipBounds();
1786            paintDoubleBuffered(clip.x, clip.y, clip.width, clip.height);
1787          }
1788        else
1789          {
1790            if (getClientProperty("bufferedDragging") != null
1791                && dragBuffer == null)
1792              {
1793                initializeDragBuffer();
1794              }
1795            else if (getClientProperty("bufferedDragging") == null
1796                && dragBuffer != null)
1797              {
1798                dragBuffer = null;
1799              }
1800    
1801            Rectangle clip = g.getClipBounds();
1802            int clipX, clipY, clipW, clipH;
1803            if (clip == null)
1804              {
1805                clipX = 0;
1806                clipY = 0;
1807                clipW = getWidth();
1808                clipH = getHeight();
1809              }
1810            else
1811              {
1812                clipX = clip.x;
1813                clipY = clip.y;
1814                clipW = clip.width;
1815                clipH = clip.height;
1816              }
1817            if (dragBuffer != null && dragBufferInitialized)
1818              {
1819                g.drawImage(dragBuffer, 0, 0, this);
1820              }
1821            else
1822              {
1823                Graphics g2 = getComponentGraphics(g);
1824                if (! isOccupiedByChild(clipX, clipY, clipW, clipH))
1825                  {
1826                    paintComponent(g2);
1827                    paintBorder(g2);
1828                  }
1829                paintChildren(g2);
1830              }
1831          }
1832      }
1833    
1834      /**
1835       * Determines if a region of this component is completely occupied by
1836       * an opaque child component, in which case we don't need to bother
1837       * painting this component at all.
1838       *
1839       * @param x the area, x coordinate
1840       * @param y the area, y coordinate
1841       * @param w the area, width
1842       * @param h the area, height
1843       *
1844       * @return <code>true</code> if the specified area is completely covered
1845       *         by a child component, <code>false</code> otherwise
1846       */
1847      private boolean isOccupiedByChild(int x, int y, int w, int h)
1848      {
1849        boolean occupied = false;
1850        int count = getComponentCount();
1851        for (int i = 0; i < count; i++)
1852          {
1853            Component child = getComponent(i);
1854            int cx = child.getX();
1855            int cy = child.getY();
1856            int cw = child.getWidth();
1857            int ch = child.getHeight();
1858            if (child.isVisible() && x >= cx && x + w <= cx + cw && y >= cy
1859                && y + h <= cy + ch)
1860              {
1861                occupied = child.isOpaque();
1862                break;
1863              }
1864          }
1865        return occupied;
1866      }
1867    
1868      /**
1869       * Initializes the drag buffer by creating a new image and painting this
1870       * component into it.
1871       */
1872      private void initializeDragBuffer()
1873      {
1874        dragBufferInitialized = false;
1875        // Allocate new dragBuffer if the current one is too small.
1876        if (dragBuffer == null || dragBuffer.getWidth(this) < getWidth()
1877            || dragBuffer.getHeight(this) < getHeight())
1878          {
1879            dragBuffer = createImage(getWidth(), getHeight());
1880          }
1881        Graphics g = dragBuffer.getGraphics();
1882        paint(g);
1883        g.dispose();
1884        dragBufferInitialized = true;
1885      }
1886    
1887      /**
1888       * Paint the component's border. This usually means calling {@link
1889       * Border#paintBorder} on the {@link #border} property, if it is
1890       * non-<code>null</code>. You may override this if you wish to customize
1891       * border painting behavior. The border is painted after the component's
1892       * body, but before the component's children.
1893       *
1894       * @param g The graphics context with which to paint the border
1895       *
1896       * @see #paint
1897       * @see #paintChildren
1898       * @see #paintComponent
1899       */
1900      protected void paintBorder(Graphics g)
1901      {
1902        if (getBorder() != null)
1903          getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
1904      }
1905    
1906      /**
1907       * Paint the component's children. This usually means calling {@link
1908       * Container#paint}, which recursively calls {@link #paint} on any of the
1909       * component's children, with appropriate changes to coordinate space and
1910       * clipping region. You may override this if you wish to customize
1911       * children painting behavior. The children are painted after the
1912       * component's body and border.
1913       *
1914       * @param g The graphics context with which to paint the children
1915       *
1916       * @see #paint
1917       * @see #paintBorder
1918       * @see #paintComponent
1919       */
1920      protected void paintChildren(Graphics g)
1921      {
1922        if (getComponentCount() > 0)
1923          {
1924            // Need to lock the tree to avoid problems with AWT and concurrency.
1925            synchronized (getTreeLock())
1926              {
1927                // Fast forward to the child to paint, if set by
1928                // paintImmediately2()
1929                int i = getComponentCount() - 1;
1930                if (paintChild != null && paintChild.isOpaque())
1931                  {
1932                    for (; i >= 0 && getComponent(i) != paintChild; i--)
1933                      ;
1934                  }
1935                for (; i >= 0; i--)
1936                  {
1937                    Component child = getComponent(i);
1938                    if (child != null && child.isLightweight()
1939                        && child.isVisible())
1940                      {
1941                        int cx = child.getX();
1942                        int cy = child.getY();
1943                        int cw = child.getWidth();
1944                        int ch = child.getHeight();
1945                        if (g.hitClip(cx, cy, cw, ch))
1946                          {
1947                            if ((! isOptimizedDrawingEnabled()) && i > 0)
1948                              {
1949                                // Check if the child is completely obscured.
1950                                Rectangle clip = g.getClipBounds(); // A copy.
1951                                SwingUtilities.computeIntersection(cx, cy, cw, ch,
1952                                                                   clip);
1953                                if (isCompletelyObscured(i, clip.x, clip.y,
1954                                                         clip.width, clip.height))
1955                                  continue; // Continues the for-loop.
1956                              }
1957                            Graphics cg = g.create(cx, cy, cw, ch);
1958                            cg.setColor(child.getForeground());
1959                            cg.setFont(child.getFont());
1960                            try
1961                              {
1962                                child.paint(cg);
1963                              }
1964                            finally
1965                              {
1966                                cg.dispose();
1967                              }
1968                          }
1969                      }
1970                  }
1971              }
1972          }
1973      }
1974    
1975      /**
1976       * Determines if a region of a child component is completely obscured by one
1977       * of its siblings.
1978       *
1979       * @param index the index of the child component
1980       * @param x the region to check, x coordinate
1981       * @param y the region to check, y coordinate
1982       * @param w the region to check, width
1983       * @param h the region to check, height
1984       *
1985       * @return <code>true</code> if the region is completely obscured by a
1986       *         sibling, <code>false</code> otherwise
1987       */
1988      private boolean isCompletelyObscured(int index, int x, int y, int w, int h)
1989      {
1990        boolean obscured = false;
1991        for (int i = index - 1; i >= 0 && obscured == false; i--)
1992          {
1993            Component sib = getComponent(i);
1994            if (sib.isVisible())
1995              {
1996                Rectangle sibRect = sib.getBounds(rectCache);
1997                if (sib.isOpaque() && x >= sibRect.x
1998                    && (x + w) <= (sibRect.x + sibRect.width)
1999                    && y >= sibRect.y
2000                    && (y + h) <= (sibRect.y + sibRect.height))
2001                  {
2002                    obscured = true;
2003                  }
2004              }
2005          }
2006        return obscured;
2007      }
2008    
2009      /**
2010       * Checks if a component/rectangle is partially obscured by one of its
2011       * siblings.
2012       * Note that this doesn't check for completely obscured, this is
2013       * done by isCompletelyObscured() and should probably also be checked.
2014       *
2015       * @param i the component index from which to start searching
2016       * @param x the x coordinate of the rectangle to check
2017       * @param y the y coordinate of the rectangle to check
2018       * @param w the width of the rectangle to check
2019       * @param h the height of the rectangle to check
2020       *
2021       * @return <code>true</code> if the rectangle is partially obscured
2022       */
2023      private boolean isPartiallyObscured(int i, int x, int y, int w, int h)
2024      {
2025        boolean obscured = false;
2026        for (int j = i - 1; j >= 0 && ! obscured; j--)
2027          {
2028            Component sibl = getComponent(j);
2029            if (sibl.isVisible())
2030              {
2031                Rectangle rect = sibl.getBounds(rectCache);
2032                if (!(x + w <= rect.x)
2033                      || (y + h <= rect.y)
2034                      || (x >= rect.x + rect.width)
2035                      || (y >= rect.y + rect.height))
2036                  obscured = true;
2037              }
2038          }
2039        return obscured;
2040      }
2041    
2042      /**
2043       * Paint the component's body. This usually means calling {@link
2044       * ComponentUI#update} on the {@link #ui} property of the component, if
2045       * it is non-<code>null</code>. You may override this if you wish to
2046       * customize the component's body-painting behavior. The component's body
2047       * is painted first, before the border and children.
2048       *
2049       * @param g The graphics context with which to paint the body
2050       *
2051       * @see #paint
2052       * @see #paintBorder
2053       * @see #paintChildren
2054       */
2055      protected void paintComponent(Graphics g)
2056      {
2057        if (ui != null)
2058          {
2059            Graphics g2 = g.create();
2060            try
2061              {
2062                ui.update(g2, this);
2063              }
2064            finally
2065              {
2066                g2.dispose();
2067              }
2068          }
2069      }
2070    
2071      /**
2072       * A variant of {@link #paintImmediately(Rectangle)} which takes
2073       * integer parameters.
2074       *
2075       * @param x The left x coordinate of the dirty region
2076       * @param y The top y coordinate of the dirty region
2077       * @param w The width of the dirty region
2078       * @param h The height of the dirty region
2079       */
2080      public void paintImmediately(int x, int y, int w, int h)
2081      {
2082        // Find opaque parent and call paintImmediately2() on it.
2083        if (isShowing())
2084          {
2085            Component c = this;
2086            Component p;
2087            while (c != null && ! c.isOpaque())
2088              {
2089                p = c.getParent();
2090                if (p != null)
2091                  {
2092                    x += c.getX();
2093                    y += c.getY();
2094                    c = p;
2095                  }
2096              }
2097            if (c instanceof JComponent)
2098              ((JComponent) c).paintImmediately2(x, y, w, h);
2099            else
2100              c.repaint(x, y, w, h);
2101          }
2102      }
2103    
2104      /**
2105       * Transform the provided dirty rectangle for this component into the
2106       * appropriate ancestral {@link JRootPane} and call {@link #paint} on
2107       * that root pane. This method is called from the {@link RepaintManager}
2108       * and should always be called within the painting thread.
2109       *
2110       * <p>This method will acquire a double buffer from the {@link
2111       * RepaintManager} if the component's {@link #doubleBuffered} property is
2112       * <code>true</code> and the <code>paint</code> call is the
2113       * <em>first</em> recursive <code>paint</code> call inside swing.</p>
2114       *
2115       * <p>The method will also modify the provided {@link Graphics} context
2116       * via the {@link #getComponentGraphics} method. If you want to customize
2117       * the graphics object used for painting, you should override that method
2118       * rather than <code>paint</code>.</p>
2119       *
2120       * @param r The dirty rectangle to paint
2121       */
2122      public void paintImmediately(Rectangle r)
2123      {
2124        paintImmediately(r.x, r.y, r.width, r.height);
2125      }
2126    
2127      /**
2128       * Performs the actual work of paintImmediatly on the repaint root.
2129       *
2130       * @param x the area to be repainted, X coordinate
2131       * @param y the area to be repainted, Y coordinate
2132       */
2133      void paintImmediately2(int x, int y, int w, int h)
2134      {
2135        // Optimization for components that are always painted on top.
2136        boolean onTop = onTop() && isOpaque();
2137    
2138        // Fetch the RepaintManager.
2139        RepaintManager rm = RepaintManager.currentManager(this);
2140    
2141        // The painting clip;
2142        int paintX = x;
2143        int paintY = y;
2144        int paintW = w;
2145        int paintH = h;
2146    
2147        // If we should paint buffered or not.
2148        boolean haveBuffer = false;
2149    
2150        // The component that is finally triggered for painting.
2151        JComponent paintRoot = this;
2152        
2153        // Stores the component and all its parents. This will be used to limit
2154        // the actually painted components in paintChildren by setting
2155        // the field paintChild.
2156        int pIndex = -1;
2157        int pCount = 0;
2158        ArrayList components = new ArrayList();
2159    
2160        // Offset to subtract from the paintRoot rectangle when painting.
2161        int offsX = 0;
2162        int offsY = 0;
2163    
2164        // The current component and its child.
2165        Component child;
2166        Container c;
2167    
2168        // Find appropriate paint root.
2169        for (c = this, child = null;
2170             c != null && ! (c instanceof Window) && ! (c instanceof Applet);
2171             child = c, c = c.getParent())
2172          {
2173            JComponent jc = c instanceof JComponent ? (JComponent) c : null;
2174            components.add(c);
2175            if (! onTop && jc != null  && ! jc.isOptimizedDrawingEnabled())
2176              {
2177                // Indicates whether we reset the paint root to be the current
2178                // component.
2179                boolean updatePaintRoot = false;
2180    
2181                // Check obscured state of the child.
2182                // Generally, we have 3 cases here:
2183                // 1. Not obscured. No need to paint from the parent.
2184                // 2. Partially obscured. Paint from the parent.
2185                // 3. Completely obscured. No need to paint anything.
2186                if (c != this)
2187                  {
2188                    if (jc.isPaintRoot())
2189                      updatePaintRoot = true;
2190                    else
2191                      {
2192                        int count = c.getComponentCount();
2193                        int i = 0;
2194                        for (; i < count && c.getComponent(i) != child; i++)
2195                          ;
2196    
2197                        if (jc.isCompletelyObscured(i, paintX, paintY, paintW,
2198                                                    paintH))
2199                          return; // No need to paint anything.
2200                        else if (jc.isPartiallyObscured(i, paintX, paintY, paintW,
2201                                                        paintH))
2202                          updatePaintRoot = true;
2203                          
2204                      }
2205                  }
2206                if (updatePaintRoot)
2207                  {
2208                    // Paint from parent.
2209                    paintRoot = jc;
2210                    pIndex = pCount;
2211                    offsX = 0;
2212                    offsY = 0;
2213                    haveBuffer = false;
2214                  }
2215              }
2216            pCount++;
2217            // Check if component is double buffered.
2218            if (rm.isDoubleBufferingEnabled() && jc != null
2219                && jc.isDoubleBuffered())
2220              {
2221                haveBuffer = true;
2222              }
2223    
2224            // Clip the paint region with the parent.
2225            if (! onTop)
2226              {
2227                paintX = Math.max(0, paintX);
2228                paintY = Math.max(0, paintY);
2229                paintW = Math.min(c.getWidth(), paintW + paintX) - paintX;
2230                paintH = Math.min(c.getHeight(), paintH + paintY) - paintY;
2231                int dx = c.getX();
2232                int dy = c.getY();
2233                paintX += dx;
2234                paintY += dy;
2235                offsX += dx;
2236                offsY += dy;
2237              }
2238          }
2239        if (c != null && c.getPeer() != null && paintW > 0 && paintH > 0)
2240          {
2241            isRepainting = true;
2242            paintX -= offsX;
2243            paintY -= offsY;
2244    
2245            // Set the painting path so that paintChildren paints only what we
2246            // want.
2247            if (paintRoot != this)
2248              {
2249                for (int i = pIndex; i > 0; i--)
2250                  {
2251                    Component paintParent = (Component) components.get(i);
2252                    if (paintParent instanceof JComponent)
2253                      ((JComponent) paintParent).paintChild =
2254                        (Component) components.get(i - 1);
2255                  }
2256              }
2257    
2258            // Actually trigger painting.
2259            if (haveBuffer)
2260              paintRoot.paintDoubleBuffered(paintX, paintY, paintW, paintH);
2261            else
2262              {
2263                Graphics g = paintRoot.getGraphics();
2264                try
2265                  {
2266                    g.setClip(paintX, paintY, paintW, paintH);
2267                    paintRoot.paint(g);
2268                  }
2269                finally
2270                  {
2271                    g.dispose();
2272                  }
2273              }
2274    
2275            // Reset the painting path.
2276            if (paintRoot != this)
2277              {
2278                for (int i = pIndex; i > 0; i--)
2279                  {
2280                    Component paintParent = (Component) components.get(i);
2281                    if (paintParent instanceof JComponent)
2282                      ((JComponent) paintParent).paintChild = null;
2283                  }
2284              }
2285    
2286            isRepainting = false;
2287          }
2288      }
2289    
2290      /**
2291       * Returns <code>true</code> if the component is guaranteed to be painted
2292       * on top of others. This returns false by default and is overridden by
2293       * components like JMenuItem, JPopupMenu and JToolTip to return true for
2294       * added efficiency.
2295       *
2296       * @return <code>true</code> if the component is guaranteed to be painted
2297       *         on top of others
2298       */
2299      boolean onTop()
2300      {
2301        return false;
2302      }
2303    
2304      /**
2305       * This returns true when a component needs to force itself as a paint
2306       * origin. This is used for example in JViewport to make sure that it
2307       * gets to update its backbuffer.
2308       *
2309       * @return true when a component needs to force itself as a paint
2310       *         origin
2311       */
2312      boolean isPaintRoot()
2313      {
2314        return false;
2315      }
2316    
2317      /**
2318       * Performs double buffered repainting.
2319       */
2320      private void paintDoubleBuffered(int x, int y, int w, int h)
2321      {
2322        RepaintManager rm = RepaintManager.currentManager(this);
2323    
2324        // Paint on the offscreen buffer.
2325        Component root = SwingUtilities.getRoot(this);
2326        Image buffer = rm.getVolatileOffscreenBuffer(this, root.getWidth(),
2327                                                     root.getHeight());
2328    
2329        // The volatile offscreen buffer may be null when that's not supported
2330        // by the AWT backend. Fall back to normal backbuffer in this case.
2331        if (buffer == null)
2332          buffer = rm.getOffscreenBuffer(this, root.getWidth(), root.getHeight());
2333    
2334        //Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root);
2335        Graphics g2 = buffer.getGraphics();
2336        clipAndTranslateGraphics(root, this, g2);
2337        g2.clipRect(x, y, w, h);
2338        g2 = getComponentGraphics(g2);
2339        paintingDoubleBuffered = true;
2340        try
2341          {
2342            if (isRepainting) // Called from paintImmediately, go through paint().
2343              paint(g2);
2344            else // Called from paint() (AWT refresh), don't call it again.
2345              {
2346                paintComponent(g2);
2347                paintBorder(g2);
2348                paintChildren(g2);
2349              }
2350          }
2351        finally
2352          {
2353            paintingDoubleBuffered = false;
2354            g2.dispose();
2355          }
2356    
2357        // Paint the buffer contents on screen.
2358        rm.commitBuffer(this, x, y, w, h);
2359      }
2360    
2361      /**
2362       * Clips and translates the Graphics instance for painting on the double
2363       * buffer. This has to be done, so that it reflects the component clip of the
2364       * target component.
2365       *
2366       * @param root the root component (top-level container usually)
2367       * @param target the component to be painted
2368       * @param g the Graphics instance
2369       */
2370      private void clipAndTranslateGraphics(Component root, Component target,
2371                                            Graphics g)
2372      {
2373        Component parent = target;
2374        int deltaX = 0;
2375        int deltaY = 0;
2376        while (parent != root)
2377          {
2378            deltaX += parent.getX();
2379            deltaY += parent.getY();
2380            parent = parent.getParent();
2381          }
2382        g.translate(deltaX, deltaY);
2383        g.clipRect(0, 0, target.getWidth(), target.getHeight());
2384      }
2385    
2386      /**
2387       * Performs normal painting without double buffering.
2388       *
2389       * @param r the area that should be repainted
2390       */
2391      void paintSimple(Rectangle r)
2392      {
2393        Graphics g = getGraphics();
2394        Graphics g2 = getComponentGraphics(g);
2395        g2.setClip(r);
2396        paint(g2);
2397        g2.dispose();
2398        if (g != g2)
2399          g.dispose();
2400      }
2401    
2402      /**
2403       * Return a string representation for this component, for use in
2404       * debugging.
2405       *
2406       * @return A string describing this component.
2407       */
2408      protected String paramString()
2409      {
2410        CPStringBuilder sb = new CPStringBuilder();
2411        sb.append(super.paramString());
2412        sb.append(",alignmentX=").append(getAlignmentX());
2413        sb.append(",alignmentY=").append(getAlignmentY());
2414        sb.append(",border=");
2415        if (getBorder() != null)
2416          sb.append(getBorder());
2417        sb.append(",maximumSize=");
2418        if (getMaximumSize() != null)
2419          sb.append(getMaximumSize());
2420        sb.append(",minimumSize=");
2421        if (getMinimumSize() != null)
2422          sb.append(getMinimumSize());
2423        sb.append(",preferredSize=");
2424        if (getPreferredSize() != null)
2425          sb.append(getPreferredSize());
2426        return sb.toString();
2427      }
2428    
2429      /**
2430       * A variant of {@link
2431       * #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which
2432       * provides <code>null</code> for the command name.
2433       * 
2434       * @param act  the action listener to notify when the keystroke occurs.
2435       * @param stroke  the key stroke.
2436       * @param cond  the condition (one of {@link #WHEN_FOCUSED}, 
2437       *     {@link #WHEN_IN_FOCUSED_WINDOW} and 
2438       *     {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}).
2439       */
2440      public void registerKeyboardAction(ActionListener act,
2441                                         KeyStroke stroke, 
2442                                         int cond)
2443      {
2444        registerKeyboardAction(act, null, stroke, cond);
2445      }
2446    
2447      /* 
2448       * There is some charmingly undocumented behavior sun seems to be using
2449       * to simulate the old register/unregister keyboard binding API. It's not
2450       * clear to me why this matters, but we shall endeavour to follow suit.
2451       *
2452       * Two main thing seem to be happening when you do registerKeyboardAction():
2453       * 
2454       *  - no actionMap() entry gets created, just an entry in inputMap()
2455       *
2456       *  - the inputMap() entry is a proxy class which invokes the the
2457       *  binding's actionListener as a target, and which clobbers the command
2458       *  name sent in the ActionEvent, providing the binding command name
2459       *  instead.
2460       *
2461       * This much you can work out just by asking the input and action maps
2462       * what they contain after making bindings, and watching the event which
2463       * gets delivered to the recipient. Beyond that, it seems to be a
2464       * sun-private solution so I will only immitate it as much as it matters
2465       * to external observers.
2466       */
2467      private static class ActionListenerProxy
2468        extends AbstractAction
2469      {
2470        ActionListener target;
2471        String bindingCommandName;
2472    
2473        public ActionListenerProxy(ActionListener li, 
2474                                   String cmd)
2475        {
2476          target = li;
2477          bindingCommandName = cmd;
2478        }
2479    
2480        public void actionPerformed(ActionEvent e)
2481        {
2482          ActionEvent derivedEvent = new ActionEvent(e.getSource(),
2483                                                     e.getID(),
2484                                                     bindingCommandName,
2485                                                     e.getModifiers());
2486          target.actionPerformed(derivedEvent);
2487        }
2488      }
2489    
2490      
2491      /**
2492       * An obsolete method to register a keyboard action on this component.
2493       * You should use <code>getInputMap</code> and <code>getActionMap</code>
2494       * to fetch mapping tables from keystrokes to commands, and commands to
2495       * actions, respectively, and modify those mappings directly.
2496       *
2497       * @param act The action to be registered
2498       * @param cmd The command to deliver in the delivered {@link
2499       *     java.awt.event.ActionEvent}
2500       * @param stroke The keystroke to register on
2501       * @param cond One of the values {@link #UNDEFINED_CONDITION},
2502       *     {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or
2503       *     {@link #WHEN_IN_FOCUSED_WINDOW}, indicating the condition which must
2504       *     be met for the action to be fired
2505       *
2506       * @see #unregisterKeyboardAction
2507       * @see #getConditionForKeyStroke
2508       * @see #resetKeyboardActions
2509       */
2510      public void registerKeyboardAction(ActionListener act, 
2511                                         String cmd,
2512                                         KeyStroke stroke, 
2513                                         int cond)
2514      {
2515        ActionListenerProxy proxy = new ActionListenerProxy(act, cmd);
2516        getInputMap(cond).put(stroke, proxy);
2517        getActionMap().put(proxy, proxy);
2518      }
2519    
2520      /**
2521       * Sets the input map for the given condition.
2522       * 
2523       * @param condition  the condition (one of {@link #WHEN_FOCUSED}, 
2524       *     {@link #WHEN_IN_FOCUSED_WINDOW} and 
2525       *     {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}).
2526       * @param map  the map.
2527       * 
2528       * @throws IllegalArgumentException if <code>condition</code> is not one of
2529       *     the specified values.
2530       */
2531      public final void setInputMap(int condition, InputMap map)
2532      {
2533        enableEvents(AWTEvent.KEY_EVENT_MASK);
2534        switch (condition)
2535          {
2536          case WHEN_FOCUSED:
2537            inputMap_whenFocused = map;
2538            break;
2539    
2540          case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
2541            inputMap_whenAncestorOfFocused = map;
2542            break;
2543    
2544          case WHEN_IN_FOCUSED_WINDOW:
2545            if (map != null && !(map instanceof ComponentInputMap))
2546                throw new 
2547                  IllegalArgumentException("WHEN_IN_FOCUSED_WINDOW " + 
2548                                           "InputMap must be a ComponentInputMap");
2549            inputMap_whenInFocusedWindow = (ComponentInputMap)map;
2550            break;
2551            
2552          case UNDEFINED_CONDITION:
2553          default:
2554            throw new IllegalArgumentException();
2555          }
2556      }
2557    
2558      /**
2559       * Returns the input map associated with this component for the given
2560       * state/condition.
2561       * 
2562       * @param condition  the state (one of {@link #WHEN_FOCUSED}, 
2563       *     {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT} and 
2564       *     {@link #WHEN_IN_FOCUSED_WINDOW}).
2565       * 
2566       * @return The input map.
2567       * @throws IllegalArgumentException if <code>condition</code> is not one of 
2568       *             the specified values.
2569       * @since 1.3
2570       */
2571      public final InputMap getInputMap(int condition)
2572      {
2573        enableEvents(AWTEvent.KEY_EVENT_MASK);
2574        switch (condition)
2575          {
2576          case WHEN_FOCUSED:
2577            if (inputMap_whenFocused == null)
2578              inputMap_whenFocused = new InputMap();
2579            return inputMap_whenFocused;
2580    
2581          case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
2582            if (inputMap_whenAncestorOfFocused == null)
2583              inputMap_whenAncestorOfFocused = new InputMap();
2584            return inputMap_whenAncestorOfFocused;
2585    
2586          case WHEN_IN_FOCUSED_WINDOW:
2587            if (inputMap_whenInFocusedWindow == null)
2588              inputMap_whenInFocusedWindow = new ComponentInputMap(this);
2589            return inputMap_whenInFocusedWindow;
2590    
2591          case UNDEFINED_CONDITION:
2592          default:
2593            throw new IllegalArgumentException("Invalid 'condition' argument: " 
2594                                               + condition);
2595          }
2596      }
2597    
2598      /**
2599       * Returns the input map associated with this component for the 
2600       * {@link #WHEN_FOCUSED} state.
2601       * 
2602       * @return The input map.
2603       * 
2604       * @since 1.3
2605       * @see #getInputMap(int)
2606       */
2607      public final InputMap getInputMap()
2608      {
2609        return getInputMap(WHEN_FOCUSED);
2610      }
2611    
2612      public final ActionMap getActionMap()
2613      {
2614        if (actionMap == null)
2615          actionMap = new ActionMap();
2616        return actionMap;
2617      }
2618    
2619      public final void setActionMap(ActionMap map)
2620      {
2621        actionMap = map;
2622      }
2623    
2624      /**
2625       * Return the condition that determines whether a registered action
2626       * occurs in response to the specified keystroke.
2627       *
2628       * As of 1.3 KeyStrokes can be registered with multiple simultaneous
2629       * conditions.
2630       *
2631       * @param ks The keystroke to return the condition of
2632       *
2633       * @return One of the values {@link #UNDEFINED_CONDITION}, {@link
2634       *     #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or {@link
2635       *     #WHEN_IN_FOCUSED_WINDOW}
2636       *
2637       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)   
2638       * @see #unregisterKeyboardAction   
2639       * @see #resetKeyboardActions
2640       */
2641      public int getConditionForKeyStroke(KeyStroke ks)
2642      {
2643        if (inputMap_whenFocused != null 
2644            && inputMap_whenFocused.get(ks) != null)
2645          return WHEN_FOCUSED;
2646        else if (inputMap_whenAncestorOfFocused != null 
2647                 && inputMap_whenAncestorOfFocused.get(ks) != null)
2648          return WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
2649        else if (inputMap_whenInFocusedWindow != null 
2650                 && inputMap_whenInFocusedWindow.get(ks) != null)
2651          return WHEN_IN_FOCUSED_WINDOW;
2652        else
2653          return UNDEFINED_CONDITION;
2654      }
2655    
2656      /**
2657       * Get the ActionListener (typically an {@link Action} object) which is
2658       * associated with a particular keystroke. 
2659       *
2660       * @param ks The keystroke to retrieve the action of
2661       *
2662       * @return The action associated with the specified keystroke
2663       */
2664      public ActionListener getActionForKeyStroke(KeyStroke ks)
2665      {
2666        Object key = getInputMap(JComponent.WHEN_FOCUSED).get(ks);
2667        if (key == null)
2668          key = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).get(ks);
2669        if (key == null)
2670          key = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).get(ks);
2671        if (key != null)
2672          {
2673            if (key instanceof ActionListenerProxy)
2674              return ((ActionListenerProxy) key).target;
2675            else
2676              return getActionMap().get(key);
2677          }
2678        return null;
2679      }
2680    
2681      /**
2682       * A hook for subclasses which want to customize event processing.
2683       */
2684      protected void processComponentKeyEvent(KeyEvent e)
2685      {
2686        // This method does nothing, it is meant to be overridden by subclasses.
2687      }
2688    
2689      /**
2690       * Override the default key dispatch system from Component to hook into
2691       * the swing {@link InputMap} / {@link ActionMap} system.
2692       *
2693       * See <a
2694       * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">
2695       * this report</a> for more details, it's somewhat complex.
2696       */
2697      protected void processKeyEvent(KeyEvent e)
2698      {
2699        // let the AWT event processing send KeyEvents to registered listeners
2700        super.processKeyEvent(e);
2701        processComponentKeyEvent(e);
2702    
2703        if (e.isConsumed())
2704          return;
2705    
2706        // Input maps are checked in this order:
2707        // 1. The focused component's WHEN_FOCUSED map is checked.
2708        // 2. The focused component's WHEN_ANCESTOR_OF_FOCUSED_COMPONENT map.
2709        // 3. The WHEN_ANCESTOR_OF_FOCUSED_COMPONENT maps of the focused
2710        //    component's parent, then its parent's parent, and so on.
2711        //    Note: Input maps for disabled components are skipped.
2712        // 4. The WHEN_IN_FOCUSED_WINDOW maps of all the enabled components in
2713        //    the focused window are searched.
2714        
2715        KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
2716        boolean pressed = e.getID() == KeyEvent.KEY_PRESSED;
2717        
2718        if (processKeyBinding(keyStroke, e, WHEN_FOCUSED, pressed))
2719          {
2720            // This is step 1 from above comment.
2721            e.consume();
2722            return;
2723          }
2724        else if (processKeyBinding
2725                 (keyStroke, e, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed))
2726          {
2727            // This is step 2 from above comment.
2728            e.consume();
2729            return;
2730          }
2731        
2732        // This is step 3 from above comment.
2733        Container current = getParent();    
2734        while (current != null)
2735          { 
2736            // If current is a JComponent, see if it handles the event in its
2737            // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT maps.
2738            if ((current instanceof JComponent) && 
2739                ((JComponent)current).processKeyBinding 
2740                (keyStroke, e,WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed))
2741              {
2742                e.consume();
2743                return;
2744              }     
2745            
2746            // Stop when we've tried a top-level container and it didn't handle it
2747            if (current instanceof Window || current instanceof Applet)
2748              break;        
2749            
2750            // Move up the hierarchy
2751            current = current.getParent();
2752          }
2753        
2754        // Current being null means the JComponent does not currently have a
2755        // top-level ancestor, in which case we don't need to check 
2756        // WHEN_IN_FOCUSED_WINDOW bindings.
2757        if (current == null || e.isConsumed())
2758          return;
2759        
2760        // This is step 4 from above comment.  KeyboardManager maintains mappings
2761        // related to WHEN_IN_FOCUSED_WINDOW bindings so that we don't have to 
2762        // traverse the containment hierarchy each time.
2763        if (KeyboardManager.getManager().processKeyStroke(current, keyStroke, e))
2764          e.consume();
2765      }
2766    
2767      protected boolean processKeyBinding(KeyStroke ks,
2768                                          KeyEvent e,
2769                                          int condition,
2770                                          boolean pressed)
2771      {
2772        if (isEnabled())
2773          {
2774            Action act = null;
2775            Object cmd = null;
2776            InputMap map = getInputMap(condition);
2777            if (map != null)
2778              {
2779                cmd = map.get(ks);
2780                if (cmd != null)
2781                  {
2782                    if (cmd instanceof ActionListenerProxy)
2783                      act = (Action) cmd;
2784                    else 
2785                      act = getActionMap().get(cmd);
2786                  }
2787              }
2788            if (act != null && act.isEnabled())
2789              {
2790                // Need to synchronize here so we don't get in trouble with
2791                // our __command__ hack.
2792                synchronized (act)
2793                  {
2794                    // We add the command as value to the action, so that
2795                    // the action can later determine the command with which it
2796                    // was called. This is undocumented, but shouldn't affect
2797                    // compatibility. It allows us to use only one Action instance
2798                    // to do the work for all components of one type, instead of
2799                    // having loads of small Actions. This effectivly saves startup
2800                    // time of Swing.
2801                    act.putValue("__command__", cmd);
2802                    return SwingUtilities.notifyAction(act, ks, e, this,
2803                                                       e.getModifiers());
2804                  }
2805              }
2806          }
2807        return false;
2808      }
2809      
2810      /**
2811       * Remove a keyboard action registry.
2812       *
2813       * @param aKeyStroke The keystroke to unregister
2814       *
2815       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
2816       * @see #getConditionForKeyStroke
2817       * @see #resetKeyboardActions
2818       */
2819      public void unregisterKeyboardAction(KeyStroke aKeyStroke)
2820      {
2821        ActionMap am = getActionMap();
2822        // This loops through the conditions WHEN_FOCUSED,
2823        // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT and WHEN_IN_FOCUSED_WINDOW.
2824        for (int cond = 0; cond < 3; cond++)
2825          {
2826            InputMap im = getInputMap(cond);
2827            if (im != null)
2828              {
2829                Object action = im.get(aKeyStroke);
2830                if (action != null && am != null)
2831                  am.remove(action);
2832                im.remove(aKeyStroke);
2833              }
2834          }
2835      }
2836    
2837    
2838      /**
2839       * Reset all keyboard action registries.
2840       *
2841       * @see #registerKeyboardAction(ActionListener, KeyStroke, int)
2842       * @see #unregisterKeyboardAction
2843       * @see #getConditionForKeyStroke
2844       */
2845      public void resetKeyboardActions()
2846      {
2847        if (inputMap_whenFocused != null)
2848          inputMap_whenFocused.clear();
2849        if (inputMap_whenAncestorOfFocused != null)
2850          inputMap_whenAncestorOfFocused.clear();
2851        if (inputMap_whenInFocusedWindow != null)
2852          inputMap_whenInFocusedWindow.clear();
2853        if (actionMap != null)
2854          actionMap.clear();
2855      }
2856    
2857      /**
2858       * Mark the described region of this component as dirty in the current
2859       * {@link RepaintManager}. This will queue an asynchronous repaint using
2860       * the system painting thread in the near future.
2861       *
2862       * @param tm ignored
2863       * @param x coordinate of the region to mark as dirty
2864       * @param y coordinate of the region to mark as dirty
2865       * @param width dimension of the region to mark as dirty
2866       * @param height dimension of the region to mark as dirty
2867       */
2868      public void repaint(long tm, int x, int y, int width, int height)
2869      {
2870         RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width,
2871                                                            height);
2872      }
2873    
2874      /**
2875       * Mark the described region of this component as dirty in the current
2876       * {@link RepaintManager}. This will queue an asynchronous repaint using
2877       * the system painting thread in the near future.
2878       *
2879       * @param r The rectangle to mark as dirty
2880       */
2881      public void repaint(Rectangle r)
2882      {
2883        RepaintManager.currentManager(this).addDirtyRegion(this, r.x, r.y, r.width,
2884                                                           r.height);
2885      }
2886    
2887      /**
2888       * Request focus on the default component of this component's {@link
2889       * FocusTraversalPolicy}.
2890       *
2891       * @return The result of {@link #requestFocus()}
2892       *
2893       * @deprecated Use {@link #requestFocus()} on the default component provided
2894       *     from the {@link FocusTraversalPolicy} instead.
2895       */
2896      public boolean requestDefaultFocus()
2897      {
2898        return false;
2899      }
2900    
2901      /**
2902       * Queue a an invalidation and revalidation of this component, using 
2903       * {@link RepaintManager#addInvalidComponent}.
2904       */
2905      public void revalidate()
2906      {
2907        // As long as we don't have a parent we don't need to do any layout, since
2908        // this is done anyway as soon as we get connected to a parent.
2909        if (getParent() == null)
2910          return;
2911    
2912        if (! EventQueue.isDispatchThread())
2913          SwingUtilities.invokeLater(new Runnable()
2914            {
2915              public void run()
2916              {
2917                revalidate();
2918              }
2919            });
2920        else
2921          {
2922            invalidate();
2923            RepaintManager.currentManager(this).addInvalidComponent(this);
2924          }
2925      }
2926    
2927      /**
2928       * Calls <code>scrollRectToVisible</code> on the component's parent. 
2929       * Components which can service this call should override.
2930       *
2931       * @param r The rectangle to make visible
2932       */
2933      public void scrollRectToVisible(Rectangle r)
2934      {
2935        // Search nearest JComponent.
2936        int xOffs = getX();
2937        int yOffs = getY();
2938        Component p;
2939        for (p = getParent(); p != null && ! (p instanceof JComponent);
2940             p = p.getParent())
2941          {
2942            xOffs += p.getX();
2943            yOffs += p.getY();
2944          }
2945        if (p != null)
2946          {
2947            r.x += xOffs;
2948            r.y += yOffs;
2949            JComponent jParent = (JComponent) p;
2950            jParent.scrollRectToVisible(r);
2951            r.x -= xOffs;
2952            r.y -= yOffs;
2953          }
2954      }
2955    
2956      /**
2957       * Set the value of the {@link #alignmentX} property.
2958       *
2959       * @param a The new value of the property
2960       */
2961      public void setAlignmentX(float a)
2962      {
2963        if (a < 0.0F)
2964          alignmentX = 0.0F;
2965        else if (a > 1.0)
2966          alignmentX = 1.0F;
2967        else
2968          alignmentX = a;
2969      }
2970    
2971      /**
2972       * Set the value of the {@link #alignmentY} property.
2973       *
2974       * @param a The new value of the property
2975       */
2976      public void setAlignmentY(float a)
2977      {
2978        if (a < 0.0F)
2979          alignmentY = 0.0F;
2980        else if (a > 1.0)
2981          alignmentY = 1.0F;
2982        else
2983          alignmentY = a;
2984      }
2985    
2986      /**
2987       * Set the value of the {@link #autoscrolls} property.
2988       *
2989       * @param a The new value of the property
2990       */
2991      public void setAutoscrolls(boolean a)
2992      {
2993        autoscrolls = a;
2994        clientAutoscrollsSet = true;
2995      }
2996    
2997      /**
2998       * Set the value of the {@link #debugGraphicsOptions} property.
2999       *
3000       * @param debugOptions The new value of the property
3001       */
3002      public void setDebugGraphicsOptions(int debugOptions)
3003      {
3004        debugGraphicsOptions = debugOptions;
3005      }
3006    
3007      /**
3008       * Set the value of the {@link #doubleBuffered} property.
3009       *
3010       * @param db The new value of the property
3011       */
3012      public void setDoubleBuffered(boolean db)
3013      {
3014        doubleBuffered = db;
3015      }
3016    
3017      /**
3018       * Set the value of the <code>enabled</code> property.
3019       *
3020       * @param enable The new value of the property
3021       */
3022      public void setEnabled(boolean enable)
3023      {
3024        if (enable == isEnabled())
3025          return;
3026        super.setEnabled(enable);
3027        firePropertyChange("enabled", !enable, enable);
3028        repaint();
3029      }
3030    
3031      /**
3032       * Set the value of the <code>font</code> property.
3033       *
3034       * @param f The new value of the property
3035       */
3036      public void setFont(Font f)
3037      {
3038        if (f == getFont())
3039          return;
3040        super.setFont(f);
3041        revalidate();
3042        repaint();
3043      }
3044    
3045      /**
3046       * Set the value of the <code>background</code> property.
3047       *
3048       * @param bg The new value of the property
3049       */
3050      public void setBackground(Color bg)
3051      {
3052        if (bg == getBackground())
3053          return;
3054        super.setBackground(bg);
3055        repaint();
3056      }
3057    
3058      /**
3059       * Set the value of the <code>foreground</code> property.
3060       *
3061       * @param fg The new value of the property
3062       */
3063      public void setForeground(Color fg)
3064      {
3065        if (fg == getForeground())
3066          return;
3067        super.setForeground(fg);
3068        repaint();
3069      }
3070    
3071      /**
3072       * Set the specified component to be the next component in the 
3073       * focus cycle, overriding the {@link FocusTraversalPolicy} for
3074       * this component.
3075       *
3076       * @param aComponent The component to set as the next focusable
3077       *
3078       * @deprecated Use FocusTraversalPolicy instead
3079       */
3080      public void setNextFocusableComponent(Component aComponent)
3081      {
3082        Container focusRoot = this;
3083        if (! this.isFocusCycleRoot())
3084          focusRoot = getFocusCycleRootAncestor();
3085    
3086        FocusTraversalPolicy policy  = focusRoot.getFocusTraversalPolicy();
3087        if (policy instanceof CompatibilityFocusTraversalPolicy)
3088          {
3089            policy = new CompatibilityFocusTraversalPolicy(policy);
3090            focusRoot.setFocusTraversalPolicy(policy);
3091          }
3092        CompatibilityFocusTraversalPolicy p =
3093          (CompatibilityFocusTraversalPolicy) policy;
3094    
3095        Component old = getNextFocusableComponent();
3096        if (old != null)
3097          {
3098            p.removeNextFocusableComponent(this, old);
3099          }
3100    
3101        if (aComponent != null)
3102          {
3103            p.addNextFocusableComponent(this, aComponent);
3104          }
3105      }
3106    
3107      /**
3108       * Set the value of the {@link #requestFocusEnabled} property.
3109       *
3110       * @param e The new value of the property
3111       */
3112      public void setRequestFocusEnabled(boolean e)
3113      {
3114        requestFocusEnabled = e;
3115      }
3116    
3117      /**
3118       * Get the value of the {@link #transferHandler} property.
3119       *
3120       * @return The current value of the property
3121       *
3122       * @see #setTransferHandler
3123       */
3124    
3125      public TransferHandler getTransferHandler()
3126      {
3127        return transferHandler;
3128      }
3129    
3130      /**
3131       * Set the value of the {@link #transferHandler} property.
3132       *
3133       * @param newHandler The new value of the property
3134       *
3135       * @see #getTransferHandler
3136       */
3137    
3138      public void setTransferHandler(TransferHandler newHandler)
3139      {
3140        if (transferHandler == newHandler)
3141          return;
3142    
3143        TransferHandler oldHandler = transferHandler;
3144        transferHandler = newHandler;
3145        firePropertyChange("transferHandler", oldHandler, newHandler);
3146      }
3147    
3148      /**
3149       * Set if the component should paint all pixels withing its bounds.
3150       * If this property is set to false, the component expects the cleared
3151       * background.
3152       *
3153       * @param isOpaque if true, paint all pixels. If false, expect the clean
3154       * background. 
3155       *
3156       * @see ComponentUI#update
3157       */
3158      public void setOpaque(boolean isOpaque)
3159      {
3160        boolean oldOpaque = opaque;
3161        opaque = isOpaque;
3162        clientOpaqueSet = true;
3163        firePropertyChange("opaque", oldOpaque, opaque);
3164      }
3165    
3166      /**
3167       * Set the value of the visible property.
3168       *
3169       * If the value is changed, then the AncestorListeners of this component
3170       * and all its children (recursivly) are notified.
3171       *
3172       * @param v The new value of the property
3173       */
3174      public void setVisible(boolean v)
3175      {
3176        // No need to do anything if the actual value doesn't change.
3177        if (isVisible() == v)
3178          return;
3179    
3180        super.setVisible(v);
3181    
3182        // Notify AncestorListeners.
3183        if (v == true)
3184          fireAncestorEvent(this, AncestorEvent.ANCESTOR_ADDED);
3185        else
3186          fireAncestorEvent(this, AncestorEvent.ANCESTOR_REMOVED);
3187    
3188        Container parent = getParent();
3189        if (parent != null)
3190          parent.repaint(getX(), getY(), getWidth(), getHeight());
3191        revalidate();
3192      }
3193    
3194      /**
3195       * Call {@link #paint}. 
3196       * 
3197       * @param g The graphics context to paint into
3198       */
3199      public void update(Graphics g)
3200      {
3201        paint(g);
3202      }
3203    
3204      /**
3205       * Get the value of the UIClassID property. This property should be a key
3206       * in the {@link UIDefaults} table managed by {@link UIManager}, the
3207       * value of which is the name of a class to load for the component's
3208       * {@link #ui} property.
3209       *
3210       * @return A "symbolic" name which will map to a class to use for the
3211       * component's UI, such as <code>"ComponentUI"</code>
3212       *
3213       * @see #setUI
3214       * @see #updateUI
3215       */
3216      public String getUIClassID()
3217      {
3218        return "ComponentUI";
3219      }
3220    
3221      /**
3222       * Install a new UI delegate as the component's {@link #ui} property. In
3223       * the process, this will call {@link ComponentUI#uninstallUI} on any
3224       * existing value for the {@link #ui} property, and {@link
3225       * ComponentUI#installUI} on the new UI delegate.
3226       *
3227       * @param newUI The new UI delegate to install
3228       *
3229       * @see #updateUI
3230       * @see #getUIClassID
3231       */
3232      protected void setUI(ComponentUI newUI)
3233      {
3234        if (ui != null)
3235          ui.uninstallUI(this);
3236    
3237        ComponentUI oldUI = ui;
3238        ui = newUI;
3239    
3240        if (ui != null)
3241          ui.installUI(this);
3242    
3243        firePropertyChange("UI", oldUI, newUI);
3244        revalidate();
3245        repaint();
3246      }
3247    
3248      /**
3249       * This method should be overridden in subclasses. In JComponent, the
3250       * method does nothing. In subclasses, it should a UI delegate
3251       * (corresponding to the symbolic name returned from {@link
3252       * #getUIClassID}) from the {@link UIManager}, and calls {@link #setUI}
3253       * with the new delegate.
3254       */
3255      public void updateUI()
3256      {
3257        // Nothing to do here.
3258      }
3259    
3260      /**
3261       * Returns the locale used as the default for all new components.  The 
3262       * default value is {@link Locale#getDefault()} (that is, the platform
3263       * default locale).
3264       * 
3265       * @return The locale (never <code>null</code>).
3266       * 
3267       * @see #setDefaultLocale(Locale)
3268       */
3269      public static Locale getDefaultLocale()
3270      {
3271        if (defaultLocale == null)
3272          defaultLocale = Locale.getDefault();
3273        return defaultLocale;
3274      }
3275      
3276      /**
3277       * Sets the locale to be used as the default for all new components.  If this
3278       * is set to <code>null</code>, the {@link #getDefaultLocale()} method will
3279       * return the platform default locale.
3280       * 
3281       * @param l  the locale (<code>null</code> permitted).
3282       */
3283      public static void setDefaultLocale(Locale l)
3284      {
3285        defaultLocale = l;
3286      }
3287      
3288      /**
3289       * Returns the currently set input verifier for this component.
3290       *
3291       * @return the input verifier, or <code>null</code> if none
3292       */
3293      public InputVerifier getInputVerifier()
3294      {
3295        return inputVerifier;
3296      }
3297    
3298      /**
3299       * Sets the input verifier to use by this component.
3300       *
3301       * @param verifier the input verifier, or <code>null</code>
3302       */
3303      public void setInputVerifier(InputVerifier verifier)
3304      {
3305        InputVerifier oldVerifier = inputVerifier;
3306        inputVerifier = verifier;
3307        firePropertyChange("inputVerifier", oldVerifier, verifier);
3308      }
3309    
3310      /**
3311       * @since 1.3
3312       */
3313      public boolean getVerifyInputWhenFocusTarget()
3314      {
3315        return verifyInputWhenFocusTarget;
3316      }
3317    
3318      /**
3319       * @since 1.3
3320       */
3321      public void setVerifyInputWhenFocusTarget(boolean verifyInputWhenFocusTarget)
3322      {
3323        if (this.verifyInputWhenFocusTarget == verifyInputWhenFocusTarget)
3324          return;
3325    
3326        this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget;
3327        firePropertyChange("verifyInputWhenFocusTarget",
3328                           ! verifyInputWhenFocusTarget,
3329                           verifyInputWhenFocusTarget);
3330      }
3331    
3332      /**
3333       * Requests that this component gets the input focus if the
3334       * requestFocusEnabled property is set to <code>true</code>.
3335       * This also means that this component's top-level window becomes
3336       * the focused window, if that is not already the case.
3337       *
3338       * The preconditions that have to be met to become a focus owner is that
3339       * the component must be displayable, visible and focusable.
3340       *
3341       * Note that this signals only a request for becoming focused. There are
3342       * situations in which it is not possible to get the focus. So developers
3343       * should not assume that the component has the focus until it receives
3344       * a {@link java.awt.event.FocusEvent} with a value of
3345       * {@link java.awt.event.FocusEvent#FOCUS_GAINED}.
3346       *
3347       * @see Component#requestFocus()
3348       */
3349      public void requestFocus()
3350      {
3351        if (isRequestFocusEnabled())
3352          super.requestFocus();
3353      }
3354    
3355      /**
3356       * This method is overridden to make it public so that it can be used
3357       * by look and feel implementations.
3358       *
3359       * You should not use this method directly. Instead you are strongly
3360       * encouraged to call {@link #requestFocus()} or 
3361       * {@link #requestFocusInWindow()} instead.
3362       *
3363       * @param temporary if the focus change is temporary
3364       *
3365       * @return <code>false</code> if the focus change request will definitly
3366       *     fail, <code>true</code> if it will likely succeed
3367       *
3368       * @see Component#requestFocus(boolean)
3369       *
3370       * @since 1.4
3371       */
3372      public boolean requestFocus(boolean temporary)
3373      {
3374        return super.requestFocus(temporary);
3375      }
3376    
3377      /**
3378       * Requests that this component gets the input focus if the top level
3379       * window that contains this component has the focus and the
3380       * requestFocusEnabled property is set to <code>true</code>.
3381       *
3382       * The preconditions that have to be met to become a focus owner is that
3383       * the component must be displayable, visible and focusable.
3384       *
3385       * Note that this signals only a request for becoming focused. There are
3386       * situations in which it is not possible to get the focus. So developers
3387       * should not assume that the component has the focus until it receives
3388       * a {@link java.awt.event.FocusEvent} with a value of
3389       * {@link java.awt.event.FocusEvent#FOCUS_GAINED}.
3390       *
3391       * @return <code>false</code> if the focus change request will definitly
3392       *     fail, <code>true</code> if it will likely succeed
3393       *
3394       * @see Component#requestFocusInWindow()
3395       */
3396      public boolean requestFocusInWindow()
3397      {
3398        if (isRequestFocusEnabled())
3399          return super.requestFocusInWindow();
3400        else
3401          return false;
3402      }
3403    
3404      /**
3405       * This method is overridden to make it public so that it can be used
3406       * by look and feel implementations.
3407       *
3408       * You should not use this method directly. Instead you are strongly
3409       * encouraged to call {@link #requestFocus()} or 
3410       * {@link #requestFocusInWindow()} instead.
3411       *
3412       * @param temporary if the focus change is temporary
3413       *
3414       * @return <code>false</code> if the focus change request will definitly
3415       *     fail, <code>true</code> if it will likely succeed
3416       *
3417       * @see Component#requestFocus(boolean)
3418       *
3419       * @since 1.4
3420       */
3421      protected boolean requestFocusInWindow(boolean temporary)
3422      {
3423        return super.requestFocusInWindow(temporary);
3424      }
3425    
3426      /**
3427       * Receives notification if this component is added to a parent component.
3428       *
3429       * Notification is sent to all registered AncestorListeners about the
3430       * new parent.
3431       *
3432       * This method sets up ActionListeners for all registered KeyStrokes of
3433       * this component in the chain of parent components.
3434       *
3435       * A PropertyChange event is fired to indicate that the ancestor property
3436       * has changed.
3437       *
3438       * This method is used internally and should not be used in applications.
3439       */
3440      public void addNotify()
3441      {
3442        // Register the WHEN_IN_FOCUSED_WINDOW keyboard bindings
3443        // Note that here we unregister all bindings associated with
3444        // this component and then re-register them.  This may be more than
3445        // necessary if the top-level ancestor hasn't changed.  Should
3446        // maybe improve this.
3447        KeyboardManager km = KeyboardManager.getManager();
3448        km.clearBindingsForComp(this);
3449        km.registerEntireMap((ComponentInputMap)
3450                             this.getInputMap(WHEN_IN_FOCUSED_WINDOW));
3451        super.addNotify();
3452    
3453        // Notify AncestorListeners.
3454        fireAncestorEvent(this, AncestorEvent.ANCESTOR_ADDED);
3455    
3456        // fire property change event for 'ancestor'
3457        firePropertyChange("ancestor", null, getParent());
3458      }
3459    
3460      /**
3461       * Receives notification that this component no longer has a parent.
3462       *
3463       * This method sends an AncestorEvent to all registered AncestorListeners,
3464       * notifying them that the parent is gone.
3465       *
3466       * The keybord actions of this component are removed from the parent and
3467       * its ancestors.
3468       *
3469       * A PropertyChangeEvent is fired to indicate that the 'ancestor' property
3470       * has changed.
3471       *
3472       * This method is called before the component is actually removed from
3473       * its parent, so the parent is still visible through 
3474       * {@link Component#getParent}.
3475       */
3476      public void removeNotify()
3477      {
3478        super.removeNotify();
3479    
3480        KeyboardManager.getManager().clearBindingsForComp(this);
3481        
3482        // Notify ancestor listeners.
3483        fireAncestorEvent(this, AncestorEvent.ANCESTOR_REMOVED);
3484    
3485        // fire property change event for 'ancestor'
3486        firePropertyChange("ancestor", getParent(), null);
3487      }
3488    
3489      /**
3490       * Returns <code>true</code> if the coordinates (x, y) lie within
3491       * the bounds of this component and <code>false</code> otherwise.
3492       * x and y are relative to the coordinate space of the component.
3493       *
3494       * @param x the X coordinate of the point to check
3495       * @param y the Y coordinate of the point to check
3496       *
3497       * @return <code>true</code> if the specified point lies within the bounds
3498       *     of this component, <code>false</code> otherwise
3499       */
3500      public boolean contains(int x, int y)
3501      {
3502        if (ui == null)
3503          return super.contains(x, y);
3504        else
3505          return ui.contains(this, x, y);
3506      }
3507    
3508      /**
3509       * Disables this component.
3510       *
3511       * @deprecated replaced by {@link #setEnabled(boolean)}
3512       */
3513      public void disable()
3514      {
3515        super.disable();
3516      }
3517    
3518      /**
3519       * Enables this component.
3520       *
3521       * @deprecated replaced by {@link #setEnabled(boolean)}
3522       */
3523      public void enable()
3524      {
3525        super.enable();
3526      }
3527    
3528      /**
3529       * Returns the Graphics context for this component. This can be used
3530       * to draw on a component.
3531       *
3532       * @return the Graphics context for this component
3533       */
3534      public Graphics getGraphics()
3535      {
3536        return super.getGraphics();
3537      }
3538    
3539      /**
3540       * Returns the X coordinate of the upper left corner of this component.
3541       * Prefer this method over {@link #getBounds} or {@link #getLocation}
3542       * because it does not cause any heap allocation.
3543       *
3544       * @return the X coordinate of the upper left corner of the component
3545       */
3546      public int getX()
3547      {
3548        return super.getX();
3549      }
3550    
3551      /**
3552       * Returns the Y coordinate of the upper left corner of this component.
3553       * Prefer this method over {@link #getBounds} or {@link #getLocation}
3554       * because it does not cause any heap allocation.
3555       *
3556       * @return the Y coordinate of the upper left corner of the component
3557       */
3558      public int getY()
3559      {
3560        return super.getY();
3561      }
3562    
3563      /**
3564       * Returns the height of this component. Prefer this method over
3565       * {@link #getBounds} or {@link #getSize} because it does not cause
3566       * any heap allocation.
3567       *
3568       * @return the height of the component
3569       */
3570      public int getHeight()
3571      {
3572        return super.getHeight();
3573      }
3574    
3575      /**
3576       * Returns the width of this component. Prefer this method over
3577       * {@link #getBounds} or {@link #getSize} because it does not cause
3578       * any heap allocation.
3579       *
3580       * @return the width of the component
3581       */
3582      public int getWidth()
3583      {
3584        return super.getWidth();
3585      }
3586    
3587      /**
3588       * Prints this component to the given Graphics context. A call to this
3589       * method results in calls to the methods {@link #printComponent},
3590       * {@link #printBorder} and {@link #printChildren} in this order.
3591       *
3592       * Double buffering is temporarily turned off so the painting goes directly
3593       * to the supplied Graphics context.
3594       *
3595       * @param g the Graphics context to print onto
3596       */
3597      public void print(Graphics g)
3598      {
3599        boolean doubleBufferState = isDoubleBuffered();
3600        setDoubleBuffered(false);
3601        printComponent(g);
3602        printBorder(g);
3603        printChildren(g);
3604        setDoubleBuffered(doubleBufferState);
3605      }
3606    
3607      /**
3608       * Prints this component to the given Graphics context. This invokes
3609       * {@link #print}.
3610       *
3611       * @param g the Graphics context to print onto
3612       */
3613      public void printAll(Graphics g)
3614      {
3615        print(g);
3616      }
3617    
3618      /**
3619       * Prints this component to the specified Graphics context. The default
3620       * behaviour is to invoke {@link #paintComponent}. Override this
3621       * if you want special behaviour for printing.
3622       *
3623       * @param g the Graphics context to print onto
3624       *
3625       * @since 1.3
3626       */
3627      protected void printComponent(Graphics g)
3628      {
3629        paintComponent(g);
3630      }
3631    
3632      /**
3633       * Print this component's children to the specified Graphics context.
3634       * The default behaviour is to invoke {@link #paintChildren}. Override this
3635       * if you want special behaviour for printing.
3636       *
3637       * @param g the Graphics context to print onto
3638       *
3639       * @since 1.3
3640       */
3641      protected void printChildren(Graphics g)
3642      {
3643        paintChildren(g);
3644      }
3645    
3646      /**
3647       * Print this component's border to the specified Graphics context.
3648       * The default behaviour is to invoke {@link #paintBorder}. Override this
3649       * if you want special behaviour for printing.
3650       *
3651       * @param g the Graphics context to print onto
3652       *
3653       * @since 1.3
3654       */
3655      protected void printBorder(Graphics g)
3656      {
3657        paintBorder(g);
3658      }
3659    
3660      /**
3661       * Processes mouse motion event, like dragging and moving.
3662       *
3663       * @param ev the MouseEvent describing the mouse motion
3664       */
3665      protected void processMouseMotionEvent(MouseEvent ev)
3666      {
3667        super.processMouseMotionEvent(ev);
3668      }
3669    
3670      /**
3671       * Moves and resizes the component.
3672       *
3673       * @param x the new horizontal location
3674       * @param y the new vertial location
3675       * @param w the new width
3676       * @param h the new height
3677       */
3678      public void reshape(int x, int y, int w, int h)
3679      {
3680        int oldX = getX();
3681        int oldY = getY();
3682        super.reshape(x, y, w, h);
3683        // Notify AncestorListeners.
3684        if (oldX != getX() || oldY != getY())
3685          fireAncestorEvent(this, AncestorEvent.ANCESTOR_MOVED);
3686      }
3687    
3688      /**
3689       * Fires an AncestorEvent to this component's and all of its child
3690       * component's AncestorListeners.
3691       *
3692       * @param ancestor the component that triggered the event
3693       * @param id the kind of ancestor event that should be fired
3694       */
3695      void fireAncestorEvent(JComponent ancestor, int id)
3696      {
3697        // Fire event for registered ancestor listeners of this component.
3698        AncestorListener[] listeners = getAncestorListeners();
3699        if (listeners.length > 0)
3700          {
3701            AncestorEvent ev = new AncestorEvent(this, id,
3702                                                 ancestor, ancestor.getParent());
3703            for (int i = 0; i < listeners.length; i++)
3704              {
3705                switch (id)
3706                  {
3707                  case AncestorEvent.ANCESTOR_MOVED:
3708                    listeners[i].ancestorMoved(ev);
3709                    break;
3710                  case AncestorEvent.ANCESTOR_ADDED:
3711                    listeners[i].ancestorAdded(ev);
3712                    break;
3713                  case AncestorEvent.ANCESTOR_REMOVED:
3714                    listeners[i].ancestorRemoved(ev);
3715                    break;
3716                  }
3717              }
3718          }
3719        // Dispatch event to all children.
3720        int numChildren = getComponentCount();
3721        for (int i = 0; i < numChildren; i++)
3722          {
3723            Component child = getComponent(i);
3724            if (! (child instanceof JComponent))
3725              continue;
3726            JComponent jc = (JComponent) child;
3727            jc.fireAncestorEvent(ancestor, id);
3728          }
3729      }
3730      
3731      /**
3732       * This is the method that gets called when the WHEN_IN_FOCUSED_WINDOW map
3733       * is changed.
3734       *
3735       * @param changed the JComponent associated with the WHEN_IN_FOCUSED_WINDOW
3736       *        map
3737       */
3738      void updateComponentInputMap(ComponentInputMap changed)
3739      {
3740        // Since you can change a component's input map via
3741        // setInputMap, we have to check if <code>changed</code>
3742        // is still in our WHEN_IN_FOCUSED_WINDOW map hierarchy
3743        InputMap curr = getInputMap(WHEN_IN_FOCUSED_WINDOW);
3744        while (curr != null && curr != changed)
3745          curr = curr.getParent();
3746        
3747        // If curr is null then changed is not in the hierarchy
3748        if (curr == null)
3749          return;
3750        
3751        // Now we have to update the keyboard manager's hashtable
3752        KeyboardManager km = KeyboardManager.getManager();
3753        
3754        // This is a poor strategy, should be improved.  We currently 
3755        // delete all the old bindings for the component and then register
3756        // the current bindings.
3757        km.clearBindingsForComp(changed.getComponent());
3758        km.registerEntireMap((ComponentInputMap) 
3759                             getInputMap(WHEN_IN_FOCUSED_WINDOW));
3760      }
3761    
3762      /**
3763       * Helper method for
3764       * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
3765       * 
3766       * @param propertyName the name of the property
3767       * @param value the value of the property
3768       *
3769       * @throws IllegalArgumentException if the specified property cannot be set
3770       *         by this method
3771       * @throws ClassCastException if the property value does not match the
3772       *         property type
3773       * @throws NullPointerException if <code>c</code> or
3774       *         <code>propertyValue</code> is <code>null</code>
3775       */
3776      void setUIProperty(String propertyName, Object value)
3777      {
3778        if (propertyName.equals("opaque"))
3779          {
3780            if (! clientOpaqueSet)
3781              {
3782                setOpaque(((Boolean) value).booleanValue());
3783                clientOpaqueSet = false;
3784              }
3785          }
3786        else if (propertyName.equals("autoscrolls"))
3787          {
3788            if (! clientAutoscrollsSet)
3789              {
3790                setAutoscrolls(((Boolean) value).booleanValue());
3791                clientAutoscrollsSet = false;
3792              }
3793          }
3794        else
3795          {
3796            throw new IllegalArgumentException
3797                ("Unsupported property for LookAndFeel.installProperty(): "
3798                 + propertyName);
3799          }
3800      }
3801    }