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