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