1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 
  27 import sun.reflect.misc.ReflectUtil;
  28 import sun.swing.SwingUtilities2;
  29 import sun.swing.UIAction;
  30 
  31 import java.applet.*;
  32 
  33 import java.awt.*;
  34 import java.awt.event.*;
  35 import java.awt.dnd.DropTarget;
  36 
  37 import java.lang.reflect.*;
  38 
  39 import javax.accessibility.*;
  40 import javax.swing.event.MenuDragMouseEvent;
  41 import javax.swing.plaf.UIResource;
  42 import javax.swing.text.View;
  43 import java.security.AccessController;
  44 import sun.security.action.GetPropertyAction;
  45 
  46 import sun.awt.AppContext;
  47 
  48 /**
  49  * A collection of utility methods for Swing.
  50  *
  51  * @author unknown
  52  * @since 1.2
  53  */
  54 public class SwingUtilities implements SwingConstants
  55 {
  56     // These states are system-wide, rather than AppContext wide.
  57     private static boolean canAccessEventQueue = false;
  58     private static boolean eventQueueTested = false;
  59 
  60     /**
  61      * Indicates if we should change the drop target when a
  62      * {@code TransferHandler} is set.
  63      */
  64     private static boolean suppressDropSupport;
  65 
  66     /**
  67      * Indiciates if we've checked the system property for suppressing
  68      * drop support.
  69      */
  70     private static boolean checkedSuppressDropSupport;
  71 
  72 
  73     /**
  74      * Returns true if <code>setTransferHandler</code> should change the
  75      * <code>DropTarget</code>.
  76      */
  77     private static boolean getSuppressDropTarget() {
  78         if (!checkedSuppressDropSupport) {
  79             suppressDropSupport = Boolean.valueOf(
  80                 AccessController.doPrivileged(
  81                     new GetPropertyAction("suppressSwingDropSupport")));
  82             checkedSuppressDropSupport = true;
  83         }
  84         return suppressDropSupport;
  85     }
  86 
  87     /**
  88      * Installs a {@code DropTarget} on the component as necessary for a
  89      * {@code TransferHandler} change.
  90      */
  91     static void installSwingDropTargetAsNecessary(Component c,
  92                                                          TransferHandler t) {
  93 
  94         if (!getSuppressDropTarget()) {
  95             DropTarget dropHandler = c.getDropTarget();
  96             if ((dropHandler == null) || (dropHandler instanceof UIResource)) {
  97                 if (t == null) {
  98                     c.setDropTarget(null);
  99                 } else if (!GraphicsEnvironment.isHeadless()) {
 100                     c.setDropTarget(new TransferHandler.SwingDropTarget(c));
 101                 }
 102             }
 103         }
 104     }
 105 
 106     /**
 107      * Return {@code true} if @{code a} contains {@code b}
 108      *
 109      * @param a the first rectangle
 110      * @param b the second rectangle
 111      *
 112      * @return {@code true} if @{code a} contains {@code b}
 113      */
 114     public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
 115         return b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
 116                 b.y >= a.y && (b.y + b.height) <= (a.y + a.height);
 117     }
 118 
 119     /**
 120      * Return the rectangle (0,0,bounds.width,bounds.height) for the component {@code aComponent}
 121      *
 122      * @param aComponent a component
 123      * @return the local bounds for the component {@code aComponent}
 124      */
 125     public static Rectangle getLocalBounds(Component aComponent) {
 126         Rectangle b = new Rectangle(aComponent.getBounds());
 127         b.x = b.y = 0;
 128         return b;
 129     }
 130 
 131 
 132     /**
 133      * Returns the first <code>Window </code> ancestor of <code>c</code>, or
 134      * {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
 135      *
 136      * @param c <code>Component</code> to get <code>Window</code> ancestor
 137      *        of.
 138      * @return the first <code>Window </code> ancestor of <code>c</code>, or
 139      *         {@code null} if <code>c</code> is not contained inside a
 140      *         <code>Window</code>.
 141      * @since 1.3
 142      */
 143     public static Window getWindowAncestor(Component c) {
 144         for(Container p = c.getParent(); p != null; p = p.getParent()) {
 145             if (p instanceof Window) {
 146                 return (Window)p;
 147             }
 148         }
 149         return null;
 150     }
 151 
 152     /**
 153      * Converts the location <code>x</code> <code>y</code> to the
 154      * parents coordinate system, returning the location.
 155      */
 156     static Point convertScreenLocationToParent(Container parent,int x, int y) {
 157         for (Container p = parent; p != null; p = p.getParent()) {
 158             if (p instanceof Window) {
 159                 Point point = new Point(x, y);
 160 
 161                 SwingUtilities.convertPointFromScreen(point, parent);
 162                 return point;
 163             }
 164         }
 165         throw new Error("convertScreenLocationToParent: no window ancestor");
 166     }
 167 
 168     /**
 169      * Convert a <code>aPoint</code> in <code>source</code> coordinate system to
 170      * <code>destination</code> coordinate system.
 171      * If <code>source</code> is {@code null}, <code>aPoint</code> is assumed to be in <code>destination</code>'s
 172      * root component coordinate system.
 173      * If <code>destination</code> is {@code null}, <code>aPoint</code> will be converted to <code>source</code>'s
 174      * root component coordinate system.
 175      * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aPoint</code>
 176      * without any conversion.
 177      *
 178      * @param source the source component
 179      * @param aPoint the point
 180      * @param destination the destination component
 181      *
 182      * @return the converted coordinate
 183      */
 184     public static Point convertPoint(Component source,Point aPoint,Component destination) {
 185         Point p;
 186 
 187         if(source == null && destination == null)
 188             return aPoint;
 189         if(source == null) {
 190             source = getWindowAncestor(destination);
 191             if(source == null)
 192                 throw new Error("Source component not connected to component tree hierarchy");
 193         }
 194         p = new Point(aPoint);
 195         convertPointToScreen(p,source);
 196         if(destination == null) {
 197             destination = getWindowAncestor(source);
 198             if(destination == null)
 199                 throw new Error("Destination component not connected to component tree hierarchy");
 200         }
 201         convertPointFromScreen(p,destination);
 202         return p;
 203     }
 204 
 205     /**
 206      * Convert the point <code>(x,y)</code> in <code>source</code> coordinate system to
 207      * <code>destination</code> coordinate system.
 208      * If <code>source</code> is {@code null}, <code>(x,y)</code> is assumed to be in <code>destination</code>'s
 209      * root component coordinate system.
 210      * If <code>destination</code> is {@code null}, <code>(x,y)</code> will be converted to <code>source</code>'s
 211      * root component coordinate system.
 212      * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>(x,y)</code>
 213      * without any conversion.
 214      *
 215      * @param source the source component
 216      * @param x the x-coordinate of the point
 217      * @param y the y-coordinate of the point
 218      * @param destination the destination component
 219      *
 220      * @return the converted coordinate
 221      */
 222     public static Point convertPoint(Component source,int x, int y,Component destination) {
 223         Point point = new Point(x,y);
 224         return convertPoint(source,point,destination);
 225     }
 226 
 227     /**
 228      * Convert the rectangle <code>aRectangle</code> in <code>source</code> coordinate system to
 229      * <code>destination</code> coordinate system.
 230      * If <code>source</code> is {@code null}, <code>aRectangle</code> is assumed to be in <code>destination</code>'s
 231      * root component coordinate system.
 232      * If <code>destination</code> is {@code null}, <code>aRectangle</code> will be converted to <code>source</code>'s
 233      * root component coordinate system.
 234      * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aRectangle</code>
 235      * without any conversion.
 236      *
 237      * @param source the source component
 238      * @param aRectangle a rectangle
 239      * @param destination the destination component
 240      *
 241      * @return the converted rectangle
 242      */
 243     public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
 244         Point point = new Point(aRectangle.x,aRectangle.y);
 245         point =  convertPoint(source,point,destination);
 246         return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
 247     }
 248 
 249     /**
 250      * Convenience method for searching above <code>comp</code> in the
 251      * component hierarchy and returns the first object of class <code>c</code> it
 252      * finds. Can return {@code null}, if a class <code>c</code> cannot be found.
 253      *
 254      * @param c the class of a component
 255      * @param comp the component
 256      *
 257      * @return the ancestor of the {@code comp},
 258      *         or {@code null} if {@code c} cannot be found.
 259      */
 260     public static Container getAncestorOfClass(Class<?> c, Component comp)
 261     {
 262         if(comp == null || c == null)
 263             return null;
 264 
 265         Container parent = comp.getParent();
 266         while(parent != null && !(c.isInstance(parent)))
 267             parent = parent.getParent();
 268         return parent;
 269     }
 270 
 271     /**
 272      * Convenience method for searching above <code>comp</code> in the
 273      * component hierarchy and returns the first object of <code>name</code> it
 274      * finds. Can return {@code null}, if <code>name</code> cannot be found.
 275      *
 276      * @param name the name of a component
 277      * @param comp the component
 278      *
 279      * @return the ancestor of the {@code comp},
 280      *         or {@code null} if {@code name} cannot be found.
 281      */
 282     public static Container getAncestorNamed(String name, Component comp) {
 283         if(comp == null || name == null)
 284             return null;
 285 
 286         Container parent = comp.getParent();
 287         while(parent != null && !(name.equals(parent.getName())))
 288             parent = parent.getParent();
 289         return parent;
 290     }
 291 
 292     /**
 293      * Returns the deepest visible descendent Component of <code>parent</code>
 294      * that contains the location <code>x</code>, <code>y</code>.
 295      * If <code>parent</code> does not contain the specified location,
 296      * then <code>null</code> is returned.  If <code>parent</code> is not a
 297      * container, or none of <code>parent</code>'s visible descendents
 298      * contain the specified location, <code>parent</code> is returned.
 299      *
 300      * @param parent the root component to begin the search
 301      * @param x the x target location
 302      * @param y the y target location
 303      *
 304      * @return the deepest component
 305      */
 306     public static Component getDeepestComponentAt(Component parent, int x, int y) {
 307         if (!parent.contains(x, y)) {
 308             return null;
 309         }
 310         if (parent instanceof Container) {
 311             Component components[] = ((Container)parent).getComponents();
 312             for (Component comp : components) {
 313                 if (comp != null && comp.isVisible()) {
 314                     Point loc = comp.getLocation();
 315                     if (comp instanceof Container) {
 316                         comp = getDeepestComponentAt(comp, x - loc.x, y - loc.y);
 317                     } else {
 318                         comp = comp.getComponentAt(x - loc.x, y - loc.y);
 319                     }
 320                     if (comp != null && comp.isVisible()) {
 321                         return comp;
 322                     }
 323                 }
 324             }
 325         }
 326         return parent;
 327     }
 328 
 329 
 330     /**
 331      * Returns a MouseEvent similar to <code>sourceEvent</code> except that its x
 332      * and y members have been converted to <code>destination</code>'s coordinate
 333      * system.  If <code>source</code> is {@code null}, <code>sourceEvent</code> x and y members
 334      * are assumed to be into <code>destination</code>'s root component coordinate system.
 335      * If <code>destination</code> is <code>null</code>, the
 336      * returned MouseEvent will be in <code>source</code>'s coordinate system.
 337      * <code>sourceEvent</code> will not be changed. A new event is returned.
 338      * the <code>source</code> field of the returned event will be set
 339      * to <code>destination</code> if destination is non-{@code null}
 340      * use the translateMouseEvent() method to translate a mouse event from
 341      * one component to another without changing the source.
 342      *
 343      * @param source the source component
 344      * @param sourceEvent the source mouse event
 345      * @param destination the destination component
 346      *
 347      * @return the new mouse event
 348      */
 349     public static MouseEvent convertMouseEvent(Component source,
 350                                                MouseEvent sourceEvent,
 351                                                Component destination) {
 352         Point p = convertPoint(source,new Point(sourceEvent.getX(),
 353                                                 sourceEvent.getY()),
 354                                destination);
 355         Component newSource;
 356 
 357         if(destination != null)
 358             newSource = destination;
 359         else
 360             newSource = source;
 361 
 362         MouseEvent newEvent;
 363         if (sourceEvent instanceof MouseWheelEvent) {
 364             MouseWheelEvent sourceWheelEvent = (MouseWheelEvent)sourceEvent;
 365             newEvent = new MouseWheelEvent(newSource,
 366                                            sourceWheelEvent.getID(),
 367                                            sourceWheelEvent.getWhen(),
 368                                            sourceWheelEvent.getModifiers()
 369                                                    | sourceWheelEvent.getModifiersEx(),
 370                                            p.x,p.y,
 371                                            sourceWheelEvent.getXOnScreen(),
 372                                            sourceWheelEvent.getYOnScreen(),
 373                                            sourceWheelEvent.getClickCount(),
 374                                            sourceWheelEvent.isPopupTrigger(),
 375                                            sourceWheelEvent.getScrollType(),
 376                                            sourceWheelEvent.getScrollAmount(),
 377                                            sourceWheelEvent.getWheelRotation(),
 378                                            sourceWheelEvent.getPreciseWheelRotation());
 379         }
 380         else if (sourceEvent instanceof MenuDragMouseEvent) {
 381             MenuDragMouseEvent sourceMenuDragEvent = (MenuDragMouseEvent)sourceEvent;
 382             newEvent = new MenuDragMouseEvent(newSource,
 383                                               sourceMenuDragEvent.getID(),
 384                                               sourceMenuDragEvent.getWhen(),
 385                                               sourceMenuDragEvent.getModifiers()
 386                                                       | sourceMenuDragEvent.getModifiersEx(),
 387                                               p.x,p.y,
 388                                               sourceMenuDragEvent.getXOnScreen(),
 389                                               sourceMenuDragEvent.getYOnScreen(),
 390                                               sourceMenuDragEvent.getClickCount(),
 391                                               sourceMenuDragEvent.isPopupTrigger(),
 392                                               sourceMenuDragEvent.getPath(),
 393                                               sourceMenuDragEvent.getMenuSelectionManager());
 394         }
 395         else {
 396             newEvent = new MouseEvent(newSource,
 397                                       sourceEvent.getID(),
 398                                       sourceEvent.getWhen(),
 399                                       sourceEvent.getModifiers()
 400                                               | sourceEvent.getModifiersEx(),
 401                                       p.x,p.y,
 402                                       sourceEvent.getXOnScreen(),
 403                                       sourceEvent.getYOnScreen(),
 404                                       sourceEvent.getClickCount(),
 405                                       sourceEvent.isPopupTrigger(),
 406                                       sourceEvent.getButton());
 407         }
 408         return newEvent;
 409     }
 410 
 411 
 412     /**
 413      * Convert a point from a component's coordinate system to
 414      * screen coordinates.
 415      *
 416      * @param p  a Point object (converted to the new coordinate system)
 417      * @param c  a Component object
 418      */
 419     public static void convertPointToScreen(Point p,Component c) {
 420             Rectangle b;
 421             int x,y;
 422 
 423             do {
 424                 if(c instanceof JComponent) {
 425                     x = c.getX();
 426                     y = c.getY();
 427                 } else if(c instanceof java.applet.Applet ||
 428                           c instanceof java.awt.Window) {
 429                     try {
 430                         Point pp = c.getLocationOnScreen();
 431                         x = pp.x;
 432                         y = pp.y;
 433                     } catch (IllegalComponentStateException icse) {
 434                         x = c.getX();
 435                         y = c.getY();
 436                     }
 437                 } else {
 438                     x = c.getX();
 439                     y = c.getY();
 440                 }
 441 
 442                 p.x += x;
 443                 p.y += y;
 444 
 445                 if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
 446                     break;
 447                 c = c.getParent();
 448             } while(c != null);
 449         }
 450 
 451     /**
 452      * Convert a point from a screen coordinates to a component's
 453      * coordinate system
 454      *
 455      * @param p  a Point object (converted to the new coordinate system)
 456      * @param c  a Component object
 457      */
 458     public static void convertPointFromScreen(Point p,Component c) {
 459         Rectangle b;
 460         int x,y;
 461 
 462         do {
 463             if(c instanceof JComponent) {
 464                 x = c.getX();
 465                 y = c.getY();
 466             }  else if(c instanceof java.applet.Applet ||
 467                        c instanceof java.awt.Window) {
 468                 try {
 469                     Point pp = c.getLocationOnScreen();
 470                     x = pp.x;
 471                     y = pp.y;
 472                 } catch (IllegalComponentStateException icse) {
 473                     x = c.getX();
 474                     y = c.getY();
 475                 }
 476             } else {
 477                 x = c.getX();
 478                 y = c.getY();
 479             }
 480 
 481             p.x -= x;
 482             p.y -= y;
 483 
 484             if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
 485                 break;
 486             c = c.getParent();
 487         } while(c != null);
 488     }
 489 
 490     /**
 491      * Returns the first <code>Window </code> ancestor of <code>c</code>, or
 492      * {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
 493      * <p>
 494      * Note: This method provides the same functionality as
 495      * <code>getWindowAncestor</code>.
 496      *
 497      * @param c <code>Component</code> to get <code>Window</code> ancestor
 498      *        of.
 499      * @return the first <code>Window </code> ancestor of <code>c</code>, or
 500      *         {@code null} if <code>c</code> is not contained inside a
 501      *         <code>Window</code>.
 502      */
 503     public static Window windowForComponent(Component c) {
 504         return getWindowAncestor(c);
 505     }
 506 
 507     /**
 508      * Return {@code true} if a component {@code a} descends from a component {@code b}
 509      *
 510      * @param a the first component
 511      * @param b the second component
 512      * @return {@code true} if a component {@code a} descends from a component {@code b}
 513      */
 514     public static boolean isDescendingFrom(Component a,Component b) {
 515         if(a == b)
 516             return true;
 517         for(Container p = a.getParent();p!=null;p=p.getParent())
 518             if(p == b)
 519                 return true;
 520         return false;
 521     }
 522 
 523 
 524     /**
 525      * Convenience to calculate the intersection of two rectangles
 526      * without allocating a new rectangle.
 527      * If the two rectangles don't intersect,
 528      * then the returned rectangle begins at (0,0)
 529      * and has zero width and height.
 530      *
 531      * @param x       the X coordinate of the first rectangle's top-left point
 532      * @param y       the Y coordinate of the first rectangle's top-left point
 533      * @param width   the width of the first rectangle
 534      * @param height  the height of the first rectangle
 535      * @param dest    the second rectangle
 536      *
 537      * @return <code>dest</code>, modified to specify the intersection
 538      */
 539     public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
 540         int x1 = (x > dest.x) ? x : dest.x;
 541         int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
 542         int y1 = (y > dest.y) ? y : dest.y;
 543         int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));
 544 
 545         dest.x = x1;
 546         dest.y = y1;
 547         dest.width = x2 - x1;
 548         dest.height = y2 - y1;
 549 
 550         // If rectangles don't intersect, return zero'd intersection.
 551         if (dest.width < 0 || dest.height < 0) {
 552             dest.x = dest.y = dest.width = dest.height = 0;
 553         }
 554 
 555         return dest;
 556     }
 557 
 558     /**
 559      * Convenience method that calculates the union of two rectangles
 560      * without allocating a new rectangle.
 561      *
 562      * @param x the x-coordinate of the first rectangle
 563      * @param y the y-coordinate of the first rectangle
 564      * @param width the width of the first rectangle
 565      * @param height the height of the first rectangle
 566      * @param dest  the coordinates of the second rectangle; the union
 567      *    of the two rectangles is returned in this rectangle
 568      * @return the <code>dest</code> <code>Rectangle</code>
 569      */
 570     public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
 571         int x1 = (x < dest.x) ? x : dest.x;
 572         int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
 573         int y1 = (y < dest.y) ? y : dest.y;
 574         int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);
 575 
 576         dest.x = x1;
 577         dest.y = y1;
 578         dest.width = (x2 - x1);
 579         dest.height= (y2 - y1);
 580         return dest;
 581     }
 582 
 583     /**
 584      * Convenience returning an array of rect representing the regions within
 585      * <code>rectA</code> that do not overlap with <code>rectB</code>. If the
 586      * two Rects do not overlap, returns an empty array
 587      *
 588      * @param rectA the first rectangle
 589      * @param rectB the second rectangle
 590      *
 591      * @return an array of rectangles representing the regions within {@code rectA}
 592      *         that do not overlap with {@code rectB}.
 593      */
 594     public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
 595         if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
 596             return new Rectangle[0];
 597         }
 598 
 599         Rectangle t = new Rectangle();
 600         Rectangle a=null,b=null,c=null,d=null;
 601         Rectangle result[];
 602         int rectCount = 0;
 603 
 604         /* rectA contains rectB */
 605         if (isRectangleContainingRectangle(rectA,rectB)) {
 606             t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
 607             if(t.width > 0 && t.height > 0) {
 608                 a = new Rectangle(t);
 609                 rectCount++;
 610             }
 611 
 612             t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
 613             if(t.width > 0 && t.height > 0) {
 614                 b = new Rectangle(t);
 615                 rectCount++;
 616             }
 617 
 618             t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width;
 619             t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
 620             if(t.width > 0 && t.height > 0) {
 621                 c = new Rectangle(t);
 622                 rectCount++;
 623             }
 624 
 625             t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - (rectB.x + rectB.width);
 626             t.height = rectA.height;
 627             if(t.width > 0 && t.height > 0) {
 628                 d = new Rectangle(t);
 629                 rectCount++;
 630             }
 631         } else {
 632             /* 1 */
 633             if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
 634                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
 635 
 636                     t.x = rectA.x; t.y = rectB.y + rectB.height;
 637                     t.width = rectA.width; t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
 638                     if(t.width > 0 && t.height > 0) {
 639                         a = t;
 640                         rectCount++;
 641                     }
 642                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
 643                     t.setBounds((rectB.x + rectB.width), rectA.y,
 644                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
 645                     if(t.width > 0 && t.height > 0) {
 646                         a = t;
 647                         rectCount++;
 648                     }
 649                 } else {
 650                     t.setBounds((rectB.x + rectB.width), rectA.y,
 651                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
 652                                 (rectB.y + rectB.height) - rectA.y);
 653                     if(t.width > 0 && t.height > 0) {
 654                         a = new Rectangle(t);
 655                         rectCount++;
 656                     }
 657 
 658                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
 659                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 660                     if(t.width > 0 && t.height > 0) {
 661                         b = new Rectangle(t);
 662                         rectCount++;
 663                     }
 664                 }
 665             } else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
 666                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
 667                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 668                     if(t.width > 0 && t.height > 0) {
 669                         a = t;
 670                         rectCount++;
 671                     }
 672                 } else {
 673                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 674                     if(t.width > 0 && t.height > 0) {
 675                         a = new Rectangle(t);
 676                         rectCount++;
 677                     }
 678                     t.setBounds((rectB.x + rectB.width), rectB.y,
 679                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
 680                                 (rectA.y + rectA.height) - rectB.y);
 681                     if(t.width > 0 && t.height > 0) {
 682                         b = new Rectangle(t);
 683                         rectCount++;
 684                     }
 685                 }
 686             } else if (rectB.x <= rectA.x) {
 687                 if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
 688                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 689                     if(t.width>0 && t.height > 0) {
 690                         a = new Rectangle(t);
 691                         rectCount++;
 692                     }
 693 
 694                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
 695                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 696                     if(t.width > 0 && t.height > 0) {
 697                         b = new Rectangle(t);
 698                         rectCount++;
 699                     }
 700                 } else {
 701                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 702                     if(t.width > 0 && t.height > 0) {
 703                         a = new Rectangle(t);
 704                         rectCount++;
 705                     }
 706 
 707                     t.setBounds((rectB.x + rectB.width), rectB.y,
 708                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
 709                                 rectB.height);
 710                     if(t.width > 0 && t.height > 0) {
 711                         b = new Rectangle(t);
 712                         rectCount++;
 713                     }
 714 
 715                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
 716                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 717                     if(t.width > 0 && t.height > 0) {
 718                         c = new Rectangle(t);
 719                         rectCount++;
 720                     }
 721                 }
 722             } else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
 723                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
 724                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
 725                     if(t.width > 0 && t.height > 0) {
 726                         a = t;
 727                         rectCount++;
 728                     }
 729                 } else if (rectB.y <= rectA.y) {
 730                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
 731                                 (rectB.y + rectB.height) - rectA.y);
 732                     if(t.width > 0 && t.height > 0) {
 733                         a = new Rectangle(t);
 734                         rectCount++;
 735                     }
 736 
 737                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
 738                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 739                     if(t.width > 0 && t.height > 0) {
 740                         b = new Rectangle(t);
 741                         rectCount++;
 742                     }
 743                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
 744                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 745                     if(t.width > 0 && t.height > 0) {
 746                         a = new Rectangle(t);
 747                         rectCount++;
 748                     }
 749 
 750                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
 751                                 (rectA.y + rectA.height) - rectB.y);
 752                     if(t.width > 0 && t.height > 0) {
 753                         b = new Rectangle(t);
 754                         rectCount++;
 755                     }
 756                 } else {
 757                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
 758                     if(t.width > 0 && t.height > 0) {
 759                         a = new Rectangle(t);
 760                         rectCount++;
 761                     }
 762 
 763                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
 764                                 rectB.height);
 765                     if(t.width > 0 && t.height > 0) {
 766                         b = new Rectangle(t);
 767                         rectCount++;
 768                     }
 769 
 770                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
 771                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 772                     if(t.width > 0 && t.height > 0) {
 773                         c = new Rectangle(t);
 774                         rectCount++;
 775                     }
 776                 }
 777             } else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
 778                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
 779                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
 780                     if(t.width > 0 && t.height > 0) {
 781                         a = new Rectangle(t);
 782                         rectCount++;
 783                     }
 784                     t.setBounds((rectB.x + rectB.width), rectA.y,
 785                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
 786                     if(t.width > 0 && t.height > 0) {
 787                         b = new Rectangle(t);
 788                         rectCount++;
 789                     }
 790                 } else if (rectB.y <= rectA.y) {
 791                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
 792                     if(t.width > 0 && t.height > 0) {
 793                         a = new Rectangle(t);
 794                         rectCount++;
 795                     }
 796 
 797                     t.setBounds(rectB.x, (rectB.y + rectB.height),
 798                                 rectB.width,
 799                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
 800                     if(t.width > 0 && t.height > 0) {
 801                         b = new Rectangle(t);
 802                         rectCount++;
 803                     }
 804 
 805                     t.setBounds((rectB.x + rectB.width), rectA.y,
 806                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
 807                     if(t.width > 0 && t.height > 0) {
 808                         c = new Rectangle(t);
 809                         rectCount++;
 810                     }
 811                 } else {
 812                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
 813                     if(t.width > 0 && t.height > 0) {
 814                         a = new Rectangle(t);
 815                         rectCount++;
 816                     }
 817 
 818                     t.setBounds(rectB.x, rectA.y, rectB.width,
 819                                 rectB.y - rectA.y);
 820                     if(t.width > 0 && t.height > 0) {
 821                         b = new Rectangle(t);
 822                         rectCount++;
 823                     }
 824 
 825                     t.setBounds((rectB.x + rectB.width), rectA.y,
 826                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
 827                     if(t.width > 0 && t.height > 0) {
 828                         c = new Rectangle(t);
 829                         rectCount++;
 830                     }
 831                 }
 832             }
 833         }
 834 
 835         result = new Rectangle[rectCount];
 836         rectCount = 0;
 837         if(a != null)
 838             result[rectCount++] = a;
 839         if(b != null)
 840             result[rectCount++] = b;
 841         if(c != null)
 842             result[rectCount++] = c;
 843         if(d != null)
 844             result[rectCount++] = d;
 845         return result;
 846     }
 847 
 848     /**
 849      * Returns true if the mouse event specifies the left mouse button.
 850      *
 851      * @param anEvent  a MouseEvent object
 852      * @return true if the left mouse button was active
 853      */
 854     public static boolean isLeftMouseButton(MouseEvent anEvent) {
 855          return ((anEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0 ||
 856                  anEvent.getButton() == MouseEvent.BUTTON1);
 857     }
 858 
 859     /**
 860      * Returns true if the mouse event specifies the middle mouse button.
 861      *
 862      * @param anEvent  a MouseEvent object
 863      * @return true if the middle mouse button was active
 864      */
 865     public static boolean isMiddleMouseButton(MouseEvent anEvent) {
 866         return ((anEvent.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0 ||
 867                 anEvent.getButton() == MouseEvent.BUTTON2);
 868     }
 869 
 870     /**
 871      * Returns true if the mouse event specifies the right mouse button.
 872      *
 873      * @param anEvent  a MouseEvent object
 874      * @return true if the right mouse button was active
 875      */
 876     public static boolean isRightMouseButton(MouseEvent anEvent) {
 877         return ((anEvent.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ||
 878                 anEvent.getButton() == MouseEvent.BUTTON3);
 879     }
 880 
 881     /**
 882      * Compute the width of the string using a font with the specified
 883      * "metrics" (sizes).
 884      *
 885      * @param fm   a FontMetrics object to compute with
 886      * @param str  the String to compute
 887      * @return an int containing the string width
 888      */
 889     public static int computeStringWidth(FontMetrics fm,String str) {
 890         // You can't assume that a string's width is the sum of its
 891         // characters' widths in Java2D -- it may be smaller due to
 892         // kerning, etc.
 893         return SwingUtilities2.stringWidth(null, fm, str);
 894     }
 895 
 896     /**
 897      * Compute and return the location of the icons origin, the
 898      * location of origin of the text baseline, and a possibly clipped
 899      * version of the compound labels string.  Locations are computed
 900      * relative to the viewR rectangle.
 901      * The JComponents orientation (LEADING/TRAILING) will also be taken
 902      * into account and translated into LEFT/RIGHT values accordingly.
 903      *
 904      * @param c the component
 905      * @param fm the instance of {@code FontMetrics}
 906      * @param text the text
 907      * @param icon the icon
 908      * @param verticalAlignment the vertical alignment
 909      * @param horizontalAlignment the horizontal alignment
 910      * @param verticalTextPosition the vertical text position
 911      * @param horizontalTextPosition the horizontal text position
 912      * @param viewR the available rectangle
 913      * @param iconR the rectangle for the icon
 914      * @param textR the rectangle for the text
 915      * @param textIconGap the gap between text and icon
 916      *
 917      * @return the possibly clipped version of the compound labels string
 918      */
 919     public static String layoutCompoundLabel(JComponent c,
 920                                              FontMetrics fm,
 921                                              String text,
 922                                              Icon icon,
 923                                              int verticalAlignment,
 924                                              int horizontalAlignment,
 925                                              int verticalTextPosition,
 926                                              int horizontalTextPosition,
 927                                              Rectangle viewR,
 928                                              Rectangle iconR,
 929                                              Rectangle textR,
 930                                              int textIconGap)
 931     {
 932         boolean orientationIsLeftToRight = true;
 933         int     hAlign = horizontalAlignment;
 934         int     hTextPos = horizontalTextPosition;
 935 
 936         if (c != null) {
 937             if (!(c.getComponentOrientation().isLeftToRight())) {
 938                 orientationIsLeftToRight = false;
 939             }
 940         }
 941 
 942         // Translate LEADING/TRAILING values in horizontalAlignment
 943         // to LEFT/RIGHT values depending on the components orientation
 944         switch (horizontalAlignment) {
 945         case LEADING:
 946             hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
 947             break;
 948         case TRAILING:
 949             hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
 950             break;
 951         }
 952 
 953         // Translate LEADING/TRAILING values in horizontalTextPosition
 954         // to LEFT/RIGHT values depending on the components orientation
 955         switch (horizontalTextPosition) {
 956         case LEADING:
 957             hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
 958             break;
 959         case TRAILING:
 960             hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
 961             break;
 962         }
 963 
 964         return layoutCompoundLabelImpl(c,
 965                                        fm,
 966                                        text,
 967                                        icon,
 968                                        verticalAlignment,
 969                                        hAlign,
 970                                        verticalTextPosition,
 971                                        hTextPos,
 972                                        viewR,
 973                                        iconR,
 974                                        textR,
 975                                        textIconGap);
 976     }
 977 
 978     /**
 979      * Compute and return the location of the icons origin, the
 980      * location of origin of the text baseline, and a possibly clipped
 981      * version of the compound labels string.  Locations are computed
 982      * relative to the viewR rectangle.
 983      * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
 984      * values in horizontalTextPosition (they will default to RIGHT) and in
 985      * horizontalAlignment (they will default to CENTER).
 986      * Use the other version of layoutCompoundLabel() instead.
 987      *
 988      * @param fm the instance of {@code FontMetrics}
 989      * @param text the text
 990      * @param icon the icon
 991      * @param verticalAlignment the vertical alignment
 992      * @param horizontalAlignment the horizontal alignment
 993      * @param verticalTextPosition the vertical text position
 994      * @param horizontalTextPosition the horizontal text position
 995      * @param viewR the available rectangle
 996      * @param iconR the rectangle for the icon
 997      * @param textR the rectangle for the text
 998      * @param textIconGap the gap between text and icon
 999      *
1000      * @return the possibly clipped version of the compound labels string
1001      */
1002     public static String layoutCompoundLabel(
1003         FontMetrics fm,
1004         String text,
1005         Icon icon,
1006         int verticalAlignment,
1007         int horizontalAlignment,
1008         int verticalTextPosition,
1009         int horizontalTextPosition,
1010         Rectangle viewR,
1011         Rectangle iconR,
1012         Rectangle textR,
1013         int textIconGap)
1014     {
1015         return layoutCompoundLabelImpl(null, fm, text, icon,
1016                                        verticalAlignment,
1017                                        horizontalAlignment,
1018                                        verticalTextPosition,
1019                                        horizontalTextPosition,
1020                                        viewR, iconR, textR, textIconGap);
1021     }
1022 
1023     /**
1024      * Compute and return the location of the icons origin, the
1025      * location of origin of the text baseline, and a possibly clipped
1026      * version of the compound labels string.  Locations are computed
1027      * relative to the viewR rectangle.
1028      * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
1029      * values in horizontalTextPosition (they will default to RIGHT) and in
1030      * horizontalAlignment (they will default to CENTER).
1031      * Use the other version of layoutCompoundLabel() instead.
1032      */
1033     private static String layoutCompoundLabelImpl(
1034         JComponent c,
1035         FontMetrics fm,
1036         String text,
1037         Icon icon,
1038         int verticalAlignment,
1039         int horizontalAlignment,
1040         int verticalTextPosition,
1041         int horizontalTextPosition,
1042         Rectangle viewR,
1043         Rectangle iconR,
1044         Rectangle textR,
1045         int textIconGap)
1046     {
1047         /* Initialize the icon bounds rectangle iconR.
1048          */
1049 
1050         if (icon != null) {
1051             iconR.width = icon.getIconWidth();
1052             iconR.height = icon.getIconHeight();
1053         }
1054         else {
1055             iconR.width = iconR.height = 0;
1056         }
1057 
1058         /* Initialize the text bounds rectangle textR.  If a null
1059          * or and empty String was specified we substitute "" here
1060          * and use 0,0,0,0 for textR.
1061          */
1062 
1063         boolean textIsEmpty = (text == null) || text.equals("");
1064         int lsb = 0;
1065         int rsb = 0;
1066         /* Unless both text and icon are non-null, we effectively ignore
1067          * the value of textIconGap.
1068          */
1069         int gap;
1070 
1071         View v;
1072         if (textIsEmpty) {
1073             textR.width = textR.height = 0;
1074             text = "";
1075             gap = 0;
1076         }
1077         else {
1078             int availTextWidth;
1079             gap = (icon == null) ? 0 : textIconGap;
1080 
1081             if (horizontalTextPosition == CENTER) {
1082                 availTextWidth = viewR.width;
1083             }
1084             else {
1085                 availTextWidth = viewR.width - (iconR.width + gap);
1086             }
1087             v = (c != null) ? (View) c.getClientProperty("html") : null;
1088             if (v != null) {
1089                 textR.width = Math.min(availTextWidth,
1090                                        (int) v.getPreferredSpan(View.X_AXIS));
1091                 textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
1092             } else {
1093                 textR.width = SwingUtilities2.getTextUIDrawing(c)
1094                         .getStringWidth(c, fm, text);
1095                 lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
1096                 if (lsb < 0) {
1097                     // If lsb is negative, add it to the width and later
1098                     // adjust the x location. This gives more space than is
1099                     // actually needed.
1100                     // This is done like this for two reasons:
1101                     // 1. If we set the width to the actual bounds all
1102                     //    callers would have to account for negative lsb
1103                     //    (pref size calculations ONLY look at width of
1104                     //    textR)
1105                     // 2. You can do a drawString at the returned location
1106                     //    and the text won't be clipped.
1107                     textR.width -= lsb;
1108                 }
1109                 if (textR.width > availTextWidth) {
1110                     text = SwingUtilities2.clipString(c, fm, text,
1111                                                       availTextWidth);
1112                     textR.width = SwingUtilities2.getTextUIDrawing(c)
1113                             .getStringWidth(c, fm, text);
1114                 }
1115                 textR.height = fm.getHeight();
1116             }
1117         }
1118 
1119 
1120         /* Compute textR.x,y given the verticalTextPosition and
1121          * horizontalTextPosition properties
1122          */
1123 
1124         if (verticalTextPosition == TOP) {
1125             if (horizontalTextPosition != CENTER) {
1126                 textR.y = 0;
1127             }
1128             else {
1129                 textR.y = -(textR.height + gap);
1130             }
1131         }
1132         else if (verticalTextPosition == CENTER) {
1133             textR.y = (iconR.height / 2) - (textR.height / 2);
1134         }
1135         else { // (verticalTextPosition == BOTTOM)
1136             if (horizontalTextPosition != CENTER) {
1137                 textR.y = iconR.height - textR.height;
1138             }
1139             else {
1140                 textR.y = (iconR.height + gap);
1141             }
1142         }
1143 
1144         if (horizontalTextPosition == LEFT) {
1145             textR.x = -(textR.width + gap);
1146         }
1147         else if (horizontalTextPosition == CENTER) {
1148             textR.x = (iconR.width / 2) - (textR.width / 2);
1149         }
1150         else { // (horizontalTextPosition == RIGHT)
1151             textR.x = (iconR.width + gap);
1152         }
1153 
1154         // WARNING: DefaultTreeCellEditor uses a shortened version of
1155         // this algorithm to position it's Icon. If you change how this
1156         // is calculated, be sure and update DefaultTreeCellEditor too.
1157 
1158         /* labelR is the rectangle that contains iconR and textR.
1159          * Move it to its proper position given the labelAlignment
1160          * properties.
1161          *
1162          * To avoid actually allocating a Rectangle, Rectangle.union
1163          * has been inlined below.
1164          */
1165         int labelR_x = Math.min(iconR.x, textR.x);
1166         int labelR_width = Math.max(iconR.x + iconR.width,
1167                                     textR.x + textR.width) - labelR_x;
1168         int labelR_y = Math.min(iconR.y, textR.y);
1169         int labelR_height = Math.max(iconR.y + iconR.height,
1170                                      textR.y + textR.height) - labelR_y;
1171 
1172         int dx, dy;
1173 
1174         if (verticalAlignment == TOP) {
1175             dy = viewR.y - labelR_y;
1176         }
1177         else if (verticalAlignment == CENTER) {
1178             dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
1179         }
1180         else { // (verticalAlignment == BOTTOM)
1181             dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
1182         }
1183 
1184         if (horizontalAlignment == LEFT) {
1185             dx = viewR.x - labelR_x;
1186         }
1187         else if (horizontalAlignment == RIGHT) {
1188             dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
1189         }
1190         else { // (horizontalAlignment == CENTER)
1191             dx = (viewR.x + (viewR.width / 2)) -
1192                  (labelR_x + (labelR_width / 2));
1193         }
1194 
1195         /* Translate textR and glypyR by dx,dy.
1196          */
1197 
1198         textR.x += dx;
1199         textR.y += dy;
1200 
1201         iconR.x += dx;
1202         iconR.y += dy;
1203 
1204         if (lsb < 0) {
1205             // lsb is negative. Shift the x location so that the text is
1206             // visually drawn at the right location.
1207             textR.x -= lsb;
1208 
1209             textR.width += lsb;
1210         }
1211         if (rsb > 0) {
1212             textR.width -= rsb;
1213         }
1214 
1215         return text;
1216     }
1217 
1218 
1219     /**
1220      * Paints a component to the specified <code>Graphics</code>.
1221      * This method is primarily useful to render
1222      * <code>Component</code>s that don't exist as part of the visible
1223      * containment hierarchy, but are used for rendering.  For
1224      * example, if you are doing your own rendering and want to render
1225      * some text (or even HTML), you could make use of
1226      * <code>JLabel</code>'s text rendering support and have it paint
1227      * directly by way of this method, without adding the label to the
1228      * visible containment hierarchy.
1229      * <p>
1230      * This method makes use of <code>CellRendererPane</code> to handle
1231      * the actual painting, and is only recommended if you use one
1232      * component for rendering.  If you make use of multiple components
1233      * to handle the rendering, as <code>JTable</code> does, use
1234      * <code>CellRendererPane</code> directly.  Otherwise, as described
1235      * below, you could end up with a <code>CellRendererPane</code>
1236      * per <code>Component</code>.
1237      * <p>
1238      * If <code>c</code>'s parent is not a <code>CellRendererPane</code>,
1239      * a new <code>CellRendererPane</code> is created, <code>c</code> is
1240      * added to it, and the <code>CellRendererPane</code> is added to
1241      * <code>p</code>.  If <code>c</code>'s parent is a
1242      * <code>CellRendererPane</code> and the <code>CellRendererPane</code>s
1243      * parent is not <code>p</code>, it is added to <code>p</code>.
1244      * <p>
1245      * The component should either descend from <code>JComponent</code>
1246      * or be another kind of lightweight component.
1247      * A lightweight component is one whose "lightweight" property
1248      * (returned by the <code>Component</code>
1249      * <code>isLightweight</code> method)
1250      * is true. If the Component is not lightweight, bad things map happen:
1251      * crashes, exceptions, painting problems...
1252      *
1253      * @param g  the <code>Graphics</code> object to draw on
1254      * @param c  the <code>Component</code> to draw
1255      * @param p  the intermediate <code>Container</code>
1256      * @param x  an int specifying the left side of the area draw in, in pixels,
1257      *           measured from the left edge of the graphics context
1258      * @param y  an int specifying the top of the area to draw in, in pixels
1259      *           measured down from the top edge of the graphics context
1260      * @param w  an int specifying the width of the area draw in, in pixels
1261      * @param h  an int specifying the height of the area draw in, in pixels
1262      *
1263      * @see CellRendererPane
1264      * @see java.awt.Component#isLightweight
1265      */
1266     public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
1267         getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
1268     }
1269 
1270     /**
1271      * Paints a component to the specified <code>Graphics</code>.  This
1272      * is a cover method for
1273      * {@link #paintComponent(Graphics,Component,Container,int,int,int,int)}.
1274      * Refer to it for more information.
1275      *
1276      * @param g  the <code>Graphics</code> object to draw on
1277      * @param c  the <code>Component</code> to draw
1278      * @param p  the intermediate <code>Container</code>
1279      * @param r  the <code>Rectangle</code> to draw in
1280      *
1281      * @see #paintComponent(Graphics,Component,Container,int,int,int,int)
1282      * @see CellRendererPane
1283      */
1284     public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
1285         paintComponent(g, c, p, r.x, r.y, r.width, r.height);
1286     }
1287 
1288 
1289     /*
1290      * Ensures that cell renderer <code>c</code> has a
1291      * <code>ComponentShell</code> parent and that
1292      * the shell's parent is p.
1293      */
1294     private static CellRendererPane getCellRendererPane(Component c, Container p) {
1295         Container shell = c.getParent();
1296         if (shell instanceof CellRendererPane) {
1297             if (shell.getParent() != p) {
1298                 p.add(shell);
1299             }
1300         } else {
1301             shell = new CellRendererPane();
1302             shell.add(c);
1303             p.add(shell);
1304         }
1305         return (CellRendererPane)shell;
1306     }
1307 
1308     /**
1309      * A simple minded look and feel change: ask each node in the tree
1310      * to <code>updateUI()</code> -- that is, to initialize its UI property
1311      * with the current look and feel.
1312      *
1313      * @param c the component
1314      */
1315     public static void updateComponentTreeUI(Component c) {
1316         updateComponentTreeUI0(c);
1317         c.invalidate();
1318         c.validate();
1319         c.repaint();
1320     }
1321 
1322     private static void updateComponentTreeUI0(Component c) {
1323         if (c instanceof JComponent) {
1324             JComponent jc = (JComponent) c;
1325             jc.updateUI();
1326             JPopupMenu jpm =jc.getComponentPopupMenu();
1327             if(jpm != null) {
1328                 updateComponentTreeUI(jpm);
1329             }
1330         }
1331         Component[] children = null;
1332         if (c instanceof JMenu) {
1333             children = ((JMenu)c).getMenuComponents();
1334         }
1335         else if (c instanceof Container) {
1336             children = ((Container)c).getComponents();
1337         }
1338         if (children != null) {
1339             for (Component child : children) {
1340                 updateComponentTreeUI0(child);
1341             }
1342         }
1343     }
1344 
1345 
1346     /**
1347      * Causes <i>doRun.run()</i> to be executed asynchronously on the
1348      * AWT event dispatching thread.  This will happen after all
1349      * pending AWT events have been processed.  This method should
1350      * be used when an application thread needs to update the GUI.
1351      * In the following example the <code>invokeLater</code> call queues
1352      * the <code>Runnable</code> object <code>doHelloWorld</code>
1353      * on the event dispatching thread and
1354      * then prints a message.
1355      * <pre>
1356      * Runnable doHelloWorld = new Runnable() {
1357      *     public void run() {
1358      *         System.out.println("Hello World on " + Thread.currentThread());
1359      *     }
1360      * };
1361      *
1362      * SwingUtilities.invokeLater(doHelloWorld);
1363      * System.out.println("This might well be displayed before the other message.");
1364      * </pre>
1365      * If invokeLater is called from the event dispatching thread --
1366      * for example, from a JButton's ActionListener -- the <i>doRun.run()</i> will
1367      * still be deferred until all pending events have been processed.
1368      * Note that if the <i>doRun.run()</i> throws an uncaught exception
1369      * the event dispatching thread will unwind (not the current thread).
1370      * <p>
1371      * Additional documentation and examples for this method can be
1372      * found in
1373      * <A HREF="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html">Concurrency in Swing</a>.
1374      * <p>
1375      * As of 1.3 this method is just a cover for <code>java.awt.EventQueue.invokeLater()</code>.
1376      * <p>
1377      * Unlike the rest of Swing, this method can be invoked from any thread.
1378      *
1379      * @param doRun the instance of {@code Runnable}
1380      * @see #invokeAndWait
1381      */
1382     public static void invokeLater(Runnable doRun) {
1383         EventQueue.invokeLater(doRun);
1384     }
1385 
1386 
1387     /**
1388      * Causes <code>doRun.run()</code> to be executed synchronously on the
1389      * AWT event dispatching thread.  This call blocks until
1390      * all pending AWT events have been processed and (then)
1391      * <code>doRun.run()</code> returns. This method should
1392      * be used when an application thread needs to update the GUI.
1393      * It shouldn't be called from the event dispatching thread.
1394      * Here's an example that creates a new application thread
1395      * that uses <code>invokeAndWait</code> to print a string from the event
1396      * dispatching thread and then, when that's finished, print
1397      * a string from the application thread.
1398      * <pre>
1399      * final Runnable doHelloWorld = new Runnable() {
1400      *     public void run() {
1401      *         System.out.println("Hello World on " + Thread.currentThread());
1402      *     }
1403      * };
1404      *
1405      * Thread appThread = new Thread() {
1406      *     public void run() {
1407      *         try {
1408      *             SwingUtilities.invokeAndWait(doHelloWorld);
1409      *         }
1410      *         catch (Exception e) {
1411      *             e.printStackTrace();
1412      *         }
1413      *         System.out.println("Finished on " + Thread.currentThread());
1414      *     }
1415      * };
1416      * appThread.start();
1417      * </pre>
1418      * Note that if the <code>Runnable.run</code> method throws an
1419      * uncaught exception
1420      * (on the event dispatching thread) it's caught and rethrown, as
1421      * an <code>InvocationTargetException</code>, on the caller's thread.
1422      * <p>
1423      * Additional documentation and examples for this method can be
1424      * found in
1425      * <A HREF="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html">Concurrency in Swing</a>.
1426      * <p>
1427      * As of 1.3 this method is just a cover for
1428      * <code>java.awt.EventQueue.invokeAndWait()</code>.
1429      *
1430      * @param doRun the instance of {@code Runnable}
1431      * @exception  InterruptedException if we're interrupted while waiting for
1432      *             the event dispatching thread to finish executing
1433      *             <code>doRun.run()</code>
1434      * @exception  InvocationTargetException  if an exception is thrown
1435      *             while running <code>doRun</code>
1436      *
1437      * @see #invokeLater
1438      */
1439     public static void invokeAndWait(final Runnable doRun)
1440         throws InterruptedException, InvocationTargetException
1441     {
1442         EventQueue.invokeAndWait(doRun);
1443     }
1444 
1445     /**
1446      * Returns true if the current thread is an AWT event dispatching thread.
1447      * <p>
1448      * As of 1.3 this method is just a cover for
1449      * <code>java.awt.EventQueue.isDispatchThread()</code>.
1450      *
1451      * @return true if the current thread is an AWT event dispatching thread
1452      */
1453     public static boolean isEventDispatchThread()
1454     {
1455         return EventQueue.isDispatchThread();
1456     }
1457 
1458 
1459     /*
1460      * --- Accessibility Support ---
1461      *
1462      */
1463 
1464     /**
1465      * Get the index of this object in its accessible parent.<p>
1466      *
1467      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1468      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1469      * of using this method.
1470      *
1471      * @param c the component
1472      * @return -1 of this object does not have an accessible parent.
1473      * Otherwise, the index of the child in its accessible parent.
1474      */
1475     public static int getAccessibleIndexInParent(Component c) {
1476         return c.getAccessibleContext().getAccessibleIndexInParent();
1477     }
1478 
1479     /**
1480      * Returns the <code>Accessible</code> child contained at the
1481      * local coordinate <code>Point</code>, if one exists.
1482      * Otherwise returns <code>null</code>.
1483      *
1484      * @param c the component
1485      * @param p the local coordinate
1486      * @return the <code>Accessible</code> at the specified location,
1487      *    if it exists; otherwise <code>null</code>
1488      */
1489     public static Accessible getAccessibleAt(Component c, Point p) {
1490         if (c instanceof Container) {
1491             return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p);
1492         } else if (c instanceof Accessible) {
1493             Accessible a = (Accessible) c;
1494             if (a != null) {
1495                 AccessibleContext ac = a.getAccessibleContext();
1496                 if (ac != null) {
1497                     AccessibleComponent acmp;
1498                     Point location;
1499                     int nchildren = ac.getAccessibleChildrenCount();
1500                     for (int i=0; i < nchildren; i++) {
1501                         a = ac.getAccessibleChild(i);
1502                         if ((a != null)) {
1503                             ac = a.getAccessibleContext();
1504                             if (ac != null) {
1505                                 acmp = ac.getAccessibleComponent();
1506                                 if ((acmp != null) && (acmp.isShowing())) {
1507                                     location = acmp.getLocation();
1508                                     Point np = new Point(p.x-location.x,
1509                                                          p.y-location.y);
1510                                     if (acmp.contains(np)){
1511                                         return a;
1512                                     }
1513                                 }
1514                             }
1515                         }
1516                     }
1517                 }
1518             }
1519             return (Accessible) c;
1520         }
1521         return null;
1522     }
1523 
1524     /**
1525      * Get the state of this object. <p>
1526      *
1527      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1528      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1529      * of using this method.
1530      *
1531      * @param c the component
1532      * @return an instance of AccessibleStateSet containing the current state
1533      * set of the object
1534      * @see AccessibleState
1535      */
1536     public static AccessibleStateSet getAccessibleStateSet(Component c) {
1537         return c.getAccessibleContext().getAccessibleStateSet();
1538     }
1539 
1540     /**
1541      * Returns the number of accessible children in the object.  If all
1542      * of the children of this object implement Accessible, than this
1543      * method should return the number of children of this object. <p>
1544      *
1545      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1546      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1547      * of using this method.
1548      *
1549      * @param c the component
1550      * @return the number of accessible children in the object.
1551      */
1552     public static int getAccessibleChildrenCount(Component c) {
1553         return c.getAccessibleContext().getAccessibleChildrenCount();
1554     }
1555 
1556     /**
1557      * Return the nth Accessible child of the object. <p>
1558      *
1559      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1560      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1561      * of using this method.
1562      *
1563      * @param c the component
1564      * @param i zero-based index of child
1565      * @return the nth Accessible child of the object
1566      */
1567     public static Accessible getAccessibleChild(Component c, int i) {
1568         return c.getAccessibleContext().getAccessibleChild(i);
1569     }
1570 
1571     /**
1572      * Return the child <code>Component</code> of the specified
1573      * <code>Component</code> that is the focus owner, if any.
1574      *
1575      * @param c the root of the <code>Component</code> hierarchy to
1576      *        search for the focus owner
1577      * @return the focus owner, or <code>null</code> if there is no focus
1578      *         owner, or if the focus owner is not <code>comp</code>, or a
1579      *         descendant of <code>comp</code>
1580      *
1581      * @see java.awt.KeyboardFocusManager#getFocusOwner
1582      * @deprecated As of 1.4, replaced by
1583      *   <code>KeyboardFocusManager.getFocusOwner()</code>.
1584      */
1585     @Deprecated
1586     public static Component findFocusOwner(Component c) {
1587         Component focusOwner = KeyboardFocusManager.
1588             getCurrentKeyboardFocusManager().getFocusOwner();
1589 
1590         // verify focusOwner is a descendant of c
1591         for (Component temp = focusOwner; temp != null;
1592              temp = (temp instanceof Window) ? null : temp.getParent())
1593         {
1594             if (temp == c) {
1595                 return focusOwner;
1596             }
1597         }
1598 
1599         return null;
1600     }
1601 
1602     /**
1603      * If c is a JRootPane descendant return its JRootPane ancestor.
1604      * If c is a RootPaneContainer then return its JRootPane.
1605      *
1606      * @param c the component
1607      * @return the JRootPane for Component c or {@code null}.
1608      */
1609     public static JRootPane getRootPane(Component c) {
1610         if (c instanceof RootPaneContainer) {
1611             return ((RootPaneContainer)c).getRootPane();
1612         }
1613         for( ; c != null; c = c.getParent()) {
1614             if (c instanceof JRootPane) {
1615                 return (JRootPane)c;
1616             }
1617         }
1618         return null;
1619     }
1620 
1621 
1622     /**
1623      * Returns the root component for the current component tree.
1624      *
1625      * @param c the component
1626      * @return the first ancestor of c that's a Window or the last Applet ancestor
1627      */
1628     public static Component getRoot(Component c) {
1629         Component applet = null;
1630         for(Component p = c; p != null; p = p.getParent()) {
1631             if (p instanceof Window) {
1632                 return p;
1633             }
1634             if (p instanceof Applet) {
1635                 applet = p;
1636             }
1637         }
1638         return applet;
1639     }
1640 
1641     static JComponent getPaintingOrigin(JComponent c) {
1642         Container p = c;
1643         while ((p = p.getParent()) instanceof JComponent) {
1644             JComponent jp = (JComponent) p;
1645             if (jp.isPaintingOrigin()) {
1646                 return jp;
1647             }
1648         }
1649         return null;
1650     }
1651 
1652     /**
1653      * Process the key bindings for the <code>Component</code> associated with
1654      * <code>event</code>. This method is only useful if
1655      * <code>event.getComponent()</code> does not descend from
1656      * <code>JComponent</code>, or your are not invoking
1657      * <code>super.processKeyEvent</code> from within your
1658      * <code>JComponent</code> subclass. <code>JComponent</code>
1659      * automatically processes bindings from within its
1660      * <code>processKeyEvent</code> method, hence you rarely need
1661      * to directly invoke this method.
1662      *
1663      * @param event KeyEvent used to identify which bindings to process, as
1664      *              well as which Component has focus.
1665      * @return true if a binding has found and processed
1666      * @since 1.4
1667      */
1668     public static boolean processKeyBindings(KeyEvent event) {
1669         if (event != null) {
1670             if (event.isConsumed()) {
1671                 return false;
1672             }
1673 
1674             Component component = event.getComponent();
1675             boolean pressed = (event.getID() == KeyEvent.KEY_PRESSED);
1676 
1677             if (!isValidKeyEventForKeyBindings(event)) {
1678                 return false;
1679             }
1680             // Find the first JComponent in the ancestor hierarchy, and
1681             // invoke processKeyBindings on it
1682             while (component != null) {
1683                 if (component instanceof JComponent) {
1684                     return ((JComponent)component).processKeyBindings(
1685                                                    event, pressed);
1686                 }
1687                 if ((component instanceof Applet) ||
1688                     (component instanceof Window)) {
1689                     // No JComponents, if Window or Applet parent, process
1690                     // WHEN_IN_FOCUSED_WINDOW bindings.
1691                     return JComponent.processKeyBindingsForAllComponents(
1692                                   event, (Container)component, pressed);
1693                 }
1694                 component = component.getParent();
1695             }
1696         }
1697         return false;
1698     }
1699 
1700     /**
1701      * Returns true if the <code>e</code> is a valid KeyEvent to use in
1702      * processing the key bindings associated with JComponents.
1703      */
1704     static boolean isValidKeyEventForKeyBindings(KeyEvent e) {
1705         return true;
1706     }
1707 
1708     /**
1709      * Invokes {@code actionPerformed} on {@code action} if {@code action}
1710      * is non-{@code null} and accepts the sender object.
1711      * The command for the ActionEvent is determined by:
1712      * <ol>
1713      *   <li>If the action was registered via
1714      *       <code>registerKeyboardAction</code>, then the command string
1715      *       passed in ({@code null} will be used if {@code null} was passed in).
1716      *   <li>Action value with name Action.ACTION_COMMAND_KEY, unless {@code null}.
1717      *   <li>String value of the KeyEvent, unless <code>getKeyChar</code>
1718      *       returns KeyEvent.CHAR_UNDEFINED..
1719      * </ol>
1720      * This will return true if <code>action</code> is non-{@code null} and
1721      * actionPerformed is invoked on it.
1722      *
1723      * @param action an action
1724      * @param ks a key stroke
1725      * @param event a key event
1726      * @param sender a sender
1727      * @param modifiers action modifiers
1728      * @return {@code true} if {@code action} is non-{@code null} and
1729      *         actionPerformed is invoked on it.
1730      * @see javax.swing.Action#accept
1731      *
1732      * @since 1.3
1733      */
1734     public static boolean notifyAction(Action action, KeyStroke ks,
1735                                        KeyEvent event, Object sender,
1736                                        int modifiers) {
1737 
1738         if (action == null || !action.accept(sender)) {
1739             return false;
1740         }
1741 
1742         Object commandO;
1743         boolean stayNull;
1744 
1745         // Get the command object.
1746         commandO = action.getValue(Action.ACTION_COMMAND_KEY);
1747         if (commandO == null && (action instanceof JComponent.ActionStandin)) {
1748             // ActionStandin is used for historical reasons to support
1749             // registerKeyboardAction with a null value.
1750             stayNull = true;
1751         }
1752         else {
1753             stayNull = false;
1754         }
1755 
1756         // Convert it to a string.
1757         String command;
1758 
1759         if (commandO != null) {
1760             command = commandO.toString();
1761         }
1762         else if (!stayNull && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
1763             command = String.valueOf(event.getKeyChar());
1764         }
1765         else {
1766             // Do null for undefined chars, or if registerKeyboardAction
1767             // was called with a null.
1768             command = null;
1769         }
1770         action.actionPerformed(new ActionEvent(sender,
1771                         ActionEvent.ACTION_PERFORMED, command, event.getWhen(),
1772                         modifiers));
1773         return true;
1774     }
1775 
1776 
1777     /**
1778      * Convenience method to change the UI InputMap for <code>component</code>
1779      * to <code>uiInputMap</code>. If <code>uiInputMap</code> is {@code null},
1780      * this removes any previously installed UI InputMap.
1781      *
1782      * @param component a component
1783      * @param type a type
1784      * @param uiInputMap an {@code InputMap}
1785      * @since 1.3
1786      */
1787     public static void replaceUIInputMap(JComponent component, int type,
1788                                          InputMap uiInputMap) {
1789         InputMap map = component.getInputMap(type, (uiInputMap != null));
1790 
1791         while (map != null) {
1792             InputMap parent = map.getParent();
1793             if (parent == null || (parent instanceof UIResource)) {
1794                 map.setParent(uiInputMap);
1795                 return;
1796             }
1797             map = parent;
1798         }
1799     }
1800 
1801 
1802     /**
1803      * Convenience method to change the UI ActionMap for <code>component</code>
1804      * to <code>uiActionMap</code>. If <code>uiActionMap</code> is {@code null},
1805      * this removes any previously installed UI ActionMap.
1806      *
1807      * @param component a component
1808      * @param uiActionMap an {@code ActionMap}
1809      * @since 1.3
1810      */
1811     public static void replaceUIActionMap(JComponent component,
1812                                           ActionMap uiActionMap) {
1813         ActionMap map = component.getActionMap((uiActionMap != null));
1814 
1815         while (map != null) {
1816             ActionMap parent = map.getParent();
1817             if (parent == null || (parent instanceof UIResource)) {
1818                 map.setParent(uiActionMap);
1819                 return;
1820             }
1821             map = parent;
1822         }
1823     }
1824 
1825 
1826     /**
1827      * Returns the InputMap provided by the UI for condition
1828      * <code>condition</code> in component <code>component</code>.
1829      * <p>This will return {@code null} if the UI has not installed an InputMap
1830      * of the specified type.
1831      *
1832      * @param component a component
1833      * @param condition a condition
1834      * @return the {@code ActionMap} provided by the UI for {@code condition}
1835      *         in the component, or {@code null} if the UI has not installed
1836      *         an InputMap of the specified type.
1837      * @since 1.3
1838      */
1839     public static InputMap getUIInputMap(JComponent component, int condition) {
1840         InputMap map = component.getInputMap(condition, false);
1841         while (map != null) {
1842             InputMap parent = map.getParent();
1843             if (parent instanceof UIResource) {
1844                 return parent;
1845             }
1846             map = parent;
1847         }
1848         return null;
1849     }
1850 
1851     /**
1852      * Returns the ActionMap provided by the UI
1853      * in component <code>component</code>.
1854      * <p>This will return {@code null} if the UI has not installed an ActionMap.
1855      *
1856      * @param component a component
1857      * @return the {@code ActionMap} provided by the UI in the component,
1858      *         or {@code null} if the UI has not installed an ActionMap.
1859      * @since 1.3
1860      */
1861     public static ActionMap getUIActionMap(JComponent component) {
1862         ActionMap map = component.getActionMap(false);
1863         while (map != null) {
1864             ActionMap parent = map.getParent();
1865             if (parent instanceof UIResource) {
1866                 return parent;
1867             }
1868             map = parent;
1869         }
1870         return null;
1871     }
1872 
1873 
1874     // Don't use String, as it's not guaranteed to be unique in a Hashtable.
1875     private static final Object sharedOwnerFrameKey =
1876        new StringBuffer("SwingUtilities.sharedOwnerFrame");
1877 
1878     @SuppressWarnings("serial") // JDK-implementation class
1879     static class SharedOwnerFrame extends Frame implements WindowListener {
1880         public void addNotify() {
1881             super.addNotify();
1882             installListeners();
1883         }
1884 
1885         /**
1886          * Install window listeners on owned windows to watch for displayability changes
1887          */
1888         void installListeners() {
1889             Window[] windows = getOwnedWindows();
1890             for (Window window : windows) {
1891                 if (window != null) {
1892                     window.removeWindowListener(this);
1893                     window.addWindowListener(this);
1894                 }
1895             }
1896         }
1897 
1898         /**
1899          * Watches for displayability changes and disposes shared instance if there are no
1900          * displayable children left.
1901          */
1902         public void windowClosed(WindowEvent e) {
1903             synchronized(getTreeLock()) {
1904                 Window[] windows = getOwnedWindows();
1905                 for (Window window : windows) {
1906                     if (window != null) {
1907                         if (window.isDisplayable()) {
1908                             return;
1909                         }
1910                         window.removeWindowListener(this);
1911                     }
1912                 }
1913                 dispose();
1914             }
1915         }
1916         public void windowOpened(WindowEvent e) {
1917         }
1918         public void windowClosing(WindowEvent e) {
1919         }
1920         public void windowIconified(WindowEvent e) {
1921         }
1922         public void windowDeiconified(WindowEvent e) {
1923         }
1924         public void windowActivated(WindowEvent e) {
1925         }
1926         public void windowDeactivated(WindowEvent e) {
1927         }
1928 
1929         @SuppressWarnings("deprecation")
1930         public void show() {
1931             // This frame can never be shown
1932         }
1933         public void dispose() {
1934             try {
1935                 getToolkit().getSystemEventQueue();
1936                 super.dispose();
1937             } catch (Exception e) {
1938                 // untrusted code not allowed to dispose
1939             }
1940         }
1941     }
1942 
1943     /**
1944      * Returns a toolkit-private, shared, invisible Frame
1945      * to be the owner for JDialogs and JWindows created with
1946      * {@code null} owners.
1947      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1948      * returns true.
1949      * @see java.awt.GraphicsEnvironment#isHeadless
1950      */
1951     static Frame getSharedOwnerFrame() throws HeadlessException {
1952         Frame sharedOwnerFrame =
1953             (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
1954         if (sharedOwnerFrame == null) {
1955             sharedOwnerFrame = new SharedOwnerFrame();
1956             SwingUtilities.appContextPut(sharedOwnerFrameKey,
1957                                          sharedOwnerFrame);
1958         }
1959         return sharedOwnerFrame;
1960     }
1961 
1962     /**
1963      * Returns a SharedOwnerFrame's shutdown listener to dispose the SharedOwnerFrame
1964      * if it has no more displayable children.
1965      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1966      * returns true.
1967      * @see java.awt.GraphicsEnvironment#isHeadless
1968      */
1969     static WindowListener getSharedOwnerFrameShutdownListener() throws HeadlessException {
1970         Frame sharedOwnerFrame = getSharedOwnerFrame();
1971         return (WindowListener)sharedOwnerFrame;
1972     }
1973 
1974     /* Don't make these AppContext accessors public or protected --
1975      * since AppContext is in sun.awt in 1.2, we shouldn't expose it
1976      * even indirectly with a public API.
1977      */
1978     // REMIND(aim): phase out use of 4 methods below since they
1979     // are just private covers for AWT methods (?)
1980 
1981     static Object appContextGet(Object key) {
1982         return AppContext.getAppContext().get(key);
1983     }
1984 
1985     static void appContextPut(Object key, Object value) {
1986         AppContext.getAppContext().put(key, value);
1987     }
1988 
1989     static void appContextRemove(Object key) {
1990         AppContext.getAppContext().remove(key);
1991     }
1992 
1993 
1994     static Class<?> loadSystemClass(String className) throws ClassNotFoundException {
1995         ReflectUtil.checkPackageAccess(className);
1996         return Class.forName(className, true, Thread.currentThread().
1997                              getContextClassLoader());
1998     }
1999 
2000 
2001    /*
2002      * Convenience function for determining ComponentOrientation.  Helps us
2003      * avoid having Munge directives throughout the code.
2004      */
2005     static boolean isLeftToRight( Component c ) {
2006         return c.getComponentOrientation().isLeftToRight();
2007     }
2008     private SwingUtilities() {
2009         throw new Error("SwingUtilities is just a container for static methods");
2010     }
2011 
2012     /**
2013      * Returns true if the Icon <code>icon</code> is an instance of
2014      * ImageIcon, and the image it contains is the same as <code>image</code>.
2015      */
2016     static boolean doesIconReferenceImage(Icon icon, Image image) {
2017         Image iconImage = (icon != null && (icon instanceof ImageIcon)) ?
2018                            ((ImageIcon)icon).getImage() : null;
2019         return (iconImage == image);
2020     }
2021 
2022     /**
2023      * Returns index of the first occurrence of <code>mnemonic</code>
2024      * within string <code>text</code>. Matching algorithm is not
2025      * case-sensitive.
2026      *
2027      * @param text The text to search through, may be {@code null}
2028      * @param mnemonic The mnemonic to find the character for.
2029      * @return index into the string if exists, otherwise -1
2030      */
2031     static int findDisplayedMnemonicIndex(String text, int mnemonic) {
2032         if (text == null || mnemonic == '\0') {
2033             return -1;
2034         }
2035 
2036         char uc = Character.toUpperCase((char)mnemonic);
2037         char lc = Character.toLowerCase((char)mnemonic);
2038 
2039         int uci = text.indexOf(uc);
2040         int lci = text.indexOf(lc);
2041 
2042         if (uci == -1) {
2043             return lci;
2044         } else if(lci == -1) {
2045             return uci;
2046         } else {
2047             return (lci < uci) ? lci : uci;
2048         }
2049     }
2050 
2051     /**
2052      * Stores the position and size of
2053      * the inner painting area of the specified component
2054      * in <code>r</code> and returns <code>r</code>.
2055      * The position and size specify the bounds of the component,
2056      * adjusted so as not to include the border area (the insets).
2057      * This method is useful for classes
2058      * that implement painting code.
2059      *
2060      * @param c  the JComponent in question; if {@code null}, this method returns {@code null}
2061      * @param r  the Rectangle instance to be modified;
2062      *           may be {@code null}
2063      * @return {@code null} if the Component is {@code null};
2064      *         otherwise, returns the passed-in rectangle (if non-{@code null})
2065      *         or a new rectangle specifying position and size information
2066      *
2067      * @since 1.4
2068      */
2069     public static Rectangle calculateInnerArea(JComponent c, Rectangle r) {
2070         if (c == null) {
2071             return null;
2072         }
2073         Rectangle rect = r;
2074         Insets insets = c.getInsets();
2075 
2076         if (rect == null) {
2077             rect = new Rectangle();
2078         }
2079 
2080         rect.x = insets.left;
2081         rect.y = insets.top;
2082         rect.width = c.getWidth() - insets.left - insets.right;
2083         rect.height = c.getHeight() - insets.top - insets.bottom;
2084 
2085         return rect;
2086     }
2087 
2088     static void updateRendererOrEditorUI(Object rendererOrEditor) {
2089         if (rendererOrEditor == null) {
2090             return;
2091         }
2092 
2093         Component component = null;
2094 
2095         if (rendererOrEditor instanceof Component) {
2096             component = (Component)rendererOrEditor;
2097         }
2098         if (rendererOrEditor instanceof DefaultCellEditor) {
2099             component = ((DefaultCellEditor)rendererOrEditor).getComponent();
2100         }
2101 
2102         if (component != null) {
2103             SwingUtilities.updateComponentTreeUI(component);
2104         }
2105     }
2106 
2107     /**
2108      * Returns the first ancestor of the {@code component}
2109      * which is not an instance of {@link JLayer}.
2110      *
2111      * @param component {@code Component} to get
2112      * the first ancestor of, which is not a {@link JLayer} instance.
2113      *
2114      * @return the first ancestor of the {@code component}
2115      * which is not an instance of {@link JLayer}.
2116      * If such an ancestor can not be found, {@code null} is returned.
2117      *
2118      * @throws NullPointerException if {@code component} is {@code null}
2119      * @see JLayer
2120      *
2121      * @since 1.7
2122      */
2123     public static Container getUnwrappedParent(Component component) {
2124         Container parent = component.getParent();
2125         while(parent instanceof JLayer) {
2126             parent = parent.getParent();
2127         }
2128         return parent;
2129     }
2130 
2131     /**
2132      * Returns the first {@code JViewport}'s descendant
2133      * which is not an instance of {@code JLayer}.
2134      * If such a descendant can not be found, {@code null} is returned.
2135      *
2136      * If the {@code viewport}'s view component is not a {@code JLayer},
2137      * this method is equivalent to {@link JViewport#getView()}
2138      * otherwise {@link JLayer#getView()} will be recursively
2139      * called on all descending {@code JLayer}s.
2140      *
2141      * @param viewport {@code JViewport} to get the first descendant of,
2142      * which in not a {@code JLayer} instance.
2143      *
2144      * @return the first {@code JViewport}'s descendant
2145      * which is not an instance of {@code JLayer}.
2146      * If such a descendant can not be found, {@code null} is returned.
2147      *
2148      * @throws NullPointerException if {@code viewport} is {@code null}
2149      * @see JViewport#getView()
2150      * @see JLayer
2151      *
2152      * @since 1.7
2153      */
2154     public static Component getUnwrappedView(JViewport viewport) {
2155         Component view = viewport.getView();
2156         while (view instanceof JLayer) {
2157             view = ((JLayer)view).getView();
2158         }
2159         return view;
2160     }
2161 
2162    /**
2163      * Retrieves the validate root of a given container.
2164      *
2165      * If the container is contained within a {@code CellRendererPane}, this
2166      * method returns {@code null} due to the synthetic nature of the {@code
2167      * CellRendererPane}.
2168      * <p>
2169      * The component hierarchy must be displayable up to the toplevel component
2170      * (either a {@code Frame} or an {@code Applet} object.) Otherwise this
2171      * method returns {@code null}.
2172      * <p>
2173      * If the {@code visibleOnly} argument is {@code true}, the found validate
2174      * root and all its parents up to the toplevel component must also be
2175      * visible. Otherwise this method returns {@code null}.
2176      *
2177      * @return the validate root of the given container or null
2178      * @see java.awt.Component#isDisplayable()
2179      * @see java.awt.Component#isVisible()
2180      * @since 1.7
2181      */
2182     static Container getValidateRoot(Container c, boolean visibleOnly) {
2183         Container root = null;
2184 
2185         for (; c != null; c = c.getParent())
2186         {
2187             if (!c.isDisplayable() || c instanceof CellRendererPane) {
2188                 return null;
2189             }
2190             if (c.isValidateRoot()) {
2191                 root = c;
2192                 break;
2193             }
2194         }
2195 
2196         if (root == null) {
2197             return null;
2198         }
2199 
2200         for (; c != null; c = c.getParent()) {
2201             if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) {
2202                 return null;
2203             }
2204             if (c instanceof Window || c instanceof Applet) {
2205                 return root;
2206             }
2207         }
2208 
2209         return null;
2210     }
2211 }