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