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.stringWidth(c, fm, text);
1094                 lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
1095                 if (lsb < 0) {
1096                     // If lsb is negative, add it to the width and later
1097                     // adjust the x location. This gives more space than is
1098                     // actually needed.
1099                     // This is done like this for two reasons:
1100                     // 1. If we set the width to the actual bounds all
1101                     //    callers would have to account for negative lsb
1102                     //    (pref size calculations ONLY look at width of
1103                     //    textR)
1104                     // 2. You can do a drawString at the returned location
1105                     //    and the text won't be clipped.
1106                     textR.width -= lsb;
1107                 }
1108                 if (textR.width > availTextWidth) {
1109                     text = SwingUtilities2.clipString(c, fm, text,
1110                                                       availTextWidth);
1111                     textR.width = SwingUtilities2.stringWidth(c, fm, text);
1112                 }
1113                 textR.height = fm.getHeight();
1114             }
1115         }
1116 
1117 
1118         /* Compute textR.x,y given the verticalTextPosition and
1119          * horizontalTextPosition properties
1120          */
1121 
1122         if (verticalTextPosition == TOP) {
1123             if (horizontalTextPosition != CENTER) {
1124                 textR.y = 0;
1125             }
1126             else {
1127                 textR.y = -(textR.height + gap);
1128             }
1129         }
1130         else if (verticalTextPosition == CENTER) {
1131             textR.y = (iconR.height / 2) - (textR.height / 2);
1132         }
1133         else { // (verticalTextPosition == BOTTOM)
1134             if (horizontalTextPosition != CENTER) {
1135                 textR.y = iconR.height - textR.height;
1136             }
1137             else {
1138                 textR.y = (iconR.height + gap);
1139             }
1140         }
1141 
1142         if (horizontalTextPosition == LEFT) {
1143             textR.x = -(textR.width + gap);
1144         }
1145         else if (horizontalTextPosition == CENTER) {
1146             textR.x = (iconR.width / 2) - (textR.width / 2);
1147         }
1148         else { // (horizontalTextPosition == RIGHT)
1149             textR.x = (iconR.width + gap);
1150         }
1151 
1152         // WARNING: DefaultTreeCellEditor uses a shortened version of
1153         // this algorithm to position it's Icon. If you change how this
1154         // is calculated, be sure and update DefaultTreeCellEditor too.
1155 
1156         /* labelR is the rectangle that contains iconR and textR.
1157          * Move it to its proper position given the labelAlignment
1158          * properties.
1159          *
1160          * To avoid actually allocating a Rectangle, Rectangle.union
1161          * has been inlined below.
1162          */
1163         int labelR_x = Math.min(iconR.x, textR.x);
1164         int labelR_width = Math.max(iconR.x + iconR.width,
1165                                     textR.x + textR.width) - labelR_x;
1166         int labelR_y = Math.min(iconR.y, textR.y);
1167         int labelR_height = Math.max(iconR.y + iconR.height,
1168                                      textR.y + textR.height) - labelR_y;
1169 
1170         int dx, dy;
1171 
1172         if (verticalAlignment == TOP) {
1173             dy = viewR.y - labelR_y;
1174         }
1175         else if (verticalAlignment == CENTER) {
1176             dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
1177         }
1178         else { // (verticalAlignment == BOTTOM)
1179             dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
1180         }
1181 
1182         if (horizontalAlignment == LEFT) {
1183             dx = viewR.x - labelR_x;
1184         }
1185         else if (horizontalAlignment == RIGHT) {
1186             dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
1187         }
1188         else { // (horizontalAlignment == CENTER)
1189             dx = (viewR.x + (viewR.width / 2)) -
1190                  (labelR_x + (labelR_width / 2));
1191         }
1192 
1193         /* Translate textR and glypyR by dx,dy.
1194          */
1195 
1196         textR.x += dx;
1197         textR.y += dy;
1198 
1199         iconR.x += dx;
1200         iconR.y += dy;
1201 
1202         if (lsb < 0) {
1203             // lsb is negative. Shift the x location so that the text is
1204             // visually drawn at the right location.
1205             textR.x -= lsb;
1206 
1207             textR.width += lsb;
1208         }
1209         if (rsb > 0) {
1210             textR.width -= rsb;
1211         }
1212 
1213         return text;
1214     }
1215 
1216 
1217     /**
1218      * Paints a component to the specified <code>Graphics</code>.
1219      * This method is primarily useful to render
1220      * <code>Component</code>s that don't exist as part of the visible
1221      * containment hierarchy, but are used for rendering.  For
1222      * example, if you are doing your own rendering and want to render
1223      * some text (or even HTML), you could make use of
1224      * <code>JLabel</code>'s text rendering support and have it paint
1225      * directly by way of this method, without adding the label to the
1226      * visible containment hierarchy.
1227      * <p>
1228      * This method makes use of <code>CellRendererPane</code> to handle
1229      * the actual painting, and is only recommended if you use one
1230      * component for rendering.  If you make use of multiple components
1231      * to handle the rendering, as <code>JTable</code> does, use
1232      * <code>CellRendererPane</code> directly.  Otherwise, as described
1233      * below, you could end up with a <code>CellRendererPane</code>
1234      * per <code>Component</code>.
1235      * <p>
1236      * If <code>c</code>'s parent is not a <code>CellRendererPane</code>,
1237      * a new <code>CellRendererPane</code> is created, <code>c</code> is
1238      * added to it, and the <code>CellRendererPane</code> is added to
1239      * <code>p</code>.  If <code>c</code>'s parent is a
1240      * <code>CellRendererPane</code> and the <code>CellRendererPane</code>s
1241      * parent is not <code>p</code>, it is added to <code>p</code>.
1242      * <p>
1243      * The component should either descend from <code>JComponent</code>
1244      * or be another kind of lightweight component.
1245      * A lightweight component is one whose "lightweight" property
1246      * (returned by the <code>Component</code>
1247      * <code>isLightweight</code> method)
1248      * is true. If the Component is not lightweight, bad things map happen:
1249      * crashes, exceptions, painting problems...
1250      *
1251      * @param g  the <code>Graphics</code> object to draw on
1252      * @param c  the <code>Component</code> to draw
1253      * @param p  the intermediate <code>Container</code>
1254      * @param x  an int specifying the left side of the area draw in, in pixels,
1255      *           measured from the left edge of the graphics context
1256      * @param y  an int specifying the top of the area to draw in, in pixels
1257      *           measured down from the top edge of the graphics context
1258      * @param w  an int specifying the width of the area draw in, in pixels
1259      * @param h  an int specifying the height of the area draw in, in pixels
1260      *
1261      * @see CellRendererPane
1262      * @see java.awt.Component#isLightweight
1263      */
1264     public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
1265         getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
1266     }
1267 
1268     /**
1269      * Paints a component to the specified <code>Graphics</code>.  This
1270      * is a cover method for
1271      * {@link #paintComponent(Graphics,Component,Container,int,int,int,int)}.
1272      * Refer to it for more information.
1273      *
1274      * @param g  the <code>Graphics</code> object to draw on
1275      * @param c  the <code>Component</code> to draw
1276      * @param p  the intermediate <code>Container</code>
1277      * @param r  the <code>Rectangle</code> to draw in
1278      *
1279      * @see #paintComponent(Graphics,Component,Container,int,int,int,int)
1280      * @see CellRendererPane
1281      */
1282     public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
1283         paintComponent(g, c, p, r.x, r.y, r.width, r.height);
1284     }
1285 
1286 
1287     /*
1288      * Ensures that cell renderer <code>c</code> has a
1289      * <code>ComponentShell</code> parent and that
1290      * the shell's parent is p.
1291      */
1292     private static CellRendererPane getCellRendererPane(Component c, Container p) {
1293         Container shell = c.getParent();
1294         if (shell instanceof CellRendererPane) {
1295             if (shell.getParent() != p) {
1296                 p.add(shell);
1297             }
1298         } else {
1299             shell = new CellRendererPane();
1300             shell.add(c);
1301             p.add(shell);
1302         }
1303         return (CellRendererPane)shell;
1304     }
1305 
1306     /**
1307      * A simple minded look and feel change: ask each node in the tree
1308      * to <code>updateUI()</code> -- that is, to initialize its UI property
1309      * with the current look and feel.
1310      *
1311      * @param c the component
1312      */
1313     public static void updateComponentTreeUI(Component c) {
1314         updateComponentTreeUI0(c);
1315         c.invalidate();
1316         c.validate();
1317         c.repaint();
1318     }
1319 
1320     private static void updateComponentTreeUI0(Component c) {
1321         if (c instanceof JComponent) {
1322             JComponent jc = (JComponent) c;
1323             jc.updateUI();
1324             JPopupMenu jpm =jc.getComponentPopupMenu();
1325             if(jpm != null) {
1326                 updateComponentTreeUI(jpm);
1327             }
1328         }
1329         Component[] children = null;
1330         if (c instanceof JMenu) {
1331             children = ((JMenu)c).getMenuComponents();
1332         }
1333         else if (c instanceof Container) {
1334             children = ((Container)c).getComponents();
1335         }
1336         if (children != null) {
1337             for (Component child : children) {
1338                 updateComponentTreeUI0(child);
1339             }
1340         }
1341     }
1342 
1343 
1344     /**
1345      * Causes <i>doRun.run()</i> to be executed asynchronously on the
1346      * AWT event dispatching thread.  This will happen after all
1347      * pending AWT events have been processed.  This method should
1348      * be used when an application thread needs to update the GUI.
1349      * In the following example the <code>invokeLater</code> call queues
1350      * the <code>Runnable</code> object <code>doHelloWorld</code>
1351      * on the event dispatching thread and
1352      * then prints a message.
1353      * <pre>
1354      * Runnable doHelloWorld = new Runnable() {
1355      *     public void run() {
1356      *         System.out.println("Hello World on " + Thread.currentThread());
1357      *     }
1358      * };
1359      *
1360      * SwingUtilities.invokeLater(doHelloWorld);
1361      * System.out.println("This might well be displayed before the other message.");
1362      * </pre>
1363      * If invokeLater is called from the event dispatching thread --
1364      * for example, from a JButton's ActionListener -- the <i>doRun.run()</i> will
1365      * still be deferred until all pending events have been processed.
1366      * Note that if the <i>doRun.run()</i> throws an uncaught exception
1367      * the event dispatching thread will unwind (not the current thread).
1368      * <p>
1369      * Additional documentation and examples for this method can be
1370      * found in
1371      * <A HREF="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html">Concurrency in Swing</a>.
1372      * <p>
1373      * As of 1.3 this method is just a cover for <code>java.awt.EventQueue.invokeLater()</code>.
1374      * <p>
1375      * Unlike the rest of Swing, this method can be invoked from any thread.
1376      *
1377      * @param doRun the instance of {@code Runnable}
1378      * @see #invokeAndWait
1379      */
1380     public static void invokeLater(Runnable doRun) {
1381         EventQueue.invokeLater(doRun);
1382     }
1383 
1384 
1385     /**
1386      * Causes <code>doRun.run()</code> to be executed synchronously on the
1387      * AWT event dispatching thread.  This call blocks until
1388      * all pending AWT events have been processed and (then)
1389      * <code>doRun.run()</code> returns. This method should
1390      * be used when an application thread needs to update the GUI.
1391      * It shouldn't be called from the event dispatching thread.
1392      * Here's an example that creates a new application thread
1393      * that uses <code>invokeAndWait</code> to print a string from the event
1394      * dispatching thread and then, when that's finished, print
1395      * a string from the application thread.
1396      * <pre>
1397      * final Runnable doHelloWorld = new Runnable() {
1398      *     public void run() {
1399      *         System.out.println("Hello World on " + Thread.currentThread());
1400      *     }
1401      * };
1402      *
1403      * Thread appThread = new Thread() {
1404      *     public void run() {
1405      *         try {
1406      *             SwingUtilities.invokeAndWait(doHelloWorld);
1407      *         }
1408      *         catch (Exception e) {
1409      *             e.printStackTrace();
1410      *         }
1411      *         System.out.println("Finished on " + Thread.currentThread());
1412      *     }
1413      * };
1414      * appThread.start();
1415      * </pre>
1416      * Note that if the <code>Runnable.run</code> method throws an
1417      * uncaught exception
1418      * (on the event dispatching thread) it's caught and rethrown, as
1419      * an <code>InvocationTargetException</code>, on the caller's thread.
1420      * <p>
1421      * Additional documentation and examples for this method can be
1422      * found in
1423      * <A HREF="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html">Concurrency in Swing</a>.
1424      * <p>
1425      * As of 1.3 this method is just a cover for
1426      * <code>java.awt.EventQueue.invokeAndWait()</code>.
1427      *
1428      * @param doRun the instance of {@code Runnable}
1429      * @exception  InterruptedException if we're interrupted while waiting for
1430      *             the event dispatching thread to finish executing
1431      *             <code>doRun.run()</code>
1432      * @exception  InvocationTargetException  if an exception is thrown
1433      *             while running <code>doRun</code>
1434      *
1435      * @see #invokeLater
1436      */
1437     public static void invokeAndWait(final Runnable doRun)
1438         throws InterruptedException, InvocationTargetException
1439     {
1440         EventQueue.invokeAndWait(doRun);
1441     }
1442 
1443     /**
1444      * Returns true if the current thread is an AWT event dispatching thread.
1445      * <p>
1446      * As of 1.3 this method is just a cover for
1447      * <code>java.awt.EventQueue.isDispatchThread()</code>.
1448      *
1449      * @return true if the current thread is an AWT event dispatching thread
1450      */
1451     public static boolean isEventDispatchThread()
1452     {
1453         return EventQueue.isDispatchThread();
1454     }
1455 
1456 
1457     /*
1458      * --- Accessibility Support ---
1459      *
1460      */
1461 
1462     /**
1463      * Get the index of this object in its accessible parent.<p>
1464      *
1465      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1466      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1467      * of using this method.
1468      *
1469      * @param c the component
1470      * @return -1 of this object does not have an accessible parent.
1471      * Otherwise, the index of the child in its accessible parent.
1472      */
1473     public static int getAccessibleIndexInParent(Component c) {
1474         return c.getAccessibleContext().getAccessibleIndexInParent();
1475     }
1476 
1477     /**
1478      * Returns the <code>Accessible</code> child contained at the
1479      * local coordinate <code>Point</code>, if one exists.
1480      * Otherwise returns <code>null</code>.
1481      *
1482      * @param c the component
1483      * @param p the local coordinate
1484      * @return the <code>Accessible</code> at the specified location,
1485      *    if it exists; otherwise <code>null</code>
1486      */
1487     public static Accessible getAccessibleAt(Component c, Point p) {
1488         if (c instanceof Container) {
1489             return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p);
1490         } else if (c instanceof Accessible) {
1491             Accessible a = (Accessible) c;
1492             if (a != null) {
1493                 AccessibleContext ac = a.getAccessibleContext();
1494                 if (ac != null) {
1495                     AccessibleComponent acmp;
1496                     Point location;
1497                     int nchildren = ac.getAccessibleChildrenCount();
1498                     for (int i=0; i < nchildren; i++) {
1499                         a = ac.getAccessibleChild(i);
1500                         if ((a != null)) {
1501                             ac = a.getAccessibleContext();
1502                             if (ac != null) {
1503                                 acmp = ac.getAccessibleComponent();
1504                                 if ((acmp != null) && (acmp.isShowing())) {
1505                                     location = acmp.getLocation();
1506                                     Point np = new Point(p.x-location.x,
1507                                                          p.y-location.y);
1508                                     if (acmp.contains(np)){
1509                                         return a;
1510                                     }
1511                                 }
1512                             }
1513                         }
1514                     }
1515                 }
1516             }
1517             return (Accessible) c;
1518         }
1519         return null;
1520     }
1521 
1522     /**
1523      * Get the state of this object. <p>
1524      *
1525      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1526      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1527      * of using this method.
1528      *
1529      * @param c the component
1530      * @return an instance of AccessibleStateSet containing the current state
1531      * set of the object
1532      * @see AccessibleState
1533      */
1534     public static AccessibleStateSet getAccessibleStateSet(Component c) {
1535         return c.getAccessibleContext().getAccessibleStateSet();
1536     }
1537 
1538     /**
1539      * Returns the number of accessible children in the object.  If all
1540      * of the children of this object implement Accessible, than this
1541      * method should return the number of children of this object. <p>
1542      *
1543      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1544      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1545      * of using this method.
1546      *
1547      * @param c the component
1548      * @return the number of accessible children in the object.
1549      */
1550     public static int getAccessibleChildrenCount(Component c) {
1551         return c.getAccessibleContext().getAccessibleChildrenCount();
1552     }
1553 
1554     /**
1555      * Return the nth Accessible child of the object. <p>
1556      *
1557      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1558      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1559      * of using this method.
1560      *
1561      * @param c the component
1562      * @param i zero-based index of child
1563      * @return the nth Accessible child of the object
1564      */
1565     public static Accessible getAccessibleChild(Component c, int i) {
1566         return c.getAccessibleContext().getAccessibleChild(i);
1567     }
1568 
1569     /**
1570      * Return the child <code>Component</code> of the specified
1571      * <code>Component</code> that is the focus owner, if any.
1572      *
1573      * @param c the root of the <code>Component</code> hierarchy to
1574      *        search for the focus owner
1575      * @return the focus owner, or <code>null</code> if there is no focus
1576      *         owner, or if the focus owner is not <code>comp</code>, or a
1577      *         descendant of <code>comp</code>
1578      *
1579      * @see java.awt.KeyboardFocusManager#getFocusOwner
1580      * @deprecated As of 1.4, replaced by
1581      *   <code>KeyboardFocusManager.getFocusOwner()</code>.
1582      */
1583     @Deprecated
1584     public static Component findFocusOwner(Component c) {
1585         Component focusOwner = KeyboardFocusManager.
1586             getCurrentKeyboardFocusManager().getFocusOwner();
1587 
1588         // verify focusOwner is a descendant of c
1589         for (Component temp = focusOwner; temp != null;
1590              temp = (temp instanceof Window) ? null : temp.getParent())
1591         {
1592             if (temp == c) {
1593                 return focusOwner;
1594             }
1595         }
1596 
1597         return null;
1598     }
1599 
1600     /**
1601      * If c is a JRootPane descendant return its JRootPane ancestor.
1602      * If c is a RootPaneContainer then return its JRootPane.
1603      *
1604      * @param c the component
1605      * @return the JRootPane for Component c or {@code null}.
1606      */
1607     public static JRootPane getRootPane(Component c) {
1608         if (c instanceof RootPaneContainer) {
1609             return ((RootPaneContainer)c).getRootPane();
1610         }
1611         for( ; c != null; c = c.getParent()) {
1612             if (c instanceof JRootPane) {
1613                 return (JRootPane)c;
1614             }
1615         }
1616         return null;
1617     }
1618 
1619 
1620     /**
1621      * Returns the root component for the current component tree.
1622      *
1623      * @param c the component
1624      * @return the first ancestor of c that's a Window or the last Applet ancestor
1625      */
1626     public static Component getRoot(Component c) {
1627         Component applet = null;
1628         for(Component p = c; p != null; p = p.getParent()) {
1629             if (p instanceof Window) {
1630                 return p;
1631             }
1632             if (p instanceof Applet) {
1633                 applet = p;
1634             }
1635         }
1636         return applet;
1637     }
1638 
1639     static JComponent getPaintingOrigin(JComponent c) {
1640         Container p = c;
1641         while ((p = p.getParent()) instanceof JComponent) {
1642             JComponent jp = (JComponent) p;
1643             if (jp.isPaintingOrigin()) {
1644                 return jp;
1645             }
1646         }
1647         return null;
1648     }
1649 
1650     /**
1651      * Process the key bindings for the <code>Component</code> associated with
1652      * <code>event</code>. This method is only useful if
1653      * <code>event.getComponent()</code> does not descend from
1654      * <code>JComponent</code>, or your are not invoking
1655      * <code>super.processKeyEvent</code> from within your
1656      * <code>JComponent</code> subclass. <code>JComponent</code>
1657      * automatically processes bindings from within its
1658      * <code>processKeyEvent</code> method, hence you rarely need
1659      * to directly invoke this method.
1660      *
1661      * @param event KeyEvent used to identify which bindings to process, as
1662      *              well as which Component has focus.
1663      * @return true if a binding has found and processed
1664      * @since 1.4
1665      */
1666     public static boolean processKeyBindings(KeyEvent event) {
1667         if (event != null) {
1668             if (event.isConsumed()) {
1669                 return false;
1670             }
1671 
1672             Component component = event.getComponent();
1673             boolean pressed = (event.getID() == KeyEvent.KEY_PRESSED);
1674 
1675             if (!isValidKeyEventForKeyBindings(event)) {
1676                 return false;
1677             }
1678             // Find the first JComponent in the ancestor hierarchy, and
1679             // invoke processKeyBindings on it
1680             while (component != null) {
1681                 if (component instanceof JComponent) {
1682                     return ((JComponent)component).processKeyBindings(
1683                                                    event, pressed);
1684                 }
1685                 if ((component instanceof Applet) ||
1686                     (component instanceof Window)) {
1687                     // No JComponents, if Window or Applet parent, process
1688                     // WHEN_IN_FOCUSED_WINDOW bindings.
1689                     return JComponent.processKeyBindingsForAllComponents(
1690                                   event, (Container)component, pressed);
1691                 }
1692                 component = component.getParent();
1693             }
1694         }
1695         return false;
1696     }
1697 
1698     /**
1699      * Returns true if the <code>e</code> is a valid KeyEvent to use in
1700      * processing the key bindings associated with JComponents.
1701      */
1702     static boolean isValidKeyEventForKeyBindings(KeyEvent e) {
1703         return true;
1704     }
1705 
1706     /**
1707      * Invokes <code>actionPerformed</code> on <code>action</code> if
1708      * <code>action</code> is enabled (and non-{@code null}). The command for the
1709      * ActionEvent is determined by:
1710      * <ol>
1711      *   <li>If the action was registered via
1712      *       <code>registerKeyboardAction</code>, then the command string
1713      *       passed in ({@code null} will be used if {@code null} was passed in).
1714      *   <li>Action value with name Action.ACTION_COMMAND_KEY, unless {@code null}.
1715      *   <li>String value of the KeyEvent, unless <code>getKeyChar</code>
1716      *       returns KeyEvent.CHAR_UNDEFINED..
1717      * </ol>
1718      * This will return true if <code>action</code> is non-{@code null} and
1719      * actionPerformed is invoked on it.
1720      *
1721      * @param action an action
1722      * @param ks a key stroke
1723      * @param event a key event
1724      * @param sender a sender
1725      * @param modifiers action modifiers
1726      * @return {@code true} if {@code action} is non-{@code null} and
1727      *         actionPerformed is invoked on it.
1728      *
1729      * @since 1.3
1730      */
1731     public static boolean notifyAction(Action action, KeyStroke ks,
1732                                        KeyEvent event, Object sender,
1733                                        int modifiers) {
1734         if (action == null) {
1735             return false;
1736         }
1737         if (action instanceof UIAction) {
1738             if (!((UIAction)action).isEnabled(sender)) {
1739                 return false;
1740             }
1741         }
1742         else if (!action.isEnabled()) {
1743             return false;
1744         }
1745         Object commandO;
1746         boolean stayNull;
1747 
1748         // Get the command object.
1749         commandO = action.getValue(Action.ACTION_COMMAND_KEY);
1750         if (commandO == null && (action instanceof JComponent.ActionStandin)) {
1751             // ActionStandin is used for historical reasons to support
1752             // registerKeyboardAction with a null value.
1753             stayNull = true;
1754         }
1755         else {
1756             stayNull = false;
1757         }
1758 
1759         // Convert it to a string.
1760         String command;
1761 
1762         if (commandO != null) {
1763             command = commandO.toString();
1764         }
1765         else if (!stayNull && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
1766             command = String.valueOf(event.getKeyChar());
1767         }
1768         else {
1769             // Do null for undefined chars, or if registerKeyboardAction
1770             // was called with a null.
1771             command = null;
1772         }
1773         action.actionPerformed(new ActionEvent(sender,
1774                         ActionEvent.ACTION_PERFORMED, command, event.getWhen(),
1775                         modifiers));
1776         return true;
1777     }
1778 
1779 
1780     /**
1781      * Convenience method to change the UI InputMap for <code>component</code>
1782      * to <code>uiInputMap</code>. If <code>uiInputMap</code> is {@code null},
1783      * this removes any previously installed UI InputMap.
1784      *
1785      * @param component a component
1786      * @param type a type
1787      * @param uiInputMap an {@code InputMap}
1788      * @since 1.3
1789      */
1790     public static void replaceUIInputMap(JComponent component, int type,
1791                                          InputMap uiInputMap) {
1792         InputMap map = component.getInputMap(type, (uiInputMap != null));
1793 
1794         while (map != null) {
1795             InputMap parent = map.getParent();
1796             if (parent == null || (parent instanceof UIResource)) {
1797                 map.setParent(uiInputMap);
1798                 return;
1799             }
1800             map = parent;
1801         }
1802     }
1803 
1804 
1805     /**
1806      * Convenience method to change the UI ActionMap for <code>component</code>
1807      * to <code>uiActionMap</code>. If <code>uiActionMap</code> is {@code null},
1808      * this removes any previously installed UI ActionMap.
1809      *
1810      * @param component a component
1811      * @param uiActionMap an {@code ActionMap}
1812      * @since 1.3
1813      */
1814     public static void replaceUIActionMap(JComponent component,
1815                                           ActionMap uiActionMap) {
1816         ActionMap map = component.getActionMap((uiActionMap != null));
1817 
1818         while (map != null) {
1819             ActionMap parent = map.getParent();
1820             if (parent == null || (parent instanceof UIResource)) {
1821                 map.setParent(uiActionMap);
1822                 return;
1823             }
1824             map = parent;
1825         }
1826     }
1827 
1828 
1829     /**
1830      * Returns the InputMap provided by the UI for condition
1831      * <code>condition</code> in component <code>component</code>.
1832      * <p>This will return {@code null} if the UI has not installed an InputMap
1833      * of the specified type.
1834      *
1835      * @param component a component
1836      * @param condition a condition
1837      * @return the {@code ActionMap} provided by the UI for {@code condition}
1838      *         in the component, or {@code null} if the UI has not installed
1839      *         an InputMap of the specified type.
1840      * @since 1.3
1841      */
1842     public static InputMap getUIInputMap(JComponent component, int condition) {
1843         InputMap map = component.getInputMap(condition, false);
1844         while (map != null) {
1845             InputMap parent = map.getParent();
1846             if (parent instanceof UIResource) {
1847                 return parent;
1848             }
1849             map = parent;
1850         }
1851         return null;
1852     }
1853 
1854     /**
1855      * Returns the ActionMap provided by the UI
1856      * in component <code>component</code>.
1857      * <p>This will return {@code null} if the UI has not installed an ActionMap.
1858      *
1859      * @param component a component
1860      * @return the {@code ActionMap} provided by the UI in the component,
1861      *         or {@code null} if the UI has not installed an ActionMap.
1862      * @since 1.3
1863      */
1864     public static ActionMap getUIActionMap(JComponent component) {
1865         ActionMap map = component.getActionMap(false);
1866         while (map != null) {
1867             ActionMap parent = map.getParent();
1868             if (parent instanceof UIResource) {
1869                 return parent;
1870             }
1871             map = parent;
1872         }
1873         return null;
1874     }
1875 
1876 
1877     // Don't use String, as it's not guaranteed to be unique in a Hashtable.
1878     private static final Object sharedOwnerFrameKey =
1879        new StringBuffer("SwingUtilities.sharedOwnerFrame");
1880 
1881     @SuppressWarnings("serial") // JDK-implementation class
1882     static class SharedOwnerFrame extends Frame implements WindowListener {
1883         public void addNotify() {
1884             super.addNotify();
1885             installListeners();
1886         }
1887 
1888         /**
1889          * Install window listeners on owned windows to watch for displayability changes
1890          */
1891         void installListeners() {
1892             Window[] windows = getOwnedWindows();
1893             for (Window window : windows) {
1894                 if (window != null) {
1895                     window.removeWindowListener(this);
1896                     window.addWindowListener(this);
1897                 }
1898             }
1899         }
1900 
1901         /**
1902          * Watches for displayability changes and disposes shared instance if there are no
1903          * displayable children left.
1904          */
1905         public void windowClosed(WindowEvent e) {
1906             synchronized(getTreeLock()) {
1907                 Window[] windows = getOwnedWindows();
1908                 for (Window window : windows) {
1909                     if (window != null) {
1910                         if (window.isDisplayable()) {
1911                             return;
1912                         }
1913                         window.removeWindowListener(this);
1914                     }
1915                 }
1916                 dispose();
1917             }
1918         }
1919         public void windowOpened(WindowEvent e) {
1920         }
1921         public void windowClosing(WindowEvent e) {
1922         }
1923         public void windowIconified(WindowEvent e) {
1924         }
1925         public void windowDeiconified(WindowEvent e) {
1926         }
1927         public void windowActivated(WindowEvent e) {
1928         }
1929         public void windowDeactivated(WindowEvent e) {
1930         }
1931 
1932         @SuppressWarnings("deprecation")
1933         public void show() {
1934             // This frame can never be shown
1935         }
1936         public void dispose() {
1937             try {
1938                 getToolkit().getSystemEventQueue();
1939                 super.dispose();
1940             } catch (Exception e) {
1941                 // untrusted code not allowed to dispose
1942             }
1943         }
1944     }
1945 
1946     /**
1947      * Returns a toolkit-private, shared, invisible Frame
1948      * to be the owner for JDialogs and JWindows created with
1949      * {@code null} owners.
1950      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1951      * returns true.
1952      * @see java.awt.GraphicsEnvironment#isHeadless
1953      */
1954     static Frame getSharedOwnerFrame() throws HeadlessException {
1955         Frame sharedOwnerFrame =
1956             (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
1957         if (sharedOwnerFrame == null) {
1958             sharedOwnerFrame = new SharedOwnerFrame();
1959             SwingUtilities.appContextPut(sharedOwnerFrameKey,
1960                                          sharedOwnerFrame);
1961         }
1962         return sharedOwnerFrame;
1963     }
1964 
1965     /**
1966      * Returns a SharedOwnerFrame's shutdown listener to dispose the SharedOwnerFrame
1967      * if it has no more displayable children.
1968      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1969      * returns true.
1970      * @see java.awt.GraphicsEnvironment#isHeadless
1971      */
1972     static WindowListener getSharedOwnerFrameShutdownListener() throws HeadlessException {
1973         Frame sharedOwnerFrame = getSharedOwnerFrame();
1974         return (WindowListener)sharedOwnerFrame;
1975     }
1976 
1977     /* Don't make these AppContext accessors public or protected --
1978      * since AppContext is in sun.awt in 1.2, we shouldn't expose it
1979      * even indirectly with a public API.
1980      */
1981     // REMIND(aim): phase out use of 4 methods below since they
1982     // are just private covers for AWT methods (?)
1983 
1984     static Object appContextGet(Object key) {
1985         return AppContext.getAppContext().get(key);
1986     }
1987 
1988     static void appContextPut(Object key, Object value) {
1989         AppContext.getAppContext().put(key, value);
1990     }
1991 
1992     static void appContextRemove(Object key) {
1993         AppContext.getAppContext().remove(key);
1994     }
1995 
1996 
1997     static Class<?> loadSystemClass(String className) throws ClassNotFoundException {
1998         ReflectUtil.checkPackageAccess(className);
1999         return Class.forName(className, true, Thread.currentThread().
2000                              getContextClassLoader());
2001     }
2002 
2003 
2004    /*
2005      * Convenience function for determining ComponentOrientation.  Helps us
2006      * avoid having Munge directives throughout the code.
2007      */
2008     static boolean isLeftToRight( Component c ) {
2009         return c.getComponentOrientation().isLeftToRight();
2010     }
2011     private SwingUtilities() {
2012         throw new Error("SwingUtilities is just a container for static methods");
2013     }
2014 
2015     /**
2016      * Returns true if the Icon <code>icon</code> is an instance of
2017      * ImageIcon, and the image it contains is the same as <code>image</code>.
2018      */
2019     static boolean doesIconReferenceImage(Icon icon, Image image) {
2020         Image iconImage = (icon != null && (icon instanceof ImageIcon)) ?
2021                            ((ImageIcon)icon).getImage() : null;
2022         return (iconImage == image);
2023     }
2024 
2025     /**
2026      * Returns index of the first occurrence of <code>mnemonic</code>
2027      * within string <code>text</code>. Matching algorithm is not
2028      * case-sensitive.
2029      *
2030      * @param text The text to search through, may be {@code null}
2031      * @param mnemonic The mnemonic to find the character for.
2032      * @return index into the string if exists, otherwise -1
2033      */
2034     static int findDisplayedMnemonicIndex(String text, int mnemonic) {
2035         if (text == null || mnemonic == '\0') {
2036             return -1;
2037         }
2038 
2039         char uc = Character.toUpperCase((char)mnemonic);
2040         char lc = Character.toLowerCase((char)mnemonic);
2041 
2042         int uci = text.indexOf(uc);
2043         int lci = text.indexOf(lc);
2044 
2045         if (uci == -1) {
2046             return lci;
2047         } else if(lci == -1) {
2048             return uci;
2049         } else {
2050             return (lci < uci) ? lci : uci;
2051         }
2052     }
2053 
2054     /**
2055      * Stores the position and size of
2056      * the inner painting area of the specified component
2057      * in <code>r</code> and returns <code>r</code>.
2058      * The position and size specify the bounds of the component,
2059      * adjusted so as not to include the border area (the insets).
2060      * This method is useful for classes
2061      * that implement painting code.
2062      *
2063      * @param c  the JComponent in question; if {@code null}, this method returns {@code null}
2064      * @param r  the Rectangle instance to be modified;
2065      *           may be {@code null}
2066      * @return {@code null} if the Component is {@code null};
2067      *         otherwise, returns the passed-in rectangle (if non-{@code null})
2068      *         or a new rectangle specifying position and size information
2069      *
2070      * @since 1.4
2071      */
2072     public static Rectangle calculateInnerArea(JComponent c, Rectangle r) {
2073         if (c == null) {
2074             return null;
2075         }
2076         Rectangle rect = r;
2077         Insets insets = c.getInsets();
2078 
2079         if (rect == null) {
2080             rect = new Rectangle();
2081         }
2082 
2083         rect.x = insets.left;
2084         rect.y = insets.top;
2085         rect.width = c.getWidth() - insets.left - insets.right;
2086         rect.height = c.getHeight() - insets.top - insets.bottom;
2087 
2088         return rect;
2089     }
2090 
2091     static void updateRendererOrEditorUI(Object rendererOrEditor) {
2092         if (rendererOrEditor == null) {
2093             return;
2094         }
2095 
2096         Component component = null;
2097 
2098         if (rendererOrEditor instanceof Component) {
2099             component = (Component)rendererOrEditor;
2100         }
2101         if (rendererOrEditor instanceof DefaultCellEditor) {
2102             component = ((DefaultCellEditor)rendererOrEditor).getComponent();
2103         }
2104 
2105         if (component != null) {
2106             SwingUtilities.updateComponentTreeUI(component);
2107         }
2108     }
2109 
2110     /**
2111      * Returns the first ancestor of the {@code component}
2112      * which is not an instance of {@link JLayer}.
2113      *
2114      * @param component {@code Component} to get
2115      * the first ancestor of, which is not a {@link JLayer} instance.
2116      *
2117      * @return the first ancestor of the {@code component}
2118      * which is not an instance of {@link JLayer}.
2119      * If such an ancestor can not be found, {@code null} is returned.
2120      *
2121      * @throws NullPointerException if {@code component} is {@code null}
2122      * @see JLayer
2123      *
2124      * @since 1.7
2125      */
2126     public static Container getUnwrappedParent(Component component) {
2127         Container parent = component.getParent();
2128         while(parent instanceof JLayer) {
2129             parent = parent.getParent();
2130         }
2131         return parent;
2132     }
2133 
2134     /**
2135      * Returns the first {@code JViewport}'s descendant
2136      * which is not an instance of {@code JLayer}.
2137      * If such a descendant can not be found, {@code null} is returned.
2138      *
2139      * If the {@code viewport}'s view component is not a {@code JLayer},
2140      * this method is equivalent to {@link JViewport#getView()}
2141      * otherwise {@link JLayer#getView()} will be recursively
2142      * called on all descending {@code JLayer}s.
2143      *
2144      * @param viewport {@code JViewport} to get the first descendant of,
2145      * which in not a {@code JLayer} instance.
2146      *
2147      * @return the first {@code JViewport}'s descendant
2148      * which is not an instance of {@code JLayer}.
2149      * If such a descendant can not be found, {@code null} is returned.
2150      *
2151      * @throws NullPointerException if {@code viewport} is {@code null}
2152      * @see JViewport#getView()
2153      * @see JLayer
2154      *
2155      * @since 1.7
2156      */
2157     public static Component getUnwrappedView(JViewport viewport) {
2158         Component view = viewport.getView();
2159         while (view instanceof JLayer) {
2160             view = ((JLayer)view).getView();
2161         }
2162         return view;
2163     }
2164 
2165    /**
2166      * Retrieves the validate root of a given container.
2167      *
2168      * If the container is contained within a {@code CellRendererPane}, this
2169      * method returns {@code null} due to the synthetic nature of the {@code
2170      * CellRendererPane}.
2171      * <p>
2172      * The component hierarchy must be displayable up to the toplevel component
2173      * (either a {@code Frame} or an {@code Applet} object.) Otherwise this
2174      * method returns {@code null}.
2175      * <p>
2176      * If the {@code visibleOnly} argument is {@code true}, the found validate
2177      * root and all its parents up to the toplevel component must also be
2178      * visible. Otherwise this method returns {@code null}.
2179      *
2180      * @return the validate root of the given container or null
2181      * @see java.awt.Component#isDisplayable()
2182      * @see java.awt.Component#isVisible()
2183      * @since 1.7
2184      */
2185     static Container getValidateRoot(Container c, boolean visibleOnly) {
2186         Container root = null;
2187 
2188         for (; c != null; c = c.getParent())
2189         {
2190             if (!c.isDisplayable() || c instanceof CellRendererPane) {
2191                 return null;
2192             }
2193             if (c.isValidateRoot()) {
2194                 root = c;
2195                 break;
2196             }
2197         }
2198 
2199         if (root == null) {
2200             return null;
2201         }
2202 
2203         for (; c != null; c = c.getParent()) {
2204             if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) {
2205                 return null;
2206             }
2207             if (c instanceof Window || c instanceof Applet) {
2208                 return root;
2209             }
2210         }
2211 
2212         return null;
2213     }
2214 }