1 /*
   2  * Copyright (c) 1997, 2010, 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.getModifiers() & InputEvent.BUTTON1_MASK) != 0);
 796     }
 797 
 798     /**
 799      * Returns true if the mouse event specifies the middle mouse button.
 800      *
 801      * @param anEvent  a MouseEvent object
 802      * @return true if the middle mouse button was active
 803      */
 804     public static boolean isMiddleMouseButton(MouseEvent anEvent) {
 805         return ((anEvent.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK);
 806     }
 807 
 808     /**
 809      * Returns true if the mouse event specifies the right mouse button.
 810      *
 811      * @param anEvent  a MouseEvent object
 812      * @return true if the right mouse button was active
 813      */
 814     public static boolean isRightMouseButton(MouseEvent anEvent) {
 815         return ((anEvent.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK);
 816     }
 817 
 818     /**
 819      * Compute the width of the string using a font with the specified
 820      * "metrics" (sizes).
 821      *
 822      * @param fm   a FontMetrics object to compute with
 823      * @param str  the String to compute
 824      * @return an int containing the string width
 825      */
 826     public static int computeStringWidth(FontMetrics fm,String str) {
 827         // You can't assume that a string's width is the sum of its
 828         // characters' widths in Java2D -- it may be smaller due to
 829         // kerning, etc.
 830         return SwingUtilities2.stringWidth(null, fm, str);
 831     }
 832 
 833     /**
 834      * Compute and return the location of the icons origin, the
 835      * location of origin of the text baseline, and a possibly clipped
 836      * version of the compound labels string.  Locations are computed
 837      * relative to the viewR rectangle.
 838      * The JComponents orientation (LEADING/TRAILING) will also be taken
 839      * into account and translated into LEFT/RIGHT values accordingly.
 840      */
 841     public static String layoutCompoundLabel(JComponent c,
 842                                              FontMetrics fm,
 843                                              String text,
 844                                              Icon icon,
 845                                              int verticalAlignment,
 846                                              int horizontalAlignment,
 847                                              int verticalTextPosition,
 848                                              int horizontalTextPosition,
 849                                              Rectangle viewR,
 850                                              Rectangle iconR,
 851                                              Rectangle textR,
 852                                              int textIconGap)
 853     {
 854         boolean orientationIsLeftToRight = true;
 855         int     hAlign = horizontalAlignment;
 856         int     hTextPos = horizontalTextPosition;
 857 
 858         if (c != null) {
 859             if (!(c.getComponentOrientation().isLeftToRight())) {
 860                 orientationIsLeftToRight = false;
 861             }
 862         }
 863 
 864         // Translate LEADING/TRAILING values in horizontalAlignment
 865         // to LEFT/RIGHT values depending on the components orientation
 866         switch (horizontalAlignment) {
 867         case LEADING:
 868             hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
 869             break;
 870         case TRAILING:
 871             hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
 872             break;
 873         }
 874 
 875         // Translate LEADING/TRAILING values in horizontalTextPosition
 876         // to LEFT/RIGHT values depending on the components orientation
 877         switch (horizontalTextPosition) {
 878         case LEADING:
 879             hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
 880             break;
 881         case TRAILING:
 882             hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
 883             break;
 884         }
 885 
 886         return layoutCompoundLabelImpl(c,
 887                                        fm,
 888                                        text,
 889                                        icon,
 890                                        verticalAlignment,
 891                                        hAlign,
 892                                        verticalTextPosition,
 893                                        hTextPos,
 894                                        viewR,
 895                                        iconR,
 896                                        textR,
 897                                        textIconGap);
 898     }
 899 
 900     /**
 901      * Compute and return the location of the icons origin, the
 902      * location of origin of the text baseline, and a possibly clipped
 903      * version of the compound labels string.  Locations are computed
 904      * relative to the viewR rectangle.
 905      * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
 906      * values in horizontalTextPosition (they will default to RIGHT) and in
 907      * horizontalAlignment (they will default to CENTER).
 908      * Use the other version of layoutCompoundLabel() instead.
 909      */
 910     public static String layoutCompoundLabel(
 911         FontMetrics fm,
 912         String text,
 913         Icon icon,
 914         int verticalAlignment,
 915         int horizontalAlignment,
 916         int verticalTextPosition,
 917         int horizontalTextPosition,
 918         Rectangle viewR,
 919         Rectangle iconR,
 920         Rectangle textR,
 921         int textIconGap)
 922     {
 923         return layoutCompoundLabelImpl(null, fm, text, icon,
 924                                        verticalAlignment,
 925                                        horizontalAlignment,
 926                                        verticalTextPosition,
 927                                        horizontalTextPosition,
 928                                        viewR, iconR, textR, textIconGap);
 929     }
 930 
 931     /**
 932      * Compute and return the location of the icons origin, the
 933      * location of origin of the text baseline, and a possibly clipped
 934      * version of the compound labels string.  Locations are computed
 935      * relative to the viewR rectangle.
 936      * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
 937      * values in horizontalTextPosition (they will default to RIGHT) and in
 938      * horizontalAlignment (they will default to CENTER).
 939      * Use the other version of layoutCompoundLabel() instead.
 940      */
 941     private static String layoutCompoundLabelImpl(
 942         JComponent c,
 943         FontMetrics fm,
 944         String text,
 945         Icon icon,
 946         int verticalAlignment,
 947         int horizontalAlignment,
 948         int verticalTextPosition,
 949         int horizontalTextPosition,
 950         Rectangle viewR,
 951         Rectangle iconR,
 952         Rectangle textR,
 953         int textIconGap)
 954     {
 955         /* Initialize the icon bounds rectangle iconR.
 956          */
 957 
 958         if (icon != null) {
 959             iconR.width = icon.getIconWidth();
 960             iconR.height = icon.getIconHeight();
 961         }
 962         else {
 963             iconR.width = iconR.height = 0;
 964         }
 965 
 966         /* Initialize the text bounds rectangle textR.  If a null
 967          * or and empty String was specified we substitute "" here
 968          * and use 0,0,0,0 for textR.
 969          */
 970 
 971         boolean textIsEmpty = (text == null) || text.equals("");
 972         int lsb = 0;
 973         int rsb = 0;
 974         /* Unless both text and icon are non-null, we effectively ignore
 975          * the value of textIconGap.
 976          */
 977         int gap;
 978 
 979         View v;
 980         if (textIsEmpty) {
 981             textR.width = textR.height = 0;
 982             text = "";
 983             gap = 0;
 984         }
 985         else {
 986             int availTextWidth;
 987             gap = (icon == null) ? 0 : textIconGap;
 988 
 989             if (horizontalTextPosition == CENTER) {
 990                 availTextWidth = viewR.width;
 991             }
 992             else {
 993                 availTextWidth = viewR.width - (iconR.width + gap);
 994             }
 995             v = (c != null) ? (View) c.getClientProperty("html") : null;
 996             if (v != null) {
 997                 textR.width = Math.min(availTextWidth,
 998                                        (int) v.getPreferredSpan(View.X_AXIS));
 999                 textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
1000             } else {
1001                 textR.width = SwingUtilities2.stringWidth(c, fm, text);
1002                 lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
1003                 if (lsb < 0) {
1004                     // If lsb is negative, add it to the width and later
1005                     // adjust the x location. This gives more space than is
1006                     // actually needed.
1007                     // This is done like this for two reasons:
1008                     // 1. If we set the width to the actual bounds all
1009                     //    callers would have to account for negative lsb
1010                     //    (pref size calculations ONLY look at width of
1011                     //    textR)
1012                     // 2. You can do a drawString at the returned location
1013                     //    and the text won't be clipped.
1014                     textR.width -= lsb;
1015                 }
1016                 if (textR.width > availTextWidth) {
1017                     text = SwingUtilities2.clipString(c, fm, text,
1018                                                       availTextWidth);
1019                     textR.width = SwingUtilities2.stringWidth(c, fm, text);
1020                 }
1021                 textR.height = fm.getHeight();
1022             }
1023         }
1024 
1025 
1026         /* Compute textR.x,y given the verticalTextPosition and
1027          * horizontalTextPosition properties
1028          */
1029 
1030         if (verticalTextPosition == TOP) {
1031             if (horizontalTextPosition != CENTER) {
1032                 textR.y = 0;
1033             }
1034             else {
1035                 textR.y = -(textR.height + gap);
1036             }
1037         }
1038         else if (verticalTextPosition == CENTER) {
1039             textR.y = (iconR.height / 2) - (textR.height / 2);
1040         }
1041         else { // (verticalTextPosition == BOTTOM)
1042             if (horizontalTextPosition != CENTER) {
1043                 textR.y = iconR.height - textR.height;
1044             }
1045             else {
1046                 textR.y = (iconR.height + gap);
1047             }
1048         }
1049 
1050         if (horizontalTextPosition == LEFT) {
1051             textR.x = -(textR.width + gap);
1052         }
1053         else if (horizontalTextPosition == CENTER) {
1054             textR.x = (iconR.width / 2) - (textR.width / 2);
1055         }
1056         else { // (horizontalTextPosition == RIGHT)
1057             textR.x = (iconR.width + gap);
1058         }
1059 
1060         // WARNING: DefaultTreeCellEditor uses a shortened version of
1061         // this algorithm to position it's Icon. If you change how this
1062         // is calculated, be sure and update DefaultTreeCellEditor too.
1063 
1064         /* labelR is the rectangle that contains iconR and textR.
1065          * Move it to its proper position given the labelAlignment
1066          * properties.
1067          *
1068          * To avoid actually allocating a Rectangle, Rectangle.union
1069          * has been inlined below.
1070          */
1071         int labelR_x = Math.min(iconR.x, textR.x);
1072         int labelR_width = Math.max(iconR.x + iconR.width,
1073                                     textR.x + textR.width) - labelR_x;
1074         int labelR_y = Math.min(iconR.y, textR.y);
1075         int labelR_height = Math.max(iconR.y + iconR.height,
1076                                      textR.y + textR.height) - labelR_y;
1077 
1078         int dx, dy;
1079 
1080         if (verticalAlignment == TOP) {
1081             dy = viewR.y - labelR_y;
1082         }
1083         else if (verticalAlignment == CENTER) {
1084             dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
1085         }
1086         else { // (verticalAlignment == BOTTOM)
1087             dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
1088         }
1089 
1090         if (horizontalAlignment == LEFT) {
1091             dx = viewR.x - labelR_x;
1092         }
1093         else if (horizontalAlignment == RIGHT) {
1094             dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
1095         }
1096         else { // (horizontalAlignment == CENTER)
1097             dx = (viewR.x + (viewR.width / 2)) -
1098                  (labelR_x + (labelR_width / 2));
1099         }
1100 
1101         /* Translate textR and glypyR by dx,dy.
1102          */
1103 
1104         textR.x += dx;
1105         textR.y += dy;
1106 
1107         iconR.x += dx;
1108         iconR.y += dy;
1109 
1110         if (lsb < 0) {
1111             // lsb is negative. Shift the x location so that the text is
1112             // visually drawn at the right location.
1113             textR.x -= lsb;
1114 
1115             textR.width += lsb;
1116         }
1117         if (rsb > 0) {
1118             textR.width -= rsb;
1119         }
1120 
1121         return text;
1122     }
1123 
1124 
1125     /**
1126      * Paints a component to the specified <code>Graphics</code>.
1127      * This method is primarily useful to render
1128      * <code>Component</code>s that don't exist as part of the visible
1129      * containment hierarchy, but are used for rendering.  For
1130      * example, if you are doing your own rendering and want to render
1131      * some text (or even HTML), you could make use of
1132      * <code>JLabel</code>'s text rendering support and have it paint
1133      * directly by way of this method, without adding the label to the
1134      * visible containment hierarchy.
1135      * <p>
1136      * This method makes use of <code>CellRendererPane</code> to handle
1137      * the actual painting, and is only recommended if you use one
1138      * component for rendering.  If you make use of multiple components
1139      * to handle the rendering, as <code>JTable</code> does, use
1140      * <code>CellRendererPane</code> directly.  Otherwise, as described
1141      * below, you could end up with a <code>CellRendererPane</code>
1142      * per <code>Component</code>.
1143      * <p>
1144      * If <code>c</code>'s parent is not a <code>CellRendererPane</code>,
1145      * a new <code>CellRendererPane</code> is created, <code>c</code> is
1146      * added to it, and the <code>CellRendererPane</code> is added to
1147      * <code>p</code>.  If <code>c</code>'s parent is a
1148      * <code>CellRendererPane</code> and the <code>CellRendererPane</code>s
1149      * parent is not <code>p</code>, it is added to <code>p</code>.
1150      * <p>
1151      * The component should either descend from <code>JComponent</code>
1152      * or be another kind of lightweight component.
1153      * A lightweight component is one whose "lightweight" property
1154      * (returned by the <code>Component</code>
1155      * <code>isLightweight</code> method)
1156      * is true. If the Component is not lightweight, bad things map happen:
1157      * crashes, exceptions, painting problems...
1158      *
1159      * @param g  the <code>Graphics</code> object to draw on
1160      * @param c  the <code>Component</code> to draw
1161      * @param p  the intermediate <code>Container</code>
1162      * @param x  an int specifying the left side of the area draw in, in pixels,
1163      *           measured from the left edge of the graphics context
1164      * @param y  an int specifying the top of the area to draw in, in pixels
1165      *           measured down from the top edge of the graphics context
1166      * @param w  an int specifying the width of the area draw in, in pixels
1167      * @param h  an int specifying the height of the area draw in, in pixels
1168      *
1169      * @see CellRendererPane
1170      * @see java.awt.Component#isLightweight
1171      */
1172     public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
1173         getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
1174     }
1175 
1176     /**
1177      * Paints a component to the specified <code>Graphics</code>.  This
1178      * is a cover method for
1179      * {@link #paintComponent(Graphics,Component,Container,int,int,int,int)}.
1180      * Refer to it for more information.
1181      *
1182      * @param g  the <code>Graphics</code> object to draw on
1183      * @param c  the <code>Component</code> to draw
1184      * @param p  the intermediate <code>Container</code>
1185      * @param r  the <code>Rectangle</code> to draw in
1186      *
1187      * @see #paintComponent(Graphics,Component,Container,int,int,int,int)
1188      * @see CellRendererPane
1189      */
1190     public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
1191         paintComponent(g, c, p, r.x, r.y, r.width, r.height);
1192     }
1193 
1194 
1195     /*
1196      * Ensures that cell renderer <code>c</code> has a
1197      * <code>ComponentShell</code> parent and that
1198      * the shell's parent is p.
1199      */
1200     private static CellRendererPane getCellRendererPane(Component c, Container p) {
1201         Container shell = c.getParent();
1202         if (shell instanceof CellRendererPane) {
1203             if (shell.getParent() != p) {
1204                 p.add(shell);
1205             }
1206         } else {
1207             shell = new CellRendererPane();
1208             shell.add(c);
1209             p.add(shell);
1210         }
1211         return (CellRendererPane)shell;
1212     }
1213 
1214     /**
1215      * A simple minded look and feel change: ask each node in the tree
1216      * to <code>updateUI()</code> -- that is, to initialize its UI property
1217      * with the current look and feel.
1218      */
1219     public static void updateComponentTreeUI(Component c) {
1220         updateComponentTreeUI0(c);
1221         c.invalidate();
1222         c.validate();
1223         c.repaint();
1224     }
1225 
1226     private static void updateComponentTreeUI0(Component c) {
1227         if (c instanceof JComponent) {
1228             JComponent jc = (JComponent) c;
1229             jc.updateUI();
1230             JPopupMenu jpm =jc.getComponentPopupMenu();
1231             if(jpm != null) {
1232                 updateComponentTreeUI(jpm);
1233             }
1234         }
1235         Component[] children = null;
1236         if (c instanceof JMenu) {
1237             children = ((JMenu)c).getMenuComponents();
1238         }
1239         else if (c instanceof Container) {
1240             children = ((Container)c).getComponents();
1241         }
1242         if (children != null) {
1243             for (Component child : children) {
1244                 updateComponentTreeUI0(child);
1245             }
1246         }
1247     }
1248 
1249 
1250     /**
1251      * Causes <i>doRun.run()</i> to be executed asynchronously on the
1252      * AWT event dispatching thread.  This will happen after all
1253      * pending AWT events have been processed.  This method should
1254      * be used when an application thread needs to update the GUI.
1255      * In the following example the <code>invokeLater</code> call queues
1256      * the <code>Runnable</code> object <code>doHelloWorld</code>
1257      * on the event dispatching thread and
1258      * then prints a message.
1259      * <pre>
1260      * Runnable doHelloWorld = new Runnable() {
1261      *     public void run() {
1262      *         System.out.println("Hello World on " + Thread.currentThread());
1263      *     }
1264      * };
1265      *
1266      * SwingUtilities.invokeLater(doHelloWorld);
1267      * System.out.println("This might well be displayed before the other message.");
1268      * </pre>
1269      * If invokeLater is called from the event dispatching thread --
1270      * for example, from a JButton's ActionListener -- the <i>doRun.run()</i> will
1271      * still be deferred until all pending events have been processed.
1272      * Note that if the <i>doRun.run()</i> throws an uncaught exception
1273      * the event dispatching thread will unwind (not the current thread).
1274      * <p>
1275      * Additional documentation and examples for this method can be
1276      * found in
1277      * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a>,
1278      * in <em>The Java Tutorial</em>.
1279      * <p>
1280      * As of 1.3 this method is just a cover for <code>java.awt.EventQueue.invokeLater()</code>.
1281      * <p>
1282      * Unlike the rest of Swing, this method can be invoked from any thread.
1283      *
1284      * @see #invokeAndWait
1285      */
1286     public static void invokeLater(Runnable doRun) {
1287         EventQueue.invokeLater(doRun);
1288     }
1289 
1290 
1291     /**
1292      * Causes <code>doRun.run()</code> to be executed synchronously on the
1293      * AWT event dispatching thread.  This call blocks until
1294      * all pending AWT events have been processed and (then)
1295      * <code>doRun.run()</code> returns. This method should
1296      * be used when an application thread needs to update the GUI.
1297      * It shouldn't be called from the event dispatching thread.
1298      * Here's an example that creates a new application thread
1299      * that uses <code>invokeAndWait</code> to print a string from the event
1300      * dispatching thread and then, when that's finished, print
1301      * a string from the application thread.
1302      * <pre>
1303      * final Runnable doHelloWorld = new Runnable() {
1304      *     public void run() {
1305      *         System.out.println("Hello World on " + Thread.currentThread());
1306      *     }
1307      * };
1308      *
1309      * Thread appThread = new Thread() {
1310      *     public void run() {
1311      *         try {
1312      *             SwingUtilities.invokeAndWait(doHelloWorld);
1313      *         }
1314      *         catch (Exception e) {
1315      *             e.printStackTrace();
1316      *         }
1317      *         System.out.println("Finished on " + Thread.currentThread());
1318      *     }
1319      * };
1320      * appThread.start();
1321      * </pre>
1322      * Note that if the <code>Runnable.run</code> method throws an
1323      * uncaught exception
1324      * (on the event dispatching thread) it's caught and rethrown, as
1325      * an <code>InvocationTargetException</code>, on the caller's thread.
1326      * <p>
1327      * Additional documentation and examples for this method can be
1328      * found in
1329      * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a>,
1330      * in <em>The Java Tutorial</em>.
1331      * <p>
1332      * As of 1.3 this method is just a cover for
1333      * <code>java.awt.EventQueue.invokeAndWait()</code>.
1334      *
1335      * @exception  InterruptedException if we're interrupted while waiting for
1336      *             the event dispatching thread to finish excecuting
1337      *             <code>doRun.run()</code>
1338      * @exception  InvocationTargetException  if an exception is thrown
1339      *             while running <code>doRun</code>
1340      *
1341      * @see #invokeLater
1342      */
1343     public static void invokeAndWait(final Runnable doRun)
1344         throws InterruptedException, InvocationTargetException
1345     {
1346         EventQueue.invokeAndWait(doRun);
1347     }
1348 
1349     /**
1350      * Returns true if the current thread is an AWT event dispatching thread.
1351      * <p>
1352      * As of 1.3 this method is just a cover for
1353      * <code>java.awt.EventQueue.isDispatchThread()</code>.
1354      *
1355      * @return true if the current thread is an AWT event dispatching thread
1356      */
1357     public static boolean isEventDispatchThread()
1358     {
1359         return EventQueue.isDispatchThread();
1360     }
1361 
1362 
1363     /*
1364      * --- Accessibility Support ---
1365      *
1366      */
1367 
1368     /**
1369      * Get the index of this object in its accessible parent.<p>
1370      *
1371      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1372      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1373      * of using this method.
1374      *
1375      * @return -1 of this object does not have an accessible parent.
1376      * Otherwise, the index of the child in its accessible parent.
1377      */
1378     public static int getAccessibleIndexInParent(Component c) {
1379         return c.getAccessibleContext().getAccessibleIndexInParent();
1380     }
1381 
1382     /**
1383      * Returns the <code>Accessible</code> child contained at the
1384      * local coordinate <code>Point</code>, if one exists.
1385      * Otherwise returns <code>null</code>.
1386      *
1387      * @return the <code>Accessible</code> at the specified location,
1388      *    if it exists; otherwise <code>null</code>
1389      */
1390     public static Accessible getAccessibleAt(Component c, Point p) {
1391         if (c instanceof Container) {
1392             return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p);
1393         } else if (c instanceof Accessible) {
1394             Accessible a = (Accessible) c;
1395             if (a != null) {
1396                 AccessibleContext ac = a.getAccessibleContext();
1397                 if (ac != null) {
1398                     AccessibleComponent acmp;
1399                     Point location;
1400                     int nchildren = ac.getAccessibleChildrenCount();
1401                     for (int i=0; i < nchildren; i++) {
1402                         a = ac.getAccessibleChild(i);
1403                         if ((a != null)) {
1404                             ac = a.getAccessibleContext();
1405                             if (ac != null) {
1406                                 acmp = ac.getAccessibleComponent();
1407                                 if ((acmp != null) && (acmp.isShowing())) {
1408                                     location = acmp.getLocation();
1409                                     Point np = new Point(p.x-location.x,
1410                                                          p.y-location.y);
1411                                     if (acmp.contains(np)){
1412                                         return a;
1413                                     }
1414                                 }
1415                             }
1416                         }
1417                     }
1418                 }
1419             }
1420             return (Accessible) c;
1421         }
1422         return null;
1423     }
1424 
1425     /**
1426      * Get the state of this object. <p>
1427      *
1428      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1429      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1430      * of using this method.
1431      *
1432      * @return an instance of AccessibleStateSet containing the current state
1433      * set of the object
1434      * @see AccessibleState
1435      */
1436     public static AccessibleStateSet getAccessibleStateSet(Component c) {
1437         return c.getAccessibleContext().getAccessibleStateSet();
1438     }
1439 
1440     /**
1441      * Returns the number of accessible children in the object.  If all
1442      * of the children of this object implement Accessible, than this
1443      * method should return the number of children of this object. <p>
1444      *
1445      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1446      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1447      * of using this method.
1448      *
1449      * @return the number of accessible children in the object.
1450      */
1451     public static int getAccessibleChildrenCount(Component c) {
1452         return c.getAccessibleContext().getAccessibleChildrenCount();
1453     }
1454 
1455     /**
1456      * Return the nth Accessible child of the object. <p>
1457      *
1458      * Note: as of the Java 2 platform v1.3, it is recommended that developers call
1459      * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
1460      * of using this method.
1461      *
1462      * @param i zero-based index of child
1463      * @return the nth Accessible child of the object
1464      */
1465     public static Accessible getAccessibleChild(Component c, int i) {
1466         return c.getAccessibleContext().getAccessibleChild(i);
1467     }
1468 
1469     /**
1470      * Return the child <code>Component</code> of the specified
1471      * <code>Component</code> that is the focus owner, if any.
1472      *
1473      * @param c the root of the <code>Component</code> hierarchy to
1474      *        search for the focus owner
1475      * @return the focus owner, or <code>null</code> if there is no focus
1476      *         owner, or if the focus owner is not <code>comp</code>, or a
1477      *         descendant of <code>comp</code>
1478      *
1479      * @see java.awt.KeyboardFocusManager#getFocusOwner
1480      * @deprecated As of 1.4, replaced by
1481      *   <code>KeyboardFocusManager.getFocusOwner()</code>.
1482      */
1483     @Deprecated
1484     public static Component findFocusOwner(Component c) {
1485         Component focusOwner = KeyboardFocusManager.
1486             getCurrentKeyboardFocusManager().getFocusOwner();
1487 
1488         // verify focusOwner is a descendant of c
1489         for (Component temp = focusOwner; temp != null;
1490              temp = (temp instanceof Window) ? null : temp.getParent())
1491         {
1492             if (temp == c) {
1493                 return focusOwner;
1494             }
1495         }
1496 
1497         return null;
1498     }
1499 
1500     /**
1501      * If c is a JRootPane descendant return its JRootPane ancestor.
1502      * If c is a RootPaneContainer then return its JRootPane.
1503      * @return the JRootPane for Component c or {@code null}.
1504      */
1505     public static JRootPane getRootPane(Component c) {
1506         if (c instanceof RootPaneContainer) {
1507             return ((RootPaneContainer)c).getRootPane();
1508         }
1509         for( ; c != null; c = c.getParent()) {
1510             if (c instanceof JRootPane) {
1511                 return (JRootPane)c;
1512             }
1513         }
1514         return null;
1515     }
1516 
1517 
1518     /**
1519      * Returns the root component for the current component tree.
1520      * @return the first ancestor of c that's a Window or the last Applet ancestor
1521      */
1522     public static Component getRoot(Component c) {
1523         Component applet = null;
1524         for(Component p = c; p != null; p = p.getParent()) {
1525             if (p instanceof Window) {
1526                 return p;
1527             }
1528             if (p instanceof Applet) {
1529                 applet = p;
1530             }
1531         }
1532         return applet;
1533     }
1534 
1535     static JComponent getPaintingOrigin(JComponent c) {
1536         Container p = c;
1537         while ((p = p.getParent()) instanceof JComponent) {
1538             JComponent jp = (JComponent) p;
1539             if (jp.isPaintingOrigin()) {
1540                 return jp;
1541             }
1542         }
1543         return null;
1544     }
1545 
1546     /**
1547      * Process the key bindings for the <code>Component</code> associated with
1548      * <code>event</code>. This method is only useful if
1549      * <code>event.getComponent()</code> does not descend from
1550      * <code>JComponent</code>, or your are not invoking
1551      * <code>super.processKeyEvent</code> from within your
1552      * <code>JComponent</code> subclass. <code>JComponent</code>
1553      * automatically processes bindings from within its
1554      * <code>processKeyEvent</code> method, hence you rarely need
1555      * to directly invoke this method.
1556      *
1557      * @param event KeyEvent used to identify which bindings to process, as
1558      *              well as which Component has focus.
1559      * @return true if a binding has found and processed
1560      * @since 1.4
1561      */
1562     public static boolean processKeyBindings(KeyEvent event) {
1563         if (event != null) {
1564             if (event.isConsumed()) {
1565                 return false;
1566             }
1567 
1568             Component component = event.getComponent();
1569             boolean pressed = (event.getID() == KeyEvent.KEY_PRESSED);
1570 
1571             if (!isValidKeyEventForKeyBindings(event)) {
1572                 return false;
1573             }
1574             // Find the first JComponent in the ancestor hierarchy, and
1575             // invoke processKeyBindings on it
1576             while (component != null) {
1577                 if (component instanceof JComponent) {
1578                     return ((JComponent)component).processKeyBindings(
1579                                                    event, pressed);
1580                 }
1581                 if ((component instanceof Applet) ||
1582                     (component instanceof Window)) {
1583                     // No JComponents, if Window or Applet parent, process
1584                     // WHEN_IN_FOCUSED_WINDOW bindings.
1585                     return JComponent.processKeyBindingsForAllComponents(
1586                                   event, (Container)component, pressed);
1587                 }
1588                 component = component.getParent();
1589             }
1590         }
1591         return false;
1592     }
1593 
1594     /**
1595      * Returns true if the <code>e</code> is a valid KeyEvent to use in
1596      * processing the key bindings associated with JComponents.
1597      */
1598     static boolean isValidKeyEventForKeyBindings(KeyEvent e) {
1599         return true;
1600     }
1601 
1602     /**
1603      * Invokes <code>actionPerformed</code> on <code>action</code> if
1604      * <code>action</code> is enabled (and non-{@code null}). The command for the
1605      * ActionEvent is determined by:
1606      * <ol>
1607      *   <li>If the action was registered via
1608      *       <code>registerKeyboardAction</code>, then the command string
1609      *       passed in ({@code null} will be used if {@code null} was passed in).
1610      *   <li>Action value with name Action.ACTION_COMMAND_KEY, unless {@code null}.
1611      *   <li>String value of the KeyEvent, unless <code>getKeyChar</code>
1612      *       returns KeyEvent.CHAR_UNDEFINED..
1613      * </ol>
1614      * This will return true if <code>action</code> is non-{@code null} and
1615      * actionPerformed is invoked on it.
1616      *
1617      * @since 1.3
1618      */
1619     public static boolean notifyAction(Action action, KeyStroke ks,
1620                                        KeyEvent event, Object sender,
1621                                        int modifiers) {
1622         if (action == null) {
1623             return false;
1624         }
1625         if (action instanceof UIAction) {
1626             if (!((UIAction)action).isEnabled(sender)) {
1627                 return false;
1628             }
1629         }
1630         else if (!action.isEnabled()) {
1631             return false;
1632         }
1633         Object commandO;
1634         boolean stayNull;
1635 
1636         // Get the command object.
1637         commandO = action.getValue(Action.ACTION_COMMAND_KEY);
1638         if (commandO == null && (action instanceof JComponent.ActionStandin)) {
1639             // ActionStandin is used for historical reasons to support
1640             // registerKeyboardAction with a null value.
1641             stayNull = true;
1642         }
1643         else {
1644             stayNull = false;
1645         }
1646 
1647         // Convert it to a string.
1648         String command;
1649 
1650         if (commandO != null) {
1651             command = commandO.toString();
1652         }
1653         else if (!stayNull && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
1654             command = String.valueOf(event.getKeyChar());
1655         }
1656         else {
1657             // Do null for undefined chars, or if registerKeyboardAction
1658             // was called with a null.
1659             command = null;
1660         }
1661         action.actionPerformed(new ActionEvent(sender,
1662                         ActionEvent.ACTION_PERFORMED, command, event.getWhen(),
1663                         modifiers));
1664         return true;
1665     }
1666 
1667 
1668     /**
1669      * Convenience method to change the UI InputMap for <code>component</code>
1670      * to <code>uiInputMap</code>. If <code>uiInputMap</code> is {@code null},
1671      * this removes any previously installed UI InputMap.
1672      *
1673      * @since 1.3
1674      */
1675     public static void replaceUIInputMap(JComponent component, int type,
1676                                          InputMap uiInputMap) {
1677         InputMap map = component.getInputMap(type, (uiInputMap != null));
1678 
1679         while (map != null) {
1680             InputMap parent = map.getParent();
1681             if (parent == null || (parent instanceof UIResource)) {
1682                 map.setParent(uiInputMap);
1683                 return;
1684             }
1685             map = parent;
1686         }
1687     }
1688 
1689 
1690     /**
1691      * Convenience method to change the UI ActionMap for <code>component</code>
1692      * to <code>uiActionMap</code>. If <code>uiActionMap</code> is {@code null},
1693      * this removes any previously installed UI ActionMap.
1694      *
1695      * @since 1.3
1696      */
1697     public static void replaceUIActionMap(JComponent component,
1698                                           ActionMap uiActionMap) {
1699         ActionMap map = component.getActionMap((uiActionMap != null));
1700 
1701         while (map != null) {
1702             ActionMap parent = map.getParent();
1703             if (parent == null || (parent instanceof UIResource)) {
1704                 map.setParent(uiActionMap);
1705                 return;
1706             }
1707             map = parent;
1708         }
1709     }
1710 
1711 
1712     /**
1713      * Returns the InputMap provided by the UI for condition
1714      * <code>condition</code> in component <code>component</code>.
1715      * <p>This will return {@code null} if the UI has not installed a InputMap
1716      * of the specified type.
1717      *
1718      * @since 1.3
1719      */
1720     public static InputMap getUIInputMap(JComponent component, int condition) {
1721         InputMap map = component.getInputMap(condition, false);
1722         while (map != null) {
1723             InputMap parent = map.getParent();
1724             if (parent instanceof UIResource) {
1725                 return parent;
1726             }
1727             map = parent;
1728         }
1729         return null;
1730     }
1731 
1732     /**
1733      * Returns the ActionMap provided by the UI
1734      * in component <code>component</code>.
1735      * <p>This will return {@code null} if the UI has not installed an ActionMap.
1736      *
1737      * @since 1.3
1738      */
1739     public static ActionMap getUIActionMap(JComponent component) {
1740         ActionMap map = component.getActionMap(false);
1741         while (map != null) {
1742             ActionMap parent = map.getParent();
1743             if (parent instanceof UIResource) {
1744                 return parent;
1745             }
1746             map = parent;
1747         }
1748         return null;
1749     }
1750 
1751 
1752     // Don't use String, as it's not guaranteed to be unique in a Hashtable.
1753     private static final Object sharedOwnerFrameKey =
1754        new StringBuffer("SwingUtilities.sharedOwnerFrame");
1755 
1756     static class SharedOwnerFrame extends Frame implements WindowListener {
1757         public void addNotify() {
1758             super.addNotify();
1759             installListeners();
1760         }
1761 
1762         /**
1763          * Install window listeners on owned windows to watch for displayability changes
1764          */
1765         void installListeners() {
1766             Window[] windows = getOwnedWindows();
1767             for (Window window : windows) {
1768                 if (window != null) {
1769                     window.removeWindowListener(this);
1770                     window.addWindowListener(this);
1771                 }
1772             }
1773         }
1774 
1775         /**
1776          * Watches for displayability changes and disposes shared instance if there are no
1777          * displayable children left.
1778          */
1779         public void windowClosed(WindowEvent e) {
1780             synchronized(getTreeLock()) {
1781                 Window[] windows = getOwnedWindows();
1782                 for (Window window : windows) {
1783                     if (window != null) {
1784                         if (window.isDisplayable()) {
1785                             return;
1786                         }
1787                         window.removeWindowListener(this);
1788                     }
1789                 }
1790                 dispose();
1791             }
1792         }
1793         public void windowOpened(WindowEvent e) {
1794         }
1795         public void windowClosing(WindowEvent e) {
1796         }
1797         public void windowIconified(WindowEvent e) {
1798         }
1799         public void windowDeiconified(WindowEvent e) {
1800         }
1801         public void windowActivated(WindowEvent e) {
1802         }
1803         public void windowDeactivated(WindowEvent e) {
1804         }
1805 
1806         public void show() {
1807             // This frame can never be shown
1808         }
1809         public void dispose() {
1810             try {
1811                 getToolkit().getSystemEventQueue();
1812                 super.dispose();
1813             } catch (Exception e) {
1814                 // untrusted code not allowed to dispose
1815             }
1816         }
1817     }
1818 
1819     /**
1820      * Returns a toolkit-private, shared, invisible Frame
1821      * to be the owner for JDialogs and JWindows created with
1822      * {@code null} owners.
1823      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1824      * returns true.
1825      * @see java.awt.GraphicsEnvironment#isHeadless
1826      */
1827     static Frame getSharedOwnerFrame() throws HeadlessException {
1828         Frame sharedOwnerFrame =
1829             (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
1830         if (sharedOwnerFrame == null) {
1831             sharedOwnerFrame = new SharedOwnerFrame();
1832             SwingUtilities.appContextPut(sharedOwnerFrameKey,
1833                                          sharedOwnerFrame);
1834         }
1835         return sharedOwnerFrame;
1836     }
1837 
1838     /**
1839      * Returns a SharedOwnerFrame's shutdown listener to dispose the SharedOwnerFrame
1840      * if it has no more displayable children.
1841      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
1842      * returns true.
1843      * @see java.awt.GraphicsEnvironment#isHeadless
1844      */
1845     static WindowListener getSharedOwnerFrameShutdownListener() throws HeadlessException {
1846         Frame sharedOwnerFrame = getSharedOwnerFrame();
1847         return (WindowListener)sharedOwnerFrame;
1848     }
1849 
1850     /* Don't make these AppContext accessors public or protected --
1851      * since AppContext is in sun.awt in 1.2, we shouldn't expose it
1852      * even indirectly with a public API.
1853      */
1854     // REMIND(aim): phase out use of 4 methods below since they
1855     // are just private covers for AWT methods (?)
1856 
1857     static Object appContextGet(Object key) {
1858         return AppContext.getAppContext().get(key);
1859     }
1860 
1861     static void appContextPut(Object key, Object value) {
1862         AppContext.getAppContext().put(key, value);
1863     }
1864 
1865     static void appContextRemove(Object key) {
1866         AppContext.getAppContext().remove(key);
1867     }
1868 
1869 
1870     static Class<?> loadSystemClass(String className) throws ClassNotFoundException {
1871         return Class.forName(className, true, Thread.currentThread().
1872                              getContextClassLoader());
1873     }
1874 
1875 
1876    /*
1877      * Convenience function for determining ComponentOrientation.  Helps us
1878      * avoid having Munge directives throughout the code.
1879      */
1880     static boolean isLeftToRight( Component c ) {
1881         return c.getComponentOrientation().isLeftToRight();
1882     }
1883     private SwingUtilities() {
1884         throw new Error("SwingUtilities is just a container for static methods");
1885     }
1886 
1887     /**
1888      * Returns true if the Icon <code>icon</code> is an instance of
1889      * ImageIcon, and the image it contains is the same as <code>image</code>.
1890      */
1891     static boolean doesIconReferenceImage(Icon icon, Image image) {
1892         Image iconImage = (icon != null && (icon instanceof ImageIcon)) ?
1893                            ((ImageIcon)icon).getImage() : null;
1894         return (iconImage == image);
1895     }
1896 
1897     /**
1898      * Returns index of the first occurrence of <code>mnemonic</code>
1899      * within string <code>text</code>. Matching algorithm is not
1900      * case-sensitive.
1901      *
1902      * @param text The text to search through, may be {@code null}
1903      * @param mnemonic The mnemonic to find the character for.
1904      * @return index into the string if exists, otherwise -1
1905      */
1906     static int findDisplayedMnemonicIndex(String text, int mnemonic) {
1907         if (text == null || mnemonic == '\0') {
1908             return -1;
1909         }
1910 
1911         char uc = Character.toUpperCase((char)mnemonic);
1912         char lc = Character.toLowerCase((char)mnemonic);
1913 
1914         int uci = text.indexOf(uc);
1915         int lci = text.indexOf(lc);
1916 
1917         if (uci == -1) {
1918             return lci;
1919         } else if(lci == -1) {
1920             return uci;
1921         } else {
1922             return (lci < uci) ? lci : uci;
1923         }
1924     }
1925 
1926     /**
1927      * Stores the position and size of
1928      * the inner painting area of the specified component
1929      * in <code>r</code> and returns <code>r</code>.
1930      * The position and size specify the bounds of the component,
1931      * adjusted so as not to include the border area (the insets).
1932      * This method is useful for classes
1933      * that implement painting code.
1934      *
1935      * @param c  the JComponent in question; if {@code null}, this method returns {@code null}
1936      * @param r  the Rectangle instance to be modified;
1937      *           may be {@code null}
1938      * @return {@code null} if the Component is {@code null};
1939      *         otherwise, returns the passed-in rectangle (if non-{@code null})
1940      *         or a new rectangle specifying position and size information
1941      *
1942      * @since 1.4
1943      */
1944     public static Rectangle calculateInnerArea(JComponent c, Rectangle r) {
1945         if (c == null) {
1946             return null;
1947         }
1948         Rectangle rect = r;
1949         Insets insets = c.getInsets();
1950 
1951         if (rect == null) {
1952             rect = new Rectangle();
1953         }
1954 
1955         rect.x = insets.left;
1956         rect.y = insets.top;
1957         rect.width = c.getWidth() - insets.left - insets.right;
1958         rect.height = c.getHeight() - insets.top - insets.bottom;
1959 
1960         return rect;
1961     }
1962 
1963     static void updateRendererOrEditorUI(Object rendererOrEditor) {
1964         if (rendererOrEditor == null) {
1965             return;
1966         }
1967 
1968         Component component = null;
1969 
1970         if (rendererOrEditor instanceof Component) {
1971             component = (Component)rendererOrEditor;
1972         }
1973         if (rendererOrEditor instanceof DefaultCellEditor) {
1974             component = ((DefaultCellEditor)rendererOrEditor).getComponent();
1975         }
1976 
1977         if (component != null) {
1978             SwingUtilities.updateComponentTreeUI(component);
1979         }
1980     }
1981 
1982     /**
1983      * Returns the first ancestor of the {@code component}
1984      * which is not an instance of {@link JLayer}.
1985      *
1986      * @param component {@code Component} to get
1987      * the first ancestor of, which is not a {@link JLayer} instance.
1988      *
1989      * @return the first ancestor of the {@code component}
1990      * which is not an instance of {@link JLayer}.
1991      * If such an ancestor can not be found, {@code null} is returned.
1992      *
1993      * @throws NullPointerException if {@code component} is {@code null}
1994      * @see JLayer
1995      *
1996      * @since 1.7
1997      */
1998     public static Container getUnwrappedParent(Component component) {
1999         Container parent = component.getParent();
2000         while(parent instanceof JLayer) {
2001             parent = parent.getParent();
2002         }
2003         return parent;
2004     }
2005 
2006     /**
2007      * Returns the first {@code JViewport}'s descendant
2008      * which is not an instance of {@code JLayer}.
2009      * If such a descendant can not be found, {@code null} is returned.
2010      *
2011      * If the {@code viewport}'s view component is not a {@code JLayer},
2012      * this method is equivalent to {@link JViewport#getView()}
2013      * otherwise {@link JLayer#getView()} will be recursively
2014      * called on all descending {@code JLayer}s.
2015      *
2016      * @param viewport {@code JViewport} to get the first descendant of,
2017      * which in not a {@code JLayer} instance.
2018      *
2019      * @return the first {@code JViewport}'s descendant
2020      * which is not an instance of {@code JLayer}.
2021      * If such a descendant can not be found, {@code null} is returned.
2022      *
2023      * @throws NullPointerException if {@code viewport} is {@code null}
2024      * @see JViewport#getView()
2025      * @see JLayer
2026      *
2027      * @since 1.7
2028      */
2029     public static Component getUnwrappedView(JViewport viewport) {
2030         Component view = viewport.getView();
2031         while (view instanceof JLayer) {
2032             view = ((JLayer)view).getView();
2033         }
2034         return view;
2035     }
2036 
2037    /**
2038      * Retrieves the validate root of a given container.
2039      *
2040      * If the container is contained within a {@code CellRendererPane}, this
2041      * method returns {@code null} due to the synthetic nature of the {@code
2042      * CellRendererPane}.
2043      * <p>
2044      * The component hierarchy must be displayable up to the toplevel component
2045      * (either a {@code Frame} or an {@code Applet} object.) Otherwise this
2046      * method returns {@code null}.
2047      * <p>
2048      * If the {@code visibleOnly} argument is {@code true}, the found validate
2049      * root and all its parents up to the toplevel component must also be
2050      * visible. Otherwise this method returns {@code null}.
2051      *
2052      * @return the validate root of the given container or null
2053      * @see java.awt.Component#isDisplayable()
2054      * @see java.awt.Component#isVisible()
2055      * @since 1.7
2056      */
2057     static Container getValidateRoot(Container c, boolean visibleOnly) {
2058         Container root = null;
2059 
2060         for (; c != null; c = c.getParent())
2061         {
2062             if (!c.isDisplayable() || c instanceof CellRendererPane) {
2063                 return null;
2064             }
2065             if (c.isValidateRoot()) {
2066                 root = c;
2067                 break;
2068             }
2069         }
2070 
2071         if (root == null) {
2072             return null;
2073         }
2074 
2075         for (; c != null; c = c.getParent()) {
2076             if (!c.isDisplayable() || (visibleOnly && !c.isVisible())) {
2077                 return null;
2078             }
2079             if (c instanceof Window || c instanceof Applet) {
2080                 return root;
2081             }
2082         }
2083 
2084         return null;
2085     }
2086 }