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 }