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