OSDN Git Service

ad7603cf76ae606492b92869322432f61840d91d
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / JComponent.java
1 /* JComponent.java -- Every component in swing inherits from this class.
2    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import java.awt.AWTEvent;
42 import java.awt.Color;
43 import java.awt.Component;
44 import java.awt.Container;
45 import java.awt.Dimension;
46 import java.awt.FlowLayout;
47 import java.awt.Font;
48 import java.awt.Graphics;
49 import java.awt.Image;
50 import java.awt.Insets;
51 import java.awt.Point;
52 import java.awt.Rectangle;
53 import java.awt.dnd.DropTarget;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.ActionListener;
56 import java.awt.event.ContainerEvent;
57 import java.awt.event.ContainerListener;
58 import java.awt.event.FocusEvent;
59 import java.awt.event.FocusListener;
60 import java.awt.event.KeyEvent;
61 import java.awt.event.MouseEvent;
62 import java.awt.geom.Rectangle2D;
63 import java.awt.image.ImageObserver;
64 import java.awt.peer.LightweightPeer;
65 import java.beans.PropertyChangeEvent;
66 import java.beans.PropertyChangeListener;
67 import java.beans.PropertyVetoException;
68 import java.beans.VetoableChangeListener;
69 import java.io.Serializable;
70 import java.util.EventListener;
71 import java.util.Hashtable;
72 import java.util.Locale;
73
74 import javax.accessibility.Accessible;
75 import javax.accessibility.AccessibleContext;
76 import javax.accessibility.AccessibleKeyBinding;
77 import javax.accessibility.AccessibleRole;
78 import javax.accessibility.AccessibleStateSet;
79 import javax.swing.border.Border;
80 import javax.swing.event.AncestorListener;
81 import javax.swing.event.EventListenerList;
82 import javax.swing.event.SwingPropertyChangeSupport;
83 import javax.swing.plaf.ComponentUI;
84
85 /**
86  * Every component in swing inherits from this class (JLabel, JButton, etc).
87  * It contains generic methods to manage events, properties and sizes. Actual
88  * drawing of the component is channeled to a look-and-feel class that is
89  * implemented elsewhere.
90  *
91  * @author Ronald Veldema (rveldema&064;cs.vu.nl)
92  * @author Graydon Hoare (graydon&064;redhat.com)
93  */
94 public abstract class JComponent extends Container implements Serializable
95 {
96   private static final long serialVersionUID = -7908749299918704233L;
97
98   /** 
99    * Accessibility support is currently missing.
100    */
101
102   protected AccessibleContext accessibleContext;
103
104   public abstract class AccessibleJComponent 
105     extends AccessibleAWTContainer
106   {
107     protected class AccessibleFocusHandler 
108       implements FocusListener
109     {
110       protected AccessibleFocusHandler(){}
111       public void focusGained(FocusEvent event){}
112       public void focusLost(FocusEvent valevent){}
113     }
114
115     protected class AccessibleContainerHandler 
116       implements ContainerListener
117     {
118       protected AccessibleContainerHandler() {}
119       public void componentAdded(ContainerEvent event) {}
120       public void componentRemoved(ContainerEvent valevent) {}
121     }
122
123     private static final long serialVersionUID = -7047089700479897799L;
124   
125     protected ContainerListener accessibleContainerHandler;
126     protected FocusListener accessibleFocusHandler;
127
128     protected AccessibleJComponent() {}
129     public void addPropertyChangeListener(PropertyChangeListener listener) {}
130     public void removePropertyChangeListener(PropertyChangeListener listener) {}
131     public int getAccessibleChildrenCount() { return 0; }
132     public Accessible getAccessibleChild(int value0) { return null; }
133     public AccessibleStateSet getAccessibleStateSet() { return null; } 
134     public String getAccessibleName() { return null; }
135     public String getAccessibleDescription() { return null; }
136     public AccessibleRole getAccessibleRole() { return null; }
137     protected String getBorderTitle(Border value0) { return null; }
138     public String getToolTipText() { return null; }
139     public String getTitledBorderText() { return null; }
140     public AccessibleKeyBinding getAccessibleKeyBinding() { return null; }
141   }
142
143   /** 
144    * An explicit value for the component's preferred size; if not set by a
145    * user, this is calculated on the fly by delegating to the {@link
146    * ComponentUI.getPreferredSize} method on the {@link #ui} property. 
147    */
148   Dimension preferredSize;
149
150   /** 
151    * An explicit value for the component's minimum size; if not set by a
152    * user, this is calculated on the fly by delegating to the {@link
153    * ComponentUI.getMinimumSize} method on the {@link #ui} property. 
154    */
155   Dimension minimumSize;
156
157   /** 
158    * An explicit value for the component's maximum size; if not set by a
159    * user, this is calculated on the fly by delegating to the {@link
160    * ComponentUI.getMaximumSize} method on the {@link #ui} property.
161    */
162   Dimension maximumSize;
163
164
165   /**
166    * A value between 0.0 and 1.0 indicating the preferred horizontal
167    * alignment of the component, relative to its siblings. The values
168    * {@link #LEFT_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link
169    * #RIGHT_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>,
170    * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout
171    * managers use this property.
172    *
173    * @see #getAlignmentX
174    * @see #setAlignmentX
175    * @see javax.swing.OverlayLayout
176    * @see javax.swing.BoxLayout
177    */
178   float alignmentX = 0.0f;
179
180   /**
181    * A value between 0.0 and 1.0 indicating the preferred vertical
182    * alignment of the component, relative to its siblings. The values
183    * {@link #TOP_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link
184    * #BOTTOM_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>,
185    * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout
186    * managers use this property.
187    *
188    * @see #getAlignmentY
189    * @see #setAlignmentY
190    * @see javax.swing.OverlayLayout
191    * @see javax.swing.BoxLayout
192    */
193   float alignmentY = 0.0f;
194
195   /** 
196    * The border painted around this component.
197    * 
198    * @see #paintBorder
199    */
200   Border border;
201
202   /** 
203    * The text to show in the tooltip associated with this component.
204    * 
205    * @see #setToolTipText
206    * @see #getToolTipText
207    */
208    String toolTipText;
209
210   /** 
211    * <p>Whether to double buffer this component when painting. This flag
212    * should generally be <code>false</code>, except for top level
213    * components such as {@link JFrame} or {@link JApplet}.</p>
214    *
215    * <p>All children of a double buffered component are painted into the
216    * double buffer automatically, so only the top widget in a window needs
217    * to be double buffered.</p>
218    *
219    * @see #setDoubleBuffered
220    * @see #isDoubleBuffered
221    * @see #paintLock
222    * @see #paint
223    */
224   boolean doubleBuffered = false;
225
226   /**
227    * A set of flags indicating which debugging graphics facilities should
228    * be enabled on this component. The values should be a combination of
229    * {@link DebugGraphics.NONE_OPTION}, {@link DebugGraphics.LOG_OPTION},
230    * {@link DebugGraphics.FLASH_OPTION}, or {@link
231    * DebugGraphics.BUFFERED_OPTION}.
232    *
233    * @see setDebugGraphicsOptions
234    * @see getDebugGraphicsOptions
235    * @see DebugGraphics
236    * @see getComponentGraphics
237    */
238   int debugGraphicsOptions;
239
240   /** 
241    * <p>This property controls two independent behaviors simultaneously.</p>
242    *
243    * <p>First, it controls whether to fill the background of this widget
244    * when painting its body. This affects calls to {@link
245    * JComponent#paintComponent}, which in turn calls {@link
246    * ComponentUI#update} on the component's {@link #ui} property. If the
247    * component is opaque during this call, the background will be filled
248    * before calling {@link ComponentUI#paint}. This happens merely as a
249    * convenience; you may fill the component's background yourself too,
250    * but there is no need to do so if you will be filling with the same
251    * color.</p>
252    *
253    * <p>Second, it the opaque property informs swing's repaint system
254    * whether it will be necessary to paint the components "underneath" this
255    * component, in Z-order. If the component is opaque, it is considered to
256    * completely occlude components "underneath" it, so they will not be
257    * repainted along with the opaque component.</p>
258    *
259    * <p>The default value for this property is <code>false</code>, but most
260    * components will want to set it to <code>true</code> when installing UI
261    * defaults in {@link ComponentUI#installUI}.</p>
262    *
263    * @see #setOpaque
264    * @see #isOpaque
265    * @see #paintComponent
266    */
267   boolean opaque = false;
268
269   /** 
270    * The user interface delegate for this component. Event delivery and
271    * repainting of the component are usually delegated to this object. 
272    *
273    * @see #setUI
274    * @see #getUI
275    * @see #updateUI
276    */
277   protected ComponentUI ui;
278
279   /**
280    * A hint to the focus system that this component should or should not
281    * get focus. If this is <code>false</code>, swing will not try to
282    * request focus on this component; if <code>true</code>, swing might
283    * try to request focus, but the request might fail. Thus it is only 
284    * a hint guiding swing's behavior.
285    *
286    * @see #requestFocus
287    * @see #isRequestFocusEnabled
288    * @see #setRequestFocusEnabled
289    */
290   boolean requestFocusEnabled;
291
292   /**
293    * Flag indicating behavior of this component when the mouse is dragged
294    * outside the component and the mouse <em>stops moving</em>. If
295    * <code>true</code>, synthetic mouse events will be delivered on regular
296    * timed intervals, continuing off in the direction the mouse exited the
297    * component, until the mouse is released or re-enters the component.
298    *
299    * @see setAutoscrolls
300    * @see getAutoscrolls
301    */
302   boolean autoscrolls = false;
303
304   /**
305    * Listeners for events other than {@link PropertyChangeEvent} are
306    * handled by this listener list. PropertyChangeEvents are handled in
307    * {@link #changeSupport}.
308    */
309   protected EventListenerList listenerList = new EventListenerList();
310
311   /** 
312    * Support for {@link PropertyChangeEvent} events. This is constructed
313    * lazily when the component gets its first {@link
314    * PropertyChangeListener} subscription; until then it's an empty slot.
315    */
316   private SwingPropertyChangeSupport changeSupport;
317
318
319   /** 
320    * Storage for "client properties", which are key/value pairs associated
321    * with this component by a "client", such as a user application or a
322    * layout manager. This is lazily constructed when the component gets its
323    * first client property.
324    */
325   private Hashtable clientProperties;
326   
327   private InputMap inputMap_whenFocused;
328   private InputMap inputMap_whenAncestorOfFocused;
329   private InputMap inputMap_whenInFocusedWindow;
330   private ActionMap actionMap;
331   /** @since 1.3 */
332   private boolean verifyInputWhenFocusTarget;
333   private InputVerifier inputVerifier;
334
335   private TransferHandler transferHandler;
336
337   /** 
338    * A lock held during recursive painting; this is used to serialize
339    * access to the double buffer, and also to select the "top level" 
340    * object which should acquire the double buffer in a given widget
341    * tree (which may have multiple double buffered children).
342    *
343    * @see #doubleBuffered
344    * @see #paint
345    */
346   private static final Object paintLock = new Object();
347
348
349   /**
350    * The default locale of the component.
351    * 
352    * @see #getDefaultLocale
353    * @see #setDefaultLocale
354    */
355   private static Locale defaultLocale;
356   
357   public static final String TOOL_TIP_TEXT_KEY = "ToolTipText";
358
359   /**
360    * Constant used to indicate that no condition has been assigned to a
361    * particular action.
362    *
363    * @see #registerKeyboardAction
364    */
365   public static final int UNDEFINED_CONDITION = -1;
366
367   /**
368    * Constant used to indicate that an action should be performed only when 
369    * the component has focus.
370    *
371    * @see #registerKeyboardAction
372    */
373   public static final int WHEN_FOCUSED = 0;
374
375   /**
376    * Constant used to indicate that an action should be performed only when 
377    * the component is an ancestor of the component which has focus.
378    *
379    * @see #registerKeyboardAction
380    */
381   public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;
382
383   /**
384    * Constant used to indicate that an action should be performed only when 
385    * the component is in the window which has focus.
386    *
387    * @see #registerKeyboardAction
388    */
389   public static final int WHEN_IN_FOCUSED_WINDOW = 2;
390
391
392   /**
393    * Creates a new <code>JComponent</code> instance.
394    */
395   public JComponent()
396   {
397     super();
398     super.setLayout(new FlowLayout());
399     setDropTarget(new DropTarget());
400     defaultLocale = Locale.getDefault();
401     debugGraphicsOptions = DebugGraphics.NONE_OPTION;
402   }
403
404   /**
405    * Helper to lazily construct and return the client properties table.
406    * 
407    * @return The current client properties table
408    *
409    * @see #clientProperties
410    * @see #getClientProperty
411    * @see #putClientProperty
412    */
413   private Hashtable getClientProperties()
414   {
415     if (clientProperties == null)
416       clientProperties = new Hashtable();
417     return clientProperties;
418   }
419
420   /**
421    * Get a client property associated with this component and a particular
422    * key.
423    *
424    * @param key The key with which to look up the client property
425    *
426    * @return A client property associated with this object and key
427    *
428    * @see #clientProperties
429    * @see #getClientProperties
430    * @see #putClientProperty
431    */
432   public final Object getClientProperty(Object key)
433   {
434     return getClientProperties().get(key);
435   }
436
437   /**
438    * Add a client property <code>value</code> to this component, associated
439    * with <code>key</code>. If there is an existing client property
440    * associated with <code>key</code>, it will be replaced.
441    *
442    * @param key The key of the client property association to add
443    * @param value The value of the client property association to add
444    *
445    * @see #clientProperties
446    * @see #getClientProperties
447    * @see #getClientProperty
448    */
449   public final void putClientProperty(Object key, Object value)
450   {
451     getClientProperties().put(key, value);
452   }
453
454   /**
455    * Unregister an <code>AncestorListener</code>.
456    *
457    * @param listener The listener to unregister
458    * 
459    * @see addAncestorListener
460    */
461   public void removeAncestorListener(AncestorListener listener)
462   {
463     listenerList.remove(AncestorListener.class, listener);
464   }
465
466   /**
467    * Unregister a <code>PropertyChangeListener</code>.
468    *
469    * @param listener The listener to register
470    *
471    * @see #addPropertyChangeListener
472    * @see #changeSupport
473    */
474   public void removePropertyChangeListener(PropertyChangeListener listener)
475   {
476     if (changeSupport != null)
477       changeSupport.removePropertyChangeListener(listener);
478   }
479
480   /**
481    * Unregister a <code>PropertyChangeListener</code>.
482    *
483    * @param propertyName The property name to unregister the listener from
484    * @param listener The listener to unregister
485    *
486    * @see #addPropertyChangeListener
487    * @see #changeSupport
488    */
489   public void removePropertyChangeListener(String propertyName,
490                                            PropertyChangeListener listener)
491   {
492     if (changeSupport != null)
493       changeSupport.removePropertyChangeListener(propertyName, listener);
494   }
495
496   /**
497    * Unregister a <code>VetoableChangeChangeListener</code>.
498    *
499    * @param listener The listener to unregister
500    *
501    * @see #addVetoableChangeListener
502    */
503   public void removeVetoableChangeListener(VetoableChangeListener listener)
504   {
505     listenerList.remove(VetoableChangeListener.class, listener);
506   }
507
508   /**
509    * Register an <code>AncestorListener</code>.
510    *
511    * @param listener The listener to register
512    *
513    * @see #removeVetoableChangeListener
514    */
515   public void addAncestorListener(AncestorListener listener)
516   {
517     listenerList.add(AncestorListener.class, listener);
518   }
519
520   /**
521    * Register a <code>PropertyChangeListener</code>. This listener will
522    * receive any PropertyChangeEvent, regardless of property name. To
523    * listen to a specific property name, use {@link
524    * #addPropertyChangeListener(String,PropertyChangeListener)} instead.
525    *
526    * @param listener The listener to register
527    *
528    * @see #removePropertyChangeListener
529    * @see #changeSupport
530    */
531   public void addPropertyChangeListener(PropertyChangeListener listener)
532   {
533     if (changeSupport == null)
534       changeSupport = new SwingPropertyChangeSupport(this);
535     changeSupport.addPropertyChangeListener(listener);
536   }
537
538   /**
539    * Register a <code>PropertyChangeListener</code> for a specific, named
540    * property. To listen to all property changes, regardless of name, use
541    * {@link #addPropertyChangeListener(PropertyChangeListener)} instead.
542    *
543    * @param propertyName The property name to listen to
544    * @param listener The listener to register
545    *
546    * @see #removePropertyChangeListener
547    * @see #changeSupport
548    */
549   public void addPropertyChangeListener(String propertyName,
550                                         PropertyChangeListener listener)
551   {
552     listenerList.add(PropertyChangeListener.class, listener);
553   }
554
555   /**
556    * Register a <code>VetoableChangeListener</code>.
557    *
558    * @param listener The listener to register
559    *
560    * @see #removeVetoableChangeListener
561    * @see #listenerList
562    */
563   public void addVetoableChangeListener(VetoableChangeListener listener)
564   {
565     listenerList.add(VetoableChangeListener.class, listener);
566   }
567
568   /**
569    * Return all registered listeners of a particular type.
570    *
571    * @param listenerType The type of listener to return
572    *
573    * @return All listeners in the {@link #listenerList} which 
574    * are of the specified type
575    *
576    * @see #listenerList
577    */
578   public EventListener[] getListeners(Class listenerType)
579   {
580     return listenerList.getListeners(listenerType);
581   }
582
583   /**
584    * Return all registered <code>AncestorListener</code> objects.
585    *
586    * @return The set of <code>AncestorListener</code> objects in {@link
587    * #listenerList}
588    */
589   public AncestorListener[] getAncestorListeners()
590   {
591     return (AncestorListener[]) getListeners(AncestorListener.class);
592   }
593
594   /**
595    * Return all registered <code>VetoableChangeListener</code> objects.
596    *
597    * @return The set of <code>VetoableChangeListener</code> objects in {@link
598    * #listenerList}
599    */
600   public VetoableChangeListener[] getVetoableChangeListeners()
601   {
602     return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class);
603   }
604
605   /**
606    * Return all <code>PropertyChangeListener</code> objects registered to listen
607    * for a particular property.
608    *
609    * @param property The property to return the listeners of
610    *
611    * @return The set of <code>PropertyChangeListener</code> objects in 
612    * {@link #changeSupport} registered to listen on the specified propert
613    */
614   public PropertyChangeListener[] getPropertyChangeListeners(String property)
615   {
616     return changeSupport == null ? new PropertyChangeListener[0]
617                                  : changeSupport.getPropertyChangeListeners(property);
618   }
619
620   /**
621    * A variant of {@link #firePropertyChange(String,Object,Object)} 
622    * for properties with <code>boolean</code> values.
623    */
624   public void firePropertyChange(String propertyName, boolean oldValue,
625                                  boolean newValue)
626   {
627     if (changeSupport != null)
628       changeSupport.firePropertyChange(propertyName, Boolean.valueOf(oldValue),
629                                        Boolean.valueOf(newValue));
630   }
631
632   /**
633    * A variant of {@link #firePropertyChange(String,Object,Object)} 
634    * for properties with <code>byte</code> values.
635    */
636   public void firePropertyChange(String propertyName, byte oldValue,
637                                  byte newValue)
638   {
639     if (changeSupport != null)
640       changeSupport.firePropertyChange(propertyName, new Byte(oldValue),
641                                        new Byte(newValue));
642   }
643
644   /**
645    * A variant of {@link #firePropertyChange(String,Object,Object)} 
646    * for properties with <code>char</code> values.
647    */
648   public void firePropertyChange(String propertyName, char oldValue,
649                                  char newValue)
650   {
651     if (changeSupport != null)
652       changeSupport.firePropertyChange(propertyName, new Character(oldValue),
653                                        new Character(newValue));
654   }
655
656   /**
657    * A variant of {@link #firePropertyChange(String,Object,Object)} 
658    * for properties with <code>double</code> values.
659    */
660   public void firePropertyChange(String propertyName, double oldValue,
661                                  double newValue)
662   {
663     if (changeSupport != null)
664       changeSupport.firePropertyChange(propertyName, new Double(oldValue),
665                                        new Double(newValue));
666   }
667
668   /**
669    * A variant of {@link #firePropertyChange(String,Object,Object)} 
670    * for properties with <code>float</code> values.
671    */
672   public void firePropertyChange(String propertyName, float oldValue,
673                                  float newValue)
674   {
675     if (changeSupport != null)
676       changeSupport.firePropertyChange(propertyName, new Float(oldValue),
677                                        new Float(newValue));
678   }
679
680   /**
681    * A variant of {@link #firePropertyChange(String,Object,Object)} 
682    * for properties with <code>int</code> values.
683    */
684   public void firePropertyChange(String propertyName, int oldValue,
685                                  int newValue)
686   {
687     if (changeSupport != null)
688       changeSupport.firePropertyChange(propertyName, new Integer(oldValue),
689                                        new Integer(newValue));
690   }
691
692   /**
693    * A variant of {@link #firePropertyChange(String,Object,Object)} 
694    * for properties with <code>long</code> values.
695    */
696   public void firePropertyChange(String propertyName, long oldValue,
697                                  long newValue)
698   {
699     if (changeSupport != null)
700       changeSupport.firePropertyChange(propertyName, new Long(oldValue),
701                                        new Long(newValue));
702   }
703
704   /**
705    * Call {@link PropertyChangeListener#propertyChange} on all listeners
706    * registered to listen to a given property. Any method which changes
707    * the specified property of this component should call this method.
708    *
709    * @param propertyName The property which changed
710    * @param oldValue The old value of the property
711    * @param newValue The new value of the property
712    *
713    * @see #changeSupport
714    * @see #addPropertyChangeListener
715    * @see #removePropertyChangeListener
716    */
717   protected void firePropertyChange(String propertyName, Object oldValue,
718                                     Object newValue)
719   {
720     if (changeSupport != null)
721       changeSupport.firePropertyChange(propertyName, oldValue, newValue);
722   }
723
724   /**
725    * A variant of {@link #firePropertyChange(String,Object,Object)} 
726    * for properties with <code>short</code> values.
727    */
728   public void firePropertyChange(String propertyName, short oldValue,
729                                  short newValue)
730   {
731     if (changeSupport != null)
732       changeSupport.firePropertyChange(propertyName, new Short(oldValue),
733                                        new Short(newValue));
734   }
735
736   /**
737    * Call {@link VetoableChangeListener#vetoableChange} on all listeners
738    * registered to listen to a given property. Any method which changes
739    * the specified property of this component should call this method.
740    *
741    * @param propertyName The property which changed
742    * @param oldValue The old value of the property
743    * @param newValue The new value of the property
744    *
745    * @throws PropertyVetoException if the change was vetoed by a listener
746    *
747    * @see addVetoableChangeListener
748    * @see removeVetoableChangeListener
749    */
750   protected void fireVetoableChange(String propertyName, Object oldValue,
751                                     Object newValue)
752     throws PropertyVetoException
753   {
754     VetoableChangeListener[] listeners = getVetoableChangeListeners();
755     
756     PropertyChangeEvent evt = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
757     
758     for (int i = 0; i < listeners.length; i++)
759       listeners[i].vetoableChange(evt);
760   }
761
762   /**
763    * Get the value of the accessibleContext property for this component.
764    *
765    * @return the current value of the property
766    */
767   public AccessibleContext getAccessibleContext()
768   {
769     return null;
770   }
771
772
773   /**
774    * Get the value of the {@link #alignmentX} property.
775    *
776    * @return The current value of the property.
777    *
778    * @see #setAlignmentX
779    * @see #alignmentY
780    */
781   public float getAlignmentX()
782   {
783     return alignmentX;
784   }
785
786   /**
787    * Get the value of the {@link #alignmentY} property.
788    *
789    * @return The current value of the property.
790    *
791    * @see #setAlignmentY
792    * @see #alignmentX
793    */
794   public float getAlignmentY()
795   {
796     return alignmentY;
797   }
798
799   /**
800    * Get the current value of the {@link #autoscrolls} property.
801    *
802    * @return The current value of the property
803    */
804   public boolean getAutoscrolls()
805   {
806     return autoscrolls;
807   }
808
809   /**
810    * Set the value of the {@link #border} property, revalidate
811    * and repaint this component.
812    *   
813    * @param newBorder The new value of the property
814    *
815    * @see #getBorder
816    */
817   public void setBorder(Border newBorder)
818   {
819     Border oldBorder = border;
820     border = newBorder;
821     firePropertyChange("border", oldBorder, newBorder);
822     revalidate();
823     repaint();
824   }
825
826   /**
827    * Get the value of the {@link #border} property.
828    *
829    * @return The property's current value
830    *
831    * @see #setBorder
832    */
833   public Border getBorder()
834   {
835     return border;
836   }
837
838   /**
839    * Get the component's current bounding box. If a rectangle is provided,
840    * use this as the return value (adjusting its fields in place);
841    * otherwise (of <code>null</code> is provided) return a new {@link
842    * Rectangle}.
843    *
844    * @param rv Optional return value to use
845    *
846    * @return A rectangle bounding the component
847    */
848   public Rectangle getBounds(Rectangle rv)
849   {
850     if (rv == null)
851       return new Rectangle(getX(), getY(), getWidth(), getHeight());
852     else
853       {
854         rv.setBounds(getX(), getY(), getWidth(), getHeight());
855         return rv;
856       }
857   }
858
859   /**
860    * Prepares a graphics context for painting this object. If {@link
861    * #debugGraphicsOptions} is not equal to {@link
862    * DebugGraphics#NONE_OPTION}, produce a new {@link DebugGraphics} object
863    * wrapping the parameter. Otherwise configure the parameter with this
864    * component's foreground color and font.
865    *
866    * @param g The graphics context to wrap or configure
867    *
868    * @return A graphics context to paint this object with
869    *
870    * @see #debugGraphicsOptions
871    * @see #paint
872    */
873   protected Graphics getComponentGraphics(Graphics g)
874   {    
875     Graphics g2 = g.create();
876     g2.setFont(this.getFont());
877     g2.setColor(this.getForeground());
878     return g2;
879   }
880
881
882   /**
883    * Get the value of the {@link #debugGraphicsOptions} property.
884    *
885    * @return The current value of the property.
886    *
887    * @see #setDebugGraphicsOptions
888    * @see #debugGraphicsOptions
889    */
890   public int getDebugGraphicsOptions()
891   {
892     return 0;
893   }
894
895   /**
896    * Get the component's insets, which are calculated from
897    * the {@link #border} property. If the border is <code>null</code>,
898    * calls {@link Container#getInsets}.
899    *
900    * @return The component's current insets
901    */
902   public Insets getInsets()
903   {
904     if (border == null)
905       return super.getInsets();
906     return getBorder().getBorderInsets(this);
907   }
908
909   /**
910    * Get the component's insets, which are calculated from the {@link
911    * #border} property. If the border is <code>null</code>, calls {@link
912    * Container#getInsets}. The passed-in {@link Insets} value will be
913    * used as the return value, if possible.
914    *
915    * @param insets Return value object to reuse, if possible
916    *
917    * @return The component's current insets
918    */
919   public Insets getInsets(Insets insets)
920   {
921     Insets t = getInsets();
922
923     if (insets == null)
924       return t;
925
926     insets.left = t.left;
927     insets.right = t.right;
928     insets.top = t.top;
929     insets.bottom = t.bottom;
930     return insets;
931   }
932
933   /**
934    * Get the component's location. The passed-in {@link Point} value
935    * will be used as the return value, if possible.
936    *
937    * @param rv Return value object to reuse, if possible
938    *
939    * @return The component's current location
940    */
941   public Point getLocation(Point rv)
942   {
943     if (rv == null)
944       return new Point(getX(), getY());
945
946     rv.setLocation(getX(), getY());
947     return rv;
948   }
949
950   /**
951    * Get the component's maximum size. If the {@link #maximumSize} property
952    * has been explicitly set, it is returned. If the {@link #maximumSize}
953    * property has not been set but the {@link ui} property has been, the
954    * result of {@link ComponentUI#getMaximumSize} is returned. If neither
955    * property has been set, the result of {@link Container#getMaximumSize}
956    * is returned.
957    *
958    * @return The maximum size of the component
959    *
960    * @see #maximumSize
961    * @see #setMaximumSize
962    */
963   public Dimension getMaximumSize()
964   {
965     if (maximumSize != null)
966       return maximumSize;
967
968     if (ui != null)
969       {
970         Dimension s = ui.getMaximumSize(this);
971         if (s != null)
972           return s;
973       }
974
975     Dimension p = super.getMaximumSize();
976     return p;
977   }
978
979   /**
980    * Get the component's minimum size. If the {@link #minimumSize} property
981    * has been explicitly set, it is returned. If the {@link #minimumSize}
982    * property has not been set but the {@link ui} property has been, the
983    * result of {@link ComponentUI#getMinimumSize} is returned. If neither
984    * property has been set, the result of {@link Container#getMinimumSize}
985    * is returned.
986    *
987    * @return The minimum size of the component
988    *
989    * @see #minimumSize
990    * @see #setMinimumSize
991    */
992   public Dimension getMinimumSize()
993   {
994     if (minimumSize != null)
995       return minimumSize;
996
997     if (ui != null)
998       {
999         Dimension s = ui.getMinimumSize(this);
1000         if (s != null)
1001           return s;
1002       }
1003
1004     Dimension p = super.getMinimumSize();
1005     return p;
1006   }
1007
1008   /**
1009    * Get the component's preferred size. If the {@link #preferredSize}
1010    * property has been explicitly set, it is returned. If the {@link
1011    * #preferredSize} property has not been set but the {@link ui} property
1012    * has been, the result of {@link ComponentUI#getPreferredSize} is
1013    * returned. If neither property has been set, the result of {@link
1014    * Container#getPreferredSize} is returned.
1015    *
1016    * @return The preferred size of the component
1017    *
1018    * @see #preferredSize
1019    * @see #setPreferredSize
1020    */
1021   public Dimension getPreferredSize()
1022   {
1023     if (preferredSize != null)
1024       return preferredSize;
1025
1026     if (ui != null)
1027       {
1028         Dimension s = ui.getPreferredSize(this);
1029         if (s != null)
1030           return s;
1031       }
1032     Dimension p = super.getPreferredSize();
1033     return p;
1034   }
1035
1036   /**
1037    * Checks if a maximum size was explicitely set on the component.
1038    *
1039    * @return <code>true</code> if a maximum size was set,
1040    * <code>false</code> otherwise
1041    * 
1042    * @since 1.3
1043    */
1044   public boolean isMaximumSizeSet()
1045   {
1046     return maximumSize != null;
1047   }
1048
1049   /**
1050    * Checks if a minimum size was explicitely set on the component.
1051    *
1052    * @return <code>true</code> if a minimum size was set,
1053    * <code>false</code> otherwise
1054    * 
1055    * @since 1.3
1056    */
1057   public boolean isMinimumSizeSet()
1058   {
1059     return minimumSize != null;
1060   }
1061
1062   /**
1063    * Checks if a preferred size was explicitely set on the component.
1064    *
1065    * @return <code>true</code> if a preferred size was set,
1066    * <code>false</code> otherwise
1067    * 
1068    * @since 1.3
1069    */
1070   public boolean isPreferredSizeSet()
1071   {
1072     return preferredSize != null;
1073   }
1074   
1075   /**
1076    * Return the value of the {@link #nextFocusableComponent} property.
1077    *
1078    * @return The current value of the property, or <code>null</code>
1079    * if none has been set.
1080    * 
1081    * @deprecated See {@link java.awt.FocusTraversalPolicy}
1082    */
1083   public Component getNextFocusableComponent()
1084   {
1085     return null;
1086   }
1087
1088   /**
1089    * Return the set of {@link KeyStroke} objects which are registered
1090    * to initiate actions on this component.
1091    *
1092    * @return An array of the registered keystrokes
1093    */
1094   public KeyStroke[] getRegisteredKeyStrokes()
1095   {
1096     return null;
1097   }
1098
1099   /**
1100    * Returns the first ancestor of this component which is a {@link JRootPane}.
1101    * Equivalent to calling <code>SwingUtilities.getRootPane(this);</code>.
1102    *
1103    * @return An ancestral JRootPane, or <code>null</code> if none exists.
1104    */
1105   public JRootPane getRootPane()
1106   {
1107     JRootPane p = SwingUtilities.getRootPane(this);
1108     return p;
1109   }
1110
1111   /**
1112    * Get the component's size. The passed-in {@link Dimension} value
1113    * will be used as the return value, if possible.
1114    *
1115    * @param rv Return value object to reuse, if possible
1116    *
1117    * @return The component's current size
1118    */
1119   public Dimension getSize(Dimension rv)
1120   {
1121     if (rv == null)
1122       return new Dimension(getWidth(), getHeight());
1123     else
1124       {
1125         rv.setSize(getWidth(), getHeight());
1126         return rv;
1127       }
1128   }
1129
1130   /**
1131    * Return the {@link #toolTip} property of this component, creating it and
1132    * setting it if it is currently <code>null</code>. This method can be
1133    * overridden in subclasses which wish to control the exact form of
1134    * tooltip created.
1135    *
1136    * @return The current toolTip
1137    */
1138   public JToolTip createToolTip()
1139   {
1140         JToolTip toolTip = new JToolTip();
1141         toolTip.setComponent(this);
1142         toolTip.setTipText(toolTipText);
1143     
1144     return toolTip;
1145   }
1146
1147   /**
1148    * Return the location at which the {@link #toolTip} property should be
1149    * displayed, when triggered by a particular mouse event. 
1150    *
1151    * @param event The event the tooltip is being presented in response to
1152    *
1153    * @return The point at which to display a tooltip, or <code>null</code>
1154    * if swing is to choose a default location.
1155    */
1156   public Point getToolTipLocation(MouseEvent event)
1157   {
1158     return null;
1159   }
1160
1161   /**
1162    * Set the value of the {@link #toolTipText} property.
1163    *
1164    * @param text The new property value
1165    *
1166    * @see #getToolTipText
1167    */
1168   public void setToolTipText(String text)
1169   {
1170     if (text == null)
1171     {
1172       ToolTipManager.sharedInstance().unregisterComponent(this);
1173       toolTipText = null;
1174       return;
1175     }
1176                 
1177     // XXX: The tip text doesn't get updated unless you set it to null
1178     // and then to something not-null. This is consistent with the behaviour
1179     // of Sun's ToolTipManager.
1180                         
1181     String oldText = toolTipText;
1182     toolTipText = text;
1183                 
1184     if (oldText == null)
1185       ToolTipManager.sharedInstance().registerComponent(this);
1186   }
1187
1188   /**
1189    * Get the value of the {@link #toolTipText} property.
1190    *
1191    * @return The current property value
1192    *
1193    * @see #setToolTipText
1194    */
1195   public String getToolTipText()
1196   {
1197     return toolTipText;
1198   }
1199
1200   /**
1201    * Get the value of the {@link #toolTipText} property, in response to a
1202    * particular mouse event.
1203    *
1204    * @param event The mouse event which triggered the tooltip
1205    *
1206    * @return The current property value
1207    *
1208    * @see #setToolTipText
1209    */
1210   public String getToolTipText(MouseEvent event)
1211   {
1212     return getToolTipText();
1213   }
1214
1215   /**
1216    * Return the top level ancestral container (usually a {@link
1217    * java.awt.Window} or {@link java.awt.Applet}) which this component is
1218    * contained within, or <code>null</code> if no ancestors exist.
1219    *
1220    * @return The top level container, if it exists
1221    */
1222   public Container getTopLevelAncestor()
1223   {
1224     Container c = getParent();
1225     for (Container peek = c; peek != null; peek = peek.getParent())
1226       c = peek;
1227     return c;
1228   }
1229
1230   /**
1231    * Compute the component's visible rectangle, which is defined
1232    * recursively as either the component's bounds, if it has no parent, or
1233    * the intersection of the component's bounds with the visible rectangle
1234    * of its parent.
1235    *
1236    * @param rect The return value slot to place the visible rectangle in
1237    */
1238   public void computeVisibleRect(Rectangle rect)
1239   {
1240     Component c = getParent();
1241     if (c != null && c instanceof JComponent)
1242       {
1243         ((JComponent) c).computeVisibleRect(rect);
1244         rect.translate(-getX(), -getY());
1245         Rectangle2D.intersect(rect,
1246                               new Rectangle(0, 0, getWidth(), getHeight()),
1247                               rect);
1248       }
1249     else
1250       rect.setRect(0, 0, getWidth(), getHeight());
1251   }
1252
1253   /**
1254    * Return the component's visible rectangle in a new {@link Rectangle},
1255    * rather than via a return slot.
1256    *
1257    * @return The component's visible rectangle
1258    *
1259    * @see #computeVisibleRect(Rectangle)
1260    */
1261   public Rectangle getVisibleRect()
1262   {
1263     Rectangle r = new Rectangle();
1264     computeVisibleRect(r);
1265     return r;
1266   }
1267
1268   /**
1269    * <p>Requests that this component receive input focus, giving window
1270    * focus to the top level ancestor of this component. Only works on
1271    * displayable, focusable, visible components.</p>
1272    *
1273    * <p>This method should not be called by clients; it is intended for
1274    * focus implementations. Use {@link Component#requestFocus} instead.</p>
1275    *
1276    * @see {@link Component#requestFocus}
1277    */
1278   public void grabFocus()
1279   {
1280   }
1281
1282   /**
1283    * Get the value of the {@link #doubleBuffered} property.
1284    *
1285    * @return The property's current value
1286    */
1287   public boolean isDoubleBuffered()
1288   {
1289     return doubleBuffered;
1290   }
1291
1292   /**
1293    * Return <code>true</code> if the provided component has no native peer;
1294    * in other words, if it is a "lightweight component".
1295    *
1296    * @param c The component to test for lightweight-ness
1297    *
1298    * @return Whether or not the component is lightweight
1299    */
1300   public static boolean isLightweightComponent(Component c)
1301   {
1302     return c.getPeer() instanceof LightweightPeer;
1303   }
1304
1305   /**
1306    * Return <code>true</code> if you wish this component to manage its own
1307    * focus. In particular: if you want this component to be sent
1308    * <code>TAB</code> and <code>SHIFT+TAB</code> key events, and to not
1309    * have its children considered as focus transfer targets. If
1310    * <code>true</code>, focus traversal around this component changes to
1311    * <code>CTRL+TAB</code> and <code>CTRL+SHIFT+TAB</code>.
1312    *
1313    * @return <code>true</code> if you want this component to manage its own
1314    * focus, otherwise (by default) <code>false</code>
1315    *
1316    * @deprecated 1.4 Use {@link Component.setFocusTraversalKeys(int,Set)} and
1317    * {@link Container.setFocusCycleRoot(boolean)} instead
1318    */
1319   public boolean isManagingFocus()
1320   {
1321     return false;
1322   }
1323
1324   /**
1325    * Return the current value of the {@link opaque} property. 
1326    *
1327    * @return The current property value
1328    */
1329   public boolean isOpaque()
1330   {
1331     return opaque;
1332   }
1333
1334   /**
1335    * Return <code>true</code> if the component can guarantee that none of its
1336    * children will overlap in Z-order. This is a hint to the painting system.
1337    * The default is to return <code>true</code>, but some components such as
1338    * {@link JLayeredPane} should override this to return <code>false</code>.
1339    *
1340    * @return Whether the component tiles its children
1341    */
1342   public boolean isOptimizedDrawingEnabled()
1343   {
1344     return true;
1345   }
1346
1347   /**
1348    * Return <code>true</code> if this component is currently painting a tile.
1349    *
1350    * @return Whether the component is painting a tile
1351    */
1352   public boolean isPaintingTile()
1353   {
1354     return false;
1355   }
1356
1357   /**
1358    * Get the value of the {@link #requestFocusEnabled} property.
1359    *
1360    * @return The current value of the property
1361    */
1362   public boolean isRequestFocusEnabled()
1363   {
1364     return requestFocusEnabled;
1365   }
1366
1367   /**
1368    * Return <code>true</code> if this component is a validation root; this
1369    * will cause calls to {@link #invalidate} in this component's children
1370    * to be "captured" at this component, and not propagate to its parents.
1371    * For most components this should return <code>false</code>, but some
1372    * components such as {@link JViewPort} will want to return
1373    * <code>true</code>.
1374    *
1375    * @return Whether this component is a validation root
1376    */
1377   public boolean isValidateRoot()
1378   {
1379     return false;
1380   }
1381
1382   /**
1383    * <p>Paint the component. This is a delicate process, and should only be
1384    * called from the repaint thread, under control of the {@link
1385    * RepaintManager}. Client code should usually call {@link #repaint} to
1386    * trigger painting.</p>
1387    *
1388    * <p>This method will acquire a double buffer from the {@link
1389    * RepaintManager} if the component's {@link #doubleBuffered} property is
1390    * <code>true</code> and the <code>paint</code> call is the
1391    * <em>first</em> recursive <code>paint</code> call inside swing.</p>
1392    *
1393    * <p>The method will also modify the provided {@link Graphics} context
1394    * via the {@link #getComponentGraphics} method. If you want to customize
1395    * the graphics object used for painting, you should override that method
1396    * rather than <code>paint</code>.</p>
1397    *
1398    * <p>The body of the <code>paint</code> call involves calling {@link
1399    * #paintComponent}, {@link #paintBorder}, and {@link #paintChildren} in
1400    * order. If you want to customize painting behavior, you should override
1401    * one of these methods rather than <code>paint</code>.</p>
1402    *
1403    * <p>For more details on the painting sequence, see <a
1404    * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this
1405    * article</a>.</p>
1406    *
1407    * @param g The graphics context to paint with
1408    *
1409    * @see #paintImmediately
1410    */
1411   public void paint(Graphics g)
1412   {
1413     Graphics g2 = g;
1414     Image doubleBuffer = null;
1415     RepaintManager rm = RepaintManager.currentManager(this);
1416
1417     if (isDoubleBuffered()
1418         && (rm.isDoubleBufferingEnabled())
1419         && (! Thread.holdsLock(paintLock)))
1420       {
1421         doubleBuffer = rm.getOffscreenBuffer(this, getWidth(), getHeight());
1422       }
1423
1424     synchronized (paintLock)
1425       {
1426         if (doubleBuffer != null)
1427           {
1428             g2 = doubleBuffer.getGraphics();
1429             g2.setClip(g.getClipBounds());
1430           }
1431           
1432         g2 = getComponentGraphics(g2);
1433         paintComponent(g2);
1434         paintBorder(g2);
1435         paintChildren(g2);
1436         
1437         if (doubleBuffer != null)
1438           g.drawImage(doubleBuffer, 0, 0, (ImageObserver) null);
1439       }
1440   }
1441
1442   /**
1443    * Paint the component's border. This usually means calling {@link
1444    * Border#paintBorder} on the {@link #border} property, if it is
1445    * non-<code>null</code>. You may override this if you wish to customize
1446    * border painting behavior. The border is painted after the component's
1447    * body, but before the component's children.
1448    *
1449    * @param g The graphics context with which to paint the border
1450    *
1451    * @see #paint
1452    * @see #paintChildren
1453    * @see #paintComponent
1454    */
1455   protected void paintBorder(Graphics g)
1456   {
1457     if (getBorder() != null)
1458       getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight());
1459   }
1460
1461   /**
1462    * Paint the component's children. This usually means calling {@link
1463    * Container#paint}, which recursively calls {@link #paint} on any of the
1464    * component's children, with appropriate changes to coordinate space and
1465    * clipping region. You may override this if you wish to customize
1466    * children painting behavior. The children are painted after the
1467    * component's body and border.
1468    *
1469    * @param g The graphics context with which to paint the children
1470    *
1471    * @see #paint
1472    * @see #paintBorder
1473    * @see #paintComponent
1474    */
1475   protected void paintChildren(Graphics g)
1476   {
1477     super.paint(g);
1478   }
1479
1480   /**
1481    * Paint the component's body. This usually means calling {@link
1482    * ComponentUI#update} on the {@link #ui} property of the component, if
1483    * it is non-<code>null</code>. You may override this if you wish to
1484    * customize the component's body-painting behavior. The component's body
1485    * is painted first, before the border and children.
1486    *
1487    * @param g The graphics context with which to paint the body
1488    *
1489    * @see #paint
1490    * @see #paintBorder
1491    * @see #paintChildren
1492    */
1493   protected void paintComponent(Graphics g)
1494   {
1495     if (ui != null)
1496       ui.update(g, this);
1497   }
1498
1499   /**
1500    * A variant of {@link #paintImmediately(Rectangle)} which takes
1501    * integer parameters.
1502    *
1503    * @param x The left x coordinate of the dirty region
1504    * @param y The top y coordinate of the dirty region
1505    * @param w The width of the dirty region
1506    * @param h The height of the dirty region
1507    */
1508   public void paintImmediately(int x, int y, int w, int h)
1509   {
1510     paintImmediately(new Rectangle(x, y, w, h));
1511   }
1512
1513   /**
1514    * Transform the provided dirty rectangle for this component into the
1515    * appropriate ancestral {@link JRootPane} and call {@link #paint} on
1516    * that root pane. This method is called from the {@link RepaintManager}
1517    * and should always be called within the painting thread.
1518    *
1519    * @param r The dirty rectangle to paint
1520    */
1521   public void paintImmediately(Rectangle r)
1522   {
1523     Component root = SwingUtilities.getRoot(this);
1524     if (root == null || ! root.isShowing())
1525       return;
1526     Graphics g = root.getGraphics();
1527     if (g == null)
1528       return;
1529
1530     Rectangle clip = SwingUtilities.convertRectangle(this, r, root);
1531     g.setClip(clip);
1532     root.paint(g);
1533     g.dispose();
1534   }
1535
1536   /**
1537    * Return a string representation for this component, for use in
1538    * debugging.
1539    *
1540    * @return A string describing this component.
1541    */
1542   protected String paramString()
1543   {
1544     StringBuffer sb = new StringBuffer();
1545     sb.append(super.paramString());
1546     sb.append(",alignmentX=").append(getAlignmentX());
1547     sb.append(",alignmentY=").append(getAlignmentY());
1548     sb.append(",border=");
1549     if (getBorder() != null)
1550       sb.append(getBorder());
1551     sb.append(",maximumSize=");
1552     if (getMaximumSize() != null)
1553       sb.append(getMaximumSize());
1554     sb.append(",minimumSize=");
1555     if (getMinimumSize() != null)
1556       sb.append(getMinimumSize());
1557     sb.append(",preferredSize=");
1558     if (getPreferredSize() != null)
1559       sb.append(getPreferredSize());
1560     return sb.toString();
1561   }
1562
1563   /**
1564    * A variant of {@link
1565    * #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which
1566    * provides <code>null</code> for the command name.   
1567    */
1568   public void registerKeyboardAction(ActionListener act,
1569                                      KeyStroke stroke, 
1570                                      int cond)
1571   {
1572     registerKeyboardAction(act, null, stroke, cond);
1573   }
1574
1575   /* 
1576    * There is some charmingly undocumented behavior sun seems to be using
1577    * to simulate the old register/unregister keyboard binding API. It's not
1578    * clear to me why this matters, but we shall endeavour to follow suit.
1579    *
1580    * Two main thing seem to be happening when you do registerKeyboardAction():
1581    * 
1582    *  - no actionMap() entry gets created, just an entry in inputMap()
1583    *
1584    *  - the inputMap() entry is a proxy class which invokes the the
1585    *  binding's actionListener as a target, and which clobbers the command
1586    *  name sent in the ActionEvent, providing the binding command name
1587    *  instead.
1588    *
1589    * This much you can work out just by asking the input and action maps
1590    * what they contain after making bindings, and watching the event which
1591    * gets delivered to the recipient. Beyond that, it seems to be a
1592    * sun-private solution so I will only immitate it as much as it matters
1593    * to external observers.
1594    */
1595
1596   private static class ActionListenerProxy
1597     extends AbstractAction
1598   {
1599     ActionListener target;
1600     String bindingCommandName;
1601
1602     public ActionListenerProxy(ActionListener li, 
1603                                String cmd)
1604     {
1605       target = li;
1606       bindingCommandName = cmd;
1607     }
1608
1609     public void actionPerformed(ActionEvent e)
1610     {
1611       ActionEvent derivedEvent = new ActionEvent(e.getSource(),
1612                                                  e.getID(),
1613                                                  bindingCommandName,
1614                                                  e.getModifiers());
1615       target.actionPerformed(derivedEvent);
1616     }
1617   }
1618
1619   
1620   /**
1621    * An obsolete method to register a keyboard action on this component.
1622    * You should use <code>getInputMap</code> and <code>getActionMap</code>
1623    * to fetch mapping tables from keystrokes to commands, and commands to
1624    * actions, respectively, and modify those mappings directly.
1625    *
1626    * @param anAction The action to be registered
1627    * @param aCommand The command to deliver in the delivered {@link
1628    * java.awt.ActionEvent}
1629    * @param aKeyStroke The keystroke to register on
1630    * @param aCondition One of the values {@link #UNDEFINED_CONDITION},
1631    * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or
1632    * {@link #WHEN_IN_FOCUSED_WINDOW}, indicating the condition which must
1633    * be met for the action to be fired
1634    *
1635    * @see #unregisterKeyboardAction
1636    * @see #getConditionForKeystroke
1637    * @see #resetKeyboardActiond
1638    */
1639   public void registerKeyboardAction(ActionListener act, 
1640                                      String cmd,
1641                                      KeyStroke stroke, 
1642                                      int cond)
1643   {
1644     getInputMap(cond).put(stroke, new ActionListenerProxy(act, cmd));
1645   }
1646
1647
1648
1649   public final void setInputMap(int condition, InputMap map)
1650   {
1651     enableEvents(AWTEvent.KEY_EVENT_MASK);
1652     switch (condition)
1653       {
1654       case WHEN_FOCUSED:
1655         inputMap_whenFocused = map;
1656         break;
1657
1658       case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
1659         inputMap_whenAncestorOfFocused = map;
1660         break;
1661
1662       case WHEN_IN_FOCUSED_WINDOW:
1663         inputMap_whenInFocusedWindow = map;
1664         break;
1665         
1666       case UNDEFINED_CONDITION:
1667       default:
1668         throw new IllegalArgumentException();
1669       }
1670   }
1671
1672   public final InputMap getInputMap(int condition)
1673   {
1674     enableEvents(AWTEvent.KEY_EVENT_MASK);
1675     switch (condition)
1676       {
1677       case WHEN_FOCUSED:
1678         if (inputMap_whenFocused == null)
1679           inputMap_whenFocused = new InputMap();
1680         return inputMap_whenFocused;
1681
1682       case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
1683         if (inputMap_whenAncestorOfFocused == null)
1684           inputMap_whenAncestorOfFocused = new InputMap();
1685         return inputMap_whenAncestorOfFocused;
1686
1687       case WHEN_IN_FOCUSED_WINDOW:
1688         if (inputMap_whenInFocusedWindow == null)
1689           inputMap_whenInFocusedWindow = new InputMap();
1690         return inputMap_whenInFocusedWindow;
1691
1692       case UNDEFINED_CONDITION:
1693       default:
1694         return null;
1695       }
1696   }
1697
1698   public final InputMap getInputMap()
1699   {
1700     return getInputMap(WHEN_FOCUSED);
1701   }
1702
1703   public final ActionMap getActionMap()
1704   {
1705     if (actionMap == null)
1706       actionMap = new ActionMap();
1707     return actionMap;
1708   }
1709
1710   public final void setActionMap(ActionMap map)
1711   {
1712     actionMap = map;
1713   }
1714
1715   /**
1716    * Return the condition that determines whether a registered action
1717    * occurs in response to the specified keystroke.
1718    *
1719    * @param aKeyStroke The keystroke to return the condition of
1720    *
1721    * @return One of the values {@link #UNDEFINED_CONDITION}, {@link
1722    * #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or {@link
1723    * #WHEN_IN_FOCUSED_WINDOW}
1724    *
1725    * @deprecated As of 1.3 KeyStrokes can be registered with multiple
1726    * simultaneous conditions.
1727    *
1728    * @see #registerKeyboardAction   
1729    * @see #unregisterKeyboardAction   
1730    * @see #resetKeyboardActiond
1731    */
1732   public int getConditionForKeyStroke(KeyStroke ks)
1733   {
1734     if (inputMap_whenFocused != null 
1735         && inputMap_whenFocused.get(ks) != null)
1736       return WHEN_FOCUSED;
1737     else if (inputMap_whenAncestorOfFocused != null 
1738              && inputMap_whenAncestorOfFocused.get(ks) != null)
1739       return WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
1740     else if (inputMap_whenInFocusedWindow != null 
1741              && inputMap_whenInFocusedWindow.get(ks) != null)
1742       return WHEN_IN_FOCUSED_WINDOW;
1743     else
1744       return UNDEFINED_CONDITION;
1745   }
1746
1747   /**
1748    * Get the ActionListener (typically an {@link Action} object) which is
1749    * associated with a particular keystroke. 
1750    *
1751    * @param aKeyStroke The keystroke to retrieve the action of
1752    *
1753    * @return The action associated with the specified keystroke
1754    *
1755    * @deprecated Use {@link #getActionMap()}
1756    */
1757   public ActionListener getActionForKeyStroke(KeyStroke ks)
1758   {
1759     Object cmd = getInputMap().get(ks);
1760     if (cmd != null)
1761       {
1762         if (cmd instanceof ActionListenerProxy)
1763           return (ActionListenerProxy) cmd;
1764         else if (cmd instanceof String)
1765           return getActionMap().get(cmd);
1766       }
1767     return null;
1768   }
1769
1770   /**
1771    * A hook for subclasses which want to customize event processing.
1772    */
1773   protected void processComponentKeyEvent(KeyEvent e)
1774   {
1775   }
1776
1777   /**
1778    * Override the default key dispatch system from Component to hook into
1779    * the swing {@link InputMap} / {@link ActionMap} system.
1780    *
1781    * See <a
1782    * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this
1783    * report</a> for more details, it's somewhat complex.
1784    */
1785   protected void processKeyEvent(KeyEvent e)
1786   {
1787     processComponentKeyEvent(e);
1788
1789     // FIXME: this needs to be elaborated significantly, to do all the
1790     // focus / ancestor / window searching for the various binding modes.
1791     if (! e.isConsumed() &&
1792         processKeyBinding(KeyStroke.getKeyStrokeForEvent(e), 
1793                           e, WHEN_FOCUSED, e.getID() == KeyEvent.KEY_PRESSED))
1794       e.consume();
1795   }
1796
1797   protected boolean processKeyBinding(KeyStroke ks,
1798                                       KeyEvent e,
1799                                       int condition,
1800                                       boolean pressed)
1801   { 
1802     if (isEnabled())
1803       {
1804         Action act = null;
1805         InputMap map = getInputMap(condition);
1806         if (map != null)
1807           {
1808             Object cmd = map.get(ks);
1809             if (cmd != null)
1810               {
1811                 if (cmd instanceof ActionListenerProxy)
1812                   act = (Action) cmd;
1813                 else 
1814                   act = (Action) getActionMap().get(cmd);
1815               }
1816           }
1817         if (act != null && act.isEnabled())
1818           return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers());
1819       }
1820     return false;
1821   }
1822   
1823   /**
1824    * Remove a keyboard action registry.
1825    *
1826    * @param stroke The keystroke to unregister
1827    *
1828    * @see #registerKeyboardAction
1829    * @see #getConditionForKeystroke
1830    * @see #resetKeyboardActiond
1831    */
1832   public void unregisterKeyboardAction(KeyStroke aKeyStroke)
1833   {
1834   }
1835
1836
1837   /**
1838    * Reset all keyboard action registries.
1839    *
1840    * @see #registerKeyboardAction
1841    * @see #unregisterKeyboardAction
1842    * @see #getConditionForKeystroke
1843    */
1844   public void resetKeyboardActions()
1845   {
1846     if (inputMap_whenFocused != null)
1847       inputMap_whenFocused.clear();
1848     if (inputMap_whenAncestorOfFocused != null)
1849       inputMap_whenAncestorOfFocused.clear();
1850     if (inputMap_whenInFocusedWindow != null)
1851       inputMap_whenInFocusedWindow.clear();
1852     if (actionMap != null)
1853       actionMap.clear();
1854   }
1855
1856
1857   /**
1858    * Mark the described region of this component as dirty in the current
1859    * {@link RepaintManager}. This will queue an asynchronous repaint using
1860    * the system painting thread in the near future.
1861    *
1862    * @param tm ignored
1863    * @param x coordinate of the region to mark as dirty
1864    * @param y coordinate of the region to mark as dirty
1865    * @param width dimension of the region to mark as dirty
1866    * @param height dimension of the region to mark as dirty
1867    */
1868   public void repaint(long tm, int x, int y, int width, int height)
1869   {
1870     Rectangle dirty = new Rectangle(x, y, width, height);
1871     Rectangle vis = getVisibleRect();
1872     dirty = dirty.intersection(vis);
1873     RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y,
1874                                                        dirty.width,
1875                                                        dirty.height);
1876   }
1877
1878   /**
1879    * Mark the described region of this component as dirty in the current
1880    * {@link RepaintManager}. This will queue an asynchronous repaint using
1881    * the system painting thread in the near future.
1882    *
1883    * @param r The rectangle to mark as dirty
1884    */
1885   public void repaint(Rectangle r)
1886   {
1887     repaint((long) 0, (int) r.getX(), (int) r.getY(), (int) r.getWidth(),
1888             (int) r.getHeight());
1889   }
1890
1891   /**
1892    * Request focus on the default component of this component's {@link
1893    * FocusTraversalPolicy}.
1894    *
1895    * @return The result of {@link #requestFocus}
1896    *
1897    * @deprecated Use {@link #requestFocus()} on the default component provided from
1898    * the {@link FocusTraversalPolicy} instead.
1899    */
1900   public boolean requestDefaultFocus()
1901   {
1902     return false;
1903   }
1904
1905   /**
1906    * Queue a an invalidation and revalidation of this component, using 
1907    * {@link RepaintManager#addInvalidComponent}.
1908    */
1909   public void revalidate()
1910   {
1911     invalidate();
1912     RepaintManager.currentManager(this).addInvalidComponent(this);
1913   }
1914
1915   /**
1916    * Calls <code>scrollRectToVisible</code> on the component's parent. 
1917    * Components which can service this call should override.
1918    *
1919    * @param r The rectangle to make visible
1920    */
1921   public void scrollRectToVisible(Rectangle r)
1922   {
1923     Component p = getParent();
1924     if (p instanceof JComponent)
1925       ((JComponent) p).scrollRectToVisible(r);
1926   }
1927
1928   /**
1929    * Set the value of the {@link #alignmentX} property.
1930    *
1931    * @param a The new value of the property
1932    */
1933   public void setAlignmentX(float a)
1934   {
1935     alignmentX = a;
1936   }
1937
1938   /**
1939    * Set the value of the {@link #alignmentY} property.
1940    *
1941    * @param a The new value of the property
1942    */
1943   public void setAlignmentY(float a)
1944   {
1945     alignmentY = a;
1946   }
1947
1948   /**
1949    * Set the value of the {@link #autoscrolls} property.
1950    *
1951    * @param a The new value of the property
1952    */
1953   public void setAutoscrolls(boolean a)
1954   {
1955     autoscrolls = a;
1956   }
1957
1958   /**
1959    * Set the value of the {@link #debugGraphicsOptions} property.
1960    *
1961    * @param debugOptions The new value of the property
1962    */
1963   public void setDebugGraphicsOptions(int debugOptions)
1964   {
1965     debugGraphicsOptions = debugOptions;
1966   }
1967
1968   /**
1969    * Set the value of the {@link #doubleBuffered} property.
1970    *
1971    * @param db The new value of the property
1972    */
1973   public void setDoubleBuffered(boolean db)
1974   {
1975     doubleBuffered = db;
1976   }
1977
1978   /**
1979    * Set the value of the {@link #enabled} property, revalidate
1980    * and repaint this component.
1981    *
1982    * @param enable The new value of the property
1983    */
1984   public void setEnabled(boolean enable)
1985   {
1986     boolean oldEnabled = isEnabled();
1987     super.setEnabled(enable);
1988     firePropertyChange("enabeld", oldEnabled, enable);
1989     revalidate();
1990     repaint();
1991   }
1992
1993   /**
1994    * Set the value of the {@link #font} property, revalidate
1995    * and repaint this component.
1996    *
1997    * @param f The new value of the property
1998    */
1999   public void setFont(Font f)
2000   {
2001     super.setFont(f);
2002     revalidate();
2003     repaint();
2004   }
2005
2006   /**
2007    * Set the value of the {@link #background} property, revalidate
2008    * and repaint this component.
2009    *
2010    * @param bg The new value of the property
2011    */
2012   public void setBackground(Color bg)
2013   {
2014     super.setBackground(bg);
2015     revalidate();
2016     repaint();
2017   }
2018
2019   /**
2020    * Set the value of the {@link #foreground} property, revalidate
2021    * and repaint this component.
2022    *
2023    * @param fg The new value of the property
2024    */
2025   public void setForeground(Color fg)
2026   {
2027     super.setForeground(fg);
2028     revalidate();
2029     repaint();
2030   }
2031
2032   /**
2033    * Set the value of the {@link #maximumSize} property, revalidate
2034    * and repaint this component.
2035    *
2036    * @param max The new value of the property
2037    */
2038   public void setMaximumSize(Dimension max)
2039   {
2040     Dimension oldMaximumSize = maximumSize;
2041     maximumSize = max;
2042     firePropertyChange("maximumSize", oldMaximumSize, maximumSize);
2043     revalidate();
2044     repaint();
2045   }
2046
2047   /**
2048    * Set the value of the {@link #minimumSize} property, revalidate
2049    * and repaint this component.
2050    *
2051    * @param min The new value of the property
2052    */
2053   public void setMinimumSize(Dimension min)
2054   {
2055     Dimension oldMinimumSize = minimumSize;
2056     minimumSize = min;
2057     firePropertyChange("minimumSize", oldMinimumSize, minimumSize);
2058     revalidate();
2059     repaint();
2060   }
2061
2062   /**
2063    * Set the value of the {@link #preferredSize} property, revalidate
2064    * and repaint this component.
2065    *
2066    * @param pref The new value of the property
2067    */
2068   public void setPreferredSize(Dimension pref)
2069   {
2070     Dimension oldPreferredSize = preferredSize;
2071     preferredSize = pref;
2072     firePropertyChange("preferredSize", oldPreferredSize, preferredSize);
2073   }
2074
2075   /**
2076    * Set the specified component to be the next component in the 
2077    * focus cycle, overriding the {@link FocusTraversalPolicy} for
2078    * this component.
2079    *
2080    * @param aComponent The component to set as the next focusable
2081    *
2082    * @deprecated Use FocusTraversalPolicy instead
2083    */
2084   public void setNextFocusableComponent(Component aComponent)
2085   {
2086   }
2087
2088   /**
2089    * Set the value of the {@link #requestFocusEnabled} property.
2090    *
2091    * @param e The new value of the property
2092    */
2093   public void setRequestFocusEnabled(boolean e)
2094   {
2095     requestFocusEnabled = e;
2096   }
2097
2098   /**
2099    * Get the value of the {@link #transferHandler} property.
2100    *
2101    * @return The current value of the property
2102    *
2103    * @see ComponentUI#setTransferHandler
2104    */
2105
2106   public TransferHandler getTransferHandler()
2107   {
2108     return transferHandler;
2109   }
2110
2111   /**
2112    * Set the value of the {@link #transferHandler} property.
2113    *
2114    * @param newHandler The new value of the property
2115    *
2116    * @see ComponentUI#getTransferHandler
2117    */
2118
2119   public void setTransferHandler(TransferHandler newHandler)
2120   {
2121     if (transferHandler == newHandler)
2122       return;
2123
2124     TransferHandler oldHandler = transferHandler;
2125     transferHandler = newHandler;
2126     firePropertyChange("transferHandler", oldHandler, newHandler);
2127   }
2128
2129   /**
2130    * Set the value of the {@link #opaque} property, revalidate and repaint
2131    * this component.
2132    *
2133    * @param isOpaque The new value of the property
2134    *
2135    * @see ComponentUI#update
2136    */
2137   public void setOpaque(boolean isOpaque)
2138   {
2139     boolean oldOpaque = opaque;
2140     opaque = isOpaque;
2141     firePropertyChange("opaque", oldOpaque, opaque);
2142     revalidate();
2143     repaint();
2144   }
2145
2146   /**
2147    * Set the value of the visible property, and revalidate / repaint the
2148    * component.
2149    *
2150    * @param v The new value of the property
2151    */
2152   public void setVisible(boolean v)
2153   {
2154     super.setVisible(v);
2155     revalidate();
2156     repaint();
2157   }
2158
2159   /**
2160    * Call {@link paint}. 
2161    * 
2162    * @param g The graphics context to paint into
2163    */
2164   public void update(Graphics g)
2165   {
2166     paint(g);
2167   }
2168
2169   /**
2170    * Get the value of the UIClassID property. This property should be a key
2171    * in the {@link UIDefaults} table managed by {@link UIManager}, the
2172    * value of which is the name of a class to load for the component's
2173    * {@link ui} property.
2174    *
2175    * @return A "symbolic" name which will map to a class to use for the
2176    * component's UI, such as <code>"ComponentUI"</code>
2177    *
2178    * @see #setUI
2179    * @see #updateUI
2180    */
2181   public String getUIClassID()
2182   {
2183     return "ComponentUI";
2184   }
2185
2186   /**
2187    * Install a new UI delegate as the component's {@link ui} property. In
2188    * the process, this will call {@link ComponentUI.uninstallUI} on any
2189    * existing value for the {@link ui} property, and {@link
2190    * ComponentUI.installUI} on the new UI delegate.
2191    *
2192    * @param newUI The new UI delegate to install
2193    *
2194    * @see #updateUI
2195    * @see #getUIClassID
2196    */
2197   protected void setUI(ComponentUI newUI)
2198   {
2199     if (ui != null)
2200       ui.uninstallUI(this);
2201
2202     ComponentUI oldUI = ui;
2203     ui = newUI;
2204
2205     if (ui != null)
2206       ui.installUI(this);
2207
2208     firePropertyChange("UI", oldUI, newUI);
2209     
2210     revalidate();
2211     repaint();
2212   }
2213
2214   /**
2215    * This method should be overridden in subclasses. In JComponent, the
2216    * method does nothing. In subclasses, it should a UI delegate
2217    * (corresponding to the symbolic name returned from {@link
2218    * getUIClassID}) from the {@link UIManager}, and calls {@link setUI}
2219    * with the new delegate.
2220    */
2221   public void updateUI()
2222   {
2223     System.out.println("update UI not overwritten in class: " + this);
2224   }
2225
2226   public static Locale getDefaultLocale()
2227   {
2228     return defaultLocale;
2229   }
2230   
2231   public static void setDefaultLocale(Locale l)
2232   {
2233     defaultLocale = l;
2234   }
2235   
2236   /**
2237    * Returns the currently set input verifier for this component.
2238    *
2239    * @return the input verifier, or <code>null</code> if none
2240    */
2241   public InputVerifier getInputVerifier()
2242   {
2243     return inputVerifier;
2244   }
2245
2246   /**
2247    * Sets the input verifier to use by this component.
2248    *
2249    * @param verifier the input verifier, or <code>null</code>
2250    */
2251   public void setInputVerifier(InputVerifier verifier)
2252   {
2253     InputVerifier oldVerifier = inputVerifier;
2254     inputVerifier = verifier;
2255     firePropertyChange("inputVerifier", oldVerifier, verifier);
2256   }
2257
2258   /**
2259    * @since 1.3
2260    */
2261   public boolean getVerifyInputWhenFocusTarget()
2262   {
2263     return verifyInputWhenFocusTarget;
2264   }
2265
2266   /**
2267    * @since 1.3
2268    */
2269   public void setVerifyInputWhenFocusTarget(boolean verifyInputWhenFocusTarget)
2270   {
2271     if (this.verifyInputWhenFocusTarget == verifyInputWhenFocusTarget)
2272       return;
2273
2274     this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget;
2275     firePropertyChange("verifyInputWhenFocusTarget",
2276                        ! verifyInputWhenFocusTarget,
2277                        verifyInputWhenFocusTarget);
2278   }
2279 }