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