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