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