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