1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing; 26 27 28 import java.util.HashSet; 29 import java.util.Hashtable; 30 import java.util.Dictionary; 31 import java.util.Enumeration; 32 import java.util.Locale; 33 import java.util.Vector; 34 import java.util.EventListener; 35 import java.util.Set; 36 import java.util.Map; 37 import java.util.HashMap; 38 39 import java.awt.*; 40 import java.awt.event.*; 41 import java.awt.image.VolatileImage; 42 import java.awt.Graphics2D; 43 import java.awt.peer.LightweightPeer; 44 import java.awt.dnd.DropTarget; 45 import java.awt.font.FontRenderContext; 46 import java.beans.PropertyChangeListener; 47 import java.beans.VetoableChangeListener; 48 import java.beans.VetoableChangeSupport; 49 import java.beans.Transient; 50 51 import java.applet.Applet; 52 53 import java.io.Serializable; 54 import java.io.ObjectOutputStream; 55 import java.io.ObjectInputStream; 56 import java.io.IOException; 57 import java.io.ObjectInputValidation; 58 import java.io.InvalidObjectException; 59 60 import javax.swing.border.*; 61 import javax.swing.event.*; 62 import javax.swing.plaf.*; 63 import static javax.swing.ClientPropertyKey.*; 64 import javax.accessibility.*; 65 66 import sun.awt.SunToolkit; 67 import sun.swing.SwingUtilities2; 68 import sun.swing.UIClientPropertyKey; 69 70 /** 71 * The base class for all Swing components except top-level containers. 72 * To use a component that inherits from <code>JComponent</code>, 73 * you must place the component in a containment hierarchy 74 * whose root is a top-level Swing container. 75 * Top-level Swing containers -- 76 * such as <code>JFrame</code>, <code>JDialog</code>, 77 * and <code>JApplet</code> -- 78 * are specialized components 79 * that provide a place for other Swing components to paint themselves. 80 * For an explanation of containment hierarchies, see 81 * <a 82 href="http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html">Swing Components and the Containment Hierarchy</a>, 83 * a section in <em>The Java Tutorial</em>. 84 * 85 * <p> 86 * The <code>JComponent</code> class provides: 87 * <ul> 88 * <li>The base class for both standard and custom components 89 * that use the Swing architecture. 90 * <li>A "pluggable look and feel" (L&F) that can be specified by the 91 * programmer or (optionally) selected by the user at runtime. 92 * The look and feel for each component is provided by a 93 * <em>UI delegate</em> -- an object that descends from 94 * {@link javax.swing.plaf.ComponentUI}. 95 * See <a 96 * href="http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html">How 97 * to Set the Look and Feel</a> 98 * in <em>The Java Tutorial</em> 99 * for more information. 100 * <li>Comprehensive keystroke handling. 101 * See the document <a 102 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html">How to Use Key Bindings</a>, 103 * an article in <em>The Java Tutorial</em>, 104 * for more information. 105 * <li>Support for tool tips -- 106 * short descriptions that pop up when the cursor lingers 107 * over a component. 108 * See <a 109 * href="http://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html">How 110 * to Use Tool Tips</a> 111 * in <em>The Java Tutorial</em> 112 * for more information. 113 * <li>Support for accessibility. 114 * <code>JComponent</code> contains all of the methods in the 115 * <code>Accessible</code> interface, 116 * but it doesn't actually implement the interface. That is the 117 * responsibility of the individual classes 118 * that extend <code>JComponent</code>. 119 * <li>Support for component-specific properties. 120 * With the {@link #putClientProperty} 121 * and {@link #getClientProperty} methods, 122 * you can associate name-object pairs 123 * with any object that descends from <code>JComponent</code>. 124 * <li>An infrastructure for painting 125 * that includes double buffering and support for borders. 126 * For more information see <a 127 * href="http://www.oracle.com/technetwork/java/painting-140037.html#swing">Painting</a> and 128 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/border.htmll">How 129 * to Use Borders</a>, 130 * both of which are sections in <em>The Java Tutorial</em>. 131 * </ul> 132 * For more information on these subjects, see the 133 * <a href="package-summary.html#package_description">Swing package description</a> 134 * and <em>The Java Tutorial</em> section 135 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/jcomponent.html">The JComponent Class</a>. 136 * <p> 137 * <code>JComponent</code> and its subclasses document default values 138 * for certain properties. For example, <code>JTable</code> documents the 139 * default row height as 16. Each <code>JComponent</code> subclass 140 * that has a <code>ComponentUI</code> will create the 141 * <code>ComponentUI</code> as part of its constructor. In order 142 * to provide a particular look and feel each 143 * <code>ComponentUI</code> may set properties back on the 144 * <code>JComponent</code> that created it. For example, a custom 145 * look and feel may require <code>JTable</code>s to have a row 146 * height of 24. The documented defaults are the value of a property 147 * BEFORE the <code>ComponentUI</code> has been installed. If you 148 * need a specific value for a particular property you should 149 * explicitly set it. 150 * <p> 151 * In release 1.4, the focus subsystem was rearchitected. 152 * For more information, see 153 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 154 * How to Use the Focus Subsystem</a>, 155 * a section in <em>The Java Tutorial</em>. 156 * <p> 157 * <strong>Warning:</strong> Swing is not thread safe. For more 158 * information see <a 159 * href="package-summary.html#threading">Swing's Threading 160 * Policy</a>. 161 * <p> 162 * <strong>Warning:</strong> 163 * Serialized objects of this class will not be compatible with 164 * future Swing releases. The current serialization support is 165 * appropriate for short term storage or RMI between applications running 166 * the same version of Swing. As of 1.4, support for long term storage 167 * of all JavaBeans™ 168 * has been added to the <code>java.beans</code> package. 169 * Please see {@link java.beans.XMLEncoder}. 170 * 171 * @see KeyStroke 172 * @see Action 173 * @see #setBorder 174 * @see #registerKeyboardAction 175 * @see JOptionPane 176 * @see #setDebugGraphicsOptions 177 * @see #setToolTipText 178 * @see #setAutoscrolls 179 * 180 * @author Hans Muller 181 * @author Arnaud Weber 182 * @since 1.2 183 */ 184 @SuppressWarnings("serial") // Same-version serialization only 185 public abstract class JComponent extends Container implements Serializable, 186 TransferHandler.HasGetTransferHandler 187 { 188 /** 189 * @see #getUIClassID 190 * @see #writeObject 191 */ 192 private static final String uiClassID = "ComponentUI"; 193 194 /** 195 * @see #readObject 196 */ 197 private static final Hashtable<ObjectInputStream, ReadObjectCallback> readObjectCallbacks = 198 new Hashtable<ObjectInputStream, ReadObjectCallback>(1); 199 200 /** 201 * Keys to use for forward focus traversal when the JComponent is 202 * managing focus. 203 */ 204 private static Set<KeyStroke> managingFocusForwardTraversalKeys; 205 206 /** 207 * Keys to use for backward focus traversal when the JComponent is 208 * managing focus. 209 */ 210 private static Set<KeyStroke> managingFocusBackwardTraversalKeys; 211 212 // Following are the possible return values from getObscuredState. 213 private static final int NOT_OBSCURED = 0; 214 private static final int PARTIALLY_OBSCURED = 1; 215 private static final int COMPLETELY_OBSCURED = 2; 216 217 /** 218 * Set to true when DebugGraphics has been loaded. 219 */ 220 static boolean DEBUG_GRAPHICS_LOADED; 221 222 /** 223 * Key used to look up a value from the AppContext to determine the 224 * JComponent the InputVerifier is running for. That is, if 225 * AppContext.get(INPUT_VERIFIER_SOURCE_KEY) returns non-null, it 226 * indicates the EDT is calling into the InputVerifier from the 227 * returned component. 228 */ 229 private static final Object INPUT_VERIFIER_SOURCE_KEY = 230 new StringBuilder("InputVerifierSourceKey"); 231 232 /* The following fields support set methods for the corresponding 233 * java.awt.Component properties. 234 */ 235 private boolean isAlignmentXSet; 236 private float alignmentX; 237 private boolean isAlignmentYSet; 238 private float alignmentY; 239 240 /** 241 * Backing store for JComponent properties and listeners 242 */ 243 244 /** The look and feel delegate for this component. */ 245 protected transient ComponentUI ui; 246 /** A list of event listeners for this component. */ 247 protected EventListenerList listenerList = new EventListenerList(); 248 249 private transient ArrayTable clientProperties; 250 private VetoableChangeSupport vetoableChangeSupport; 251 /** 252 * Whether or not autoscroll has been enabled. 253 */ 254 private boolean autoscrolls; 255 private Border border; 256 private int flags; 257 258 /* Input verifier for this component */ 259 private InputVerifier inputVerifier = null; 260 261 private boolean verifyInputWhenFocusTarget = true; 262 263 /** 264 * Set in <code>_paintImmediately</code>. 265 * Will indicate the child that initiated the painting operation. 266 * If <code>paintingChild</code> is opaque, no need to paint 267 * any child components after <code>paintingChild</code>. 268 * Test used in <code>paintChildren</code>. 269 */ 270 transient Component paintingChild; 271 272 /** 273 * Constant used for <code>registerKeyboardAction</code> that 274 * means that the command should be invoked when 275 * the component has the focus. 276 */ 277 public static final int WHEN_FOCUSED = 0; 278 279 /** 280 * Constant used for <code>registerKeyboardAction</code> that 281 * means that the command should be invoked when the receiving 282 * component is an ancestor of the focused component or is 283 * itself the focused component. 284 */ 285 public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1; 286 287 /** 288 * Constant used for <code>registerKeyboardAction</code> that 289 * means that the command should be invoked when 290 * the receiving component is in the window that has the focus 291 * or is itself the focused component. 292 */ 293 public static final int WHEN_IN_FOCUSED_WINDOW = 2; 294 295 /** 296 * Constant used by some of the APIs to mean that no condition is defined. 297 */ 298 public static final int UNDEFINED_CONDITION = -1; 299 300 /** 301 * The key used by <code>JComponent</code> to access keyboard bindings. 302 */ 303 private static final String KEYBOARD_BINDINGS_KEY = "_KeyboardBindings"; 304 305 /** 306 * An array of <code>KeyStroke</code>s used for 307 * <code>WHEN_IN_FOCUSED_WINDOW</code> are stashed 308 * in the client properties under this string. 309 */ 310 private static final String WHEN_IN_FOCUSED_WINDOW_BINDINGS = "_WhenInFocusedWindow"; 311 312 /** 313 * The comment to display when the cursor is over the component, 314 * also known as a "value tip", "flyover help", or "flyover label". 315 */ 316 public static final String TOOL_TIP_TEXT_KEY = "ToolTipText"; 317 318 private static final String NEXT_FOCUS = "nextFocus"; 319 320 /** 321 * <code>JPopupMenu</code> assigned to this component 322 * and all of its children 323 */ 324 private JPopupMenu popupMenu; 325 326 /** Private flags **/ 327 private static final int IS_DOUBLE_BUFFERED = 0; 328 private static final int ANCESTOR_USING_BUFFER = 1; 329 private static final int IS_PAINTING_TILE = 2; 330 private static final int IS_OPAQUE = 3; 331 private static final int KEY_EVENTS_ENABLED = 4; 332 private static final int FOCUS_INPUTMAP_CREATED = 5; 333 private static final int ANCESTOR_INPUTMAP_CREATED = 6; 334 private static final int WIF_INPUTMAP_CREATED = 7; 335 private static final int ACTIONMAP_CREATED = 8; 336 private static final int CREATED_DOUBLE_BUFFER = 9; 337 // bit 10 is free 338 private static final int IS_PRINTING = 11; 339 private static final int IS_PRINTING_ALL = 12; 340 private static final int IS_REPAINTING = 13; 341 /** Bits 14-21 are used to handle nested writeObject calls. **/ 342 private static final int WRITE_OBJ_COUNTER_FIRST = 14; 343 private static final int RESERVED_1 = 15; 344 private static final int RESERVED_2 = 16; 345 private static final int RESERVED_3 = 17; 346 private static final int RESERVED_4 = 18; 347 private static final int RESERVED_5 = 19; 348 private static final int RESERVED_6 = 20; 349 private static final int WRITE_OBJ_COUNTER_LAST = 21; 350 351 private static final int REQUEST_FOCUS_DISABLED = 22; 352 private static final int INHERITS_POPUP_MENU = 23; 353 private static final int OPAQUE_SET = 24; 354 private static final int AUTOSCROLLS_SET = 25; 355 private static final int FOCUS_TRAVERSAL_KEYS_FORWARD_SET = 26; 356 private static final int FOCUS_TRAVERSAL_KEYS_BACKWARD_SET = 27; 357 private static final int REVALIDATE_RUNNABLE_SCHEDULED = 28; 358 359 /** 360 * Temporary rectangles. 361 */ 362 private static java.util.List<Rectangle> tempRectangles = new java.util.ArrayList<Rectangle>(11); 363 364 /** Used for <code>WHEN_FOCUSED</code> bindings. */ 365 private InputMap focusInputMap; 366 /** Used for <code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> bindings. */ 367 private InputMap ancestorInputMap; 368 /** Used for <code>WHEN_IN_FOCUSED_KEY</code> bindings. */ 369 private ComponentInputMap windowInputMap; 370 371 /** ActionMap. */ 372 private ActionMap actionMap; 373 374 /** Key used to store the default locale in an AppContext **/ 375 private static final String defaultLocale = "JComponent.defaultLocale"; 376 377 private static Component componentObtainingGraphicsFrom; 378 private static Object componentObtainingGraphicsFromLock = new 379 StringBuilder("componentObtainingGraphicsFrom"); 380 381 /** 382 * AA text hints. 383 */ 384 transient private Object aaTextInfo; 385 386 static Graphics safelyGetGraphics(Component c) { 387 return safelyGetGraphics(c, SwingUtilities.getRoot(c)); 388 } 389 390 static Graphics safelyGetGraphics(Component c, Component root) { 391 synchronized(componentObtainingGraphicsFromLock) { 392 componentObtainingGraphicsFrom = root; 393 Graphics g = c.getGraphics(); 394 componentObtainingGraphicsFrom = null; 395 return g; 396 } 397 } 398 399 static void getGraphicsInvoked(Component root) { 400 if (!JComponent.isComponentObtainingGraphicsFrom(root)) { 401 JRootPane rootPane = ((RootPaneContainer)root).getRootPane(); 402 if (rootPane != null) { 403 rootPane.disableTrueDoubleBuffering(); 404 } 405 } 406 } 407 408 409 /** 410 * Returns true if {@code c} is the component the graphics is being 411 * requested of. This is intended for use when getGraphics is invoked. 412 */ 413 private static boolean isComponentObtainingGraphicsFrom(Component c) { 414 synchronized(componentObtainingGraphicsFromLock) { 415 return (componentObtainingGraphicsFrom == c); 416 } 417 } 418 419 /** 420 * Returns the Set of <code>KeyStroke</code>s to use if the component 421 * is managing focus for forward focus traversal. 422 */ 423 static Set<KeyStroke> getManagingFocusForwardTraversalKeys() { 424 synchronized(JComponent.class) { 425 if (managingFocusForwardTraversalKeys == null) { 426 managingFocusForwardTraversalKeys = new HashSet<KeyStroke>(1); 427 managingFocusForwardTraversalKeys.add( 428 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 429 InputEvent.CTRL_MASK)); 430 } 431 } 432 return managingFocusForwardTraversalKeys; 433 } 434 435 /** 436 * Returns the Set of <code>KeyStroke</code>s to use if the component 437 * is managing focus for backward focus traversal. 438 */ 439 static Set<KeyStroke> getManagingFocusBackwardTraversalKeys() { 440 synchronized(JComponent.class) { 441 if (managingFocusBackwardTraversalKeys == null) { 442 managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>(1); 443 managingFocusBackwardTraversalKeys.add( 444 KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 445 InputEvent.SHIFT_MASK | 446 InputEvent.CTRL_MASK)); 447 } 448 } 449 return managingFocusBackwardTraversalKeys; 450 } 451 452 private static Rectangle fetchRectangle() { 453 synchronized(tempRectangles) { 454 Rectangle rect; 455 int size = tempRectangles.size(); 456 if (size > 0) { 457 rect = tempRectangles.remove(size - 1); 458 } 459 else { 460 rect = new Rectangle(0, 0, 0, 0); 461 } 462 return rect; 463 } 464 } 465 466 private static void recycleRectangle(Rectangle rect) { 467 synchronized(tempRectangles) { 468 tempRectangles.add(rect); 469 } 470 } 471 472 /** 473 * Sets whether or not <code>getComponentPopupMenu</code> should delegate 474 * to the parent if this component does not have a <code>JPopupMenu</code> 475 * assigned to it. 476 * <p> 477 * The default value for this is false, but some <code>JComponent</code> 478 * subclasses that are implemented as a number of <code>JComponent</code>s 479 * may set this to true. 480 * <p> 481 * This is a bound property. 482 * 483 * @param value whether or not the JPopupMenu is inherited 484 * @see #setComponentPopupMenu 485 * @beaninfo 486 * bound: true 487 * description: Whether or not the JPopupMenu is inherited 488 * @since 1.5 489 */ 490 public void setInheritsPopupMenu(boolean value) { 491 boolean oldValue = getFlag(INHERITS_POPUP_MENU); 492 setFlag(INHERITS_POPUP_MENU, value); 493 firePropertyChange("inheritsPopupMenu", oldValue, value); 494 } 495 496 /** 497 * Returns true if the JPopupMenu should be inherited from the parent. 498 * 499 * @see #setComponentPopupMenu 500 * @since 1.5 501 */ 502 public boolean getInheritsPopupMenu() { 503 return getFlag(INHERITS_POPUP_MENU); 504 } 505 506 /** 507 * Sets the <code>JPopupMenu</code> for this <code>JComponent</code>. 508 * The UI is responsible for registering bindings and adding the necessary 509 * listeners such that the <code>JPopupMenu</code> will be shown at 510 * the appropriate time. When the <code>JPopupMenu</code> is shown 511 * depends upon the look and feel: some may show it on a mouse event, 512 * some may enable a key binding. 513 * <p> 514 * If <code>popup</code> is null, and <code>getInheritsPopupMenu</code> 515 * returns true, then <code>getComponentPopupMenu</code> will be delegated 516 * to the parent. This provides for a way to make all child components 517 * inherit the popupmenu of the parent. 518 * <p> 519 * This is a bound property. 520 * 521 * @param popup - the popup that will be assigned to this component 522 * may be null 523 * @see #getComponentPopupMenu 524 * @beaninfo 525 * bound: true 526 * preferred: true 527 * description: Popup to show 528 * @since 1.5 529 */ 530 public void setComponentPopupMenu(JPopupMenu popup) { 531 if(popup != null) { 532 enableEvents(AWTEvent.MOUSE_EVENT_MASK); 533 } 534 JPopupMenu oldPopup = this.popupMenu; 535 this.popupMenu = popup; 536 firePropertyChange("componentPopupMenu", oldPopup, popup); 537 } 538 539 /** 540 * Returns <code>JPopupMenu</code> that assigned for this component. 541 * If this component does not have a <code>JPopupMenu</code> assigned 542 * to it and <code>getInheritsPopupMenu</code> is true, this 543 * will return <code>getParent().getComponentPopupMenu()</code> (assuming 544 * the parent is valid.) 545 * 546 * @return <code>JPopupMenu</code> assigned for this component 547 * or <code>null</code> if no popup assigned 548 * @see #setComponentPopupMenu 549 * @since 1.5 550 */ 551 public JPopupMenu getComponentPopupMenu() { 552 553 if(!getInheritsPopupMenu()) { 554 return popupMenu; 555 } 556 557 if(popupMenu == null) { 558 // Search parents for its popup 559 Container parent = getParent(); 560 while (parent != null) { 561 if(parent instanceof JComponent) { 562 return ((JComponent)parent).getComponentPopupMenu(); 563 } 564 if(parent instanceof Window || 565 parent instanceof Applet) { 566 // Reached toplevel, break and return null 567 break; 568 } 569 parent = parent.getParent(); 570 } 571 return null; 572 } 573 574 return popupMenu; 575 } 576 577 /** 578 * Default <code>JComponent</code> constructor. This constructor does 579 * very little initialization beyond calling the <code>Container</code> 580 * constructor. For example, the initial layout manager is 581 * <code>null</code>. It does, however, set the component's locale 582 * property to the value returned by 583 * <code>JComponent.getDefaultLocale</code>. 584 * 585 * @see #getDefaultLocale 586 */ 587 public JComponent() { 588 super(); 589 // We enable key events on all JComponents so that accessibility 590 // bindings will work everywhere. This is a partial fix to BugID 591 // 4282211. 592 enableEvents(AWTEvent.KEY_EVENT_MASK); 593 if (isManagingFocus()) { 594 LookAndFeel.installProperty(this, 595 "focusTraversalKeysForward", 596 getManagingFocusForwardTraversalKeys()); 597 LookAndFeel.installProperty(this, 598 "focusTraversalKeysBackward", 599 getManagingFocusBackwardTraversalKeys()); 600 } 601 602 super.setLocale( JComponent.getDefaultLocale() ); 603 } 604 605 606 /** 607 * Resets the UI property to a value from the current look and feel. 608 * <code>JComponent</code> subclasses must override this method 609 * like this: 610 * <pre> 611 * public void updateUI() { 612 * setUI((SliderUI)UIManager.getUI(this); 613 * } 614 * </pre> 615 * 616 * @see #setUI 617 * @see UIManager#getLookAndFeel 618 * @see UIManager#getUI 619 */ 620 public void updateUI() {} 621 622 623 /** 624 * Sets the look and feel delegate for this component. 625 * <code>JComponent</code> subclasses generally override this method 626 * to narrow the argument type. For example, in <code>JSlider</code>: 627 * <pre> 628 * public void setUI(SliderUI newUI) { 629 * super.setUI(newUI); 630 * } 631 * </pre> 632 * <p> 633 * Additionally <code>JComponent</code> subclasses must provide a 634 * <code>getUI</code> method that returns the correct type. For example: 635 * <pre> 636 * public SliderUI getUI() { 637 * return (SliderUI)ui; 638 * } 639 * </pre> 640 * 641 * @param newUI the new UI delegate 642 * @see #updateUI 643 * @see UIManager#getLookAndFeel 644 * @see UIManager#getUI 645 * @beaninfo 646 * bound: true 647 * hidden: true 648 * attribute: visualUpdate true 649 * description: The component's look and feel delegate. 650 */ 651 protected void setUI(ComponentUI newUI) { 652 /* We do not check that the UI instance is different 653 * before allowing the switch in order to enable the 654 * same UI instance *with different default settings* 655 * to be installed. 656 */ 657 658 uninstallUIAndProperties(); 659 660 // aaText shouldn't persist between look and feels, reset it. 661 aaTextInfo = 662 UIManager.getDefaults().get(SwingUtilities2.AA_TEXT_PROPERTY_KEY); 663 ComponentUI oldUI = ui; 664 ui = newUI; 665 if (ui != null) { 666 ui.installUI(this); 667 } 668 669 firePropertyChange("UI", oldUI, newUI); 670 revalidate(); 671 repaint(); 672 } 673 674 /** 675 * Uninstalls the UI, if any, and any client properties designated 676 * as being specific to the installed UI - instances of 677 * {@code UIClientPropertyKey}. 678 */ 679 private void uninstallUIAndProperties() { 680 if (ui != null) { 681 ui.uninstallUI(this); 682 //clean UIClientPropertyKeys from client properties 683 if (clientProperties != null) { 684 synchronized(clientProperties) { 685 Object[] clientPropertyKeys = 686 clientProperties.getKeys(null); 687 if (clientPropertyKeys != null) { 688 for (Object key : clientPropertyKeys) { 689 if (key instanceof UIClientPropertyKey) { 690 putClientProperty(key, null); 691 } 692 } 693 } 694 } 695 } 696 } 697 } 698 699 /** 700 * Returns the <code>UIDefaults</code> key used to 701 * look up the name of the <code>swing.plaf.ComponentUI</code> 702 * class that defines the look and feel 703 * for this component. Most applications will never need to 704 * call this method. Subclasses of <code>JComponent</code> that support 705 * pluggable look and feel should override this method to 706 * return a <code>UIDefaults</code> key that maps to the 707 * <code>ComponentUI</code> subclass that defines their look and feel. 708 * 709 * @return the <code>UIDefaults</code> key for a 710 * <code>ComponentUI</code> subclass 711 * @see UIDefaults#getUI 712 * @beaninfo 713 * expert: true 714 * description: UIClassID 715 */ 716 public String getUIClassID() { 717 return uiClassID; 718 } 719 720 721 /** 722 * Returns the graphics object used to paint this component. 723 * If <code>DebugGraphics</code> is turned on we create a new 724 * <code>DebugGraphics</code> object if necessary. 725 * Otherwise we just configure the 726 * specified graphics object's foreground and font. 727 * 728 * @param g the original <code>Graphics</code> object 729 * @return a <code>Graphics</code> object configured for this component 730 */ 731 protected Graphics getComponentGraphics(Graphics g) { 732 Graphics componentGraphics = g; 733 if (ui != null && DEBUG_GRAPHICS_LOADED) { 734 if ((DebugGraphics.debugComponentCount() != 0) && 735 (shouldDebugGraphics() != 0) && 736 !(g instanceof DebugGraphics)) { 737 componentGraphics = new DebugGraphics(g,this); 738 } 739 } 740 componentGraphics.setColor(getForeground()); 741 componentGraphics.setFont(getFont()); 742 743 return componentGraphics; 744 } 745 746 747 /** 748 * Calls the UI delegate's paint method, if the UI delegate 749 * is non-<code>null</code>. We pass the delegate a copy of the 750 * <code>Graphics</code> object to protect the rest of the 751 * paint code from irrevocable changes 752 * (for example, <code>Graphics.translate</code>). 753 * <p> 754 * If you override this in a subclass you should not make permanent 755 * changes to the passed in <code>Graphics</code>. For example, you 756 * should not alter the clip <code>Rectangle</code> or modify the 757 * transform. If you need to do these operations you may find it 758 * easier to create a new <code>Graphics</code> from the passed in 759 * <code>Graphics</code> and manipulate it. Further, if you do not 760 * invoker super's implementation you must honor the opaque property, 761 * that is 762 * if this component is opaque, you must completely fill in the background 763 * in a non-opaque color. If you do not honor the opaque property you 764 * will likely see visual artifacts. 765 * <p> 766 * The passed in <code>Graphics</code> object might 767 * have a transform other than the identify transform 768 * installed on it. In this case, you might get 769 * unexpected results if you cumulatively apply 770 * another transform. 771 * 772 * @param g the <code>Graphics</code> object to protect 773 * @see #paint 774 * @see ComponentUI 775 */ 776 protected void paintComponent(Graphics g) { 777 if (ui != null) { 778 Graphics scratchGraphics = (g == null) ? null : g.create(); 779 try { 780 ui.update(scratchGraphics, this); 781 } 782 finally { 783 scratchGraphics.dispose(); 784 } 785 } 786 } 787 788 /** 789 * Paints this component's children. 790 * If <code>shouldUseBuffer</code> is true, 791 * no component ancestor has a buffer and 792 * the component children can use a buffer if they have one. 793 * Otherwise, one ancestor has a buffer currently in use and children 794 * should not use a buffer to paint. 795 * @param g the <code>Graphics</code> context in which to paint 796 * @see #paint 797 * @see java.awt.Container#paint 798 */ 799 protected void paintChildren(Graphics g) { 800 Graphics sg = g; 801 802 synchronized(getTreeLock()) { 803 int i = getComponentCount() - 1; 804 if (i < 0) { 805 return; 806 } 807 // If we are only to paint to a specific child, determine 808 // its index. 809 if (paintingChild != null && 810 (paintingChild instanceof JComponent) && 811 paintingChild.isOpaque()) { 812 for (; i >= 0; i--) { 813 if (getComponent(i) == paintingChild){ 814 break; 815 } 816 } 817 } 818 Rectangle tmpRect = fetchRectangle(); 819 boolean checkSiblings = (!isOptimizedDrawingEnabled() && 820 checkIfChildObscuredBySibling()); 821 Rectangle clipBounds = null; 822 if (checkSiblings) { 823 clipBounds = sg.getClipBounds(); 824 if (clipBounds == null) { 825 clipBounds = new Rectangle(0, 0, getWidth(), 826 getHeight()); 827 } 828 } 829 boolean printing = getFlag(IS_PRINTING); 830 final Window window = SwingUtilities.getWindowAncestor(this); 831 final boolean isWindowOpaque = window == null || window.isOpaque(); 832 for (; i >= 0 ; i--) { 833 Component comp = getComponent(i); 834 if (comp == null) { 835 continue; 836 } 837 838 final boolean isJComponent = comp instanceof JComponent; 839 840 // Enable painting of heavyweights in non-opaque windows. 841 // See 6884960 842 if ((!isWindowOpaque || isJComponent || 843 isLightweightComponent(comp)) && comp.isVisible()) 844 { 845 Rectangle cr; 846 847 cr = comp.getBounds(tmpRect); 848 849 boolean hitClip = g.hitClip(cr.x, cr.y, cr.width, 850 cr.height); 851 852 if (hitClip) { 853 if (checkSiblings && i > 0) { 854 int x = cr.x; 855 int y = cr.y; 856 int width = cr.width; 857 int height = cr.height; 858 SwingUtilities.computeIntersection 859 (clipBounds.x, clipBounds.y, 860 clipBounds.width, clipBounds.height, cr); 861 862 if(getObscuredState(i, cr.x, cr.y, cr.width, 863 cr.height) == COMPLETELY_OBSCURED) { 864 continue; 865 } 866 cr.x = x; 867 cr.y = y; 868 cr.width = width; 869 cr.height = height; 870 } 871 Graphics cg = sg.create(cr.x, cr.y, cr.width, 872 cr.height); 873 cg.setColor(comp.getForeground()); 874 cg.setFont(comp.getFont()); 875 boolean shouldSetFlagBack = false; 876 try { 877 if(isJComponent) { 878 if(getFlag(ANCESTOR_USING_BUFFER)) { 879 ((JComponent)comp).setFlag( 880 ANCESTOR_USING_BUFFER,true); 881 shouldSetFlagBack = true; 882 } 883 if(getFlag(IS_PAINTING_TILE)) { 884 ((JComponent)comp).setFlag( 885 IS_PAINTING_TILE,true); 886 shouldSetFlagBack = true; 887 } 888 if(!printing) { 889 comp.paint(cg); 890 } 891 else { 892 if (!getFlag(IS_PRINTING_ALL)) { 893 comp.print(cg); 894 } 895 else { 896 comp.printAll(cg); 897 } 898 } 899 } else { 900 // The component is either lightweight, or 901 // heavyweight in a non-opaque window 902 if (!printing) { 903 comp.paint(cg); 904 } 905 else { 906 if (!getFlag(IS_PRINTING_ALL)) { 907 comp.print(cg); 908 } 909 else { 910 comp.printAll(cg); 911 } 912 } 913 } 914 } finally { 915 cg.dispose(); 916 if(shouldSetFlagBack) { 917 ((JComponent)comp).setFlag( 918 ANCESTOR_USING_BUFFER,false); 919 ((JComponent)comp).setFlag( 920 IS_PAINTING_TILE,false); 921 } 922 } 923 } 924 } 925 926 } 927 recycleRectangle(tmpRect); 928 } 929 } 930 931 /** 932 * Paints the component's border. 933 * <p> 934 * If you override this in a subclass you should not make permanent 935 * changes to the passed in <code>Graphics</code>. For example, you 936 * should not alter the clip <code>Rectangle</code> or modify the 937 * transform. If you need to do these operations you may find it 938 * easier to create a new <code>Graphics</code> from the passed in 939 * <code>Graphics</code> and manipulate it. 940 * 941 * @param g the <code>Graphics</code> context in which to paint 942 * 943 * @see #paint 944 * @see #setBorder 945 */ 946 protected void paintBorder(Graphics g) { 947 Border border = getBorder(); 948 if (border != null) { 949 border.paintBorder(this, g, 0, 0, getWidth(), getHeight()); 950 } 951 } 952 953 954 /** 955 * Calls <code>paint</code>. Doesn't clear the background but see 956 * <code>ComponentUI.update</code>, which is called by 957 * <code>paintComponent</code>. 958 * 959 * @param g the <code>Graphics</code> context in which to paint 960 * @see #paint 961 * @see #paintComponent 962 * @see javax.swing.plaf.ComponentUI 963 */ 964 public void update(Graphics g) { 965 paint(g); 966 } 967 968 969 /** 970 * Invoked by Swing to draw components. 971 * Applications should not invoke <code>paint</code> directly, 972 * but should instead use the <code>repaint</code> method to 973 * schedule the component for redrawing. 974 * <p> 975 * This method actually delegates the work of painting to three 976 * protected methods: <code>paintComponent</code>, 977 * <code>paintBorder</code>, 978 * and <code>paintChildren</code>. They're called in the order 979 * listed to ensure that children appear on top of component itself. 980 * Generally speaking, the component and its children should not 981 * paint in the insets area allocated to the border. Subclasses can 982 * just override this method, as always. A subclass that just 983 * wants to specialize the UI (look and feel) delegate's 984 * <code>paint</code> method should just override 985 * <code>paintComponent</code>. 986 * 987 * @param g the <code>Graphics</code> context in which to paint 988 * @see #paintComponent 989 * @see #paintBorder 990 * @see #paintChildren 991 * @see #getComponentGraphics 992 * @see #repaint 993 */ 994 public void paint(Graphics g) { 995 boolean shouldClearPaintFlags = false; 996 997 if ((getWidth() <= 0) || (getHeight() <= 0)) { 998 return; 999 } 1000 1001 Graphics componentGraphics = getComponentGraphics(g); 1002 Graphics co = componentGraphics.create(); 1003 try { 1004 RepaintManager repaintManager = RepaintManager.currentManager(this); 1005 Rectangle clipRect = co.getClipBounds(); 1006 int clipX; 1007 int clipY; 1008 int clipW; 1009 int clipH; 1010 if (clipRect == null) { 1011 clipX = clipY = 0; 1012 clipW = getWidth(); 1013 clipH = getHeight(); 1014 } 1015 else { 1016 clipX = clipRect.x; 1017 clipY = clipRect.y; 1018 clipW = clipRect.width; 1019 clipH = clipRect.height; 1020 } 1021 1022 if(clipW > getWidth()) { 1023 clipW = getWidth(); 1024 } 1025 if(clipH > getHeight()) { 1026 clipH = getHeight(); 1027 } 1028 1029 if(getParent() != null && !(getParent() instanceof JComponent)) { 1030 adjustPaintFlags(); 1031 shouldClearPaintFlags = true; 1032 } 1033 1034 int bw,bh; 1035 boolean printing = getFlag(IS_PRINTING); 1036 if (!printing && repaintManager.isDoubleBufferingEnabled() && 1037 !getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered() && 1038 (getFlag(IS_REPAINTING) || repaintManager.isPainting())) 1039 { 1040 repaintManager.beginPaint(); 1041 try { 1042 repaintManager.paint(this, this, co, clipX, clipY, clipW, 1043 clipH); 1044 } finally { 1045 repaintManager.endPaint(); 1046 } 1047 } 1048 else { 1049 // Will ocassionaly happen in 1.2, especially when printing. 1050 if (clipRect == null) { 1051 co.setClip(clipX, clipY, clipW, clipH); 1052 } 1053 1054 if (!rectangleIsObscured(clipX,clipY,clipW,clipH)) { 1055 if (!printing) { 1056 paintComponent(co); 1057 paintBorder(co); 1058 } 1059 else { 1060 printComponent(co); 1061 printBorder(co); 1062 } 1063 } 1064 if (!printing) { 1065 paintChildren(co); 1066 } 1067 else { 1068 printChildren(co); 1069 } 1070 } 1071 } finally { 1072 co.dispose(); 1073 if(shouldClearPaintFlags) { 1074 setFlag(ANCESTOR_USING_BUFFER,false); 1075 setFlag(IS_PAINTING_TILE,false); 1076 setFlag(IS_PRINTING,false); 1077 setFlag(IS_PRINTING_ALL,false); 1078 } 1079 } 1080 } 1081 1082 // paint forcing use of the double buffer. This is used for historical 1083 // reasons: JViewport, when scrolling, previously directly invoked paint 1084 // while turning off double buffering at the RepaintManager level, this 1085 // codes simulates that. 1086 void paintForceDoubleBuffered(Graphics g) { 1087 RepaintManager rm = RepaintManager.currentManager(this); 1088 Rectangle clip = g.getClipBounds(); 1089 rm.beginPaint(); 1090 setFlag(IS_REPAINTING, true); 1091 try { 1092 rm.paint(this, this, g, clip.x, clip.y, clip.width, clip.height); 1093 } finally { 1094 rm.endPaint(); 1095 setFlag(IS_REPAINTING, false); 1096 } 1097 } 1098 1099 /** 1100 * Returns true if this component, or any of its ancestors, are in 1101 * the processing of painting. 1102 */ 1103 boolean isPainting() { 1104 Container component = this; 1105 while (component != null) { 1106 if (component instanceof JComponent && 1107 ((JComponent)component).getFlag(ANCESTOR_USING_BUFFER)) { 1108 return true; 1109 } 1110 component = component.getParent(); 1111 } 1112 return false; 1113 } 1114 1115 private void adjustPaintFlags() { 1116 JComponent jparent; 1117 Container parent; 1118 for(parent = getParent() ; parent != null ; parent = 1119 parent.getParent()) { 1120 if(parent instanceof JComponent) { 1121 jparent = (JComponent) parent; 1122 if(jparent.getFlag(ANCESTOR_USING_BUFFER)) 1123 setFlag(ANCESTOR_USING_BUFFER, true); 1124 if(jparent.getFlag(IS_PAINTING_TILE)) 1125 setFlag(IS_PAINTING_TILE, true); 1126 if(jparent.getFlag(IS_PRINTING)) 1127 setFlag(IS_PRINTING, true); 1128 if(jparent.getFlag(IS_PRINTING_ALL)) 1129 setFlag(IS_PRINTING_ALL, true); 1130 break; 1131 } 1132 } 1133 } 1134 1135 /** 1136 * Invoke this method to print the component. This method invokes 1137 * <code>print</code> on the component. 1138 * 1139 * @param g the <code>Graphics</code> context in which to paint 1140 * @see #print 1141 * @see #printComponent 1142 * @see #printBorder 1143 * @see #printChildren 1144 */ 1145 public void printAll(Graphics g) { 1146 setFlag(IS_PRINTING_ALL, true); 1147 try { 1148 print(g); 1149 } 1150 finally { 1151 setFlag(IS_PRINTING_ALL, false); 1152 } 1153 } 1154 1155 /** 1156 * Invoke this method to print the component to the specified 1157 * <code>Graphics</code>. This method will result in invocations 1158 * of <code>printComponent</code>, <code>printBorder</code> and 1159 * <code>printChildren</code>. It is recommended that you override 1160 * one of the previously mentioned methods rather than this one if 1161 * your intention is to customize the way printing looks. However, 1162 * it can be useful to override this method should you want to prepare 1163 * state before invoking the superclass behavior. As an example, 1164 * if you wanted to change the component's background color before 1165 * printing, you could do the following: 1166 * <pre> 1167 * public void print(Graphics g) { 1168 * Color orig = getBackground(); 1169 * setBackground(Color.WHITE); 1170 * 1171 * // wrap in try/finally so that we always restore the state 1172 * try { 1173 * super.print(g); 1174 * } finally { 1175 * setBackground(orig); 1176 * } 1177 * } 1178 * </pre> 1179 * <p> 1180 * Alternatively, or for components that delegate painting to other objects, 1181 * you can query during painting whether or not the component is in the 1182 * midst of a print operation. The <code>isPaintingForPrint</code> method provides 1183 * this ability and its return value will be changed by this method: to 1184 * <code>true</code> immediately before rendering and to <code>false</code> 1185 * immediately after. With each change a property change event is fired on 1186 * this component with the name <code>"paintingForPrint"</code>. 1187 * <p> 1188 * This method sets the component's state such that the double buffer 1189 * will not be used: painting will be done directly on the passed in 1190 * <code>Graphics</code>. 1191 * 1192 * @param g the <code>Graphics</code> context in which to paint 1193 * @see #printComponent 1194 * @see #printBorder 1195 * @see #printChildren 1196 * @see #isPaintingForPrint 1197 */ 1198 public void print(Graphics g) { 1199 setFlag(IS_PRINTING, true); 1200 firePropertyChange("paintingForPrint", false, true); 1201 try { 1202 paint(g); 1203 } 1204 finally { 1205 setFlag(IS_PRINTING, false); 1206 firePropertyChange("paintingForPrint", true, false); 1207 } 1208 } 1209 1210 /** 1211 * This is invoked during a printing operation. This is implemented to 1212 * invoke <code>paintComponent</code> on the component. Override this 1213 * if you wish to add special painting behavior when printing. 1214 * 1215 * @param g the <code>Graphics</code> context in which to paint 1216 * @see #print 1217 * @since 1.3 1218 */ 1219 protected void printComponent(Graphics g) { 1220 paintComponent(g); 1221 } 1222 1223 /** 1224 * Prints this component's children. This is implemented to invoke 1225 * <code>paintChildren</code> on the component. Override this if you 1226 * wish to print the children differently than painting. 1227 * 1228 * @param g the <code>Graphics</code> context in which to paint 1229 * @see #print 1230 * @since 1.3 1231 */ 1232 protected void printChildren(Graphics g) { 1233 paintChildren(g); 1234 } 1235 1236 /** 1237 * Prints the component's border. This is implemented to invoke 1238 * <code>paintBorder</code> on the component. Override this if you 1239 * wish to print the border differently that it is painted. 1240 * 1241 * @param g the <code>Graphics</code> context in which to paint 1242 * @see #print 1243 * @since 1.3 1244 */ 1245 protected void printBorder(Graphics g) { 1246 paintBorder(g); 1247 } 1248 1249 /** 1250 * Returns true if the component is currently painting a tile. 1251 * If this method returns true, paint will be called again for another 1252 * tile. This method returns false if you are not painting a tile or 1253 * if the last tile is painted. 1254 * Use this method to keep some state you might need between tiles. 1255 * 1256 * @return true if the component is currently painting a tile, 1257 * false otherwise 1258 */ 1259 public boolean isPaintingTile() { 1260 return getFlag(IS_PAINTING_TILE); 1261 } 1262 1263 /** 1264 * Returns <code>true</code> if the current painting operation on this 1265 * component is part of a <code>print</code> operation. This method is 1266 * useful when you want to customize what you print versus what you show 1267 * on the screen. 1268 * <p> 1269 * You can detect changes in the value of this property by listening for 1270 * property change events on this component with name 1271 * <code>"paintingForPrint"</code>. 1272 * <p> 1273 * Note: This method provides complimentary functionality to that provided 1274 * by other high level Swing printing APIs. However, it deals strictly with 1275 * painting and should not be confused as providing information on higher 1276 * level print processes. For example, a {@link javax.swing.JTable#print()} 1277 * operation doesn't necessarily result in a continuous rendering of the 1278 * full component, and the return value of this method can change multiple 1279 * times during that operation. It is even possible for the component to be 1280 * painted to the screen while the printing process is ongoing. In such a 1281 * case, the return value of this method is <code>true</code> when, and only 1282 * when, the table is being painted as part of the printing process. 1283 * 1284 * @return true if the current painting operation on this component 1285 * is part of a print operation 1286 * @see #print 1287 * @since 1.6 1288 */ 1289 public final boolean isPaintingForPrint() { 1290 return getFlag(IS_PRINTING); 1291 } 1292 1293 /** 1294 * In release 1.4, the focus subsystem was rearchitected. 1295 * For more information, see 1296 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1297 * How to Use the Focus Subsystem</a>, 1298 * a section in <em>The Java Tutorial</em>. 1299 * <p> 1300 * Changes this <code>JComponent</code>'s focus traversal keys to 1301 * CTRL+TAB and CTRL+SHIFT+TAB. Also prevents 1302 * <code>SortingFocusTraversalPolicy</code> from considering descendants 1303 * of this JComponent when computing a focus traversal cycle. 1304 * 1305 * @see java.awt.Component#setFocusTraversalKeys 1306 * @see SortingFocusTraversalPolicy 1307 * @deprecated As of 1.4, replaced by 1308 * <code>Component.setFocusTraversalKeys(int, Set)</code> and 1309 * <code>Container.setFocusCycleRoot(boolean)</code>. 1310 */ 1311 @Deprecated 1312 public boolean isManagingFocus() { 1313 return false; 1314 } 1315 1316 private void registerNextFocusableComponent() { 1317 registerNextFocusableComponent(getNextFocusableComponent()); 1318 } 1319 1320 private void registerNextFocusableComponent(Component 1321 nextFocusableComponent) { 1322 if (nextFocusableComponent == null) { 1323 return; 1324 } 1325 1326 Container nearestRoot = 1327 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor(); 1328 FocusTraversalPolicy policy = nearestRoot.getFocusTraversalPolicy(); 1329 if (!(policy instanceof LegacyGlueFocusTraversalPolicy)) { 1330 policy = new LegacyGlueFocusTraversalPolicy(policy); 1331 nearestRoot.setFocusTraversalPolicy(policy); 1332 } 1333 ((LegacyGlueFocusTraversalPolicy)policy). 1334 setNextFocusableComponent(this, nextFocusableComponent); 1335 } 1336 1337 private void deregisterNextFocusableComponent() { 1338 Component nextFocusableComponent = getNextFocusableComponent(); 1339 if (nextFocusableComponent == null) { 1340 return; 1341 } 1342 1343 Container nearestRoot = 1344 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor(); 1345 if (nearestRoot == null) { 1346 return; 1347 } 1348 FocusTraversalPolicy policy = nearestRoot.getFocusTraversalPolicy(); 1349 if (policy instanceof LegacyGlueFocusTraversalPolicy) { 1350 ((LegacyGlueFocusTraversalPolicy)policy). 1351 unsetNextFocusableComponent(this, nextFocusableComponent); 1352 } 1353 } 1354 1355 /** 1356 * In release 1.4, the focus subsystem was rearchitected. 1357 * For more information, see 1358 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1359 * How to Use the Focus Subsystem</a>, 1360 * a section in <em>The Java Tutorial</em>. 1361 * <p> 1362 * Overrides the default <code>FocusTraversalPolicy</code> for this 1363 * <code>JComponent</code>'s focus traversal cycle by unconditionally 1364 * setting the specified <code>Component</code> as the next 1365 * <code>Component</code> in the cycle, and this <code>JComponent</code> 1366 * as the specified <code>Component</code>'s previous 1367 * <code>Component</code> in the cycle. 1368 * 1369 * @param aComponent the <code>Component</code> that should follow this 1370 * <code>JComponent</code> in the focus traversal cycle 1371 * 1372 * @see #getNextFocusableComponent 1373 * @see java.awt.FocusTraversalPolicy 1374 * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code> 1375 */ 1376 @Deprecated 1377 public void setNextFocusableComponent(Component aComponent) { 1378 boolean displayable = isDisplayable(); 1379 if (displayable) { 1380 deregisterNextFocusableComponent(); 1381 } 1382 putClientProperty(NEXT_FOCUS, aComponent); 1383 if (displayable) { 1384 registerNextFocusableComponent(aComponent); 1385 } 1386 } 1387 1388 /** 1389 * In release 1.4, the focus subsystem was rearchitected. 1390 * For more information, see 1391 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1392 * How to Use the Focus Subsystem</a>, 1393 * a section in <em>The Java Tutorial</em>. 1394 * <p> 1395 * Returns the <code>Component</code> set by a prior call to 1396 * <code>setNextFocusableComponent(Component)</code> on this 1397 * <code>JComponent</code>. 1398 * 1399 * @return the <code>Component</code> that will follow this 1400 * <code>JComponent</code> in the focus traversal cycle, or 1401 * <code>null</code> if none has been explicitly specified 1402 * 1403 * @see #setNextFocusableComponent 1404 * @deprecated As of 1.4, replaced by <code>FocusTraversalPolicy</code>. 1405 */ 1406 @Deprecated 1407 public Component getNextFocusableComponent() { 1408 return (Component)getClientProperty(NEXT_FOCUS); 1409 } 1410 1411 /** 1412 * Provides a hint as to whether or not this <code>JComponent</code> 1413 * should get focus. This is only a hint, and it is up to consumers that 1414 * are requesting focus to honor this property. This is typically honored 1415 * for mouse operations, but not keyboard operations. For example, look 1416 * and feels could verify this property is true before requesting focus 1417 * during a mouse operation. This would often times be used if you did 1418 * not want a mouse press on a <code>JComponent</code> to steal focus, 1419 * but did want the <code>JComponent</code> to be traversable via the 1420 * keyboard. If you do not want this <code>JComponent</code> focusable at 1421 * all, use the <code>setFocusable</code> method instead. 1422 * <p> 1423 * Please see 1424 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1425 * How to Use the Focus Subsystem</a>, 1426 * a section in <em>The Java Tutorial</em>, 1427 * for more information. 1428 * 1429 * @param requestFocusEnabled indicates whether you want this 1430 * <code>JComponent</code> to be focusable or not 1431 * @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a> 1432 * @see java.awt.Component#setFocusable 1433 */ 1434 public void setRequestFocusEnabled(boolean requestFocusEnabled) { 1435 setFlag(REQUEST_FOCUS_DISABLED, !requestFocusEnabled); 1436 } 1437 1438 /** 1439 * Returns <code>true</code> if this <code>JComponent</code> should 1440 * get focus; otherwise returns <code>false</code>. 1441 * <p> 1442 * Please see 1443 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1444 * How to Use the Focus Subsystem</a>, 1445 * a section in <em>The Java Tutorial</em>, 1446 * for more information. 1447 * 1448 * @return <code>true</code> if this component should get focus, 1449 * otherwise returns <code>false</code> 1450 * @see #setRequestFocusEnabled 1451 * @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus 1452 * Specification</a> 1453 * @see java.awt.Component#isFocusable 1454 */ 1455 public boolean isRequestFocusEnabled() { 1456 return !getFlag(REQUEST_FOCUS_DISABLED); 1457 } 1458 1459 /** 1460 * Requests that this <code>Component</code> gets the input focus. 1461 * Refer to {@link java.awt.Component#requestFocus() 1462 * Component.requestFocus()} for a complete description of 1463 * this method. 1464 * <p> 1465 * Note that the use of this method is discouraged because 1466 * its behavior is platform dependent. Instead we recommend the 1467 * use of {@link #requestFocusInWindow() requestFocusInWindow()}. 1468 * If you would like more information on focus, see 1469 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1470 * How to Use the Focus Subsystem</a>, 1471 * a section in <em>The Java Tutorial</em>. 1472 * 1473 * @see java.awt.Component#requestFocusInWindow() 1474 * @see java.awt.Component#requestFocusInWindow(boolean) 1475 * @since 1.4 1476 */ 1477 public void requestFocus() { 1478 super.requestFocus(); 1479 } 1480 1481 /** 1482 * Requests that this <code>Component</code> gets the input focus. 1483 * Refer to {@link java.awt.Component#requestFocus(boolean) 1484 * Component.requestFocus(boolean)} for a complete description of 1485 * this method. 1486 * <p> 1487 * Note that the use of this method is discouraged because 1488 * its behavior is platform dependent. Instead we recommend the 1489 * use of {@link #requestFocusInWindow(boolean) 1490 * requestFocusInWindow(boolean)}. 1491 * If you would like more information on focus, see 1492 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1493 * How to Use the Focus Subsystem</a>, 1494 * a section in <em>The Java Tutorial</em>. 1495 * 1496 * @param temporary boolean indicating if the focus change is temporary 1497 * @return <code>false</code> if the focus change request is guaranteed to 1498 * fail; <code>true</code> if it is likely to succeed 1499 * @see java.awt.Component#requestFocusInWindow() 1500 * @see java.awt.Component#requestFocusInWindow(boolean) 1501 * @since 1.4 1502 */ 1503 public boolean requestFocus(boolean temporary) { 1504 return super.requestFocus(temporary); 1505 } 1506 1507 /** 1508 * Requests that this <code>Component</code> gets the input focus. 1509 * Refer to {@link java.awt.Component#requestFocusInWindow() 1510 * Component.requestFocusInWindow()} for a complete description of 1511 * this method. 1512 * <p> 1513 * If you would like more information on focus, see 1514 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1515 * How to Use the Focus Subsystem</a>, 1516 * a section in <em>The Java Tutorial</em>. 1517 * 1518 * @return <code>false</code> if the focus change request is guaranteed to 1519 * fail; <code>true</code> if it is likely to succeed 1520 * @see java.awt.Component#requestFocusInWindow() 1521 * @see java.awt.Component#requestFocusInWindow(boolean) 1522 * @since 1.4 1523 */ 1524 public boolean requestFocusInWindow() { 1525 return super.requestFocusInWindow(); 1526 } 1527 1528 /** 1529 * Requests that this <code>Component</code> gets the input focus. 1530 * Refer to {@link java.awt.Component#requestFocusInWindow(boolean) 1531 * Component.requestFocusInWindow(boolean)} for a complete description of 1532 * this method. 1533 * <p> 1534 * If you would like more information on focus, see 1535 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 1536 * How to Use the Focus Subsystem</a>, 1537 * a section in <em>The Java Tutorial</em>. 1538 * 1539 * @param temporary boolean indicating if the focus change is temporary 1540 * @return <code>false</code> if the focus change request is guaranteed to 1541 * fail; <code>true</code> if it is likely to succeed 1542 * @see java.awt.Component#requestFocusInWindow() 1543 * @see java.awt.Component#requestFocusInWindow(boolean) 1544 * @since 1.4 1545 */ 1546 protected boolean requestFocusInWindow(boolean temporary) { 1547 return super.requestFocusInWindow(temporary); 1548 } 1549 1550 /** 1551 * Requests that this Component get the input focus, and that this 1552 * Component's top-level ancestor become the focused Window. This component 1553 * must be displayable, visible, and focusable for the request to be 1554 * granted. 1555 * <p> 1556 * This method is intended for use by focus implementations. Client code 1557 * should not use this method; instead, it should use 1558 * <code>requestFocusInWindow()</code>. 1559 * 1560 * @see #requestFocusInWindow() 1561 */ 1562 public void grabFocus() { 1563 requestFocus(); 1564 } 1565 1566 /** 1567 * Sets the value to indicate whether input verifier for the 1568 * current focus owner will be called before this component requests 1569 * focus. The default is true. Set to false on components such as a 1570 * Cancel button or a scrollbar, which should activate even if the 1571 * input in the current focus owner is not "passed" by the input 1572 * verifier for that component. 1573 * 1574 * @param verifyInputWhenFocusTarget value for the 1575 * <code>verifyInputWhenFocusTarget</code> property 1576 * @see InputVerifier 1577 * @see #setInputVerifier 1578 * @see #getInputVerifier 1579 * @see #getVerifyInputWhenFocusTarget 1580 * 1581 * @since 1.3 1582 * @beaninfo 1583 * bound: true 1584 * description: Whether the Component verifies input before accepting 1585 * focus. 1586 */ 1587 public void setVerifyInputWhenFocusTarget(boolean 1588 verifyInputWhenFocusTarget) { 1589 boolean oldVerifyInputWhenFocusTarget = 1590 this.verifyInputWhenFocusTarget; 1591 this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget; 1592 firePropertyChange("verifyInputWhenFocusTarget", 1593 oldVerifyInputWhenFocusTarget, 1594 verifyInputWhenFocusTarget); 1595 } 1596 1597 /** 1598 * Returns the value that indicates whether the input verifier for the 1599 * current focus owner will be called before this component requests 1600 * focus. 1601 * 1602 * @return value of the <code>verifyInputWhenFocusTarget</code> property 1603 * 1604 * @see InputVerifier 1605 * @see #setInputVerifier 1606 * @see #getInputVerifier 1607 * @see #setVerifyInputWhenFocusTarget 1608 * 1609 * @since 1.3 1610 */ 1611 public boolean getVerifyInputWhenFocusTarget() { 1612 return verifyInputWhenFocusTarget; 1613 } 1614 1615 1616 /** 1617 * Gets the <code>FontMetrics</code> for the specified <code>Font</code>. 1618 * 1619 * @param font the font for which font metrics is to be 1620 * obtained 1621 * @return the font metrics for <code>font</code> 1622 * @throws NullPointerException if <code>font</code> is null 1623 * @since 1.5 1624 */ 1625 public FontMetrics getFontMetrics(Font font) { 1626 return SwingUtilities2.getFontMetrics(this, font); 1627 } 1628 1629 1630 /** 1631 * Sets the preferred size of this component. 1632 * If <code>preferredSize</code> is <code>null</code>, the UI will 1633 * be asked for the preferred size. 1634 * @beaninfo 1635 * preferred: true 1636 * bound: true 1637 * description: The preferred size of the component. 1638 */ 1639 public void setPreferredSize(Dimension preferredSize) { 1640 super.setPreferredSize(preferredSize); 1641 } 1642 1643 1644 /** 1645 * If the <code>preferredSize</code> has been set to a 1646 * non-<code>null</code> value just returns it. 1647 * If the UI delegate's <code>getPreferredSize</code> 1648 * method returns a non <code>null</code> value then return that; 1649 * otherwise defer to the component's layout manager. 1650 * 1651 * @return the value of the <code>preferredSize</code> property 1652 * @see #setPreferredSize 1653 * @see ComponentUI 1654 */ 1655 @Transient 1656 public Dimension getPreferredSize() { 1657 if (isPreferredSizeSet()) { 1658 return super.getPreferredSize(); 1659 } 1660 Dimension size = null; 1661 if (ui != null) { 1662 size = ui.getPreferredSize(this); 1663 } 1664 return (size != null) ? size : super.getPreferredSize(); 1665 } 1666 1667 1668 /** 1669 * Sets the maximum size of this component to a constant 1670 * value. Subsequent calls to <code>getMaximumSize</code> will always 1671 * return this value; the component's UI will not be asked 1672 * to compute it. Setting the maximum size to <code>null</code> 1673 * restores the default behavior. 1674 * 1675 * @param maximumSize a <code>Dimension</code> containing the 1676 * desired maximum allowable size 1677 * @see #getMaximumSize 1678 * @beaninfo 1679 * bound: true 1680 * description: The maximum size of the component. 1681 */ 1682 public void setMaximumSize(Dimension maximumSize) { 1683 super.setMaximumSize(maximumSize); 1684 } 1685 1686 1687 /** 1688 * If the maximum size has been set to a non-<code>null</code> value 1689 * just returns it. If the UI delegate's <code>getMaximumSize</code> 1690 * method returns a non-<code>null</code> value then return that; 1691 * otherwise defer to the component's layout manager. 1692 * 1693 * @return the value of the <code>maximumSize</code> property 1694 * @see #setMaximumSize 1695 * @see ComponentUI 1696 */ 1697 @Transient 1698 public Dimension getMaximumSize() { 1699 if (isMaximumSizeSet()) { 1700 return super.getMaximumSize(); 1701 } 1702 Dimension size = null; 1703 if (ui != null) { 1704 size = ui.getMaximumSize(this); 1705 } 1706 return (size != null) ? size : super.getMaximumSize(); 1707 } 1708 1709 1710 /** 1711 * Sets the minimum size of this component to a constant 1712 * value. Subsequent calls to <code>getMinimumSize</code> will always 1713 * return this value; the component's UI will not be asked 1714 * to compute it. Setting the minimum size to <code>null</code> 1715 * restores the default behavior. 1716 * 1717 * @param minimumSize the new minimum size of this component 1718 * @see #getMinimumSize 1719 * @beaninfo 1720 * bound: true 1721 * description: The minimum size of the component. 1722 */ 1723 public void setMinimumSize(Dimension minimumSize) { 1724 super.setMinimumSize(minimumSize); 1725 } 1726 1727 /** 1728 * If the minimum size has been set to a non-<code>null</code> value 1729 * just returns it. If the UI delegate's <code>getMinimumSize</code> 1730 * method returns a non-<code>null</code> value then return that; otherwise 1731 * defer to the component's layout manager. 1732 * 1733 * @return the value of the <code>minimumSize</code> property 1734 * @see #setMinimumSize 1735 * @see ComponentUI 1736 */ 1737 @Transient 1738 public Dimension getMinimumSize() { 1739 if (isMinimumSizeSet()) { 1740 return super.getMinimumSize(); 1741 } 1742 Dimension size = null; 1743 if (ui != null) { 1744 size = ui.getMinimumSize(this); 1745 } 1746 return (size != null) ? size : super.getMinimumSize(); 1747 } 1748 1749 /** 1750 * Gives the UI delegate an opportunity to define the precise 1751 * shape of this component for the sake of mouse processing. 1752 * 1753 * @return true if this component logically contains x,y 1754 * @see java.awt.Component#contains(int, int) 1755 * @see ComponentUI 1756 */ 1757 public boolean contains(int x, int y) { 1758 return (ui != null) ? ui.contains(this, x, y) : super.contains(x, y); 1759 } 1760 1761 /** 1762 * Sets the border of this component. The <code>Border</code> object is 1763 * responsible for defining the insets for the component 1764 * (overriding any insets set directly on the component) and 1765 * for optionally rendering any border decorations within the 1766 * bounds of those insets. Borders should be used (rather 1767 * than insets) for creating both decorative and non-decorative 1768 * (such as margins and padding) regions for a swing component. 1769 * Compound borders can be used to nest multiple borders within a 1770 * single component. 1771 * <p> 1772 * Although technically you can set the border on any object 1773 * that inherits from <code>JComponent</code>, the look and 1774 * feel implementation of many standard Swing components 1775 * doesn't work well with user-set borders. In general, 1776 * when you want to set a border on a standard Swing 1777 * component other than <code>JPanel</code> or <code>JLabel</code>, 1778 * we recommend that you put the component in a <code>JPanel</code> 1779 * and set the border on the <code>JPanel</code>. 1780 * <p> 1781 * This is a bound property. 1782 * 1783 * @param border the border to be rendered for this component 1784 * @see Border 1785 * @see CompoundBorder 1786 * @beaninfo 1787 * bound: true 1788 * preferred: true 1789 * attribute: visualUpdate true 1790 * description: The component's border. 1791 */ 1792 public void setBorder(Border border) { 1793 Border oldBorder = this.border; 1794 1795 this.border = border; 1796 firePropertyChange("border", oldBorder, border); 1797 if (border != oldBorder) { 1798 if (border == null || oldBorder == null || 1799 !(border.getBorderInsets(this).equals(oldBorder.getBorderInsets(this)))) { 1800 revalidate(); 1801 } 1802 repaint(); 1803 } 1804 } 1805 1806 /** 1807 * Returns the border of this component or <code>null</code> if no 1808 * border is currently set. 1809 * 1810 * @return the border object for this component 1811 * @see #setBorder 1812 */ 1813 public Border getBorder() { 1814 return border; 1815 } 1816 1817 /** 1818 * If a border has been set on this component, returns the 1819 * border's insets; otherwise calls <code>super.getInsets</code>. 1820 * 1821 * @return the value of the insets property 1822 * @see #setBorder 1823 */ 1824 public Insets getInsets() { 1825 if (border != null) { 1826 return border.getBorderInsets(this); 1827 } 1828 return super.getInsets(); 1829 } 1830 1831 /** 1832 * Returns an <code>Insets</code> object containing this component's inset 1833 * values. The passed-in <code>Insets</code> object will be reused 1834 * if possible. 1835 * Calling methods cannot assume that the same object will be returned, 1836 * however. All existing values within this object are overwritten. 1837 * If <code>insets</code> is null, this will allocate a new one. 1838 * 1839 * @param insets the <code>Insets</code> object, which can be reused 1840 * @return the <code>Insets</code> object 1841 * @see #getInsets 1842 * @beaninfo 1843 * expert: true 1844 */ 1845 public Insets getInsets(Insets insets) { 1846 if (insets == null) { 1847 insets = new Insets(0, 0, 0, 0); 1848 } 1849 if (border != null) { 1850 if (border instanceof AbstractBorder) { 1851 return ((AbstractBorder)border).getBorderInsets(this, insets); 1852 } else { 1853 // Can't reuse border insets because the Border interface 1854 // can't be enhanced. 1855 return border.getBorderInsets(this); 1856 } 1857 } else { 1858 // super.getInsets() always returns an Insets object with 1859 // all of its value zeroed. No need for a new object here. 1860 insets.left = insets.top = insets.right = insets.bottom = 0; 1861 return insets; 1862 } 1863 } 1864 1865 /** 1866 * Overrides <code>Container.getAlignmentY</code> to return 1867 * the horizontal alignment. 1868 * 1869 * @return the value of the <code>alignmentY</code> property 1870 * @see #setAlignmentY 1871 * @see java.awt.Component#getAlignmentY 1872 */ 1873 public float getAlignmentY() { 1874 if (isAlignmentYSet) { 1875 return alignmentY; 1876 } 1877 return super.getAlignmentY(); 1878 } 1879 1880 /** 1881 * Sets the the horizontal alignment. 1882 * 1883 * @param alignmentY the new horizontal alignment 1884 * @see #getAlignmentY 1885 * @beaninfo 1886 * description: The preferred vertical alignment of the component. 1887 */ 1888 public void setAlignmentY(float alignmentY) { 1889 this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY; 1890 isAlignmentYSet = true; 1891 } 1892 1893 1894 /** 1895 * Overrides <code>Container.getAlignmentX</code> to return 1896 * the vertical alignment. 1897 * 1898 * @return the value of the <code>alignmentX</code> property 1899 * @see #setAlignmentX 1900 * @see java.awt.Component#getAlignmentX 1901 */ 1902 public float getAlignmentX() { 1903 if (isAlignmentXSet) { 1904 return alignmentX; 1905 } 1906 return super.getAlignmentX(); 1907 } 1908 1909 /** 1910 * Sets the the vertical alignment. 1911 * 1912 * @param alignmentX the new vertical alignment 1913 * @see #getAlignmentX 1914 * @beaninfo 1915 * description: The preferred horizontal alignment of the component. 1916 */ 1917 public void setAlignmentX(float alignmentX) { 1918 this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX; 1919 isAlignmentXSet = true; 1920 } 1921 1922 /** 1923 * Sets the input verifier for this component. 1924 * 1925 * @param inputVerifier the new input verifier 1926 * @since 1.3 1927 * @see InputVerifier 1928 * @beaninfo 1929 * bound: true 1930 * description: The component's input verifier. 1931 */ 1932 public void setInputVerifier(InputVerifier inputVerifier) { 1933 InputVerifier oldInputVerifier = (InputVerifier)getClientProperty( 1934 JComponent_INPUT_VERIFIER); 1935 putClientProperty(JComponent_INPUT_VERIFIER, inputVerifier); 1936 firePropertyChange("inputVerifier", oldInputVerifier, inputVerifier); 1937 } 1938 1939 /** 1940 * Returns the input verifier for this component. 1941 * 1942 * @return the <code>inputVerifier</code> property 1943 * @since 1.3 1944 * @see InputVerifier 1945 */ 1946 public InputVerifier getInputVerifier() { 1947 return (InputVerifier)getClientProperty(JComponent_INPUT_VERIFIER); 1948 } 1949 1950 /** 1951 * Returns this component's graphics context, which lets you draw 1952 * on a component. Use this method to get a <code>Graphics</code> object and 1953 * then invoke operations on that object to draw on the component. 1954 * @return this components graphics context 1955 */ 1956 public Graphics getGraphics() { 1957 if (DEBUG_GRAPHICS_LOADED && shouldDebugGraphics() != 0) { 1958 DebugGraphics graphics = new DebugGraphics(super.getGraphics(), 1959 this); 1960 return graphics; 1961 } 1962 return super.getGraphics(); 1963 } 1964 1965 1966 /** Enables or disables diagnostic information about every graphics 1967 * operation performed within the component or one of its children. 1968 * 1969 * @param debugOptions determines how the component should display 1970 * the information; one of the following options: 1971 * <ul> 1972 * <li>DebugGraphics.LOG_OPTION - causes a text message to be printed. 1973 * <li>DebugGraphics.FLASH_OPTION - causes the drawing to flash several 1974 * times. 1975 * <li>DebugGraphics.BUFFERED_OPTION - creates an 1976 * <code>ExternalWindow</code> that displays the operations 1977 * performed on the View's offscreen buffer. 1978 * <li>DebugGraphics.NONE_OPTION disables debugging. 1979 * <li>A value of 0 causes no changes to the debugging options. 1980 * </ul> 1981 * <code>debugOptions</code> is bitwise OR'd into the current value 1982 * 1983 * @beaninfo 1984 * preferred: true 1985 * enum: NONE_OPTION DebugGraphics.NONE_OPTION 1986 * LOG_OPTION DebugGraphics.LOG_OPTION 1987 * FLASH_OPTION DebugGraphics.FLASH_OPTION 1988 * BUFFERED_OPTION DebugGraphics.BUFFERED_OPTION 1989 * description: Diagnostic options for graphics operations. 1990 */ 1991 public void setDebugGraphicsOptions(int debugOptions) { 1992 DebugGraphics.setDebugOptions(this, debugOptions); 1993 } 1994 1995 /** Returns the state of graphics debugging. 1996 * 1997 * @return a bitwise OR'd flag of zero or more of the following options: 1998 * <ul> 1999 * <li>DebugGraphics.LOG_OPTION - causes a text message to be printed. 2000 * <li>DebugGraphics.FLASH_OPTION - causes the drawing to flash several 2001 * times. 2002 * <li>DebugGraphics.BUFFERED_OPTION - creates an 2003 * <code>ExternalWindow</code> that displays the operations 2004 * performed on the View's offscreen buffer. 2005 * <li>DebugGraphics.NONE_OPTION disables debugging. 2006 * <li>A value of 0 causes no changes to the debugging options. 2007 * </ul> 2008 * @see #setDebugGraphicsOptions 2009 */ 2010 public int getDebugGraphicsOptions() { 2011 return DebugGraphics.getDebugOptions(this); 2012 } 2013 2014 2015 /** 2016 * Returns true if debug information is enabled for this 2017 * <code>JComponent</code> or one of its parents. 2018 */ 2019 int shouldDebugGraphics() { 2020 return DebugGraphics.shouldComponentDebug(this); 2021 } 2022 2023 /** 2024 * This method is now obsolete, please use a combination of 2025 * <code>getActionMap()</code> and <code>getInputMap()</code> for 2026 * similar behavior. For example, to bind the <code>KeyStroke</code> 2027 * <code>aKeyStroke</code> to the <code>Action</code> <code>anAction</code> 2028 * now use: 2029 * <pre> 2030 * component.getInputMap().put(aKeyStroke, aCommand); 2031 * component.getActionMap().put(aCommmand, anAction); 2032 * </pre> 2033 * The above assumes you want the binding to be applicable for 2034 * <code>WHEN_FOCUSED</code>. To register bindings for other focus 2035 * states use the <code>getInputMap</code> method that takes an integer. 2036 * <p> 2037 * Register a new keyboard action. 2038 * <code>anAction</code> will be invoked if a key event matching 2039 * <code>aKeyStroke</code> occurs and <code>aCondition</code> is verified. 2040 * The <code>KeyStroke</code> object defines a 2041 * particular combination of a keyboard key and one or more modifiers 2042 * (alt, shift, ctrl, meta). 2043 * <p> 2044 * The <code>aCommand</code> will be set in the delivered event if 2045 * specified. 2046 * <p> 2047 * The <code>aCondition</code> can be one of: 2048 * <blockquote> 2049 * <DL> 2050 * <DT>WHEN_FOCUSED 2051 * <DD>The action will be invoked only when the keystroke occurs 2052 * while the component has the focus. 2053 * <DT>WHEN_IN_FOCUSED_WINDOW 2054 * <DD>The action will be invoked when the keystroke occurs while 2055 * the component has the focus or if the component is in the 2056 * window that has the focus. Note that the component need not 2057 * be an immediate descendent of the window -- it can be 2058 * anywhere in the window's containment hierarchy. In other 2059 * words, whenever <em>any</em> component in the window has the focus, 2060 * the action registered with this component is invoked. 2061 * <DT>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 2062 * <DD>The action will be invoked when the keystroke occurs while the 2063 * component has the focus or if the component is an ancestor of 2064 * the component that has the focus. 2065 * </DL> 2066 * </blockquote> 2067 * <p> 2068 * The combination of keystrokes and conditions lets you define high 2069 * level (semantic) action events for a specified keystroke+modifier 2070 * combination (using the KeyStroke class) and direct to a parent or 2071 * child of a component that has the focus, or to the component itself. 2072 * In other words, in any hierarchical structure of components, an 2073 * arbitrary key-combination can be immediately directed to the 2074 * appropriate component in the hierarchy, and cause a specific method 2075 * to be invoked (usually by way of adapter objects). 2076 * <p> 2077 * If an action has already been registered for the receiving 2078 * container, with the same charCode and the same modifiers, 2079 * <code>anAction</code> will replace the action. 2080 * 2081 * @param anAction the <code>Action</code> to be registered 2082 * @param aCommand the command to be set in the delivered event 2083 * @param aKeyStroke the <code>KeyStroke</code> to bind to the action 2084 * @param aCondition the condition that needs to be met, see above 2085 * @see KeyStroke 2086 */ 2087 public void registerKeyboardAction(ActionListener anAction,String aCommand,KeyStroke aKeyStroke,int aCondition) { 2088 2089 InputMap inputMap = getInputMap(aCondition, true); 2090 2091 if (inputMap != null) { 2092 ActionMap actionMap = getActionMap(true); 2093 ActionStandin action = new ActionStandin(anAction, aCommand); 2094 inputMap.put(aKeyStroke, action); 2095 if (actionMap != null) { 2096 actionMap.put(action, action); 2097 } 2098 } 2099 } 2100 2101 /** 2102 * Registers any bound <code>WHEN_IN_FOCUSED_WINDOW</code> actions with 2103 * the <code>KeyboardManager</code>. If <code>onlyIfNew</code> 2104 * is true only actions that haven't been registered are pushed 2105 * to the <code>KeyboardManager</code>; 2106 * otherwise all actions are pushed to the <code>KeyboardManager</code>. 2107 * 2108 * @param onlyIfNew if true, only actions that haven't been registered 2109 * are pushed to the <code>KeyboardManager</code> 2110 */ 2111 private void registerWithKeyboardManager(boolean onlyIfNew) { 2112 InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW, false); 2113 KeyStroke[] strokes; 2114 @SuppressWarnings("unchecked") 2115 Hashtable<KeyStroke, KeyStroke> registered = 2116 (Hashtable<KeyStroke, KeyStroke>)getClientProperty 2117 (WHEN_IN_FOCUSED_WINDOW_BINDINGS); 2118 2119 if (inputMap != null) { 2120 // Push any new KeyStrokes to the KeyboardManager. 2121 strokes = inputMap.allKeys(); 2122 if (strokes != null) { 2123 for (int counter = strokes.length - 1; counter >= 0; 2124 counter--) { 2125 if (!onlyIfNew || registered == null || 2126 registered.get(strokes[counter]) == null) { 2127 registerWithKeyboardManager(strokes[counter]); 2128 } 2129 if (registered != null) { 2130 registered.remove(strokes[counter]); 2131 } 2132 } 2133 } 2134 } 2135 else { 2136 strokes = null; 2137 } 2138 // Remove any old ones. 2139 if (registered != null && registered.size() > 0) { 2140 Enumeration<KeyStroke> keys = registered.keys(); 2141 2142 while (keys.hasMoreElements()) { 2143 KeyStroke ks = keys.nextElement(); 2144 unregisterWithKeyboardManager(ks); 2145 } 2146 registered.clear(); 2147 } 2148 // Updated the registered Hashtable. 2149 if (strokes != null && strokes.length > 0) { 2150 if (registered == null) { 2151 registered = new Hashtable<KeyStroke, KeyStroke>(strokes.length); 2152 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, registered); 2153 } 2154 for (int counter = strokes.length - 1; counter >= 0; counter--) { 2155 registered.put(strokes[counter], strokes[counter]); 2156 } 2157 } 2158 else { 2159 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, null); 2160 } 2161 } 2162 2163 /** 2164 * Unregisters all the previously registered 2165 * <code>WHEN_IN_FOCUSED_WINDOW</code> <code>KeyStroke</code> bindings. 2166 */ 2167 private void unregisterWithKeyboardManager() { 2168 @SuppressWarnings("unchecked") 2169 Hashtable<KeyStroke, KeyStroke> registered = 2170 (Hashtable<KeyStroke, KeyStroke>)getClientProperty 2171 (WHEN_IN_FOCUSED_WINDOW_BINDINGS); 2172 2173 if (registered != null && registered.size() > 0) { 2174 Enumeration<KeyStroke> keys = registered.keys(); 2175 2176 while (keys.hasMoreElements()) { 2177 KeyStroke ks = keys.nextElement(); 2178 unregisterWithKeyboardManager(ks); 2179 } 2180 } 2181 putClientProperty(WHEN_IN_FOCUSED_WINDOW_BINDINGS, null); 2182 } 2183 2184 /** 2185 * Invoked from <code>ComponentInputMap</code> when its bindings change. 2186 * If <code>inputMap</code> is the current <code>windowInputMap</code> 2187 * (or a parent of the window <code>InputMap</code>) 2188 * the <code>KeyboardManager</code> is notified of the new bindings. 2189 * 2190 * @param inputMap the map containing the new bindings 2191 */ 2192 void componentInputMapChanged(ComponentInputMap inputMap) { 2193 InputMap km = getInputMap(WHEN_IN_FOCUSED_WINDOW, false); 2194 2195 while (km != inputMap && km != null) { 2196 km = km.getParent(); 2197 } 2198 if (km != null) { 2199 registerWithKeyboardManager(false); 2200 } 2201 } 2202 2203 private void registerWithKeyboardManager(KeyStroke aKeyStroke) { 2204 KeyboardManager.getCurrentManager().registerKeyStroke(aKeyStroke,this); 2205 } 2206 2207 private void unregisterWithKeyboardManager(KeyStroke aKeyStroke) { 2208 KeyboardManager.getCurrentManager().unregisterKeyStroke(aKeyStroke, 2209 this); 2210 } 2211 2212 /** 2213 * This method is now obsolete, please use a combination of 2214 * <code>getActionMap()</code> and <code>getInputMap()</code> for 2215 * similar behavior. 2216 */ 2217 public void registerKeyboardAction(ActionListener anAction,KeyStroke aKeyStroke,int aCondition) { 2218 registerKeyboardAction(anAction,null,aKeyStroke,aCondition); 2219 } 2220 2221 /** 2222 * This method is now obsolete. To unregister an existing binding 2223 * you can either remove the binding from the 2224 * <code>ActionMap/InputMap</code>, or place a dummy binding the 2225 * <code>InputMap</code>. Removing the binding from the 2226 * <code>InputMap</code> allows bindings in parent <code>InputMap</code>s 2227 * to be active, whereas putting a dummy binding in the 2228 * <code>InputMap</code> effectively disables 2229 * the binding from ever happening. 2230 * <p> 2231 * Unregisters a keyboard action. 2232 * This will remove the binding from the <code>ActionMap</code> 2233 * (if it exists) as well as the <code>InputMap</code>s. 2234 */ 2235 public void unregisterKeyboardAction(KeyStroke aKeyStroke) { 2236 ActionMap am = getActionMap(false); 2237 for (int counter = 0; counter < 3; counter++) { 2238 InputMap km = getInputMap(counter, false); 2239 if (km != null) { 2240 Object actionID = km.get(aKeyStroke); 2241 2242 if (am != null && actionID != null) { 2243 am.remove(actionID); 2244 } 2245 km.remove(aKeyStroke); 2246 } 2247 } 2248 } 2249 2250 /** 2251 * Returns the <code>KeyStrokes</code> that will initiate 2252 * registered actions. 2253 * 2254 * @return an array of <code>KeyStroke</code> objects 2255 * @see #registerKeyboardAction 2256 */ 2257 public KeyStroke[] getRegisteredKeyStrokes() { 2258 int[] counts = new int[3]; 2259 KeyStroke[][] strokes = new KeyStroke[3][]; 2260 2261 for (int counter = 0; counter < 3; counter++) { 2262 InputMap km = getInputMap(counter, false); 2263 strokes[counter] = (km != null) ? km.allKeys() : null; 2264 counts[counter] = (strokes[counter] != null) ? 2265 strokes[counter].length : 0; 2266 } 2267 KeyStroke[] retValue = new KeyStroke[counts[0] + counts[1] + 2268 counts[2]]; 2269 for (int counter = 0, last = 0; counter < 3; counter++) { 2270 if (counts[counter] > 0) { 2271 System.arraycopy(strokes[counter], 0, retValue, last, 2272 counts[counter]); 2273 last += counts[counter]; 2274 } 2275 } 2276 return retValue; 2277 } 2278 2279 /** 2280 * Returns the condition that determines whether a registered action 2281 * occurs in response to the specified keystroke. 2282 * <p> 2283 * For Java 2 platform v1.3, a <code>KeyStroke</code> can be associated 2284 * with more than one condition. 2285 * For example, 'a' could be bound for the two 2286 * conditions <code>WHEN_FOCUSED</code> and 2287 * <code>WHEN_IN_FOCUSED_WINDOW</code> condition. 2288 * 2289 * @return the action-keystroke condition 2290 */ 2291 public int getConditionForKeyStroke(KeyStroke aKeyStroke) { 2292 for (int counter = 0; counter < 3; counter++) { 2293 InputMap inputMap = getInputMap(counter, false); 2294 if (inputMap != null && inputMap.get(aKeyStroke) != null) { 2295 return counter; 2296 } 2297 } 2298 return UNDEFINED_CONDITION; 2299 } 2300 2301 /** 2302 * Returns the object that will perform the action registered for a 2303 * given keystroke. 2304 * 2305 * @return the <code>ActionListener</code> 2306 * object invoked when the keystroke occurs 2307 */ 2308 public ActionListener getActionForKeyStroke(KeyStroke aKeyStroke) { 2309 ActionMap am = getActionMap(false); 2310 2311 if (am == null) { 2312 return null; 2313 } 2314 for (int counter = 0; counter < 3; counter++) { 2315 InputMap inputMap = getInputMap(counter, false); 2316 if (inputMap != null) { 2317 Object actionBinding = inputMap.get(aKeyStroke); 2318 2319 if (actionBinding != null) { 2320 Action action = am.get(actionBinding); 2321 if (action instanceof ActionStandin) { 2322 return ((ActionStandin)action).actionListener; 2323 } 2324 return action; 2325 } 2326 } 2327 } 2328 return null; 2329 } 2330 2331 /** 2332 * Unregisters all the bindings in the first tier <code>InputMaps</code> 2333 * and <code>ActionMap</code>. This has the effect of removing any 2334 * local bindings, and allowing the bindings defined in parent 2335 * <code>InputMap/ActionMaps</code> 2336 * (the UI is usually defined in the second tier) to persist. 2337 */ 2338 public void resetKeyboardActions() { 2339 // Keys 2340 for (int counter = 0; counter < 3; counter++) { 2341 InputMap inputMap = getInputMap(counter, false); 2342 2343 if (inputMap != null) { 2344 inputMap.clear(); 2345 } 2346 } 2347 2348 // Actions 2349 ActionMap am = getActionMap(false); 2350 2351 if (am != null) { 2352 am.clear(); 2353 } 2354 } 2355 2356 /** 2357 * Sets the <code>InputMap</code> to use under the condition 2358 * <code>condition</code> to 2359 * <code>map</code>. A <code>null</code> value implies you 2360 * do not want any bindings to be used, even from the UI. This will 2361 * not reinstall the UI <code>InputMap</code> (if there was one). 2362 * <code>condition</code> has one of the following values: 2363 * <ul> 2364 * <li><code>WHEN_IN_FOCUSED_WINDOW</code> 2365 * <li><code>WHEN_FOCUSED</code> 2366 * <li><code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> 2367 * </ul> 2368 * If <code>condition</code> is <code>WHEN_IN_FOCUSED_WINDOW</code> 2369 * and <code>map</code> is not a <code>ComponentInputMap</code>, an 2370 * <code>IllegalArgumentException</code> will be thrown. 2371 * Similarly, if <code>condition</code> is not one of the values 2372 * listed, an <code>IllegalArgumentException</code> will be thrown. 2373 * 2374 * @param condition one of the values listed above 2375 * @param map the <code>InputMap</code> to use for the given condition 2376 * @exception IllegalArgumentException if <code>condition</code> is 2377 * <code>WHEN_IN_FOCUSED_WINDOW</code> and <code>map</code> 2378 * is not an instance of <code>ComponentInputMap</code>; or 2379 * if <code>condition</code> is not one of the legal values 2380 * specified above 2381 * @since 1.3 2382 */ 2383 public final void setInputMap(int condition, InputMap map) { 2384 switch (condition) { 2385 case WHEN_IN_FOCUSED_WINDOW: 2386 if (map != null && !(map instanceof ComponentInputMap)) { 2387 throw new IllegalArgumentException("WHEN_IN_FOCUSED_WINDOW InputMaps must be of type ComponentInputMap"); 2388 } 2389 windowInputMap = (ComponentInputMap)map; 2390 setFlag(WIF_INPUTMAP_CREATED, true); 2391 registerWithKeyboardManager(false); 2392 break; 2393 case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: 2394 ancestorInputMap = map; 2395 setFlag(ANCESTOR_INPUTMAP_CREATED, true); 2396 break; 2397 case WHEN_FOCUSED: 2398 focusInputMap = map; 2399 setFlag(FOCUS_INPUTMAP_CREATED, true); 2400 break; 2401 default: 2402 throw new IllegalArgumentException("condition must be one of JComponent.WHEN_IN_FOCUSED_WINDOW, JComponent.WHEN_FOCUSED or JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT"); 2403 } 2404 } 2405 2406 /** 2407 * Returns the <code>InputMap</code> that is used during 2408 * <code>condition</code>. 2409 * 2410 * @param condition one of WHEN_IN_FOCUSED_WINDOW, WHEN_FOCUSED, 2411 * WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 2412 * @return the <code>InputMap</code> for the specified 2413 * <code>condition</code> 2414 * @since 1.3 2415 */ 2416 public final InputMap getInputMap(int condition) { 2417 return getInputMap(condition, true); 2418 } 2419 2420 /** 2421 * Returns the <code>InputMap</code> that is used when the 2422 * component has focus. 2423 * This is convenience method for <code>getInputMap(WHEN_FOCUSED)</code>. 2424 * 2425 * @return the <code>InputMap</code> used when the component has focus 2426 * @since 1.3 2427 */ 2428 public final InputMap getInputMap() { 2429 return getInputMap(WHEN_FOCUSED, true); 2430 } 2431 2432 /** 2433 * Sets the <code>ActionMap</code> to <code>am</code>. This does not set 2434 * the parent of the <code>am</code> to be the <code>ActionMap</code> 2435 * from the UI (if there was one), it is up to the caller to have done this. 2436 * 2437 * @param am the new <code>ActionMap</code> 2438 * @since 1.3 2439 */ 2440 public final void setActionMap(ActionMap am) { 2441 actionMap = am; 2442 setFlag(ACTIONMAP_CREATED, true); 2443 } 2444 2445 /** 2446 * Returns the <code>ActionMap</code> used to determine what 2447 * <code>Action</code> to fire for particular <code>KeyStroke</code> 2448 * binding. The returned <code>ActionMap</code>, unless otherwise 2449 * set, will have the <code>ActionMap</code> from the UI set as the parent. 2450 * 2451 * @return the <code>ActionMap</code> containing the key/action bindings 2452 * @since 1.3 2453 */ 2454 public final ActionMap getActionMap() { 2455 return getActionMap(true); 2456 } 2457 2458 /** 2459 * Returns the <code>InputMap</code> to use for condition 2460 * <code>condition</code>. If the <code>InputMap</code> hasn't 2461 * been created, and <code>create</code> is 2462 * true, it will be created. 2463 * 2464 * @param condition one of the following values: 2465 * <ul> 2466 * <li>JComponent.FOCUS_INPUTMAP_CREATED 2467 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 2468 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW 2469 * </ul> 2470 * @param create if true, create the <code>InputMap</code> if it 2471 * is not already created 2472 * @return the <code>InputMap</code> for the given <code>condition</code>; 2473 * if <code>create</code> is false and the <code>InputMap</code> 2474 * hasn't been created, returns <code>null</code> 2475 * @exception IllegalArgumentException if <code>condition</code> 2476 * is not one of the legal values listed above 2477 */ 2478 final InputMap getInputMap(int condition, boolean create) { 2479 switch (condition) { 2480 case WHEN_FOCUSED: 2481 if (getFlag(FOCUS_INPUTMAP_CREATED)) { 2482 return focusInputMap; 2483 } 2484 // Hasn't been created yet. 2485 if (create) { 2486 InputMap km = new InputMap(); 2487 setInputMap(condition, km); 2488 return km; 2489 } 2490 break; 2491 case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: 2492 if (getFlag(ANCESTOR_INPUTMAP_CREATED)) { 2493 return ancestorInputMap; 2494 } 2495 // Hasn't been created yet. 2496 if (create) { 2497 InputMap km = new InputMap(); 2498 setInputMap(condition, km); 2499 return km; 2500 } 2501 break; 2502 case WHEN_IN_FOCUSED_WINDOW: 2503 if (getFlag(WIF_INPUTMAP_CREATED)) { 2504 return windowInputMap; 2505 } 2506 // Hasn't been created yet. 2507 if (create) { 2508 ComponentInputMap km = new ComponentInputMap(this); 2509 setInputMap(condition, km); 2510 return km; 2511 } 2512 break; 2513 default: 2514 throw new IllegalArgumentException("condition must be one of JComponent.WHEN_IN_FOCUSED_WINDOW, JComponent.WHEN_FOCUSED or JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT"); 2515 } 2516 return null; 2517 } 2518 2519 /** 2520 * Finds and returns the appropriate <code>ActionMap</code>. 2521 * 2522 * @param create if true, create the <code>ActionMap</code> if it 2523 * is not already created 2524 * @return the <code>ActionMap</code> for this component; if the 2525 * <code>create</code> flag is false and there is no 2526 * current <code>ActionMap</code>, returns <code>null</code> 2527 */ 2528 final ActionMap getActionMap(boolean create) { 2529 if (getFlag(ACTIONMAP_CREATED)) { 2530 return actionMap; 2531 } 2532 // Hasn't been created. 2533 if (create) { 2534 ActionMap am = new ActionMap(); 2535 setActionMap(am); 2536 return am; 2537 } 2538 return null; 2539 } 2540 2541 /** 2542 * Returns the baseline. The baseline is measured from the top of 2543 * the component. This method is primarily meant for 2544 * <code>LayoutManager</code>s to align components along their 2545 * baseline. A return value less than 0 indicates this component 2546 * does not have a reasonable baseline and that 2547 * <code>LayoutManager</code>s should not align this component on 2548 * its baseline. 2549 * <p> 2550 * This method calls into the <code>ComponentUI</code> method of the 2551 * same name. If this component does not have a <code>ComponentUI</code> 2552 * -1 will be returned. If a value >= 0 is 2553 * returned, then the component has a valid baseline for any 2554 * size >= the minimum size and <code>getBaselineResizeBehavior</code> 2555 * can be used to determine how the baseline changes with size. 2556 * 2557 * @throws IllegalArgumentException {@inheritDoc} 2558 * @see #getBaselineResizeBehavior 2559 * @see java.awt.FontMetrics 2560 * @since 1.6 2561 */ 2562 public int getBaseline(int width, int height) { 2563 // check size. 2564 super.getBaseline(width, height); 2565 if (ui != null) { 2566 return ui.getBaseline(this, width, height); 2567 } 2568 return -1; 2569 } 2570 2571 /** 2572 * Returns an enum indicating how the baseline of the component 2573 * changes as the size changes. This method is primarily meant for 2574 * layout managers and GUI builders. 2575 * <p> 2576 * This method calls into the <code>ComponentUI</code> method of 2577 * the same name. If this component does not have a 2578 * <code>ComponentUI</code> 2579 * <code>BaselineResizeBehavior.OTHER</code> will be 2580 * returned. Subclasses should 2581 * never return <code>null</code>; if the baseline can not be 2582 * calculated return <code>BaselineResizeBehavior.OTHER</code>. Callers 2583 * should first ask for the baseline using 2584 * <code>getBaseline</code> and if a value >= 0 is returned use 2585 * this method. It is acceptable for this method to return a 2586 * value other than <code>BaselineResizeBehavior.OTHER</code> even if 2587 * <code>getBaseline</code> returns a value less than 0. 2588 * 2589 * @see #getBaseline(int, int) 2590 * @since 1.6 2591 */ 2592 public BaselineResizeBehavior getBaselineResizeBehavior() { 2593 if (ui != null) { 2594 return ui.getBaselineResizeBehavior(this); 2595 } 2596 return BaselineResizeBehavior.OTHER; 2597 } 2598 2599 /** 2600 * In release 1.4, the focus subsystem was rearchitected. 2601 * For more information, see 2602 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html"> 2603 * How to Use the Focus Subsystem</a>, 2604 * a section in <em>The Java Tutorial</em>. 2605 * <p> 2606 * Requests focus on this <code>JComponent</code>'s 2607 * <code>FocusTraversalPolicy</code>'s default <code>Component</code>. 2608 * If this <code>JComponent</code> is a focus cycle root, then its 2609 * <code>FocusTraversalPolicy</code> is used. Otherwise, the 2610 * <code>FocusTraversalPolicy</code> of this <code>JComponent</code>'s 2611 * focus-cycle-root ancestor is used. 2612 * 2613 * @see java.awt.FocusTraversalPolicy#getDefaultComponent 2614 * @deprecated As of 1.4, replaced by 2615 * <code>FocusTraversalPolicy.getDefaultComponent(Container).requestFocus()</code> 2616 */ 2617 @Deprecated 2618 public boolean requestDefaultFocus() { 2619 Container nearestRoot = 2620 (isFocusCycleRoot()) ? this : getFocusCycleRootAncestor(); 2621 if (nearestRoot == null) { 2622 return false; 2623 } 2624 Component comp = nearestRoot.getFocusTraversalPolicy(). 2625 getDefaultComponent(nearestRoot); 2626 if (comp != null) { 2627 comp.requestFocus(); 2628 return true; 2629 } else { 2630 return false; 2631 } 2632 } 2633 2634 /** 2635 * Makes the component visible or invisible. 2636 * Overrides <code>Component.setVisible</code>. 2637 * 2638 * @param aFlag true to make the component visible; false to 2639 * make it invisible 2640 * 2641 * @beaninfo 2642 * attribute: visualUpdate true 2643 */ 2644 public void setVisible(boolean aFlag) { 2645 if (aFlag != isVisible()) { 2646 super.setVisible(aFlag); 2647 if (aFlag) { 2648 Container parent = getParent(); 2649 if (parent != null) { 2650 Rectangle r = getBounds(); 2651 parent.repaint(r.x, r.y, r.width, r.height); 2652 } 2653 revalidate(); 2654 } 2655 } 2656 } 2657 2658 /** 2659 * Sets whether or not this component is enabled. 2660 * A component that is enabled may respond to user input, 2661 * while a component that is not enabled cannot respond to 2662 * user input. Some components may alter their visual 2663 * representation when they are disabled in order to 2664 * provide feedback to the user that they cannot take input. 2665 * <p>Note: Disabling a component does not disable its children. 2666 * 2667 * <p>Note: Disabling a lightweight component does not prevent it from 2668 * receiving MouseEvents. 2669 * 2670 * @param enabled true if this component should be enabled, false otherwise 2671 * @see java.awt.Component#isEnabled 2672 * @see java.awt.Component#isLightweight 2673 * 2674 * @beaninfo 2675 * preferred: true 2676 * bound: true 2677 * attribute: visualUpdate true 2678 * description: The enabled state of the component. 2679 */ 2680 public void setEnabled(boolean enabled) { 2681 boolean oldEnabled = isEnabled(); 2682 super.setEnabled(enabled); 2683 firePropertyChange("enabled", oldEnabled, enabled); 2684 if (enabled != oldEnabled) { 2685 repaint(); 2686 } 2687 } 2688 2689 /** 2690 * Sets the foreground color of this component. It is up to the 2691 * look and feel to honor this property, some may choose to ignore 2692 * it. 2693 * 2694 * @param fg the desired foreground <code>Color</code> 2695 * @see java.awt.Component#getForeground 2696 * 2697 * @beaninfo 2698 * preferred: true 2699 * bound: true 2700 * attribute: visualUpdate true 2701 * description: The foreground color of the component. 2702 */ 2703 public void setForeground(Color fg) { 2704 Color oldFg = getForeground(); 2705 super.setForeground(fg); 2706 if ((oldFg != null) ? !oldFg.equals(fg) : ((fg != null) && !fg.equals(oldFg))) { 2707 // foreground already bound in AWT1.2 2708 repaint(); 2709 } 2710 } 2711 2712 /** 2713 * Sets the background color of this component. The background 2714 * color is used only if the component is opaque, and only 2715 * by subclasses of <code>JComponent</code> or 2716 * <code>ComponentUI</code> implementations. Direct subclasses of 2717 * <code>JComponent</code> must override 2718 * <code>paintComponent</code> to honor this property. 2719 * <p> 2720 * It is up to the look and feel to honor this property, some may 2721 * choose to ignore it. 2722 * 2723 * @param bg the desired background <code>Color</code> 2724 * @see java.awt.Component#getBackground 2725 * @see #setOpaque 2726 * 2727 * @beaninfo 2728 * preferred: true 2729 * bound: true 2730 * attribute: visualUpdate true 2731 * description: The background color of the component. 2732 */ 2733 public void setBackground(Color bg) { 2734 Color oldBg = getBackground(); 2735 super.setBackground(bg); 2736 if ((oldBg != null) ? !oldBg.equals(bg) : ((bg != null) && !bg.equals(oldBg))) { 2737 // background already bound in AWT1.2 2738 repaint(); 2739 } 2740 } 2741 2742 /** 2743 * Sets the font for this component. 2744 * 2745 * @param font the desired <code>Font</code> for this component 2746 * @see java.awt.Component#getFont 2747 * 2748 * @beaninfo 2749 * preferred: true 2750 * bound: true 2751 * attribute: visualUpdate true 2752 * description: The font for the component. 2753 */ 2754 public void setFont(Font font) { 2755 Font oldFont = getFont(); 2756 super.setFont(font); 2757 // font already bound in AWT1.2 2758 if (font != oldFont) { 2759 revalidate(); 2760 repaint(); 2761 } 2762 } 2763 2764 /** 2765 * Returns the default locale used to initialize each JComponent's 2766 * locale property upon creation. 2767 * 2768 * The default locale has "AppContext" scope so that applets (and 2769 * potentially multiple lightweight applications running in a single VM) 2770 * can have their own setting. An applet can safely alter its default 2771 * locale because it will have no affect on other applets (or the browser). 2772 * 2773 * @return the default <code>Locale</code>. 2774 * @see #setDefaultLocale 2775 * @see java.awt.Component#getLocale 2776 * @see #setLocale 2777 * @since 1.4 2778 */ 2779 static public Locale getDefaultLocale() { 2780 Locale l = (Locale) SwingUtilities.appContextGet(defaultLocale); 2781 if( l == null ) { 2782 //REMIND(bcb) choosing the default value is more complicated 2783 //than this. 2784 l = Locale.getDefault(); 2785 JComponent.setDefaultLocale( l ); 2786 } 2787 return l; 2788 } 2789 2790 2791 /** 2792 * Sets the default locale used to initialize each JComponent's locale 2793 * property upon creation. The initial value is the VM's default locale. 2794 * 2795 * The default locale has "AppContext" scope so that applets (and 2796 * potentially multiple lightweight applications running in a single VM) 2797 * can have their own setting. An applet can safely alter its default 2798 * locale because it will have no affect on other applets (or the browser). 2799 * 2800 * @param l the desired default <code>Locale</code> for new components. 2801 * @see #getDefaultLocale 2802 * @see java.awt.Component#getLocale 2803 * @see #setLocale 2804 * @since 1.4 2805 */ 2806 static public void setDefaultLocale( Locale l ) { 2807 SwingUtilities.appContextPut(defaultLocale, l); 2808 } 2809 2810 2811 /** 2812 * Processes any key events that the component itself 2813 * recognizes. This is called after the focus 2814 * manager and any interested listeners have been 2815 * given a chance to steal away the event. This 2816 * method is called only if the event has not 2817 * yet been consumed. This method is called prior 2818 * to the keyboard UI logic. 2819 * <p> 2820 * This method is implemented to do nothing. Subclasses would 2821 * normally override this method if they process some 2822 * key events themselves. If the event is processed, 2823 * it should be consumed. 2824 */ 2825 protected void processComponentKeyEvent(KeyEvent e) { 2826 } 2827 2828 /** Overrides <code>processKeyEvent</code> to process events. **/ 2829 protected void processKeyEvent(KeyEvent e) { 2830 boolean result; 2831 boolean shouldProcessKey; 2832 2833 // This gives the key event listeners a crack at the event 2834 super.processKeyEvent(e); 2835 2836 // give the component itself a crack at the event 2837 if (! e.isConsumed()) { 2838 processComponentKeyEvent(e); 2839 } 2840 2841 shouldProcessKey = KeyboardState.shouldProcess(e); 2842 2843 if(e.isConsumed()) { 2844 return; 2845 } 2846 2847 if (shouldProcessKey && processKeyBindings(e, e.getID() == 2848 KeyEvent.KEY_PRESSED)) { 2849 e.consume(); 2850 } 2851 } 2852 2853 /** 2854 * Invoked to process the key bindings for <code>ks</code> as the result 2855 * of the <code>KeyEvent</code> <code>e</code>. This obtains 2856 * the appropriate <code>InputMap</code>, 2857 * gets the binding, gets the action from the <code>ActionMap</code>, 2858 * and then (if the action is found and the component 2859 * is enabled) invokes <code>notifyAction</code> to notify the action. 2860 * 2861 * @param ks the <code>KeyStroke</code> queried 2862 * @param e the <code>KeyEvent</code> 2863 * @param condition one of the following values: 2864 * <ul> 2865 * <li>JComponent.WHEN_FOCUSED 2866 * <li>JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT 2867 * <li>JComponent.WHEN_IN_FOCUSED_WINDOW 2868 * </ul> 2869 * @param pressed true if the key is pressed 2870 * @return true if there was a binding to an action, and the action 2871 * was enabled 2872 * 2873 * @since 1.3 2874 */ 2875 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, 2876 int condition, boolean pressed) { 2877 InputMap map = getInputMap(condition, false); 2878 ActionMap am = getActionMap(false); 2879 2880 if(map != null && am != null && isEnabled()) { 2881 Object binding = map.get(ks); 2882 Action action = (binding == null) ? null : am.get(binding); 2883 if (action != null) { 2884 return SwingUtilities.notifyAction(action, ks, e, this, 2885 e.getModifiers()); 2886 } 2887 } 2888 return false; 2889 } 2890 2891 /** 2892 * This is invoked as the result of a <code>KeyEvent</code> 2893 * that was not consumed by the <code>FocusManager</code>, 2894 * <code>KeyListeners</code>, or the component. It will first try 2895 * <code>WHEN_FOCUSED</code> bindings, 2896 * then <code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> bindings, 2897 * and finally <code>WHEN_IN_FOCUSED_WINDOW</code> bindings. 2898 * 2899 * @param e the unconsumed <code>KeyEvent</code> 2900 * @param pressed true if the key is pressed 2901 * @return true if there is a key binding for <code>e</code> 2902 */ 2903 boolean processKeyBindings(KeyEvent e, boolean pressed) { 2904 if (!SwingUtilities.isValidKeyEventForKeyBindings(e)) { 2905 return false; 2906 } 2907 // Get the KeyStroke 2908 // There may be two keystrokes associated with a low-level key event; 2909 // in this case a keystroke made of an extended key code has a priority. 2910 KeyStroke ks; 2911 KeyStroke ksE = null; 2912 2913 if (e.getID() == KeyEvent.KEY_TYPED) { 2914 ks = KeyStroke.getKeyStroke(e.getKeyChar()); 2915 } 2916 else { 2917 ks = KeyStroke.getKeyStroke(e.getKeyCode(),e.getModifiers(), 2918 (pressed ? false:true)); 2919 if (e.getKeyCode() != e.getExtendedKeyCode()) { 2920 ksE = KeyStroke.getKeyStroke(e.getExtendedKeyCode(),e.getModifiers(), 2921 (pressed ? false:true)); 2922 } 2923 } 2924 2925 // Do we have a key binding for e? 2926 // If we have a binding by an extended code, use it. 2927 // If not, check for regular code binding. 2928 if(ksE != null && processKeyBinding(ksE, e, WHEN_FOCUSED, pressed)) { 2929 return true; 2930 } 2931 if(processKeyBinding(ks, e, WHEN_FOCUSED, pressed)) 2932 return true; 2933 2934 /* We have no key binding. Let's try the path from our parent to the 2935 * window excluded. We store the path components so we can avoid 2936 * asking the same component twice. 2937 */ 2938 Container parent = this; 2939 while (parent != null && !(parent instanceof Window) && 2940 !(parent instanceof Applet)) { 2941 if(parent instanceof JComponent) { 2942 if(ksE != null && ((JComponent)parent).processKeyBinding(ksE, e, 2943 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed)) 2944 return true; 2945 if(((JComponent)parent).processKeyBinding(ks, e, 2946 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, pressed)) 2947 return true; 2948 } 2949 // This is done so that the children of a JInternalFrame are 2950 // given precedence for WHEN_IN_FOCUSED_WINDOW bindings before 2951 // other components WHEN_IN_FOCUSED_WINDOW bindings. This also gives 2952 // more precedence to the WHEN_IN_FOCUSED_WINDOW bindings of the 2953 // JInternalFrame's children vs the 2954 // WHEN_ANCESTOR_OF_FOCUSED_COMPONENT bindings of the parents. 2955 // maybe generalize from JInternalFrame (like isFocusCycleRoot). 2956 if ((parent instanceof JInternalFrame) && 2957 JComponent.processKeyBindingsForAllComponents(e,parent,pressed)){ 2958 return true; 2959 } 2960 parent = parent.getParent(); 2961 } 2962 2963 /* No components between the focused component and the window is 2964 * actually interested by the key event. Let's try the other 2965 * JComponent in this window. 2966 */ 2967 if(parent != null) { 2968 return JComponent.processKeyBindingsForAllComponents(e,parent,pressed); 2969 } 2970 return false; 2971 } 2972 2973 static boolean processKeyBindingsForAllComponents(KeyEvent e, 2974 Container container, boolean pressed) { 2975 while (true) { 2976 if (KeyboardManager.getCurrentManager().fireKeyboardAction( 2977 e, pressed, container)) { 2978 return true; 2979 } 2980 if (container instanceof Popup.HeavyWeightWindow) { 2981 container = ((Window)container).getOwner(); 2982 } 2983 else { 2984 return false; 2985 } 2986 } 2987 } 2988 2989 /** 2990 * Registers the text to display in a tool tip. 2991 * The text displays when the cursor lingers over the component. 2992 * <p> 2993 * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html">How to Use Tool Tips</a> 2994 * in <em>The Java Tutorial</em> 2995 * for further documentation. 2996 * 2997 * @param text the string to display; if the text is <code>null</code>, 2998 * the tool tip is turned off for this component 2999 * @see #TOOL_TIP_TEXT_KEY 3000 * @beaninfo 3001 * preferred: true 3002 * description: The text to display in a tool tip. 3003 */ 3004 public void setToolTipText(String text) { 3005 String oldText = getToolTipText(); 3006 putClientProperty(TOOL_TIP_TEXT_KEY, text); 3007 ToolTipManager toolTipManager = ToolTipManager.sharedInstance(); 3008 if (text != null) { 3009 if (oldText == null) { 3010 toolTipManager.registerComponent(this); 3011 } 3012 } else { 3013 toolTipManager.unregisterComponent(this); 3014 } 3015 } 3016 3017 /** 3018 * Returns the tooltip string that has been set with 3019 * <code>setToolTipText</code>. 3020 * 3021 * @return the text of the tool tip 3022 * @see #TOOL_TIP_TEXT_KEY 3023 */ 3024 public String getToolTipText() { 3025 return (String)getClientProperty(TOOL_TIP_TEXT_KEY); 3026 } 3027 3028 3029 /** 3030 * Returns the string to be used as the tooltip for <i>event</i>. 3031 * By default this returns any string set using 3032 * <code>setToolTipText</code>. If a component provides 3033 * more extensive API to support differing tooltips at different locations, 3034 * this method should be overridden. 3035 */ 3036 public String getToolTipText(MouseEvent event) { 3037 return getToolTipText(); 3038 } 3039 3040 /** 3041 * Returns the tooltip location in this component's coordinate system. 3042 * If <code>null</code> is returned, Swing will choose a location. 3043 * The default implementation returns <code>null</code>. 3044 * 3045 * @param event the <code>MouseEvent</code> that caused the 3046 * <code>ToolTipManager</code> to show the tooltip 3047 * @return always returns <code>null</code> 3048 */ 3049 public Point getToolTipLocation(MouseEvent event) { 3050 return null; 3051 } 3052 3053 /** 3054 * Returns the preferred location to display the popup menu in this 3055 * component's coordinate system. It is up to the look and feel to 3056 * honor this property, some may choose to ignore it. 3057 * If {@code null}, the look and feel will choose a suitable location. 3058 * 3059 * @param event the {@code MouseEvent} that triggered the popup to be 3060 * shown, or {@code null} if the popup is not being shown as the 3061 * result of a mouse event 3062 * @return location to display the {@code JPopupMenu}, or {@code null} 3063 * @since 1.5 3064 */ 3065 public Point getPopupLocation(MouseEvent event) { 3066 return null; 3067 } 3068 3069 3070 /** 3071 * Returns the instance of <code>JToolTip</code> that should be used 3072 * to display the tooltip. 3073 * Components typically would not override this method, 3074 * but it can be used to 3075 * cause different tooltips to be displayed differently. 3076 * 3077 * @return the <code>JToolTip</code> used to display this toolTip 3078 */ 3079 public JToolTip createToolTip() { 3080 JToolTip tip = new JToolTip(); 3081 tip.setComponent(this); 3082 return tip; 3083 } 3084 3085 /** 3086 * Forwards the <code>scrollRectToVisible()</code> message to the 3087 * <code>JComponent</code>'s parent. Components that can service 3088 * the request, such as <code>JViewport</code>, 3089 * override this method and perform the scrolling. 3090 * 3091 * @param aRect the visible <code>Rectangle</code> 3092 * @see JViewport 3093 */ 3094 public void scrollRectToVisible(Rectangle aRect) { 3095 Container parent; 3096 int dx = getX(), dy = getY(); 3097 3098 for (parent = getParent(); 3099 !(parent == null) && 3100 !(parent instanceof JComponent) && 3101 !(parent instanceof CellRendererPane); 3102 parent = parent.getParent()) { 3103 Rectangle bounds = parent.getBounds(); 3104 3105 dx += bounds.x; 3106 dy += bounds.y; 3107 } 3108 3109 if (!(parent == null) && !(parent instanceof CellRendererPane)) { 3110 aRect.x += dx; 3111 aRect.y += dy; 3112 3113 ((JComponent)parent).scrollRectToVisible(aRect); 3114 aRect.x -= dx; 3115 aRect.y -= dy; 3116 } 3117 } 3118 3119 /** 3120 * Sets the <code>autoscrolls</code> property. 3121 * If <code>true</code> mouse dragged events will be 3122 * synthetically generated when the mouse is dragged 3123 * outside of the component's bounds and mouse motion 3124 * has paused (while the button continues to be held 3125 * down). The synthetic events make it appear that the 3126 * drag gesture has resumed in the direction established when 3127 * the component's boundary was crossed. Components that 3128 * support autoscrolling must handle <code>mouseDragged</code> 3129 * events by calling <code>scrollRectToVisible</code> with a 3130 * rectangle that contains the mouse event's location. All of 3131 * the Swing components that support item selection and are 3132 * typically displayed in a <code>JScrollPane</code> 3133 * (<code>JTable</code>, <code>JList</code>, <code>JTree</code>, 3134 * <code>JTextArea</code>, and <code>JEditorPane</code>) 3135 * already handle mouse dragged events in this way. To enable 3136 * autoscrolling in any other component, add a mouse motion 3137 * listener that calls <code>scrollRectToVisible</code>. 3138 * For example, given a <code>JPanel</code>, <code>myPanel</code>: 3139 * <pre> 3140 * MouseMotionListener doScrollRectToVisible = new MouseMotionAdapter() { 3141 * public void mouseDragged(MouseEvent e) { 3142 * Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1); 3143 * ((JPanel)e.getSource()).scrollRectToVisible(r); 3144 * } 3145 * }; 3146 * myPanel.addMouseMotionListener(doScrollRectToVisible); 3147 * </pre> 3148 * The default value of the <code>autoScrolls</code> 3149 * property is <code>false</code>. 3150 * 3151 * @param autoscrolls if true, synthetic mouse dragged events 3152 * are generated when the mouse is dragged outside of a component's 3153 * bounds and the mouse button continues to be held down; otherwise 3154 * false 3155 * @see #getAutoscrolls 3156 * @see JViewport 3157 * @see JScrollPane 3158 * 3159 * @beaninfo 3160 * expert: true 3161 * description: Determines if this component automatically scrolls its contents when dragged. 3162 */ 3163 public void setAutoscrolls(boolean autoscrolls) { 3164 setFlag(AUTOSCROLLS_SET, true); 3165 if (this.autoscrolls != autoscrolls) { 3166 this.autoscrolls = autoscrolls; 3167 if (autoscrolls) { 3168 enableEvents(AWTEvent.MOUSE_EVENT_MASK); 3169 enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); 3170 } 3171 else { 3172 Autoscroller.stop(this); 3173 } 3174 } 3175 } 3176 3177 /** 3178 * Gets the <code>autoscrolls</code> property. 3179 * 3180 * @return the value of the <code>autoscrolls</code> property 3181 * @see JViewport 3182 * @see #setAutoscrolls 3183 */ 3184 public boolean getAutoscrolls() { 3185 return autoscrolls; 3186 } 3187 3188 /** 3189 * Sets the {@code TransferHandler}, which provides support for transfer 3190 * of data into and out of this component via cut/copy/paste and drag 3191 * and drop. This may be {@code null} if the component does not support 3192 * data transfer operations. 3193 * <p> 3194 * If the new {@code TransferHandler} is not {@code null}, this method 3195 * also installs a <b>new</b> {@code DropTarget} on the component to 3196 * activate drop handling through the {@code TransferHandler} and activate 3197 * any built-in support (such as calculating and displaying potential drop 3198 * locations). If you do not wish for this component to respond in any way 3199 * to drops, you can disable drop support entirely either by removing the 3200 * drop target ({@code setDropTarget(null)}) or by de-activating it 3201 * ({@code getDropTaget().setActive(false)}). 3202 * <p> 3203 * If the new {@code TransferHandler} is {@code null}, this method removes 3204 * the drop target. 3205 * <p> 3206 * Under two circumstances, this method does not modify the drop target: 3207 * First, if the existing drop target on this component was explicitly 3208 * set by the developer to a {@code non-null} value. Second, if the 3209 * system property {@code suppressSwingDropSupport} is {@code true}. The 3210 * default value for the system property is {@code false}. 3211 * <p> 3212 * Please see 3213 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html"> 3214 * How to Use Drag and Drop and Data Transfer</a>, 3215 * a section in <em>The Java Tutorial</em>, for more information. 3216 * 3217 * @param newHandler the new {@code TransferHandler} 3218 * 3219 * @see TransferHandler 3220 * @see #getTransferHandler 3221 * @since 1.4 3222 * @beaninfo 3223 * bound: true 3224 * hidden: true 3225 * description: Mechanism for transfer of data to and from the component 3226 */ 3227 public void setTransferHandler(TransferHandler newHandler) { 3228 TransferHandler oldHandler = (TransferHandler)getClientProperty( 3229 JComponent_TRANSFER_HANDLER); 3230 putClientProperty(JComponent_TRANSFER_HANDLER, newHandler); 3231 3232 SwingUtilities.installSwingDropTargetAsNecessary(this, newHandler); 3233 firePropertyChange("transferHandler", oldHandler, newHandler); 3234 } 3235 3236 /** 3237 * Gets the <code>transferHandler</code> property. 3238 * 3239 * @return the value of the <code>transferHandler</code> property 3240 * 3241 * @see TransferHandler 3242 * @see #setTransferHandler 3243 * @since 1.4 3244 */ 3245 public TransferHandler getTransferHandler() { 3246 return (TransferHandler)getClientProperty(JComponent_TRANSFER_HANDLER); 3247 } 3248 3249 /** 3250 * Calculates a custom drop location for this type of component, 3251 * representing where a drop at the given point should insert data. 3252 * <code>null</code> is returned if this component doesn't calculate 3253 * custom drop locations. In this case, <code>TransferHandler</code> 3254 * will provide a default <code>DropLocation</code> containing just 3255 * the point. 3256 * 3257 * @param p the point to calculate a drop location for 3258 * @return the drop location, or <code>null</code> 3259 */ 3260 TransferHandler.DropLocation dropLocationForPoint(Point p) { 3261 return null; 3262 } 3263 3264 /** 3265 * Called to set or clear the drop location during a DnD operation. 3266 * In some cases, the component may need to use its internal selection 3267 * temporarily to indicate the drop location. To help facilitate this, 3268 * this method returns and accepts as a parameter a state object. 3269 * This state object can be used to store, and later restore, the selection 3270 * state. Whatever this method returns will be passed back to it in 3271 * future calls, as the state parameter. If it wants the DnD system to 3272 * continue storing the same state, it must pass it back every time. 3273 * Here's how this is used: 3274 * <p> 3275 * Let's say that on the first call to this method the component decides 3276 * to save some state (because it is about to use the selection to show 3277 * a drop index). It can return a state object to the caller encapsulating 3278 * any saved selection state. On a second call, let's say the drop location 3279 * is being changed to something else. The component doesn't need to 3280 * restore anything yet, so it simply passes back the same state object 3281 * to have the DnD system continue storing it. Finally, let's say this 3282 * method is messaged with <code>null</code>. This means DnD 3283 * is finished with this component for now, meaning it should restore 3284 * state. At this point, it can use the state parameter to restore 3285 * said state, and of course return <code>null</code> since there's 3286 * no longer anything to store. 3287 * 3288 * @param location the drop location (as calculated by 3289 * <code>dropLocationForPoint</code>) or <code>null</code> 3290 * if there's no longer a valid drop location 3291 * @param state the state object saved earlier for this component, 3292 * or <code>null</code> 3293 * @param forDrop whether or not the method is being called because an 3294 * actual drop occurred 3295 * @return any saved state for this component, or <code>null</code> if none 3296 */ 3297 Object setDropLocation(TransferHandler.DropLocation location, 3298 Object state, 3299 boolean forDrop) { 3300 3301 return null; 3302 } 3303 3304 /** 3305 * Called to indicate to this component that DnD is done. 3306 * Needed by <code>JTree</code>. 3307 */ 3308 void dndDone() { 3309 } 3310 3311 /** 3312 * Processes mouse events occurring on this component by 3313 * dispatching them to any registered 3314 * <code>MouseListener</code> objects, refer to 3315 * {@link java.awt.Component#processMouseEvent(MouseEvent)} 3316 * for a complete description of this method. 3317 * 3318 * @param e the mouse event 3319 * @see java.awt.Component#processMouseEvent 3320 * @since 1.5 3321 */ 3322 protected void processMouseEvent(MouseEvent e) { 3323 if (autoscrolls && e.getID() == MouseEvent.MOUSE_RELEASED) { 3324 Autoscroller.stop(this); 3325 } 3326 super.processMouseEvent(e); 3327 } 3328 3329 /** 3330 * Processes mouse motion events, such as MouseEvent.MOUSE_DRAGGED. 3331 * 3332 * @param e the <code>MouseEvent</code> 3333 * @see MouseEvent 3334 */ 3335 protected void processMouseMotionEvent(MouseEvent e) { 3336 boolean dispatch = true; 3337 if (autoscrolls && e.getID() == MouseEvent.MOUSE_DRAGGED) { 3338 // We don't want to do the drags when the mouse moves if we're 3339 // autoscrolling. It makes it feel spastic. 3340 dispatch = !Autoscroller.isRunning(this); 3341 Autoscroller.processMouseDragged(e); 3342 } 3343 if (dispatch) { 3344 super.processMouseMotionEvent(e); 3345 } 3346 } 3347 3348 // Inner classes can't get at this method from a super class 3349 void superProcessMouseMotionEvent(MouseEvent e) { 3350 super.processMouseMotionEvent(e); 3351 } 3352 3353 /** 3354 * This is invoked by the <code>RepaintManager</code> if 3355 * <code>createImage</code> is called on the component. 3356 * 3357 * @param newValue true if the double buffer image was created from this component 3358 */ 3359 void setCreatedDoubleBuffer(boolean newValue) { 3360 setFlag(CREATED_DOUBLE_BUFFER, newValue); 3361 } 3362 3363 /** 3364 * Returns true if the <code>RepaintManager</code> 3365 * created the double buffer image from the component. 3366 * 3367 * @return true if this component had a double buffer image, false otherwise 3368 */ 3369 boolean getCreatedDoubleBuffer() { 3370 return getFlag(CREATED_DOUBLE_BUFFER); 3371 } 3372 3373 /** 3374 * <code>ActionStandin</code> is used as a standin for 3375 * <code>ActionListeners</code> that are 3376 * added via <code>registerKeyboardAction</code>. 3377 */ 3378 final class ActionStandin implements Action { 3379 private final ActionListener actionListener; 3380 private final String command; 3381 // This will be non-null if actionListener is an Action. 3382 private final Action action; 3383 3384 ActionStandin(ActionListener actionListener, String command) { 3385 this.actionListener = actionListener; 3386 if (actionListener instanceof Action) { 3387 this.action = (Action)actionListener; 3388 } 3389 else { 3390 this.action = null; 3391 } 3392 this.command = command; 3393 } 3394 3395 public Object getValue(String key) { 3396 if (key != null) { 3397 if (key.equals(Action.ACTION_COMMAND_KEY)) { 3398 return command; 3399 } 3400 if (action != null) { 3401 return action.getValue(key); 3402 } 3403 if (key.equals(NAME)) { 3404 return "ActionStandin"; 3405 } 3406 } 3407 return null; 3408 } 3409 3410 public boolean isEnabled() { 3411 if (actionListener == null) { 3412 // This keeps the old semantics where 3413 // registerKeyboardAction(null) would essentialy remove 3414 // the binding. We don't remove the binding from the 3415 // InputMap as that would still allow parent InputMaps 3416 // bindings to be accessed. 3417 return false; 3418 } 3419 if (action == null) { 3420 return true; 3421 } 3422 return action.isEnabled(); 3423 } 3424 3425 public void actionPerformed(ActionEvent ae) { 3426 if (actionListener != null) { 3427 actionListener.actionPerformed(ae); 3428 } 3429 } 3430 3431 // We don't allow any values to be added. 3432 public void putValue(String key, Object value) {} 3433 3434 // Does nothing, our enabledness is determiend from our asociated 3435 // action. 3436 public void setEnabled(boolean b) { } 3437 3438 public void addPropertyChangeListener 3439 (PropertyChangeListener listener) {} 3440 public void removePropertyChangeListener 3441 (PropertyChangeListener listener) {} 3442 } 3443 3444 3445 // This class is used by the KeyboardState class to provide a single 3446 // instance that can be stored in the AppContext. 3447 static final class IntVector { 3448 int array[] = null; 3449 int count = 0; 3450 int capacity = 0; 3451 3452 int size() { 3453 return count; 3454 } 3455 3456 int elementAt(int index) { 3457 return array[index]; 3458 } 3459 3460 void addElement(int value) { 3461 if (count == capacity) { 3462 capacity = (capacity + 2) * 2; 3463 int[] newarray = new int[capacity]; 3464 if (count > 0) { 3465 System.arraycopy(array, 0, newarray, 0, count); 3466 } 3467 array = newarray; 3468 } 3469 array[count++] = value; 3470 } 3471 3472 void setElementAt(int value, int index) { 3473 array[index] = value; 3474 } 3475 } 3476 3477 @SuppressWarnings("serial") 3478 static class KeyboardState implements Serializable { 3479 private static final Object keyCodesKey = 3480 JComponent.KeyboardState.class; 3481 3482 // Get the array of key codes from the AppContext. 3483 static IntVector getKeyCodeArray() { 3484 IntVector iv = 3485 (IntVector)SwingUtilities.appContextGet(keyCodesKey); 3486 if (iv == null) { 3487 iv = new IntVector(); 3488 SwingUtilities.appContextPut(keyCodesKey, iv); 3489 } 3490 return iv; 3491 } 3492 3493 static void registerKeyPressed(int keyCode) { 3494 IntVector kca = getKeyCodeArray(); 3495 int count = kca.size(); 3496 int i; 3497 for(i=0;i<count;i++) { 3498 if(kca.elementAt(i) == -1){ 3499 kca.setElementAt(keyCode, i); 3500 return; 3501 } 3502 } 3503 kca.addElement(keyCode); 3504 } 3505 3506 static void registerKeyReleased(int keyCode) { 3507 IntVector kca = getKeyCodeArray(); 3508 int count = kca.size(); 3509 int i; 3510 for(i=0;i<count;i++) { 3511 if(kca.elementAt(i) == keyCode) { 3512 kca.setElementAt(-1, i); 3513 return; 3514 } 3515 } 3516 } 3517 3518 static boolean keyIsPressed(int keyCode) { 3519 IntVector kca = getKeyCodeArray(); 3520 int count = kca.size(); 3521 int i; 3522 for(i=0;i<count;i++) { 3523 if(kca.elementAt(i) == keyCode) { 3524 return true; 3525 } 3526 } 3527 return false; 3528 } 3529 3530 /** 3531 * Updates internal state of the KeyboardState and returns true 3532 * if the event should be processed further. 3533 */ 3534 static boolean shouldProcess(KeyEvent e) { 3535 switch (e.getID()) { 3536 case KeyEvent.KEY_PRESSED: 3537 if (!keyIsPressed(e.getKeyCode())) { 3538 registerKeyPressed(e.getKeyCode()); 3539 } 3540 return true; 3541 case KeyEvent.KEY_RELEASED: 3542 // We are forced to process VK_PRINTSCREEN separately because 3543 // the Windows doesn't generate the key pressed event for 3544 // printscreen and it block the processing of key release 3545 // event for printscreen. 3546 if (keyIsPressed(e.getKeyCode()) || e.getKeyCode()==KeyEvent.VK_PRINTSCREEN) { 3547 registerKeyReleased(e.getKeyCode()); 3548 return true; 3549 } 3550 return false; 3551 case KeyEvent.KEY_TYPED: 3552 return true; 3553 default: 3554 // Not a known KeyEvent type, bail. 3555 return false; 3556 } 3557 } 3558 } 3559 3560 static final sun.awt.RequestFocusController focusController = 3561 new sun.awt.RequestFocusController() { 3562 public boolean acceptRequestFocus(Component from, Component to, 3563 boolean temporary, boolean focusedWindowChangeAllowed, 3564 sun.awt.CausedFocusEvent.Cause cause) 3565 { 3566 if ((to == null) || !(to instanceof JComponent)) { 3567 return true; 3568 } 3569 3570 if ((from == null) || !(from instanceof JComponent)) { 3571 return true; 3572 } 3573 3574 JComponent target = (JComponent) to; 3575 if (!target.getVerifyInputWhenFocusTarget()) { 3576 return true; 3577 } 3578 3579 JComponent jFocusOwner = (JComponent)from; 3580 InputVerifier iv = jFocusOwner.getInputVerifier(); 3581 3582 if (iv == null) { 3583 return true; 3584 } else { 3585 Object currentSource = SwingUtilities.appContextGet( 3586 INPUT_VERIFIER_SOURCE_KEY); 3587 if (currentSource == jFocusOwner) { 3588 // We're currently calling into the InputVerifier 3589 // for this component, so allow the focus change. 3590 return true; 3591 } 3592 SwingUtilities.appContextPut(INPUT_VERIFIER_SOURCE_KEY, 3593 jFocusOwner); 3594 try { 3595 return iv.shouldYieldFocus(jFocusOwner); 3596 } finally { 3597 if (currentSource != null) { 3598 // We're already in the InputVerifier for 3599 // currentSource. By resetting the currentSource 3600 // we ensure that if the InputVerifier for 3601 // currentSource does a requestFocus, we don't 3602 // try and run the InputVerifier again. 3603 SwingUtilities.appContextPut( 3604 INPUT_VERIFIER_SOURCE_KEY, currentSource); 3605 } else { 3606 SwingUtilities.appContextRemove( 3607 INPUT_VERIFIER_SOURCE_KEY); 3608 } 3609 } 3610 } 3611 } 3612 }; 3613 3614 /* 3615 * --- Accessibility Support --- 3616 */ 3617 3618 /** 3619 * @deprecated As of JDK version 1.1, 3620 * replaced by <code>java.awt.Component.setEnabled(boolean)</code>. 3621 */ 3622 @Deprecated 3623 public void enable() { 3624 if (isEnabled() != true) { 3625 super.enable(); 3626 if (accessibleContext != null) { 3627 accessibleContext.firePropertyChange( 3628 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 3629 null, AccessibleState.ENABLED); 3630 } 3631 } 3632 } 3633 3634 /** 3635 * @deprecated As of JDK version 1.1, 3636 * replaced by <code>java.awt.Component.setEnabled(boolean)</code>. 3637 */ 3638 @Deprecated 3639 public void disable() { 3640 if (isEnabled() != false) { 3641 super.disable(); 3642 if (accessibleContext != null) { 3643 accessibleContext.firePropertyChange( 3644 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 3645 AccessibleState.ENABLED, null); 3646 } 3647 } 3648 } 3649 3650 /** 3651 * Inner class of JComponent used to provide default support for 3652 * accessibility. This class is not meant to be used directly by 3653 * application developers, but is instead meant only to be 3654 * subclassed by component developers. 3655 * <p> 3656 * <strong>Warning:</strong> 3657 * Serialized objects of this class will not be compatible with 3658 * future Swing releases. The current serialization support is 3659 * appropriate for short term storage or RMI between applications running 3660 * the same version of Swing. As of 1.4, support for long term storage 3661 * of all JavaBeans™ 3662 * has been added to the <code>java.beans</code> package. 3663 * Please see {@link java.beans.XMLEncoder}. 3664 */ 3665 @SuppressWarnings("serial") // Same-version serialization only 3666 public abstract class AccessibleJComponent extends AccessibleAWTContainer 3667 implements AccessibleExtendedComponent 3668 { 3669 /** 3670 * Though the class is abstract, this should be called by 3671 * all sub-classes. 3672 */ 3673 protected AccessibleJComponent() { 3674 super(); 3675 } 3676 3677 /** 3678 * Number of PropertyChangeListener objects registered. It's used 3679 * to add/remove ContainerListener and FocusListener to track 3680 * target JComponent's state 3681 */ 3682 private volatile transient int propertyListenersCount = 0; 3683 3684 /** 3685 * This field duplicates the function of the accessibleAWTFocusHandler field 3686 * in java.awt.Component.AccessibleAWTComponent, so it has been deprecated. 3687 */ 3688 @Deprecated 3689 protected FocusListener accessibleFocusHandler = null; 3690 3691 /** 3692 * Fire PropertyChange listener, if one is registered, 3693 * when children added/removed. 3694 */ 3695 protected class AccessibleContainerHandler 3696 implements ContainerListener { 3697 public void componentAdded(ContainerEvent e) { 3698 Component c = e.getChild(); 3699 if (c != null && c instanceof Accessible) { 3700 AccessibleJComponent.this.firePropertyChange( 3701 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3702 null, c.getAccessibleContext()); 3703 } 3704 } 3705 public void componentRemoved(ContainerEvent e) { 3706 Component c = e.getChild(); 3707 if (c != null && c instanceof Accessible) { 3708 AccessibleJComponent.this.firePropertyChange( 3709 AccessibleContext.ACCESSIBLE_CHILD_PROPERTY, 3710 c.getAccessibleContext(), null); 3711 } 3712 } 3713 } 3714 3715 /** 3716 * Fire PropertyChange listener, if one is registered, 3717 * when focus events happen 3718 * @since 1.3 3719 */ 3720 protected class AccessibleFocusHandler implements FocusListener { 3721 public void focusGained(FocusEvent event) { 3722 if (accessibleContext != null) { 3723 accessibleContext.firePropertyChange( 3724 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 3725 null, AccessibleState.FOCUSED); 3726 } 3727 } 3728 public void focusLost(FocusEvent event) { 3729 if (accessibleContext != null) { 3730 accessibleContext.firePropertyChange( 3731 AccessibleContext.ACCESSIBLE_STATE_PROPERTY, 3732 AccessibleState.FOCUSED, null); 3733 } 3734 } 3735 } // inner class AccessibleFocusHandler 3736 3737 3738 /** 3739 * Adds a PropertyChangeListener to the listener list. 3740 * 3741 * @param listener the PropertyChangeListener to be added 3742 */ 3743 public void addPropertyChangeListener(PropertyChangeListener listener) { 3744 if (accessibleContainerHandler == null) { 3745 accessibleContainerHandler = new AccessibleContainerHandler(); 3746 } 3747 if (propertyListenersCount++ == 0) { 3748 JComponent.this.addContainerListener(accessibleContainerHandler); 3749 } 3750 super.addPropertyChangeListener(listener); 3751 } 3752 3753 /** 3754 * Removes a PropertyChangeListener from the listener list. 3755 * This removes a PropertyChangeListener that was registered 3756 * for all properties. 3757 * 3758 * @param listener the PropertyChangeListener to be removed 3759 */ 3760 public void removePropertyChangeListener(PropertyChangeListener listener) { 3761 if (--propertyListenersCount == 0) { 3762 JComponent.this.removeContainerListener(accessibleContainerHandler); 3763 } 3764 super.removePropertyChangeListener(listener); 3765 } 3766 3767 3768 3769 /** 3770 * Recursively search through the border hierarchy (if it exists) 3771 * for a TitledBorder with a non-null title. This does a depth 3772 * first search on first the inside borders then the outside borders. 3773 * The assumption is that titles make really pretty inside borders 3774 * but not very pretty outside borders in compound border situations. 3775 * It's rather arbitrary, but hopefully decent UI programmers will 3776 * not create multiple titled borders for the same component. 3777 */ 3778 protected String getBorderTitle(Border b) { 3779 String s; 3780 if (b instanceof TitledBorder) { 3781 return ((TitledBorder) b).getTitle(); 3782 } else if (b instanceof CompoundBorder) { 3783 s = getBorderTitle(((CompoundBorder) b).getInsideBorder()); 3784 if (s == null) { 3785 s = getBorderTitle(((CompoundBorder) b).getOutsideBorder()); 3786 } 3787 return s; 3788 } else { 3789 return null; 3790 } 3791 } 3792 3793 // AccessibleContext methods 3794 // 3795 /** 3796 * Gets the accessible name of this object. This should almost never 3797 * return java.awt.Component.getName(), as that generally isn't 3798 * a localized name, and doesn't have meaning for the user. If the 3799 * object is fundamentally a text object (such as a menu item), the 3800 * accessible name should be the text of the object (for example, 3801 * "save"). 3802 * If the object has a tooltip, the tooltip text may also be an 3803 * appropriate String to return. 3804 * 3805 * @return the localized name of the object -- can be null if this 3806 * object does not have a name 3807 * @see AccessibleContext#setAccessibleName 3808 */ 3809 public String getAccessibleName() { 3810 String name = accessibleName; 3811 3812 // fallback to the client name property 3813 // 3814 if (name == null) { 3815 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY); 3816 } 3817 3818 // fallback to the titled border if it exists 3819 // 3820 if (name == null) { 3821 name = getBorderTitle(getBorder()); 3822 } 3823 3824 // fallback to the label labeling us if it exists 3825 // 3826 if (name == null) { 3827 Object o = getClientProperty(JLabel.LABELED_BY_PROPERTY); 3828 if (o instanceof Accessible) { 3829 AccessibleContext ac = ((Accessible) o).getAccessibleContext(); 3830 if (ac != null) { 3831 name = ac.getAccessibleName(); 3832 } 3833 } 3834 } 3835 return name; 3836 } 3837 3838 /** 3839 * Gets the accessible description of this object. This should be 3840 * a concise, localized description of what this object is - what 3841 * is its meaning to the user. If the object has a tooltip, the 3842 * tooltip text may be an appropriate string to return, assuming 3843 * it contains a concise description of the object (instead of just 3844 * the name of the object - for example a "Save" icon on a toolbar that 3845 * had "save" as the tooltip text shouldn't return the tooltip 3846 * text as the description, but something like "Saves the current 3847 * text document" instead). 3848 * 3849 * @return the localized description of the object -- can be null if 3850 * this object does not have a description 3851 * @see AccessibleContext#setAccessibleDescription 3852 */ 3853 public String getAccessibleDescription() { 3854 String description = accessibleDescription; 3855 3856 // fallback to the client description property 3857 // 3858 if (description == null) { 3859 description = (String)getClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY); 3860 } 3861 3862 // fallback to the tool tip text if it exists 3863 // 3864 if (description == null) { 3865 try { 3866 description = getToolTipText(); 3867 } catch (Exception e) { 3868 // Just in case the subclass overrode the 3869 // getToolTipText method and actually 3870 // requires a MouseEvent. 3871 // [[[FIXME: WDW - we probably should require this 3872 // method to take a MouseEvent and just pass it on 3873 // to getToolTipText. The swing-feedback traffic 3874 // leads me to believe getToolTipText might change, 3875 // though, so I was hesitant to make this change at 3876 // this time.]]] 3877 } 3878 } 3879 3880 // fallback to the label labeling us if it exists 3881 // 3882 if (description == null) { 3883 Object o = getClientProperty(JLabel.LABELED_BY_PROPERTY); 3884 if (o instanceof Accessible) { 3885 AccessibleContext ac = ((Accessible) o).getAccessibleContext(); 3886 if (ac != null) { 3887 description = ac.getAccessibleDescription(); 3888 } 3889 } 3890 } 3891 3892 return description; 3893 } 3894 3895 /** 3896 * Gets the role of this object. 3897 * 3898 * @return an instance of AccessibleRole describing the role of the 3899 * object 3900 * @see AccessibleRole 3901 */ 3902 public AccessibleRole getAccessibleRole() { 3903 return AccessibleRole.SWING_COMPONENT; 3904 } 3905 3906 /** 3907 * Gets the state of this object. 3908 * 3909 * @return an instance of AccessibleStateSet containing the current 3910 * state set of the object 3911 * @see AccessibleState 3912 */ 3913 public AccessibleStateSet getAccessibleStateSet() { 3914 AccessibleStateSet states = super.getAccessibleStateSet(); 3915 if (JComponent.this.isOpaque()) { 3916 states.add(AccessibleState.OPAQUE); 3917 } 3918 return states; 3919 } 3920 3921 /** 3922 * Returns the number of accessible children in the object. If all 3923 * of the children of this object implement Accessible, than this 3924 * method should return the number of children of this object. 3925 * 3926 * @return the number of accessible children in the object. 3927 */ 3928 public int getAccessibleChildrenCount() { 3929 return super.getAccessibleChildrenCount(); 3930 } 3931 3932 /** 3933 * Returns the nth Accessible child of the object. 3934 * 3935 * @param i zero-based index of child 3936 * @return the nth Accessible child of the object 3937 */ 3938 public Accessible getAccessibleChild(int i) { 3939 return super.getAccessibleChild(i); 3940 } 3941 3942 // ----- AccessibleExtendedComponent 3943 3944 /** 3945 * Returns the AccessibleExtendedComponent 3946 * 3947 * @return the AccessibleExtendedComponent 3948 */ 3949 AccessibleExtendedComponent getAccessibleExtendedComponent() { 3950 return this; 3951 } 3952 3953 /** 3954 * Returns the tool tip text 3955 * 3956 * @return the tool tip text, if supported, of the object; 3957 * otherwise, null 3958 * @since 1.4 3959 */ 3960 public String getToolTipText() { 3961 return JComponent.this.getToolTipText(); 3962 } 3963 3964 /** 3965 * Returns the titled border text 3966 * 3967 * @return the titled border text, if supported, of the object; 3968 * otherwise, null 3969 * @since 1.4 3970 */ 3971 public String getTitledBorderText() { 3972 Border border = JComponent.this.getBorder(); 3973 if (border instanceof TitledBorder) { 3974 return ((TitledBorder)border).getTitle(); 3975 } else { 3976 return null; 3977 } 3978 } 3979 3980 /** 3981 * Returns key bindings associated with this object 3982 * 3983 * @return the key bindings, if supported, of the object; 3984 * otherwise, null 3985 * @see AccessibleKeyBinding 3986 * @since 1.4 3987 */ 3988 public AccessibleKeyBinding getAccessibleKeyBinding(){ 3989 // Try to get the linked label's mnemonic if it exists 3990 Object o = getClientProperty(JLabel.LABELED_BY_PROPERTY); 3991 if (o instanceof Accessible){ 3992 AccessibleContext ac = ((Accessible) o).getAccessibleContext(); 3993 if (ac != null){ 3994 AccessibleComponent comp = ac.getAccessibleComponent(); 3995 if (! (comp instanceof AccessibleExtendedComponent)) 3996 return null; 3997 return ((AccessibleExtendedComponent)comp).getAccessibleKeyBinding(); 3998 } 3999 } 4000 return null; 4001 } 4002 } // inner class AccessibleJComponent 4003 4004 4005 /** 4006 * Returns an <code>ArrayTable</code> used for 4007 * key/value "client properties" for this component. If the 4008 * <code>clientProperties</code> table doesn't exist, an empty one 4009 * will be created. 4010 * 4011 * @return an ArrayTable 4012 * @see #putClientProperty 4013 * @see #getClientProperty 4014 */ 4015 private ArrayTable getClientProperties() { 4016 if (clientProperties == null) { 4017 clientProperties = new ArrayTable(); 4018 } 4019 return clientProperties; 4020 } 4021 4022 4023 /** 4024 * Returns the value of the property with the specified key. Only 4025 * properties added with <code>putClientProperty</code> will return 4026 * a non-<code>null</code> value. 4027 * 4028 * @param key the being queried 4029 * @return the value of this property or <code>null</code> 4030 * @see #putClientProperty 4031 */ 4032 public final Object getClientProperty(Object key) { 4033 if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) { 4034 return aaTextInfo; 4035 } else if (key == SwingUtilities2.COMPONENT_UI_PROPERTY_KEY) { 4036 return ui; 4037 } 4038 if(clientProperties == null) { 4039 return null; 4040 } else { 4041 synchronized(clientProperties) { 4042 return clientProperties.get(key); 4043 } 4044 } 4045 } 4046 4047 /** 4048 * Adds an arbitrary key/value "client property" to this component. 4049 * <p> 4050 * The <code>get/putClientProperty</code> methods provide access to 4051 * a small per-instance hashtable. Callers can use get/putClientProperty 4052 * to annotate components that were created by another module. 4053 * For example, a 4054 * layout manager might store per child constraints this way. For example: 4055 * <pre> 4056 * componentA.putClientProperty("to the left of", componentB); 4057 * </pre> 4058 * If value is <code>null</code> this method will remove the property. 4059 * Changes to client properties are reported with 4060 * <code>PropertyChange</code> events. 4061 * The name of the property (for the sake of PropertyChange 4062 * events) is <code>key.toString()</code>. 4063 * <p> 4064 * The <code>clientProperty</code> dictionary is not intended to 4065 * support large 4066 * scale extensions to JComponent nor should be it considered an 4067 * alternative to subclassing when designing a new component. 4068 * 4069 * @param key the new client property key 4070 * @param value the new client property value; if <code>null</code> 4071 * this method will remove the property 4072 * @see #getClientProperty 4073 * @see #addPropertyChangeListener 4074 */ 4075 public final void putClientProperty(Object key, Object value) { 4076 if (key == SwingUtilities2.AA_TEXT_PROPERTY_KEY) { 4077 aaTextInfo = value; 4078 return; 4079 } 4080 if (value == null && clientProperties == null) { 4081 // Both the value and ArrayTable are null, implying we don't 4082 // have to do anything. 4083 return; 4084 } 4085 ArrayTable clientProperties = getClientProperties(); 4086 Object oldValue; 4087 synchronized(clientProperties) { 4088 oldValue = clientProperties.get(key); 4089 if (value != null) { 4090 clientProperties.put(key, value); 4091 } else if (oldValue != null) { 4092 clientProperties.remove(key); 4093 } else { 4094 // old == new == null 4095 return; 4096 } 4097 } 4098 clientPropertyChanged(key, oldValue, value); 4099 firePropertyChange(key.toString(), oldValue, value); 4100 } 4101 4102 // Invoked from putClientProperty. This is provided for subclasses 4103 // in Swing. 4104 void clientPropertyChanged(Object key, Object oldValue, 4105 Object newValue) { 4106 } 4107 4108 4109 /* 4110 * Sets the property with the specified name to the specified value if 4111 * the property has not already been set by the client program. 4112 * This method is used primarily to set UI defaults for properties 4113 * with primitive types, where the values cannot be marked with 4114 * UIResource. 4115 * @see LookAndFeel#installProperty 4116 * @param propertyName String containing the name of the property 4117 * @param value Object containing the property value 4118 */ 4119 void setUIProperty(String propertyName, Object value) { 4120 if (propertyName == "opaque") { 4121 if (!getFlag(OPAQUE_SET)) { 4122 setOpaque(((Boolean)value).booleanValue()); 4123 setFlag(OPAQUE_SET, false); 4124 } 4125 } else if (propertyName == "autoscrolls") { 4126 if (!getFlag(AUTOSCROLLS_SET)) { 4127 setAutoscrolls(((Boolean)value).booleanValue()); 4128 setFlag(AUTOSCROLLS_SET, false); 4129 } 4130 } else if (propertyName == "focusTraversalKeysForward") { 4131 @SuppressWarnings("unchecked") 4132 Set<AWTKeyStroke> strokeSet = (Set<AWTKeyStroke>) value; 4133 if (!getFlag(FOCUS_TRAVERSAL_KEYS_FORWARD_SET)) { 4134 super.setFocusTraversalKeys(KeyboardFocusManager. 4135 FORWARD_TRAVERSAL_KEYS, 4136 strokeSet); 4137 } 4138 } else if (propertyName == "focusTraversalKeysBackward") { 4139 @SuppressWarnings("unchecked") 4140 Set<AWTKeyStroke> strokeSet = (Set<AWTKeyStroke>) value; 4141 if (!getFlag(FOCUS_TRAVERSAL_KEYS_BACKWARD_SET)) { 4142 super.setFocusTraversalKeys(KeyboardFocusManager. 4143 BACKWARD_TRAVERSAL_KEYS, 4144 strokeSet); 4145 } 4146 } else { 4147 throw new IllegalArgumentException("property \""+ 4148 propertyName+ "\" cannot be set using this method"); 4149 } 4150 } 4151 4152 4153 /** 4154 * Sets the focus traversal keys for a given traversal operation for this 4155 * Component. 4156 * Refer to 4157 * {@link java.awt.Component#setFocusTraversalKeys} 4158 * for a complete description of this method. 4159 * <p> 4160 * This method may throw a {@code ClassCastException} if any {@code Object} 4161 * in {@code keystrokes} is not an {@code AWTKeyStroke}. 4162 * 4163 * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 4164 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or 4165 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS 4166 * @param keystrokes the Set of AWTKeyStroke for the specified operation 4167 * @see java.awt.KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS 4168 * @see java.awt.KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS 4169 * @see java.awt.KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS 4170 * @throws IllegalArgumentException if id is not one of 4171 * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, 4172 * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or 4173 * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or if keystrokes 4174 * contains null, or if any keystroke represents a KEY_TYPED event, 4175 * or if any keystroke already maps to another focus traversal 4176 * operation for this Component 4177 * @since 1.5 4178 * @beaninfo 4179 * bound: true 4180 */ 4181 public void 4182 setFocusTraversalKeys(int id, Set<? extends AWTKeyStroke> keystrokes) 4183 { 4184 if (id == KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS) { 4185 setFlag(FOCUS_TRAVERSAL_KEYS_FORWARD_SET,true); 4186 } else if (id == KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS) { 4187 setFlag(FOCUS_TRAVERSAL_KEYS_BACKWARD_SET,true); 4188 } 4189 super.setFocusTraversalKeys(id,keystrokes); 4190 } 4191 4192 /* --- Transitional java.awt.Component Support --- 4193 * The methods and fields in this section will migrate to 4194 * java.awt.Component in the next JDK release. 4195 */ 4196 4197 /** 4198 * Returns true if this component is lightweight, that is, if it doesn't 4199 * have a native window system peer. 4200 * 4201 * @return true if this component is lightweight 4202 */ 4203 @SuppressWarnings("deprecation") 4204 public static boolean isLightweightComponent(Component c) { 4205 return c.getPeer() instanceof LightweightPeer; 4206 } 4207 4208 4209 /** 4210 * @deprecated As of JDK 5, 4211 * replaced by <code>Component.setBounds(int, int, int, int)</code>. 4212 * <p> 4213 * Moves and resizes this component. 4214 * 4215 * @param x the new horizontal location 4216 * @param y the new vertical location 4217 * @param w the new width 4218 * @param h the new height 4219 * @see java.awt.Component#setBounds 4220 */ 4221 @Deprecated 4222 public void reshape(int x, int y, int w, int h) { 4223 super.reshape(x, y, w, h); 4224 } 4225 4226 4227 /** 4228 * Stores the bounds of this component into "return value" 4229 * <code>rv</code> and returns <code>rv</code>. 4230 * If <code>rv</code> is <code>null</code> a new <code>Rectangle</code> 4231 * is allocated. This version of <code>getBounds</code> is useful 4232 * if the caller wants to avoid allocating a new <code>Rectangle</code> 4233 * object on the heap. 4234 * 4235 * @param rv the return value, modified to the component's bounds 4236 * @return <code>rv</code>; if <code>rv</code> is <code>null</code> 4237 * return a newly created <code>Rectangle</code> with this 4238 * component's bounds 4239 */ 4240 public Rectangle getBounds(Rectangle rv) { 4241 if (rv == null) { 4242 return new Rectangle(getX(), getY(), getWidth(), getHeight()); 4243 } 4244 else { 4245 rv.setBounds(getX(), getY(), getWidth(), getHeight()); 4246 return rv; 4247 } 4248 } 4249 4250 4251 /** 4252 * Stores the width/height of this component into "return value" 4253 * <code>rv</code> and returns <code>rv</code>. 4254 * If <code>rv</code> is <code>null</code> a new <code>Dimension</code> 4255 * object is allocated. This version of <code>getSize</code> 4256 * is useful if the caller wants to avoid allocating a new 4257 * <code>Dimension</code> object on the heap. 4258 * 4259 * @param rv the return value, modified to the component's size 4260 * @return <code>rv</code> 4261 */ 4262 public Dimension getSize(Dimension rv) { 4263 if (rv == null) { 4264 return new Dimension(getWidth(), getHeight()); 4265 } 4266 else { 4267 rv.setSize(getWidth(), getHeight()); 4268 return rv; 4269 } 4270 } 4271 4272 4273 /** 4274 * Stores the x,y origin of this component into "return value" 4275 * <code>rv</code> and returns <code>rv</code>. 4276 * If <code>rv</code> is <code>null</code> a new <code>Point</code> 4277 * is allocated. This version of <code>getLocation</code> is useful 4278 * if the caller wants to avoid allocating a new <code>Point</code> 4279 * object on the heap. 4280 * 4281 * @param rv the return value, modified to the component's location 4282 * @return <code>rv</code> 4283 */ 4284 public Point getLocation(Point rv) { 4285 if (rv == null) { 4286 return new Point(getX(), getY()); 4287 } 4288 else { 4289 rv.setLocation(getX(), getY()); 4290 return rv; 4291 } 4292 } 4293 4294 4295 /** 4296 * Returns the current x coordinate of the component's origin. 4297 * This method is preferable to writing 4298 * <code>component.getBounds().x</code>, or 4299 * <code>component.getLocation().x</code> because it doesn't cause any 4300 * heap allocations. 4301 * 4302 * @return the current x coordinate of the component's origin 4303 */ 4304 public int getX() { return super.getX(); } 4305 4306 4307 /** 4308 * Returns the current y coordinate of the component's origin. 4309 * This method is preferable to writing 4310 * <code>component.getBounds().y</code>, or 4311 * <code>component.getLocation().y</code> because it doesn't cause any 4312 * heap allocations. 4313 * 4314 * @return the current y coordinate of the component's origin 4315 */ 4316 public int getY() { return super.getY(); } 4317 4318 4319 /** 4320 * Returns the current width of this component. 4321 * This method is preferable to writing 4322 * <code>component.getBounds().width</code>, or 4323 * <code>component.getSize().width</code> because it doesn't cause any 4324 * heap allocations. 4325 * 4326 * @return the current width of this component 4327 */ 4328 public int getWidth() { return super.getWidth(); } 4329 4330 4331 /** 4332 * Returns the current height of this component. 4333 * This method is preferable to writing 4334 * <code>component.getBounds().height</code>, or 4335 * <code>component.getSize().height</code> because it doesn't cause any 4336 * heap allocations. 4337 * 4338 * @return the current height of this component 4339 */ 4340 public int getHeight() { return super.getHeight(); } 4341 4342 /** 4343 * Returns true if this component is completely opaque. 4344 * <p> 4345 * An opaque component paints every pixel within its 4346 * rectangular bounds. A non-opaque component paints only a subset of 4347 * its pixels or none at all, allowing the pixels underneath it to 4348 * "show through". Therefore, a component that does not fully paint 4349 * its pixels provides a degree of transparency. 4350 * <p> 4351 * Subclasses that guarantee to always completely paint their contents 4352 * should override this method and return true. 4353 * 4354 * @return true if this component is completely opaque 4355 * @see #setOpaque 4356 */ 4357 public boolean isOpaque() { 4358 return getFlag(IS_OPAQUE); 4359 } 4360 4361 /** 4362 * If true the component paints every pixel within its bounds. 4363 * Otherwise, the component may not paint some or all of its 4364 * pixels, allowing the underlying pixels to show through. 4365 * <p> 4366 * The default value of this property is false for <code>JComponent</code>. 4367 * However, the default value for this property on most standard 4368 * <code>JComponent</code> subclasses (such as <code>JButton</code> and 4369 * <code>JTree</code>) is look-and-feel dependent. 4370 * 4371 * @param isOpaque true if this component should be opaque 4372 * @see #isOpaque 4373 * @beaninfo 4374 * bound: true 4375 * expert: true 4376 * description: The component's opacity 4377 */ 4378 public void setOpaque(boolean isOpaque) { 4379 boolean oldValue = getFlag(IS_OPAQUE); 4380 setFlag(IS_OPAQUE, isOpaque); 4381 setFlag(OPAQUE_SET, true); 4382 firePropertyChange("opaque", oldValue, isOpaque); 4383 } 4384 4385 4386 /** 4387 * If the specified rectangle is completely obscured by any of this 4388 * component's opaque children then returns true. Only direct children 4389 * are considered, more distant descendants are ignored. A 4390 * <code>JComponent</code> is opaque if 4391 * <code>JComponent.isOpaque()</code> returns true, other lightweight 4392 * components are always considered transparent, and heavyweight components 4393 * are always considered opaque. 4394 * 4395 * @param x x value of specified rectangle 4396 * @param y y value of specified rectangle 4397 * @param width width of specified rectangle 4398 * @param height height of specified rectangle 4399 * @return true if the specified rectangle is obscured by an opaque child 4400 */ 4401 boolean rectangleIsObscured(int x,int y,int width,int height) 4402 { 4403 int numChildren = getComponentCount(); 4404 4405 for(int i = 0; i < numChildren; i++) { 4406 Component child = getComponent(i); 4407 int cx, cy, cw, ch; 4408 4409 cx = child.getX(); 4410 cy = child.getY(); 4411 cw = child.getWidth(); 4412 ch = child.getHeight(); 4413 4414 if (x >= cx && (x + width) <= (cx + cw) && 4415 y >= cy && (y + height) <= (cy + ch) && child.isVisible()) { 4416 4417 if(child instanceof JComponent) { 4418 // System.out.println("A) checking opaque: " + ((JComponent)child).isOpaque() + " " + child); 4419 // System.out.print("B) "); 4420 // Thread.dumpStack(); 4421 return child.isOpaque(); 4422 } else { 4423 /** Sometimes a heavy weight can have a bound larger than its peer size 4424 * so we should always draw under heavy weights 4425 */ 4426 return false; 4427 } 4428 } 4429 } 4430 4431 return false; 4432 } 4433 4434 4435 /** 4436 * Returns the <code>Component</code>'s "visible rect rectangle" - the 4437 * intersection of the visible rectangles for the component <code>c</code> 4438 * and all of its ancestors. The return value is stored in 4439 * <code>visibleRect</code>. 4440 * 4441 * @param c the component 4442 * @param visibleRect a <code>Rectangle</code> computed as the 4443 * intersection of all visible rectangles for the component 4444 * <code>c</code> and all of its ancestors -- this is the 4445 * return value for this method 4446 * @see #getVisibleRect 4447 */ 4448 static final void computeVisibleRect(Component c, Rectangle visibleRect) { 4449 Container p = c.getParent(); 4450 Rectangle bounds = c.getBounds(); 4451 4452 if (p == null || p instanceof Window || p instanceof Applet) { 4453 visibleRect.setBounds(0, 0, bounds.width, bounds.height); 4454 } else { 4455 computeVisibleRect(p, visibleRect); 4456 visibleRect.x -= bounds.x; 4457 visibleRect.y -= bounds.y; 4458 SwingUtilities.computeIntersection(0,0,bounds.width,bounds.height,visibleRect); 4459 } 4460 } 4461 4462 4463 /** 4464 * Returns the <code>Component</code>'s "visible rect rectangle" - the 4465 * intersection of the visible rectangles for this component 4466 * and all of its ancestors. The return value is stored in 4467 * <code>visibleRect</code>. 4468 * 4469 * @param visibleRect a <code>Rectangle</code> computed as the 4470 * intersection of all visible rectangles for this 4471 * component and all of its ancestors -- this is the return 4472 * value for this method 4473 * @see #getVisibleRect 4474 */ 4475 public void computeVisibleRect(Rectangle visibleRect) { 4476 computeVisibleRect(this, visibleRect); 4477 } 4478 4479 4480 /** 4481 * Returns the <code>Component</code>'s "visible rectangle" - the 4482 * intersection of this component's visible rectangle, 4483 * <code>new Rectangle(0, 0, getWidth(), getHeight())</code>, 4484 * and all of its ancestors' visible rectangles. 4485 * 4486 * @return the visible rectangle 4487 */ 4488 public Rectangle getVisibleRect() { 4489 Rectangle visibleRect = new Rectangle(); 4490 4491 computeVisibleRect(visibleRect); 4492 return visibleRect; 4493 } 4494 4495 /** 4496 * Support for reporting bound property changes for boolean properties. 4497 * This method can be called when a bound property has changed and it will 4498 * send the appropriate PropertyChangeEvent to any registered 4499 * PropertyChangeListeners. 4500 * 4501 * @param propertyName the property whose value has changed 4502 * @param oldValue the property's previous value 4503 * @param newValue the property's new value 4504 */ 4505 public void firePropertyChange(String propertyName, 4506 boolean oldValue, boolean newValue) { 4507 super.firePropertyChange(propertyName, oldValue, newValue); 4508 } 4509 4510 4511 /** 4512 * Support for reporting bound property changes for integer properties. 4513 * This method can be called when a bound property has changed and it will 4514 * send the appropriate PropertyChangeEvent to any registered 4515 * PropertyChangeListeners. 4516 * 4517 * @param propertyName the property whose value has changed 4518 * @param oldValue the property's previous value 4519 * @param newValue the property's new value 4520 */ 4521 public void firePropertyChange(String propertyName, 4522 int oldValue, int newValue) { 4523 super.firePropertyChange(propertyName, oldValue, newValue); 4524 } 4525 4526 // XXX This method is implemented as a workaround to a JLS issue with ambiguous 4527 // methods. This should be removed once 4758654 is resolved. 4528 public void firePropertyChange(String propertyName, char oldValue, char newValue) { 4529 super.firePropertyChange(propertyName, oldValue, newValue); 4530 } 4531 4532 /** 4533 * Supports reporting constrained property changes. 4534 * This method can be called when a constrained property has changed 4535 * and it will send the appropriate <code>PropertyChangeEvent</code> 4536 * to any registered <code>VetoableChangeListeners</code>. 4537 * 4538 * @param propertyName the name of the property that was listened on 4539 * @param oldValue the old value of the property 4540 * @param newValue the new value of the property 4541 * @exception java.beans.PropertyVetoException when the attempt to set the 4542 * property is vetoed by the component 4543 */ 4544 protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue) 4545 throws java.beans.PropertyVetoException 4546 { 4547 if (vetoableChangeSupport == null) { 4548 return; 4549 } 4550 vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue); 4551 } 4552 4553 4554 /** 4555 * Adds a <code>VetoableChangeListener</code> to the listener list. 4556 * The listener is registered for all properties. 4557 * 4558 * @param listener the <code>VetoableChangeListener</code> to be added 4559 */ 4560 public synchronized void addVetoableChangeListener(VetoableChangeListener listener) { 4561 if (vetoableChangeSupport == null) { 4562 vetoableChangeSupport = new java.beans.VetoableChangeSupport(this); 4563 } 4564 vetoableChangeSupport.addVetoableChangeListener(listener); 4565 } 4566 4567 4568 /** 4569 * Removes a <code>VetoableChangeListener</code> from the listener list. 4570 * This removes a <code>VetoableChangeListener</code> that was registered 4571 * for all properties. 4572 * 4573 * @param listener the <code>VetoableChangeListener</code> to be removed 4574 */ 4575 public synchronized void removeVetoableChangeListener(VetoableChangeListener listener) { 4576 if (vetoableChangeSupport == null) { 4577 return; 4578 } 4579 vetoableChangeSupport.removeVetoableChangeListener(listener); 4580 } 4581 4582 4583 /** 4584 * Returns an array of all the vetoable change listeners 4585 * registered on this component. 4586 * 4587 * @return all of the component's <code>VetoableChangeListener</code>s 4588 * or an empty 4589 * array if no vetoable change listeners are currently registered 4590 * 4591 * @see #addVetoableChangeListener 4592 * @see #removeVetoableChangeListener 4593 * 4594 * @since 1.4 4595 */ 4596 public synchronized VetoableChangeListener[] getVetoableChangeListeners() { 4597 if (vetoableChangeSupport == null) { 4598 return new VetoableChangeListener[0]; 4599 } 4600 return vetoableChangeSupport.getVetoableChangeListeners(); 4601 } 4602 4603 4604 /** 4605 * Returns the top-level ancestor of this component (either the 4606 * containing <code>Window</code> or <code>Applet</code>), 4607 * or <code>null</code> if this component has not 4608 * been added to any container. 4609 * 4610 * @return the top-level <code>Container</code> that this component is in, 4611 * or <code>null</code> if not in any container 4612 */ 4613 public Container getTopLevelAncestor() { 4614 for(Container p = this; p != null; p = p.getParent()) { 4615 if(p instanceof Window || p instanceof Applet) { 4616 return p; 4617 } 4618 } 4619 return null; 4620 } 4621 4622 private AncestorNotifier getAncestorNotifier() { 4623 return (AncestorNotifier) 4624 getClientProperty(JComponent_ANCESTOR_NOTIFIER); 4625 } 4626 4627 /** 4628 * Registers <code>listener</code> so that it will receive 4629 * <code>AncestorEvents</code> when it or any of its ancestors 4630 * move or are made visible or invisible. 4631 * Events are also sent when the component or its ancestors are added 4632 * or removed from the containment hierarchy. 4633 * 4634 * @param listener the <code>AncestorListener</code> to register 4635 * @see AncestorEvent 4636 */ 4637 public void addAncestorListener(AncestorListener listener) { 4638 AncestorNotifier ancestorNotifier = getAncestorNotifier(); 4639 if (ancestorNotifier == null) { 4640 ancestorNotifier = new AncestorNotifier(this); 4641 putClientProperty(JComponent_ANCESTOR_NOTIFIER, 4642 ancestorNotifier); 4643 } 4644 ancestorNotifier.addAncestorListener(listener); 4645 } 4646 4647 /** 4648 * Unregisters <code>listener</code> so that it will no longer receive 4649 * <code>AncestorEvents</code>. 4650 * 4651 * @param listener the <code>AncestorListener</code> to be removed 4652 * @see #addAncestorListener 4653 */ 4654 public void removeAncestorListener(AncestorListener listener) { 4655 AncestorNotifier ancestorNotifier = getAncestorNotifier(); 4656 if (ancestorNotifier == null) { 4657 return; 4658 } 4659 ancestorNotifier.removeAncestorListener(listener); 4660 if (ancestorNotifier.listenerList.getListenerList().length == 0) { 4661 ancestorNotifier.removeAllListeners(); 4662 putClientProperty(JComponent_ANCESTOR_NOTIFIER, null); 4663 } 4664 } 4665 4666 /** 4667 * Returns an array of all the ancestor listeners 4668 * registered on this component. 4669 * 4670 * @return all of the component's <code>AncestorListener</code>s 4671 * or an empty 4672 * array if no ancestor listeners are currently registered 4673 * 4674 * @see #addAncestorListener 4675 * @see #removeAncestorListener 4676 * 4677 * @since 1.4 4678 */ 4679 public AncestorListener[] getAncestorListeners() { 4680 AncestorNotifier ancestorNotifier = getAncestorNotifier(); 4681 if (ancestorNotifier == null) { 4682 return new AncestorListener[0]; 4683 } 4684 return ancestorNotifier.getAncestorListeners(); 4685 } 4686 4687 /** 4688 * Returns an array of all the objects currently registered 4689 * as <code><em>Foo</em>Listener</code>s 4690 * upon this <code>JComponent</code>. 4691 * <code><em>Foo</em>Listener</code>s are registered using the 4692 * <code>add<em>Foo</em>Listener</code> method. 4693 * 4694 * <p> 4695 * 4696 * You can specify the <code>listenerType</code> argument 4697 * with a class literal, 4698 * such as 4699 * <code><em>Foo</em>Listener.class</code>. 4700 * For example, you can query a 4701 * <code>JComponent</code> <code>c</code> 4702 * for its mouse listeners with the following code: 4703 * <pre>MouseListener[] mls = (MouseListener[])(c.getListeners(MouseListener.class));</pre> 4704 * If no such listeners exist, this method returns an empty array. 4705 * 4706 * @param listenerType the type of listeners requested; this parameter 4707 * should specify an interface that descends from 4708 * <code>java.util.EventListener</code> 4709 * @return an array of all objects registered as 4710 * <code><em>Foo</em>Listener</code>s on this component, 4711 * or an empty array if no such 4712 * listeners have been added 4713 * @exception ClassCastException if <code>listenerType</code> 4714 * doesn't specify a class or interface that implements 4715 * <code>java.util.EventListener</code> 4716 * 4717 * @since 1.3 4718 * 4719 * @see #getVetoableChangeListeners 4720 * @see #getAncestorListeners 4721 */ 4722 @SuppressWarnings("unchecked") // Casts to (T[]) 4723 public <T extends EventListener> T[] getListeners(Class<T> listenerType) { 4724 T[] result; 4725 if (listenerType == AncestorListener.class) { 4726 // AncestorListeners are handled by the AncestorNotifier 4727 result = (T[])getAncestorListeners(); 4728 } 4729 else if (listenerType == VetoableChangeListener.class) { 4730 // VetoableChangeListeners are handled by VetoableChangeSupport 4731 result = (T[])getVetoableChangeListeners(); 4732 } 4733 else if (listenerType == PropertyChangeListener.class) { 4734 // PropertyChangeListeners are handled by PropertyChangeSupport 4735 result = (T[])getPropertyChangeListeners(); 4736 } 4737 else { 4738 result = listenerList.getListeners(listenerType); 4739 } 4740 4741 if (result.length == 0) { 4742 return super.getListeners(listenerType); 4743 } 4744 return result; 4745 } 4746 4747 /** 4748 * Notifies this component that it now has a parent component. 4749 * When this method is invoked, the chain of parent components is 4750 * set up with <code>KeyboardAction</code> event listeners. 4751 * This method is called by the toolkit internally and should 4752 * not be called directly by programs. 4753 * 4754 * @see #registerKeyboardAction 4755 */ 4756 public void addNotify() { 4757 super.addNotify(); 4758 firePropertyChange("ancestor", null, getParent()); 4759 4760 registerWithKeyboardManager(false); 4761 registerNextFocusableComponent(); 4762 } 4763 4764 4765 /** 4766 * Notifies this component that it no longer has a parent component. 4767 * When this method is invoked, any <code>KeyboardAction</code>s 4768 * set up in the the chain of parent components are removed. 4769 * This method is called by the toolkit internally and should 4770 * not be called directly by programs. 4771 * 4772 * @see #registerKeyboardAction 4773 */ 4774 public void removeNotify() { 4775 super.removeNotify(); 4776 // This isn't strictly correct. The event shouldn't be 4777 // fired until *after* the parent is set to null. But 4778 // we only get notified before that happens 4779 firePropertyChange("ancestor", getParent(), null); 4780 4781 unregisterWithKeyboardManager(); 4782 deregisterNextFocusableComponent(); 4783 4784 if (getCreatedDoubleBuffer()) { 4785 RepaintManager.currentManager(this).resetDoubleBuffer(); 4786 setCreatedDoubleBuffer(false); 4787 } 4788 if (autoscrolls) { 4789 Autoscroller.stop(this); 4790 } 4791 } 4792 4793 4794 /** 4795 * Adds the specified region to the dirty region list if the component 4796 * is showing. The component will be repainted after all of the 4797 * currently pending events have been dispatched. 4798 * 4799 * @param tm this parameter is not used 4800 * @param x the x value of the dirty region 4801 * @param y the y value of the dirty region 4802 * @param width the width of the dirty region 4803 * @param height the height of the dirty region 4804 * @see #isPaintingOrigin() 4805 * @see java.awt.Component#isShowing 4806 * @see RepaintManager#addDirtyRegion 4807 */ 4808 public void repaint(long tm, int x, int y, int width, int height) { 4809 RepaintManager.currentManager(SunToolkit.targetToAppContext(this)) 4810 .addDirtyRegion(this, x, y, width, height); 4811 } 4812 4813 4814 /** 4815 * Adds the specified region to the dirty region list if the component 4816 * is showing. The component will be repainted after all of the 4817 * currently pending events have been dispatched. 4818 * 4819 * @param r a <code>Rectangle</code> containing the dirty region 4820 * @see #isPaintingOrigin() 4821 * @see java.awt.Component#isShowing 4822 * @see RepaintManager#addDirtyRegion 4823 */ 4824 public void repaint(Rectangle r) { 4825 repaint(0,r.x,r.y,r.width,r.height); 4826 } 4827 4828 4829 /** 4830 * Supports deferred automatic layout. 4831 * <p> 4832 * Calls <code>invalidate</code> and then adds this component's 4833 * <code>validateRoot</code> to a list of components that need to be 4834 * validated. Validation will occur after all currently pending 4835 * events have been dispatched. In other words after this method 4836 * is called, the first validateRoot (if any) found when walking 4837 * up the containment hierarchy of this component will be validated. 4838 * By default, <code>JRootPane</code>, <code>JScrollPane</code>, 4839 * and <code>JTextField</code> return true 4840 * from <code>isValidateRoot</code>. 4841 * <p> 4842 * This method will automatically be called on this component 4843 * when a property value changes such that size, location, or 4844 * internal layout of this component has been affected. This automatic 4845 * updating differs from the AWT because programs generally no 4846 * longer need to invoke <code>validate</code> to get the contents of the 4847 * GUI to update. 4848 * 4849 * @see java.awt.Component#invalidate 4850 * @see java.awt.Container#validate 4851 * @see #isValidateRoot 4852 * @see RepaintManager#addInvalidComponent 4853 */ 4854 public void revalidate() { 4855 if (getParent() == null) { 4856 // Note: We don't bother invalidating here as once added 4857 // to a valid parent invalidate will be invoked (addImpl 4858 // invokes addNotify which will invoke invalidate on the 4859 // new Component). Also, if we do add a check to isValid 4860 // here it can potentially be called before the constructor 4861 // which was causing some people grief. 4862 return; 4863 } 4864 if (SunToolkit.isDispatchThreadForAppContext(this)) { 4865 invalidate(); 4866 RepaintManager.currentManager(this).addInvalidComponent(this); 4867 } 4868 else { 4869 // To avoid a flood of Runnables when constructing GUIs off 4870 // the EDT, a flag is maintained as to whether or not 4871 // a Runnable has been scheduled. 4872 synchronized(this) { 4873 if (getFlag(REVALIDATE_RUNNABLE_SCHEDULED)) { 4874 return; 4875 } 4876 setFlag(REVALIDATE_RUNNABLE_SCHEDULED, true); 4877 } 4878 SunToolkit.executeOnEventHandlerThread(this, () -> { 4879 synchronized(JComponent.this) { 4880 setFlag(REVALIDATE_RUNNABLE_SCHEDULED, false); 4881 } 4882 revalidate(); 4883 }); 4884 } 4885 } 4886 4887 /** 4888 * If this method returns true, <code>revalidate</code> calls by 4889 * descendants of this component will cause the entire tree 4890 * beginning with this root to be validated. 4891 * Returns false by default. <code>JScrollPane</code> overrides 4892 * this method and returns true. 4893 * 4894 * @return always returns false 4895 * @see #revalidate 4896 * @see java.awt.Component#invalidate 4897 * @see java.awt.Container#validate 4898 * @see java.awt.Container#isValidateRoot 4899 */ 4900 @Override 4901 public boolean isValidateRoot() { 4902 return false; 4903 } 4904 4905 4906 /** 4907 * Returns true if this component tiles its children -- that is, if 4908 * it can guarantee that the children will not overlap. The 4909 * repainting system is substantially more efficient in this 4910 * common case. <code>JComponent</code> subclasses that can't make this 4911 * guarantee, such as <code>JLayeredPane</code>, 4912 * should override this method to return false. 4913 * 4914 * @return always returns true 4915 */ 4916 public boolean isOptimizedDrawingEnabled() { 4917 return true; 4918 } 4919 4920 /** 4921 * Returns {@code true} if a paint triggered on a child component should cause 4922 * painting to originate from this Component, or one of its ancestors. 4923 * <p> 4924 * Calling {@link #repaint} or {@link #paintImmediately(int, int, int, int)} 4925 * on a Swing component will result in calling 4926 * the {@link JComponent#paintImmediately(int, int, int, int)} method of 4927 * the first ancestor which {@code isPaintingOrigin()} returns {@code true}, if there are any. 4928 * <p> 4929 * {@code JComponent} subclasses that need to be painted when any of their 4930 * children are repainted should override this method to return {@code true}. 4931 * 4932 * @return always returns {@code false} 4933 * 4934 * @see #paintImmediately(int, int, int, int) 4935 */ 4936 protected boolean isPaintingOrigin() { 4937 return false; 4938 } 4939 4940 /** 4941 * Paints the specified region in this component and all of its 4942 * descendants that overlap the region, immediately. 4943 * <p> 4944 * It's rarely necessary to call this method. In most cases it's 4945 * more efficient to call repaint, which defers the actual painting 4946 * and can collapse redundant requests into a single paint call. 4947 * This method is useful if one needs to update the display while 4948 * the current event is being dispatched. 4949 * <p> 4950 * This method is to be overridden when the dirty region needs to be changed 4951 * for components that are painting origins. 4952 * 4953 * @param x the x value of the region to be painted 4954 * @param y the y value of the region to be painted 4955 * @param w the width of the region to be painted 4956 * @param h the height of the region to be painted 4957 * @see #repaint 4958 * @see #isPaintingOrigin() 4959 */ 4960 public void paintImmediately(int x,int y,int w, int h) { 4961 Component c = this; 4962 Component parent; 4963 4964 if(!isShowing()) { 4965 return; 4966 } 4967 4968 JComponent paintingOigin = SwingUtilities.getPaintingOrigin(this); 4969 if (paintingOigin != null) { 4970 Rectangle rectangle = SwingUtilities.convertRectangle( 4971 c, new Rectangle(x, y, w, h), paintingOigin); 4972 paintingOigin.paintImmediately(rectangle.x, rectangle.y, rectangle.width, rectangle.height); 4973 return; 4974 } 4975 4976 while(!c.isOpaque()) { 4977 parent = c.getParent(); 4978 if(parent != null) { 4979 x += c.getX(); 4980 y += c.getY(); 4981 c = parent; 4982 } else { 4983 break; 4984 } 4985 4986 if(!(c instanceof JComponent)) { 4987 break; 4988 } 4989 } 4990 if(c instanceof JComponent) { 4991 ((JComponent)c)._paintImmediately(x,y,w,h); 4992 } else { 4993 c.repaint(x,y,w,h); 4994 } 4995 } 4996 4997 /** 4998 * Paints the specified region now. 4999 * 5000 * @param r a <code>Rectangle</code> containing the region to be painted 5001 */ 5002 public void paintImmediately(Rectangle r) { 5003 paintImmediately(r.x,r.y,r.width,r.height); 5004 } 5005 5006 /** 5007 * Returns whether this component should be guaranteed to be on top. 5008 * For example, it would make no sense for <code>Menu</code>s to pop up 5009 * under another component, so they would always return true. 5010 * Most components will want to return false, hence that is the default. 5011 * 5012 * @return always returns false 5013 */ 5014 // package private 5015 boolean alwaysOnTop() { 5016 return false; 5017 } 5018 5019 void setPaintingChild(Component paintingChild) { 5020 this.paintingChild = paintingChild; 5021 } 5022 5023 void _paintImmediately(int x, int y, int w, int h) { 5024 Graphics g; 5025 Container c; 5026 Rectangle b; 5027 5028 int tmpX, tmpY, tmpWidth, tmpHeight; 5029 int offsetX=0,offsetY=0; 5030 5031 boolean hasBuffer = false; 5032 5033 JComponent bufferedComponent = null; 5034 JComponent paintingComponent = this; 5035 5036 RepaintManager repaintManager = RepaintManager.currentManager(this); 5037 // parent Container's up to Window or Applet. First container is 5038 // the direct parent. Note that in testing it was faster to 5039 // alloc a new Vector vs keeping a stack of them around, and gc 5040 // seemed to have a minimal effect on this. 5041 java.util.List<Component> path = new java.util.ArrayList<Component>(7); 5042 int pIndex = -1; 5043 int pCount = 0; 5044 5045 tmpX = tmpY = tmpWidth = tmpHeight = 0; 5046 5047 Rectangle paintImmediatelyClip = fetchRectangle(); 5048 paintImmediatelyClip.x = x; 5049 paintImmediatelyClip.y = y; 5050 paintImmediatelyClip.width = w; 5051 paintImmediatelyClip.height = h; 5052 5053 5054 // System.out.println("1) ************* in _paintImmediately for " + this); 5055 5056 boolean ontop = alwaysOnTop() && isOpaque(); 5057 if (ontop) { 5058 SwingUtilities.computeIntersection(0, 0, getWidth(), getHeight(), 5059 paintImmediatelyClip); 5060 if (paintImmediatelyClip.width == 0) { 5061 recycleRectangle(paintImmediatelyClip); 5062 return; 5063 } 5064 } 5065 Component child; 5066 for (c = this, child = null; 5067 c != null && !(c instanceof Window) && !(c instanceof Applet); 5068 child = c, c = c.getParent()) { 5069 JComponent jc = (c instanceof JComponent) ? (JComponent)c : 5070 null; 5071 path.add(c); 5072 if(!ontop && jc != null && !jc.isOptimizedDrawingEnabled()) { 5073 boolean resetPC; 5074 5075 // Children of c may overlap, three possible cases for the 5076 // painting region: 5077 // . Completely obscured by an opaque sibling, in which 5078 // case there is no need to paint. 5079 // . Partially obscured by a sibling: need to start 5080 // painting from c. 5081 // . Otherwise we aren't obscured and thus don't need to 5082 // start painting from parent. 5083 if (c != this) { 5084 if (jc.isPaintingOrigin()) { 5085 resetPC = true; 5086 } 5087 else { 5088 Component[] children = c.getComponents(); 5089 int i = 0; 5090 for (; i<children.length; i++) { 5091 if (children[i] == child) break; 5092 } 5093 switch (jc.getObscuredState(i, 5094 paintImmediatelyClip.x, 5095 paintImmediatelyClip.y, 5096 paintImmediatelyClip.width, 5097 paintImmediatelyClip.height)) { 5098 case NOT_OBSCURED: 5099 resetPC = false; 5100 break; 5101 case COMPLETELY_OBSCURED: 5102 recycleRectangle(paintImmediatelyClip); 5103 return; 5104 default: 5105 resetPC = true; 5106 break; 5107 } 5108 } 5109 } 5110 else { 5111 resetPC = false; 5112 } 5113 5114 if (resetPC) { 5115 // Get rid of any buffer since we draw from here and 5116 // we might draw something larger 5117 paintingComponent = jc; 5118 pIndex = pCount; 5119 offsetX = offsetY = 0; 5120 hasBuffer = false; 5121 } 5122 } 5123 pCount++; 5124 5125 // look to see if the parent (and therefor this component) 5126 // is double buffered 5127 if(repaintManager.isDoubleBufferingEnabled() && jc != null && 5128 jc.isDoubleBuffered()) { 5129 hasBuffer = true; 5130 bufferedComponent = jc; 5131 } 5132 5133 // if we aren't on top, include the parent's clip 5134 if (!ontop) { 5135 int bx = c.getX(); 5136 int by = c.getY(); 5137 tmpWidth = c.getWidth(); 5138 tmpHeight = c.getHeight(); 5139 SwingUtilities.computeIntersection(tmpX,tmpY,tmpWidth,tmpHeight,paintImmediatelyClip); 5140 paintImmediatelyClip.x += bx; 5141 paintImmediatelyClip.y += by; 5142 offsetX += bx; 5143 offsetY += by; 5144 } 5145 } 5146 5147 // If the clip width or height is negative, don't bother painting 5148 if(c == null || c.getPeer() == null || 5149 paintImmediatelyClip.width <= 0 || 5150 paintImmediatelyClip.height <= 0) { 5151 recycleRectangle(paintImmediatelyClip); 5152 return; 5153 } 5154 5155 paintingComponent.setFlag(IS_REPAINTING, true); 5156 5157 paintImmediatelyClip.x -= offsetX; 5158 paintImmediatelyClip.y -= offsetY; 5159 5160 // Notify the Components that are going to be painted of the 5161 // child component to paint to. 5162 if(paintingComponent != this) { 5163 Component comp; 5164 int i = pIndex; 5165 for(; i > 0 ; i--) { 5166 comp = path.get(i); 5167 if(comp instanceof JComponent) { 5168 ((JComponent)comp).setPaintingChild(path.get(i-1)); 5169 } 5170 } 5171 } 5172 try { 5173 if ((g = safelyGetGraphics(paintingComponent, c)) != null) { 5174 try { 5175 if (hasBuffer) { 5176 RepaintManager rm = RepaintManager.currentManager( 5177 bufferedComponent); 5178 rm.beginPaint(); 5179 try { 5180 rm.paint(paintingComponent, bufferedComponent, g, 5181 paintImmediatelyClip.x, 5182 paintImmediatelyClip.y, 5183 paintImmediatelyClip.width, 5184 paintImmediatelyClip.height); 5185 } finally { 5186 rm.endPaint(); 5187 } 5188 } else { 5189 g.setClip(paintImmediatelyClip.x, paintImmediatelyClip.y, 5190 paintImmediatelyClip.width, paintImmediatelyClip.height); 5191 paintingComponent.paint(g); 5192 } 5193 } finally { 5194 g.dispose(); 5195 } 5196 } 5197 } 5198 finally { 5199 // Reset the painting child for the parent components. 5200 if(paintingComponent != this) { 5201 Component comp; 5202 int i = pIndex; 5203 for(; i > 0 ; i--) { 5204 comp = path.get(i); 5205 if(comp instanceof JComponent) { 5206 ((JComponent)comp).setPaintingChild(null); 5207 } 5208 } 5209 } 5210 paintingComponent.setFlag(IS_REPAINTING, false); 5211 } 5212 recycleRectangle(paintImmediatelyClip); 5213 } 5214 5215 /** 5216 * Paints to the specified graphics. This does not set the clip and it 5217 * does not adjust the Graphics in anyway, callers must do that first. 5218 * This method is package-private for RepaintManager.PaintManager and 5219 * its subclasses to call, it is NOT intended for general use outside 5220 * of that. 5221 */ 5222 void paintToOffscreen(Graphics g, int x, int y, int w, int h, int maxX, 5223 int maxY) { 5224 try { 5225 setFlag(ANCESTOR_USING_BUFFER, true); 5226 if ((y + h) < maxY || (x + w) < maxX) { 5227 setFlag(IS_PAINTING_TILE, true); 5228 } 5229 if (getFlag(IS_REPAINTING)) { 5230 // Called from paintImmediately (RepaintManager) to fill 5231 // repaint request 5232 paint(g); 5233 } else { 5234 // Called from paint() (AWT) to repair damage 5235 if(!rectangleIsObscured(x, y, w, h)) { 5236 paintComponent(g); 5237 paintBorder(g); 5238 } 5239 paintChildren(g); 5240 } 5241 } finally { 5242 setFlag(ANCESTOR_USING_BUFFER, false); 5243 setFlag(IS_PAINTING_TILE, false); 5244 } 5245 } 5246 5247 /** 5248 * Returns whether or not the region of the specified component is 5249 * obscured by a sibling. 5250 * 5251 * @return NOT_OBSCURED if non of the siblings above the Component obscure 5252 * it, COMPLETELY_OBSCURED if one of the siblings completely 5253 * obscures the Component or PARTIALLY_OBSCURED if the Component is 5254 * only partially obscured. 5255 */ 5256 private int getObscuredState(int compIndex, int x, int y, int width, 5257 int height) { 5258 int retValue = NOT_OBSCURED; 5259 Rectangle tmpRect = fetchRectangle(); 5260 5261 for (int i = compIndex - 1 ; i >= 0 ; i--) { 5262 Component sibling = getComponent(i); 5263 if (!sibling.isVisible()) { 5264 continue; 5265 } 5266 Rectangle siblingRect; 5267 boolean opaque; 5268 if (sibling instanceof JComponent) { 5269 opaque = sibling.isOpaque(); 5270 if (!opaque) { 5271 if (retValue == PARTIALLY_OBSCURED) { 5272 continue; 5273 } 5274 } 5275 } 5276 else { 5277 opaque = true; 5278 } 5279 siblingRect = sibling.getBounds(tmpRect); 5280 if (opaque && x >= siblingRect.x && (x + width) <= 5281 (siblingRect.x + siblingRect.width) && 5282 y >= siblingRect.y && (y + height) <= 5283 (siblingRect.y + siblingRect.height)) { 5284 recycleRectangle(tmpRect); 5285 return COMPLETELY_OBSCURED; 5286 } 5287 else if (retValue == NOT_OBSCURED && 5288 !((x + width <= siblingRect.x) || 5289 (y + height <= siblingRect.y) || 5290 (x >= siblingRect.x + siblingRect.width) || 5291 (y >= siblingRect.y + siblingRect.height))) { 5292 retValue = PARTIALLY_OBSCURED; 5293 } 5294 } 5295 recycleRectangle(tmpRect); 5296 return retValue; 5297 } 5298 5299 /** 5300 * Returns true, which implies that before checking if a child should 5301 * be painted it is first check that the child is not obscured by another 5302 * sibling. This is only checked if <code>isOptimizedDrawingEnabled</code> 5303 * returns false. 5304 * 5305 * @return always returns true 5306 */ 5307 boolean checkIfChildObscuredBySibling() { 5308 return true; 5309 } 5310 5311 5312 private void setFlag(int aFlag, boolean aValue) { 5313 if(aValue) { 5314 flags |= (1 << aFlag); 5315 } else { 5316 flags &= ~(1 << aFlag); 5317 } 5318 } 5319 private boolean getFlag(int aFlag) { 5320 int mask = (1 << aFlag); 5321 return ((flags & mask) == mask); 5322 } 5323 // These functions must be static so that they can be called from 5324 // subclasses inside the package, but whose inheritance hierarhcy includes 5325 // classes outside of the package below JComponent (e.g., JTextArea). 5326 static void setWriteObjCounter(JComponent comp, byte count) { 5327 comp.flags = (comp.flags & ~(0xFF << WRITE_OBJ_COUNTER_FIRST)) | 5328 (count << WRITE_OBJ_COUNTER_FIRST); 5329 } 5330 static byte getWriteObjCounter(JComponent comp) { 5331 return (byte)((comp.flags >> WRITE_OBJ_COUNTER_FIRST) & 0xFF); 5332 } 5333 5334 /** Buffering **/ 5335 5336 /** 5337 * Sets whether this component should use a buffer to paint. 5338 * If set to true, all the drawing from this component will be done 5339 * in an offscreen painting buffer. The offscreen painting buffer will 5340 * the be copied onto the screen. 5341 * If a <code>Component</code> is buffered and one of its ancestor 5342 * is also buffered, the ancestor buffer will be used. 5343 * 5344 * @param aFlag if true, set this component to be double buffered 5345 */ 5346 public void setDoubleBuffered(boolean aFlag) { 5347 setFlag(IS_DOUBLE_BUFFERED,aFlag); 5348 } 5349 5350 /** 5351 * Returns whether this component should use a buffer to paint. 5352 * 5353 * @return true if this component is double buffered, otherwise false 5354 */ 5355 public boolean isDoubleBuffered() { 5356 return getFlag(IS_DOUBLE_BUFFERED); 5357 } 5358 5359 /** 5360 * Returns the <code>JRootPane</code> ancestor for this component. 5361 * 5362 * @return the <code>JRootPane</code> that contains this component, 5363 * or <code>null</code> if no <code>JRootPane</code> is found 5364 */ 5365 public JRootPane getRootPane() { 5366 return SwingUtilities.getRootPane(this); 5367 } 5368 5369 5370 /** Serialization **/ 5371 5372 /** 5373 * This is called from Component by way of reflection. Do NOT change 5374 * the name unless you change the code in Component as well. 5375 */ 5376 void compWriteObjectNotify() { 5377 byte count = JComponent.getWriteObjCounter(this); 5378 JComponent.setWriteObjCounter(this, (byte)(count + 1)); 5379 if (count != 0) { 5380 return; 5381 } 5382 5383 uninstallUIAndProperties(); 5384 5385 /* JTableHeader is in a separate package, which prevents it from 5386 * being able to override this package-private method the way the 5387 * other components can. We don't want to make this method protected 5388 * because it would introduce public-api for a less-than-desirable 5389 * serialization scheme, so we compromise with this 'instanceof' hack 5390 * for now. 5391 */ 5392 if (getToolTipText() != null || 5393 this instanceof javax.swing.table.JTableHeader) { 5394 ToolTipManager.sharedInstance().unregisterComponent(JComponent.this); 5395 } 5396 } 5397 5398 /** 5399 * This object is the <code>ObjectInputStream</code> callback 5400 * that's called after a complete graph of objects (including at least 5401 * one <code>JComponent</code>) has been read. 5402 * It sets the UI property of each Swing component 5403 * that was read to the current default with <code>updateUI</code>. 5404 * <p> 5405 * As each component is read in we keep track of the current set of 5406 * root components here, in the roots vector. Note that there's only one 5407 * <code>ReadObjectCallback</code> per <code>ObjectInputStream</code>, 5408 * they're stored in the static <code>readObjectCallbacks</code> 5409 * hashtable. 5410 * 5411 * @see java.io.ObjectInputStream#registerValidation 5412 * @see SwingUtilities#updateComponentTreeUI 5413 */ 5414 private class ReadObjectCallback implements ObjectInputValidation 5415 { 5416 private final Vector<JComponent> roots = new Vector<JComponent>(1); 5417 private final ObjectInputStream inputStream; 5418 5419 ReadObjectCallback(ObjectInputStream s) throws Exception { 5420 inputStream = s; 5421 s.registerValidation(this, 0); 5422 } 5423 5424 /** 5425 * This is the method that's called after the entire graph 5426 * of objects has been read in. It initializes 5427 * the UI property of all of the copmonents with 5428 * <code>SwingUtilities.updateComponentTreeUI</code>. 5429 */ 5430 public void validateObject() throws InvalidObjectException { 5431 try { 5432 for (JComponent root : roots) { 5433 SwingUtilities.updateComponentTreeUI(root); 5434 } 5435 } 5436 finally { 5437 readObjectCallbacks.remove(inputStream); 5438 } 5439 } 5440 5441 /** 5442 * If <code>c</code> isn't a descendant of a component we've already 5443 * seen, then add it to the roots <code>Vector</code>. 5444 * 5445 * @param c the <code>JComponent</code> to add 5446 */ 5447 private void registerComponent(JComponent c) 5448 { 5449 /* If the Component c is a descendant of one of the 5450 * existing roots (or it IS an existing root), we're done. 5451 */ 5452 for (JComponent root : roots) { 5453 for(Component p = c; p != null; p = p.getParent()) { 5454 if (p == root) { 5455 return; 5456 } 5457 } 5458 } 5459 5460 /* Otherwise: if Component c is an ancestor of any of the 5461 * existing roots then remove them and add c (the "new root") 5462 * to the roots vector. 5463 */ 5464 for(int i = 0; i < roots.size(); i++) { 5465 JComponent root = roots.elementAt(i); 5466 for(Component p = root.getParent(); p != null; p = p.getParent()) { 5467 if (p == c) { 5468 roots.removeElementAt(i--); // !! 5469 break; 5470 } 5471 } 5472 } 5473 5474 roots.addElement(c); 5475 } 5476 } 5477 5478 5479 /** 5480 * We use the <code>ObjectInputStream</code> "registerValidation" 5481 * callback to update the UI for the entire tree of components 5482 * after they've all been read in. 5483 * 5484 * @param s the <code>ObjectInputStream</code> from which to read 5485 */ 5486 private void readObject(ObjectInputStream s) 5487 throws IOException, ClassNotFoundException 5488 { 5489 s.defaultReadObject(); 5490 5491 /* If there's no ReadObjectCallback for this stream yet, that is, if 5492 * this is the first call to JComponent.readObject() for this 5493 * graph of objects, then create a callback and stash it 5494 * in the readObjectCallbacks table. Note that the ReadObjectCallback 5495 * constructor takes care of calling s.registerValidation(). 5496 */ 5497 ReadObjectCallback cb = readObjectCallbacks.get(s); 5498 if (cb == null) { 5499 try { 5500 readObjectCallbacks.put(s, cb = new ReadObjectCallback(s)); 5501 } 5502 catch (Exception e) { 5503 throw new IOException(e.toString()); 5504 } 5505 } 5506 cb.registerComponent(this); 5507 5508 // Read back the client properties. 5509 int cpCount = s.readInt(); 5510 if (cpCount > 0) { 5511 clientProperties = new ArrayTable(); 5512 for (int counter = 0; counter < cpCount; counter++) { 5513 clientProperties.put(s.readObject(), 5514 s.readObject()); 5515 } 5516 } 5517 if (getToolTipText() != null) { 5518 ToolTipManager.sharedInstance().registerComponent(this); 5519 } 5520 setWriteObjCounter(this, (byte)0); 5521 } 5522 5523 5524 /** 5525 * Before writing a <code>JComponent</code> to an 5526 * <code>ObjectOutputStream</code> we temporarily uninstall its UI. 5527 * This is tricky to do because we want to uninstall 5528 * the UI before any of the <code>JComponent</code>'s children 5529 * (or its <code>LayoutManager</code> etc.) are written, 5530 * and we don't want to restore the UI until the most derived 5531 * <code>JComponent</code> subclass has been been stored. 5532 * 5533 * @param s the <code>ObjectOutputStream</code> in which to write 5534 */ 5535 private void writeObject(ObjectOutputStream s) throws IOException { 5536 s.defaultWriteObject(); 5537 if (getUIClassID().equals(uiClassID)) { 5538 byte count = JComponent.getWriteObjCounter(this); 5539 JComponent.setWriteObjCounter(this, --count); 5540 if (count == 0 && ui != null) { 5541 ui.installUI(this); 5542 } 5543 } 5544 ArrayTable.writeArrayTable(s, clientProperties); 5545 } 5546 5547 5548 /** 5549 * Returns a string representation of this <code>JComponent</code>. 5550 * This method 5551 * is intended to be used only for debugging purposes, and the 5552 * content and format of the returned string may vary between 5553 * implementations. The returned string may be empty but may not 5554 * be <code>null</code>. 5555 * 5556 * @return a string representation of this <code>JComponent</code> 5557 */ 5558 protected String paramString() { 5559 String preferredSizeString = (isPreferredSizeSet() ? 5560 getPreferredSize().toString() : ""); 5561 String minimumSizeString = (isMinimumSizeSet() ? 5562 getMinimumSize().toString() : ""); 5563 String maximumSizeString = (isMaximumSizeSet() ? 5564 getMaximumSize().toString() : ""); 5565 String borderString = (border == null ? "" 5566 : (border == this ? "this" : border.toString())); 5567 5568 return super.paramString() + 5569 ",alignmentX=" + alignmentX + 5570 ",alignmentY=" + alignmentY + 5571 ",border=" + borderString + 5572 ",flags=" + flags + // should beef this up a bit 5573 ",maximumSize=" + maximumSizeString + 5574 ",minimumSize=" + minimumSizeString + 5575 ",preferredSize=" + preferredSizeString; 5576 } 5577 5578 /** 5579 * {@inheritDoc} 5580 */ 5581 @Override 5582 @Deprecated 5583 public void hide() { 5584 boolean showing = isShowing(); 5585 super.hide(); 5586 if (showing) { 5587 Container parent = getParent(); 5588 if (parent != null) { 5589 Rectangle r = getBounds(); 5590 parent.repaint(r.x, r.y, r.width, r.height); 5591 } 5592 revalidate(); 5593 } 5594 } 5595 5596 }