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