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