History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/SwingUtilities.java (1 of 18352 files). Show all

Unified · Split

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