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