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