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