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