1 /* SwingUtilities.java -- 2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.swing; 40 41 import java.applet.Applet; 42 import java.awt.Component; 43 import java.awt.ComponentOrientation; 44 import java.awt.Container; 45 import java.awt.FontMetrics; 46 import java.awt.Frame; 47 import java.awt.Graphics; 48 import java.awt.Insets; 49 import java.awt.KeyboardFocusManager; 50 import java.awt.Point; 51 import java.awt.Rectangle; 52 import java.awt.Shape; 53 import java.awt.Window; 54 import java.awt.event.ActionEvent; 55 import java.awt.event.InputEvent; 56 import java.awt.event.KeyEvent; 57 import java.awt.event.MouseEvent; 58 import java.lang.reflect.InvocationTargetException; 59 60 import javax.accessibility.Accessible; 61 import javax.accessibility.AccessibleStateSet; 62 import javax.swing.plaf.ActionMapUIResource; 63 import javax.swing.plaf.InputMapUIResource; 64 65 /** 66 * A number of static utility functions which are 67 * useful when drawing swing components, dispatching events, or calculating 68 * regions which need painting. 69 * 70 * @author Graydon Hoare (graydon@redhat.com) 71 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 72 */ 73 public class SwingUtilities 74 implements SwingConstants 75 { 76 /** 77 * This frame should be used as parent for JWindow or JDialog 78 * that doesn't an owner 79 */ 80 private static OwnerFrame ownerFrame; 81 SwingUtilities()82 private SwingUtilities() 83 { 84 // Do nothing. 85 } 86 87 /** 88 * Calculates the portion of the base rectangle which is inside the 89 * insets. 90 * 91 * @param base The rectangle to apply the insets to 92 * @param insets The insets to apply to the base rectangle 93 * @param ret A rectangle to use for storing the return value, or 94 * <code>null</code> 95 * 96 * @return The calculated area inside the base rectangle and its insets, 97 * either stored in ret or a new Rectangle if ret is <code>null</code> 98 * 99 * @see #calculateInnerArea 100 */ calculateInsetArea(Rectangle base, Insets insets, Rectangle ret)101 public static Rectangle calculateInsetArea(Rectangle base, Insets insets, 102 Rectangle ret) 103 { 104 if (ret == null) 105 ret = new Rectangle(); 106 ret.setBounds(base.x + insets.left, base.y + insets.top, 107 base.width - (insets.left + insets.right), 108 base.height - (insets.top + insets.bottom)); 109 return ret; 110 } 111 112 /** 113 * Calculates the portion of the component's bounds which is inside the 114 * component's border insets. This area is usually the area a component 115 * should confine its painting to. The coordinates are returned in terms 116 * of the <em>component's</em> coordinate system, where (0,0) is the 117 * upper left corner of the component's bounds. 118 * 119 * @param c The component to measure the bounds of 120 * @param r A Rectangle to store the return value in, or 121 * <code>null</code> 122 * 123 * @return The calculated area inside the component and its border 124 * insets 125 * 126 * @see #calculateInsetArea 127 */ calculateInnerArea(JComponent c, Rectangle r)128 public static Rectangle calculateInnerArea(JComponent c, Rectangle r) 129 { 130 Rectangle b = getLocalBounds(c); 131 return calculateInsetArea(b, c.getInsets(), r); 132 } 133 134 /** 135 * Returns the focus owner or <code>null</code> if <code>comp</code> is not 136 * the focus owner or a parent of it. 137 * 138 * @param comp the focus owner or a parent of it 139 * 140 * @return the focus owner, or <code>null</code> 141 * 142 * @deprecated 1.4 Replaced by 143 * <code>KeyboardFocusManager.getFocusOwner()</code>. 144 */ findFocusOwner(Component comp)145 public static Component findFocusOwner(Component comp) 146 { 147 // Get real focus owner. 148 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager() 149 .getFocusOwner(); 150 151 // Check if comp is the focus owner or a parent of it. 152 Component tmp = focusOwner; 153 154 while (tmp != null) 155 { 156 if (tmp == comp) 157 return focusOwner; 158 159 tmp = tmp.getParent(); 160 } 161 162 return null; 163 } 164 165 /** 166 * Returns the <code>Accessible</code> child of the specified component 167 * which appears at the supplied <code>Point</code>. If there is no 168 * child located at that particular pair of co-ordinates, null is returned 169 * instead. 170 * 171 * @param c the component whose children may be found at the specified 172 * point. 173 * @param p the point at which to look for the existence of children 174 * of the specified component. 175 * @return the <code>Accessible</code> child at the point, <code>p</code>, 176 * or null if there is no child at this point. 177 * @see javax.accessibility.AccessibleComponent#getAccessibleAt 178 */ getAccessibleAt(Component c, Point p)179 public static Accessible getAccessibleAt(Component c, Point p) 180 { 181 return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p); 182 } 183 184 /** 185 * <p> 186 * Returns the <code>Accessible</code> child of the specified component 187 * that has the supplied index within the parent component. The indexing 188 * of the children is zero-based, making the first child have an index of 189 * 0. 190 * </p> 191 * <p> 192 * Caution is advised when using this method, as its operation relies 193 * on the behaviour of varying implementations of an abstract method. 194 * For greater surety, direct use of the AWT component implementation 195 * of this method is advised. 196 * </p> 197 * 198 * @param c the component whose child should be returned. 199 * @param i the index of the child within the parent component. 200 * @return the <code>Accessible</code> child at index <code>i</code> 201 * in the component, <code>c</code>. 202 * @see javax.accessibility.AccessibleContext#getAccessibleChild 203 * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChild 204 */ getAccessibleChild(Component c, int i)205 public static Accessible getAccessibleChild(Component c, int i) 206 { 207 return c.getAccessibleContext().getAccessibleChild(i); 208 } 209 210 /** 211 * <p> 212 * Returns the number of <code>Accessible</code> children within 213 * the supplied component. 214 * </p> 215 * <p> 216 * Caution is advised when using this method, as its operation relies 217 * on the behaviour of varying implementations of an abstract method. 218 * For greater surety, direct use of the AWT component implementation 219 * of this method is advised. 220 * </p> 221 * 222 * @param c the component whose children should be counted. 223 * @return the number of children belonging to the component, 224 * <code>c</code>. 225 * @see javax.accessibility.AccessibleContext#getAccessibleChildrenCount 226 * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChildrenCount 227 */ getAccessibleChildrenCount(Component c)228 public static int getAccessibleChildrenCount(Component c) 229 { 230 return c.getAccessibleContext().getAccessibleChildrenCount(); 231 } 232 233 /** 234 * <p> 235 * Returns the zero-based index of the specified component 236 * within its parent. If the component doesn't have a parent, 237 * -1 is returned. 238 * </p> 239 * <p> 240 * Caution is advised when using this method, as its operation relies 241 * on the behaviour of varying implementations of an abstract method. 242 * For greater surety, direct use of the AWT component implementation 243 * of this method is advised. 244 * </p> 245 * 246 * @param c the component whose parental index should be found. 247 * @return the index of the component within its parent, or -1 248 * if the component doesn't have a parent. 249 * @see javax.accessibility.AccessibleContext#getAccessibleIndexInParent 250 * @see java.awt.Component.AccessibleAWTComponent#getAccessibleIndexInParent 251 */ getAccessibleIndexInParent(Component c)252 public static int getAccessibleIndexInParent(Component c) 253 { 254 return c.getAccessibleContext().getAccessibleIndexInParent(); 255 } 256 257 /** 258 * <p> 259 * Returns a set of <code>AccessibleState</code>s, which represent 260 * the state of the supplied component. 261 * </p> 262 * <p> 263 * Caution is advised when using this method, as its operation relies 264 * on the behaviour of varying implementations of an abstract method. 265 * For greater surety, direct use of the AWT component implementation 266 * of this method is advised. 267 * </p> 268 * 269 * @param c the component whose accessible state should be retrieved. 270 * @return a set of <code>AccessibleState</code> objects, which represent 271 * the state of the supplied component. 272 * @see javax.accessibility.AccessibleContext#getAccessibleStateSet 273 * @see java.awt.Component.AccessibleAWTComponent#getAccessibleStateSet 274 */ getAccessibleStateSet(Component c)275 public static AccessibleStateSet getAccessibleStateSet(Component c) 276 { 277 return c.getAccessibleContext().getAccessibleStateSet(); 278 } 279 280 /** 281 * Calculates the bounds of a component in the component's own coordinate 282 * space. The result has the same height and width as the component's 283 * bounds, but its location is set to (0,0). 284 * 285 * @param aComponent The component to measure 286 * 287 * @return The component's bounds in its local coordinate space 288 */ getLocalBounds(Component aComponent)289 public static Rectangle getLocalBounds(Component aComponent) 290 { 291 Rectangle bounds = aComponent.getBounds(); 292 return new Rectangle(0, 0, bounds.width, bounds.height); 293 } 294 295 /** 296 * If <code>comp</code> is a RootPaneContainer, return its JRootPane. 297 * Otherwise call <code>getAncestorOfClass(JRootPane.class, a)</code>. 298 * 299 * @param comp The component to get the JRootPane of 300 * 301 * @return a suitable JRootPane for <code>comp</code>, or <code>null</code> 302 * 303 * @see javax.swing.RootPaneContainer#getRootPane 304 * @see #getAncestorOfClass 305 */ getRootPane(Component comp)306 public static JRootPane getRootPane(Component comp) 307 { 308 if (comp instanceof RootPaneContainer) 309 return ((RootPaneContainer)comp).getRootPane(); 310 else 311 return (JRootPane) getAncestorOfClass(JRootPane.class, comp); 312 } 313 314 /** 315 * Returns the least ancestor of <code>comp</code> which has the 316 * specified name. 317 * 318 * @param name The name to search for 319 * @param comp The component to search the ancestors of 320 * 321 * @return The nearest ancestor of <code>comp</code> with the given 322 * name, or <code>null</code> if no such ancestor exists 323 * 324 * @see java.awt.Component#getName 325 * @see #getAncestorOfClass 326 */ getAncestorNamed(String name, Component comp)327 public static Container getAncestorNamed(String name, Component comp) 328 { 329 while (comp != null && (comp.getName() != name)) 330 comp = comp.getParent(); 331 return (Container) comp; 332 } 333 334 /** 335 * Returns the least ancestor of <code>comp</code> which is an instance 336 * of the specified class. 337 * 338 * @param c The class to search for 339 * @param comp The component to search the ancestors of 340 * 341 * @return The nearest ancestor of <code>comp</code> which is an instance 342 * of the given class, or <code>null</code> if no such ancestor exists 343 * 344 * @see #getAncestorOfClass 345 * @see #windowForComponent 346 */ getAncestorOfClass(Class c, Component comp)347 public static Container getAncestorOfClass(Class c, Component comp) 348 { 349 while (comp != null && (! c.isInstance(comp))) 350 comp = comp.getParent(); 351 return (Container) comp; 352 } 353 354 /** 355 * Returns the first ancestor of <code>comp</code> that is a {@link Window} 356 * or <code>null</code> if <code>comp</code> is not contained in a 357 * {@link Window}. 358 * 359 * This is equivalent to calling 360 * <code>getAncestorOfClass(Window, comp)</code> or 361 * <code>windowForComponent(comp)</code>. 362 * 363 * @param comp the component for which we are searching the ancestor Window 364 * 365 * @return the first ancestor Window of <code>comp</code> or 366 * <code>null</code> if <code>comp</code> is not contained in a Window 367 */ getWindowAncestor(Component comp)368 public static Window getWindowAncestor(Component comp) 369 { 370 return (Window) getAncestorOfClass(Window.class, comp); 371 } 372 373 /** 374 * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>. 375 * 376 * @param comp The component to search for an ancestor window 377 * 378 * @return An ancestral window, or <code>null</code> if none exists 379 */ windowForComponent(Component comp)380 public static Window windowForComponent(Component comp) 381 { 382 return (Window) getAncestorOfClass(Window.class, comp); 383 } 384 385 /** 386 * Returns the "root" of the component tree containint <code>comp</code> 387 * The root is defined as either the <em>least</em> ancestor of 388 * <code>comp</code> which is a {@link Window}, or the <em>greatest</em> 389 * ancestor of <code>comp</code> which is a {@link Applet} if no {@link 390 * Window} ancestors are found. 391 * 392 * @param comp The component to search for a root 393 * 394 * @return The root of the component's tree, or <code>null</code> 395 */ getRoot(Component comp)396 public static Component getRoot(Component comp) 397 { 398 Applet app = null; 399 Window win = null; 400 401 while (comp != null) 402 { 403 if (win == null && comp instanceof Window) 404 win = (Window) comp; 405 else if (comp instanceof Applet) 406 app = (Applet) comp; 407 comp = comp.getParent(); 408 } 409 410 if (win != null) 411 return win; 412 else 413 return app; 414 } 415 416 /** 417 * Return true if a descends from b, in other words if b is an 418 * ancestor of a. 419 * 420 * @param a The child to search the ancestry of 421 * @param b The potential ancestor to search for 422 * 423 * @return true if a is a descendent of b, false otherwise 424 */ isDescendingFrom(Component a, Component b)425 public static boolean isDescendingFrom(Component a, Component b) 426 { 427 while (true) 428 { 429 if (a == null || b == null) 430 return false; 431 if (a == b) 432 return true; 433 a = a.getParent(); 434 } 435 } 436 437 /** 438 * Returns the deepest descendent of parent which is both visible and 439 * contains the point <code>(x,y)</code>. Returns parent when either 440 * parent is not a container, or has no children which contain 441 * <code>(x,y)</code>. Returns <code>null</code> when either 442 * <code>(x,y)</code> is outside the bounds of parent, or parent is 443 * <code>null</code>. 444 * 445 * @param parent The component to search the descendents of 446 * @param x Horizontal coordinate to search for 447 * @param y Vertical coordinate to search for 448 * 449 * @return A component containing <code>(x,y)</code>, or 450 * <code>null</code> 451 * 452 * @see java.awt.Container#findComponentAt(int, int) 453 */ getDeepestComponentAt(Component parent, int x, int y)454 public static Component getDeepestComponentAt(Component parent, int x, int y) 455 { 456 if (parent == null || (! parent.contains(x, y))) 457 return null; 458 459 if (! (parent instanceof Container)) 460 return parent; 461 462 Container c = (Container) parent; 463 return c.findComponentAt(x, y); 464 } 465 466 /** 467 * Converts a point from a component's local coordinate space to "screen" 468 * coordinates (such as the coordinate space mouse events are delivered 469 * in). This operation is equivalent to translating the point by the 470 * location of the component (which is the origin of its coordinate 471 * space). 472 * 473 * @param p The point to convert 474 * @param c The component which the point is expressed in terms of 475 * 476 * @see #convertPointFromScreen 477 */ convertPointToScreen(Point p, Component c)478 public static void convertPointToScreen(Point p, Component c) 479 { 480 Point c0 = c.getLocationOnScreen(); 481 p.translate(c0.x, c0.y); 482 } 483 484 /** 485 * Converts a point from "screen" coordinates (such as the coordinate 486 * space mouse events are delivered in) to a component's local coordinate 487 * space. This operation is equivalent to translating the point by the 488 * negation of the component's location (which is the origin of its 489 * coordinate space). 490 * 491 * @param p The point to convert 492 * @param c The component which the point should be expressed in terms of 493 */ convertPointFromScreen(Point p, Component c)494 public static void convertPointFromScreen(Point p, Component c) 495 { 496 Point c0 = c.getLocationOnScreen(); 497 p.translate(-c0.x, -c0.y); 498 } 499 500 /** 501 * Converts a point <code>(x,y)</code> from the coordinate space of one 502 * component to another. This is equivalent to converting the point from 503 * <code>source</code> space to screen space, then back from screen space 504 * to <code>destination</code> space. If exactly one of the two 505 * Components is <code>null</code>, it is taken to refer to the root 506 * ancestor of the other component. If both are <code>null</code>, no 507 * transformation is done. 508 * 509 * @param source The component which the point is expressed in terms of 510 * @param x Horizontal coordinate of point to transform 511 * @param y Vertical coordinate of point to transform 512 * @param destination The component which the return value will be 513 * expressed in terms of 514 * 515 * @return The point <code>(x,y)</code> converted from the coordinate space of the 516 * source component to the coordinate space of the destination component 517 * 518 * @see #convertPointToScreen 519 * @see #convertPointFromScreen 520 * @see #convertRectangle 521 * @see #getRoot 522 */ convertPoint(Component source, int x, int y, Component destination)523 public static Point convertPoint(Component source, int x, int y, 524 Component destination) 525 { 526 Point pt = new Point(x, y); 527 528 if (source == null && destination == null) 529 return pt; 530 531 if (source == null) 532 source = getRoot(destination); 533 534 if (destination == null) 535 destination = getRoot(source); 536 537 if (source.isShowing() && destination.isShowing()) 538 { 539 convertPointToScreen(pt, source); 540 convertPointFromScreen(pt, destination); 541 } 542 543 return pt; 544 } 545 convertPoint(Component source, Point aPoint, Component destination)546 public static Point convertPoint(Component source, Point aPoint, Component destination) 547 { 548 return convertPoint(source, aPoint.x, aPoint.y, destination); 549 } 550 551 /** 552 * Converts a rectangle from the coordinate space of one component to 553 * another. This is equivalent to converting the rectangle from 554 * <code>source</code> space to screen space, then back from screen space 555 * to <code>destination</code> space. If exactly one of the two 556 * Components is <code>null</code>, it is taken to refer to the root 557 * ancestor of the other component. If both are <code>null</code>, no 558 * transformation is done. 559 * 560 * @param source The component which the rectangle is expressed in terms of 561 * @param rect The rectangle to convert 562 * @param destination The component which the return value will be 563 * expressed in terms of 564 * 565 * @return A new rectangle, equal in size to the input rectangle, but 566 * with its position converted from the coordinate space of the source 567 * component to the coordinate space of the destination component 568 * 569 * @see #convertPointToScreen 570 * @see #convertPointFromScreen 571 * @see #convertPoint(Component, int, int, Component) 572 * @see #getRoot 573 */ convertRectangle(Component source, Rectangle rect, Component destination)574 public static Rectangle convertRectangle(Component source, 575 Rectangle rect, 576 Component destination) 577 { 578 Point pt = convertPoint(source, rect.x, rect.y, destination); 579 return new Rectangle(pt.x, pt.y, rect.width, rect.height); 580 } 581 582 /** 583 * Convert a mouse event which refrers to one component to another. This 584 * includes changing the mouse event's coordinate space, as well as the 585 * source property of the event. If <code>source</code> is 586 * <code>null</code>, it is taken to refer to <code>destination</code>'s 587 * root component. If <code>destination</code> is <code>null</code>, the 588 * new event will remain expressed in <code>source</code>'s coordinate 589 * system. 590 * 591 * @param source The component the mouse event currently refers to 592 * @param sourceEvent The mouse event to convert 593 * @param destination The component the new mouse event should refer to 594 * 595 * @return A new mouse event expressed in terms of the destination 596 * component's coordinate space, and with the destination component as 597 * its source 598 * 599 * @see #convertPoint(Component, int, int, Component) 600 */ convertMouseEvent(Component source, MouseEvent sourceEvent, Component destination)601 public static MouseEvent convertMouseEvent(Component source, 602 MouseEvent sourceEvent, 603 Component destination) 604 { 605 Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), 606 destination); 607 608 return new MouseEvent(destination, sourceEvent.getID(), 609 sourceEvent.getWhen(), sourceEvent.getModifiersEx(), 610 newpt.x, newpt.y, sourceEvent.getClickCount(), 611 sourceEvent.isPopupTrigger(), sourceEvent.getButton()); 612 } 613 614 /** 615 * Recursively walk the component tree under <code>comp</code> calling 616 * <code>updateUI</code> on each {@link JComponent} found. This causes 617 * the entire tree to re-initialize its UI delegates. 618 * 619 * @param comp The component to walk the children of, calling <code>updateUI</code> 620 */ updateComponentTreeUI(Component comp)621 public static void updateComponentTreeUI(Component comp) 622 { 623 if (comp == null) 624 return; 625 626 if (comp instanceof Container) 627 { 628 Component[] children = ((Container)comp).getComponents(); 629 for (int i = 0; i < children.length; ++i) 630 updateComponentTreeUI(children[i]); 631 } 632 633 if (comp instanceof JComponent) 634 ((JComponent)comp).updateUI(); 635 } 636 637 638 /** 639 * <p>Layout a "compound label" consisting of a text string and an icon 640 * which is to be placed near the rendered text. Once the text and icon 641 * are laid out, the text rectangle and icon rectangle parameters are 642 * altered to store the calculated positions.</p> 643 * 644 * <p>The size of the text is calculated from the provided font metrics 645 * object. This object should be the metrics of the font you intend to 646 * paint the label with.</p> 647 * 648 * <p>The position values control where the text is placed relative to 649 * the icon. The horizontal position value should be one of the constants 650 * <code>LEADING</code>, <code>TRAILING</code>, <code>LEFT</code>, 651 * <code>RIGHT</code> or <code>CENTER</code>. The vertical position value 652 * should be one fo the constants <code>TOP</code>, <code>BOTTOM</code> 653 * or <code>CENTER</code>.</p> 654 * 655 * <p>The text-icon gap value controls the number of pixels between the 656 * icon and the text.</p> 657 * 658 * <p>The alignment values control where the text and icon are placed, as 659 * a combined unit, within the view rectangle. The horizontal alignment 660 * value should be one of the constants <code>LEADING</code>, 661 * <code>TRAILING</code>, <code>LEFT</code>, <code>RIGHT</code> or 662 * <code>CENTER</code>. The vertical alignment valus should be one of the 663 * constants <code>TOP</code>, <code>BOTTOM</code> or 664 * <code>CENTER</code>.</p> 665 * 666 * <p>If the <code>LEADING</code> or <code>TRAILING</code> constants are 667 * given for horizontal alignment or horizontal text position, they are 668 * interpreted relative to the provided component's orientation property, 669 * a constant in the {@link java.awt.ComponentOrientation} class. For 670 * example, if the component's orientation is <code>LEFT_TO_RIGHT</code>, 671 * then the <code>LEADING</code> value is a synonym for <code>LEFT</code> 672 * and the <code>TRAILING</code> value is a synonym for 673 * <code>RIGHT</code></p> 674 * 675 * <p>If the text and icon are equal to or larger than the view 676 * rectangle, the horizontal and vertical alignment values have no 677 * affect.</p> 678 * 679 * @param c A component used for its orientation value 680 * @param fm The font metrics used to measure the text 681 * @param text The text to place in the compound label 682 * @param icon The icon to place next to the text 683 * @param verticalAlignment The vertical alignment of the label relative 684 * to its component 685 * @param horizontalAlignment The horizontal alignment of the label 686 * relative to its component 687 * @param verticalTextPosition The vertical position of the label's text 688 * relative to its icon 689 * @param horizontalTextPosition The horizontal position of the label's 690 * text relative to its icon 691 * @param viewR The view rectangle, specifying the area which layout is 692 * constrained to 693 * @param iconR A rectangle which is modified to hold the laid-out 694 * position of the icon 695 * @param textR A rectangle which is modified to hold the laid-out 696 * position of the text 697 * @param textIconGap The distance between text and icon 698 * 699 * @return The string of characters, possibly truncated with an elipsis, 700 * which is laid out in this label 701 */ 702 layoutCompoundLabel(JComponent c, FontMetrics fm, String text, Icon icon, int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap)703 public static String layoutCompoundLabel(JComponent c, 704 FontMetrics fm, 705 String text, 706 Icon icon, 707 int verticalAlignment, 708 int horizontalAlignment, 709 int verticalTextPosition, 710 int horizontalTextPosition, 711 Rectangle viewR, 712 Rectangle iconR, 713 Rectangle textR, 714 int textIconGap) 715 { 716 717 // Fix up the orientation-based horizontal positions. 718 719 if (horizontalTextPosition == LEADING) 720 { 721 if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) 722 horizontalTextPosition = RIGHT; 723 else 724 horizontalTextPosition = LEFT; 725 } 726 else if (horizontalTextPosition == TRAILING) 727 { 728 if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) 729 horizontalTextPosition = LEFT; 730 else 731 horizontalTextPosition = RIGHT; 732 } 733 734 // Fix up the orientation-based alignments. 735 736 if (horizontalAlignment == LEADING) 737 { 738 if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) 739 horizontalAlignment = RIGHT; 740 else 741 horizontalAlignment = LEFT; 742 } 743 else if (horizontalAlignment == TRAILING) 744 { 745 if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) 746 horizontalAlignment = LEFT; 747 else 748 horizontalAlignment = RIGHT; 749 } 750 751 return layoutCompoundLabel(fm, text, icon, 752 verticalAlignment, 753 horizontalAlignment, 754 verticalTextPosition, 755 horizontalTextPosition, 756 viewR, iconR, textR, textIconGap); 757 } 758 759 /** 760 * <p>Layout a "compound label" consisting of a text string and an icon 761 * which is to be placed near the rendered text. Once the text and icon 762 * are laid out, the text rectangle and icon rectangle parameters are 763 * altered to store the calculated positions.</p> 764 * 765 * <p>The size of the text is calculated from the provided font metrics 766 * object. This object should be the metrics of the font you intend to 767 * paint the label with.</p> 768 * 769 * <p>The position values control where the text is placed relative to 770 * the icon. The horizontal position value should be one of the constants 771 * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The 772 * vertical position value should be one fo the constants 773 * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p> 774 * 775 * <p>The text-icon gap value controls the number of pixels between the 776 * icon and the text.</p> 777 * 778 * <p>The alignment values control where the text and icon are placed, as 779 * a combined unit, within the view rectangle. The horizontal alignment 780 * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or 781 * <code>CENTER</code>. The vertical alignment valus should be one of the 782 * constants <code>TOP</code>, <code>BOTTOM</code> or 783 * <code>CENTER</code>.</p> 784 * 785 * <p>If the text and icon are equal to or larger than the view 786 * rectangle, the horizontal and vertical alignment values have no 787 * affect.</p> 788 * 789 * <p>Note that this method does <em>not</em> know how to deal with 790 * horizontal alignments or positions given as <code>LEADING</code> or 791 * <code>TRAILING</code> values. Use the other overloaded variant of this 792 * method if you wish to use such values. 793 * 794 * @param fm The font metrics used to measure the text 795 * @param text The text to place in the compound label 796 * @param icon The icon to place next to the text 797 * @param verticalAlignment The vertical alignment of the label relative 798 * to its component 799 * @param horizontalAlignment The horizontal alignment of the label 800 * relative to its component 801 * @param verticalTextPosition The vertical position of the label's text 802 * relative to its icon 803 * @param horizontalTextPosition The horizontal position of the label's 804 * text relative to its icon 805 * @param viewR The view rectangle, specifying the area which layout is 806 * constrained to 807 * @param iconR A rectangle which is modified to hold the laid-out 808 * position of the icon 809 * @param textR A rectangle which is modified to hold the laid-out 810 * position of the text 811 * @param textIconGap The distance between text and icon 812 * 813 * @return The string of characters, possibly truncated with an elipsis, 814 * which is laid out in this label 815 */ 816 layoutCompoundLabel(FontMetrics fm, String text, Icon icon, int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap)817 public static String layoutCompoundLabel(FontMetrics fm, 818 String text, 819 Icon icon, 820 int verticalAlignment, 821 int horizontalAlignment, 822 int verticalTextPosition, 823 int horizontalTextPosition, 824 Rectangle viewR, 825 Rectangle iconR, 826 Rectangle textR, 827 int textIconGap) 828 { 829 830 // Work out basic height and width. 831 832 if (icon == null) 833 { 834 textIconGap = 0; 835 iconR.width = 0; 836 iconR.height = 0; 837 } 838 else 839 { 840 iconR.width = icon.getIconWidth(); 841 iconR.height = icon.getIconHeight(); 842 } 843 if (text == null || text.equals("")) 844 { 845 textIconGap = 0; 846 textR.width = 0; 847 textR.height = 0; 848 } 849 else 850 { 851 int fromIndex = 0; 852 textR.width = fm.stringWidth(text); 853 textR.height = fm.getHeight(); 854 while (text.indexOf('\n', fromIndex) != -1) 855 { 856 textR.height += fm.getHeight(); 857 fromIndex = text.indexOf('\n', fromIndex) + 1; 858 } 859 } 860 861 // Work out the position of text and icon, assuming the top-left coord 862 // starts at (0,0). We will fix that up momentarily, after these 863 // "position" decisions are made and we look at alignment. 864 865 switch (horizontalTextPosition) 866 { 867 case LEFT: 868 textR.x = 0; 869 iconR.x = textR.width + textIconGap; 870 break; 871 case RIGHT: 872 iconR.x = 0; 873 textR.x = iconR.width + textIconGap; 874 break; 875 case CENTER: 876 int centerLine = Math.max(textR.width, iconR.width) / 2; 877 textR.x = centerLine - textR.width/2; 878 iconR.x = centerLine - iconR.width/2; 879 break; 880 } 881 882 switch (verticalTextPosition) 883 { 884 case TOP: 885 textR.y = 0; 886 iconR.y = (horizontalTextPosition == CENTER 887 ? textR.height + textIconGap : 0); 888 break; 889 case BOTTOM: 890 iconR.y = 0; 891 textR.y = (horizontalTextPosition == CENTER 892 ? iconR.height + textIconGap 893 : Math.max(iconR.height - textR.height, 0)); 894 break; 895 case CENTER: 896 int centerLine = Math.max(textR.height, iconR.height) / 2; 897 textR.y = centerLine - textR.height/2; 898 iconR.y = centerLine - iconR.height/2; 899 break; 900 } 901 // The two rectangles are laid out correctly now, but only assuming 902 // that their upper left corner is at (0,0). If we have any alignment other 903 // than TOP and LEFT, we need to adjust them. 904 905 Rectangle u = textR.union(iconR); 906 int horizontalAdjustment = viewR.x; 907 int verticalAdjustment = viewR.y; 908 switch (verticalAlignment) 909 { 910 case TOP: 911 break; 912 case BOTTOM: 913 verticalAdjustment += (viewR.height - u.height); 914 break; 915 case CENTER: 916 verticalAdjustment += ((viewR.height/2) - (u.height/2)); 917 break; 918 } 919 switch (horizontalAlignment) 920 { 921 case LEFT: 922 break; 923 case RIGHT: 924 horizontalAdjustment += (viewR.width - u.width); 925 break; 926 case CENTER: 927 horizontalAdjustment += ((viewR.width/2) - (u.width/2)); 928 break; 929 } 930 931 iconR.x += horizontalAdjustment; 932 iconR.y += verticalAdjustment; 933 934 textR.x += horizontalAdjustment; 935 textR.y += verticalAdjustment; 936 937 return text; 938 } 939 940 /** 941 * Calls {@link java.awt.EventQueue#invokeLater} with the 942 * specified {@link Runnable}. 943 */ invokeLater(Runnable doRun)944 public static void invokeLater(Runnable doRun) 945 { 946 java.awt.EventQueue.invokeLater(doRun); 947 } 948 949 /** 950 * Calls {@link java.awt.EventQueue#invokeAndWait} with the 951 * specified {@link Runnable}. 952 */ invokeAndWait(Runnable doRun)953 public static void invokeAndWait(Runnable doRun) 954 throws InterruptedException, 955 InvocationTargetException 956 { 957 java.awt.EventQueue.invokeAndWait(doRun); 958 } 959 960 /** 961 * Calls {@link java.awt.EventQueue#isDispatchThread()}. 962 * 963 * @return <code>true</code> if the current thread is the current AWT event 964 * dispatch thread. 965 */ isEventDispatchThread()966 public static boolean isEventDispatchThread() 967 { 968 return java.awt.EventQueue.isDispatchThread(); 969 } 970 971 /** 972 * This method paints the given component at the given position and size. 973 * The component will be reparented to the container given. 974 * 975 * @param g The Graphics object to draw with. 976 * @param c The Component to draw 977 * @param p The Container to reparent to. 978 * @param x The x coordinate to draw at. 979 * @param y The y coordinate to draw at. 980 * @param w The width of the drawing area. 981 * @param h The height of the drawing area. 982 */ paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h)983 public static void paintComponent(Graphics g, Component c, Container p, 984 int x, int y, int w, int h) 985 { 986 Container parent = c.getParent(); 987 if (parent != null) 988 parent.remove(c); 989 if (p != null) 990 p.add(c); 991 992 Shape savedClip = g.getClip(); 993 994 g.setClip(x, y, w, h); 995 g.translate(x, y); 996 997 c.paint(g); 998 999 g.translate(-x, -y); 1000 g.setClip(savedClip); 1001 } 1002 1003 /** 1004 * This method paints the given component in the given rectangle. 1005 * The component will be reparented to the container given. 1006 * 1007 * @param g The Graphics object to draw with. 1008 * @param c The Component to draw 1009 * @param p The Container to reparent to. 1010 * @param r The rectangle that describes the drawing area. 1011 */ paintComponent(Graphics g, Component c, Container p, Rectangle r)1012 public static void paintComponent(Graphics g, Component c, 1013 Container p, Rectangle r) 1014 { 1015 paintComponent(g, c, p, r.x, r.y, r.width, r.height); 1016 } 1017 1018 /** 1019 * This method returns the common Frame owner used in JDialogs or 1020 * JWindow when no owner is provided. 1021 * 1022 * @return The common Frame 1023 */ getOwnerFrame()1024 static Frame getOwnerFrame() 1025 { 1026 if (ownerFrame == null) 1027 ownerFrame = new OwnerFrame(); 1028 return ownerFrame; 1029 } 1030 1031 /** 1032 * Checks if left mouse button was clicked. 1033 * 1034 * @param event the event to check 1035 * 1036 * @return true if left mouse was clicked, false otherwise. 1037 */ isLeftMouseButton(MouseEvent event)1038 public static boolean isLeftMouseButton(MouseEvent event) 1039 { 1040 return ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) 1041 == InputEvent.BUTTON1_DOWN_MASK); 1042 } 1043 1044 /** 1045 * Checks if middle mouse button was clicked. 1046 * 1047 * @param event the event to check 1048 * 1049 * @return true if middle mouse was clicked, false otherwise. 1050 */ isMiddleMouseButton(MouseEvent event)1051 public static boolean isMiddleMouseButton(MouseEvent event) 1052 { 1053 return ((event.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) 1054 == InputEvent.BUTTON2_DOWN_MASK); 1055 } 1056 1057 /** 1058 * Checks if right mouse button was clicked. 1059 * 1060 * @param event the event to check 1061 * 1062 * @return true if right mouse was clicked, false otherwise. 1063 */ isRightMouseButton(MouseEvent event)1064 public static boolean isRightMouseButton(MouseEvent event) 1065 { 1066 return ((event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) 1067 == InputEvent.BUTTON3_DOWN_MASK); 1068 } 1069 1070 /** 1071 * This frame should be used when constructing a Window/JDialog without 1072 * a parent. In this case, we are forced to use this frame as a window's 1073 * parent, because we simply cannot pass null instead of parent to Window 1074 * constructor, since doing it will result in NullPointerException. 1075 */ 1076 private static class OwnerFrame extends Frame 1077 { setVisible(boolean b)1078 public void setVisible(boolean b) 1079 { 1080 // Do nothing here. 1081 } 1082 isShowing()1083 public boolean isShowing() 1084 { 1085 return true; 1086 } 1087 } 1088 notifyAction(Action action, KeyStroke ks, KeyEvent event, Object sender, int modifiers)1089 public static boolean notifyAction(Action action, 1090 KeyStroke ks, 1091 KeyEvent event, 1092 Object sender, 1093 int modifiers) 1094 { 1095 if (action != null && action.isEnabled()) 1096 { 1097 String name = (String) action.getValue(Action.ACTION_COMMAND_KEY); 1098 if (name == null 1099 && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) 1100 name = new String(new char[] {event.getKeyChar()}); 1101 action.actionPerformed(new ActionEvent(sender, 1102 ActionEvent.ACTION_PERFORMED, 1103 name, modifiers)); 1104 return true; 1105 } 1106 return false; 1107 } 1108 1109 /** 1110 * <p>Change the shared, UI-managed {@link ActionMap} for a given 1111 * component. ActionMaps are arranged in a hierarchy, in order to 1112 * encourage sharing of common actions between components. The hierarchy 1113 * unfortunately places UI-managed ActionMaps at the <em>end</em> of the 1114 * parent-pointer chain, as illustrated:</p> 1115 * 1116 * <pre> 1117 * [{@link javax.swing.JComponent#getActionMap()}] 1118 * --> [{@link javax.swing.ActionMap}] 1119 * parent --> [{@link javax.swing.text.JTextComponent.KeymapActionMap}] 1120 * parent --> [{@link javax.swing.plaf.ActionMapUIResource}] 1121 * </pre> 1122 * 1123 * <p>Our goal with this method is to replace the first ActionMap along 1124 * this chain which is an instance of {@link ActionMapUIResource}, since 1125 * these are the ActionMaps which are supposed to be shared between 1126 * components.</p> 1127 * 1128 * <p>If the provided ActionMap is <code>null</code>, we interpret the 1129 * call as a request to remove the UI-managed ActionMap from the 1130 * component's ActionMap parent chain.</p> 1131 */ replaceUIActionMap(JComponent component, ActionMap uiActionMap)1132 public static void replaceUIActionMap(JComponent component, 1133 ActionMap uiActionMap) 1134 { 1135 ActionMap child = component.getActionMap(); 1136 if (child == null) 1137 component.setActionMap(uiActionMap); 1138 else 1139 { 1140 ActionMap parent = child.getParent(); 1141 while(parent != null) 1142 { 1143 child = parent; 1144 parent = child.getParent(); 1145 } 1146 1147 if (child != null) 1148 child.setParent(uiActionMap); 1149 } 1150 } 1151 1152 /** 1153 * <p>Change the shared, UI-managed {@link InputMap} for a given 1154 * component. InputMaps are arranged in a hierarchy, in order to 1155 * encourage sharing of common input mappings between components. The 1156 * hierarchy unfortunately places UI-managed InputMaps at the 1157 * <em>end</em> of the parent-pointer chain, as illustrated:</p> 1158 * 1159 * <pre> 1160 * [{@link javax.swing.JComponent#getInputMap()}] 1161 * --> [{@link javax.swing.InputMap}] 1162 * parent --> [{@link javax.swing.text.JTextComponent.KeymapWrapper}] 1163 * parent --> [{@link javax.swing.plaf.InputMapUIResource}] 1164 * </pre> 1165 * 1166 * <p>Our goal with this method is to replace the first InputMap along 1167 * this chain which is an instance of {@link InputMapUIResource}, since 1168 * these are the InputMaps which are supposed to be shared between 1169 * components.</p> 1170 * 1171 * <p>If the provided InputMap is <code>null</code>, we interpret the 1172 * call as a request to remove the UI-managed InputMap from the 1173 * component's InputMap parent chain.</p> 1174 */ replaceUIInputMap(JComponent component, int condition, InputMap uiInputMap)1175 public static void replaceUIInputMap(JComponent component, 1176 int condition, 1177 InputMap uiInputMap) 1178 { 1179 InputMap child = component.getInputMap(condition); 1180 if (child == null) 1181 component.setInputMap(condition, uiInputMap); 1182 else 1183 { 1184 while(child.getParent() != null 1185 && !(child.getParent() instanceof InputMapUIResource)) 1186 child = child.getParent(); 1187 if (child != null) 1188 child.setParent(uiInputMap); 1189 } 1190 } 1191 1192 /** 1193 * Subtracts a rectangle from another and return the area as an array 1194 * of rectangles. 1195 * Returns the areas of rectA which are not covered by rectB. 1196 * If the rectangles do not overlap, or if either parameter is 1197 * <code>null</code>, a zero-size array is returned. 1198 * @param rectA The first rectangle 1199 * @param rectB The rectangle to subtract from the first 1200 * @return An array of rectangles representing the area in rectA 1201 * not overlapped by rectB 1202 */ computeDifference(Rectangle rectA, Rectangle rectB)1203 public static Rectangle[] computeDifference(Rectangle rectA, Rectangle rectB) 1204 { 1205 if (rectA == null || rectB == null) 1206 return new Rectangle[0]; 1207 1208 Rectangle[] r = new Rectangle[4]; 1209 int x1 = rectA.x; 1210 int y1 = rectA.y; 1211 int w1 = rectA.width; 1212 int h1 = rectA.height; 1213 int x2 = rectB.x; 1214 int y2 = rectB.y; 1215 int w2 = rectB.width; 1216 int h2 = rectB.height; 1217 1218 // (outer box = rectA) 1219 // ------------- 1220 // |_____0_____| 1221 // | |rectB| | 1222 // |_1|_____|_2| 1223 // | 3 | 1224 // ------------- 1225 int H0 = (y2 > y1) ? y2 - y1 : 0; // height of box 0 1226 int H3 = (y2 + h2 < y1 + h1) ? y1 + h1 - y2 - h2 : 0; // height box 3 1227 int W1 = (x2 > x1) ? x2 - x1 : 0; // width box 1 1228 int W2 = (x1 + w1 > x2 + w2) ? x1 + w1 - x2 - w2 : 0; // w. box 2 1229 int H12 = (H0 + H3 < h1) ? h1 - H0 - H3 : 0; // height box 1 & 2 1230 1231 if (H0 > 0) 1232 r[0] = new Rectangle(x1, y1, w1, H0); 1233 else 1234 r[0] = null; 1235 1236 if (W1 > 0 && H12 > 0) 1237 r[1] = new Rectangle(x1, y1 + H0, W1, H12); 1238 else 1239 r[1] = null; 1240 1241 if (W2 > 0 && H12 > 0) 1242 r[2] = new Rectangle(x2 + w2, y1 + H0, W2, H12); 1243 else 1244 r[2] = null; 1245 1246 if (H3 > 0) 1247 r[3] = new Rectangle(x1, y1 + H0 + H12, w1, H3); 1248 else 1249 r[3] = null; 1250 1251 // sort out null objects 1252 int n = 0; 1253 for (int i = 0; i < 4; i++) 1254 if (r[i] != null) 1255 n++; 1256 Rectangle[] out = new Rectangle[n]; 1257 for (int i = 3; i >= 0; i--) 1258 if (r[i] != null) 1259 out[--n] = r[i]; 1260 1261 return out; 1262 } 1263 1264 /** 1265 * Calculates the intersection of two rectangles. 1266 * 1267 * @param x upper-left x coodinate of first rectangle 1268 * @param y upper-left y coodinate of first rectangle 1269 * @param w width of first rectangle 1270 * @param h height of first rectangle 1271 * @param rect a Rectangle object of the second rectangle 1272 * @throws NullPointerException if rect is null. 1273 * 1274 * @return a rectangle corresponding to the intersection of the 1275 * two rectangles. A zero rectangle is returned if the rectangles 1276 * do not overlap. 1277 */ computeIntersection(int x, int y, int w, int h, Rectangle rect)1278 public static Rectangle computeIntersection(int x, int y, int w, int h, 1279 Rectangle rect) 1280 { 1281 int x2 = (int) rect.getX(); 1282 int y2 = (int) rect.getY(); 1283 int w2 = (int) rect.getWidth(); 1284 int h2 = (int) rect.getHeight(); 1285 1286 int dx = (x > x2) ? x : x2; 1287 int dy = (y > y2) ? y : y2; 1288 int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); 1289 int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); 1290 1291 if (dw >= 0 && dh >= 0) 1292 return new Rectangle(dx, dy, dw, dh); 1293 1294 return new Rectangle(0, 0, 0, 0); 1295 } 1296 1297 /** 1298 * Calculates the width of a given string. 1299 * 1300 * @param fm the <code>FontMetrics</code> object to use 1301 * @param str the string 1302 * 1303 * @return the width of the the string. 1304 */ computeStringWidth(FontMetrics fm, String str)1305 public static int computeStringWidth(FontMetrics fm, String str) 1306 { 1307 return fm.stringWidth(str); 1308 } 1309 1310 /** 1311 * Calculates the union of two rectangles. 1312 * 1313 * @param x upper-left x coodinate of first rectangle 1314 * @param y upper-left y coodinate of first rectangle 1315 * @param w width of first rectangle 1316 * @param h height of first rectangle 1317 * @param rect a Rectangle object of the second rectangle 1318 * @throws NullPointerException if rect is null. 1319 * 1320 * @return a rectangle corresponding to the union of the 1321 * two rectangles. A rectangle encompassing both is returned if the 1322 * rectangles do not overlap. 1323 */ computeUnion(int x, int y, int w, int h, Rectangle rect)1324 public static Rectangle computeUnion(int x, int y, int w, int h, 1325 Rectangle rect) 1326 { 1327 int x2 = (int) rect.getX(); 1328 int y2 = (int) rect.getY(); 1329 int w2 = (int) rect.getWidth(); 1330 int h2 = (int) rect.getHeight(); 1331 1332 int dx = (x < x2) ? x : x2; 1333 int dy = (y < y2) ? y : y2; 1334 int dw = (x + w > x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); 1335 int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); 1336 1337 if (dw >= 0 && dh >= 0) 1338 return new Rectangle(dx, dy, dw, dh); 1339 1340 return new Rectangle(0, 0, 0, 0); 1341 } 1342 1343 /** 1344 * Tests if a rectangle contains another. 1345 * @param a first rectangle 1346 * @param b second rectangle 1347 * @return true if a contains b, false otherwise 1348 * @throws NullPointerException 1349 */ isRectangleContainingRectangle(Rectangle a, Rectangle b)1350 public static boolean isRectangleContainingRectangle(Rectangle a, Rectangle b) 1351 { 1352 // Note: zero-size rects inclusive, differs from Rectangle.contains() 1353 return b.width >= 0 && b.height >= 0 && b.width >= 0 && b.height >= 0 1354 && b.x >= a.x && b.x + b.width <= a.x + a.width && b.y >= a.y 1355 && b.y + b.height <= a.y + a.height; 1356 } 1357 1358 /** 1359 * Returns the InputMap that is provided by the ComponentUI of 1360 * <code>component</code> for the specified condition. 1361 * 1362 * @param component the component for which the InputMap is returned 1363 * @param cond the condition that specifies which of the three input 1364 * maps should be returned, may be 1365 * {@link JComponent#WHEN_IN_FOCUSED_WINDOW}, 1366 * {@link JComponent#WHEN_FOCUSED} or 1367 * {@link JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT} 1368 * 1369 * @return The input map. 1370 */ getUIInputMap(JComponent component, int cond)1371 public static InputMap getUIInputMap(JComponent component, int cond) 1372 { 1373 if (UIManager.getUI(component) != null) 1374 // we assume here that the UI class sets the parent of the component's 1375 // InputMap, which is the correct behaviour. If it's not, then 1376 // this can be considered a bug 1377 return component.getInputMap(cond).getParent(); 1378 else 1379 return null; 1380 } 1381 1382 /** 1383 * Returns the ActionMap that is provided by the ComponentUI of 1384 * <code>component</code>. 1385 * 1386 * @param component the component for which the ActionMap is returned 1387 */ getUIActionMap(JComponent component)1388 public static ActionMap getUIActionMap(JComponent component) 1389 { 1390 if (UIManager.getUI(component) != null) 1391 // we assume here that the UI class sets the parent of the component's 1392 // ActionMap, which is the correct behaviour. If it's not, then 1393 // this can be considered a bug 1394 return component.getActionMap().getParent(); 1395 else 1396 return null; 1397 } 1398 } 1399