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+ */
25+package javax.swing;
26+
27+import sun.swing.SwingUtilities2;
28+import sun.swing.UIAction;
29+
30+import java.applet.*;
31+
32+import java.awt.*;
33+import java.awt.event.*;
34+import java.awt.dnd.DropTarget;
35+
36+import java.util.Vector;
37+import java.util.Hashtable;
38+
39+import java.lang.reflect.*;
40+
41+import javax.accessibility.*;
42+import javax.swing.event.MenuDragMouseEvent;
43+import javax.swing.plaf.UIResource;
44+import javax.swing.text.View;
45+import java.security.AccessController;
46+import sun.security.action.GetPropertyAction;
47+
48+import sun.awt.AppContext;
49+
50+/**
51+ * A collection of utility methods for Swing.
52+ *
53+ * @author unknown
54+ */
55+public class SwingUtilities implements SwingConstants
56+{
57+ // These states are system-wide, rather than AppContext wide.
58+ private static boolean canAccessEventQueue = false;
59+ private static boolean eventQueueTested = false;
60+
61+ /**
62+ * Indicates if we should change the drop target when a
63+ * {@code TransferHandler} is set.
64+ */
65+ private static boolean suppressDropSupport;
66+
67+ /**
68+ * Indiciates if we've checked the system property for suppressing
69+ * drop support.
70+ */
71+ private static boolean checkedSuppressDropSupport;
72+
73+
74+ /**
75+ * Returns true if <code>setTransferHandler</code> should change the
76+ * <code>DropTarget</code>.
77+ */
78+ private static boolean getSuppressDropTarget() {
79+ if (!checkedSuppressDropSupport) {
80+ suppressDropSupport = Boolean.valueOf(
81+ AccessController.doPrivileged(
82+ new GetPropertyAction("suppressSwingDropSupport")));
83+ checkedSuppressDropSupport = true;
84+ }
85+ return suppressDropSupport;
86+ }
87+
88+ /**
89+ * Installs a {@code DropTarget} on the component as necessary for a
90+ * {@code TransferHandler} change.
91+ */
92+ static void installSwingDropTargetAsNecessary(Component c,
93+ TransferHandler t) {
94+
95+ if (!getSuppressDropTarget()) {
96+ DropTarget dropHandler = c.getDropTarget();
97+ if ((dropHandler == null) || (dropHandler instanceof UIResource)) {
98+ if (t == null) {
99+ c.setDropTarget(null);
100+ } else if (!GraphicsEnvironment.isHeadless()) {
101+ c.setDropTarget(new TransferHandler.SwingDropTarget(c));
102+ }
103+ }
104+ }
105+ }
106+
107+ /**
108+ * Return true if <code>a</code> contains <code>b</code>
109+ */
110+ public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
111+ return b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
112+ b.y >= a.y && (b.y + b.height) <= (a.y + a.height);
113+ }
114+
115+ /**
116+ * Return the rectangle (0,0,bounds.width,bounds.height) for the component <code>aComponent</code>
117+ */
118+ public static Rectangle getLocalBounds(Component aComponent) {
119+ Rectangle b = new Rectangle(aComponent.getBounds());
120+ b.x = b.y = 0;
121+ return b;
122+ }
123+
124+
125+ /**
126+ * Returns the first <code>Window </code> ancestor of <code>c</code>, or
127+ * {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
128+ *
129+ * @param c <code>Component</code> to get <code>Window</code> ancestor
130+ * of.
131+ * @return the first <code>Window </code> ancestor of <code>c</code>, or
132+ * {@code null} if <code>c</code> is not contained inside a
133+ * <code>Window</code>.
134+ * @since 1.3
135+ */
136+ public static Window getWindowAncestor(Component c) {
137+ for(Container p = c.getParent(); p != null; p = p.getParent()) {
138+ if (p instanceof Window) {
139+ return (Window)p;
140+ }
141+ }
142+ return null;
143+ }
144+
145+ /**
146+ * Converts the location <code>x</code> <code>y</code> to the
147+ * parents coordinate system, returning the location.
148+ */
149+ static Point convertScreenLocationToParent(Container parent,int x, int y) {
150+ for (Container p = parent; p != null; p = p.getParent()) {
151+ if (p instanceof Window) {
152+ Point point = new Point(x, y);
153+
154+ SwingUtilities.convertPointFromScreen(point, parent);
155+ return point;
156+ }
157+ }
158+ throw new Error("convertScreenLocationToParent: no window ancestor");
159+ }
160+
161+ /**
162+ * Convert a <code>aPoint</code> in <code>source</code> coordinate system to
163+ * <code>destination</code> coordinate system.
164+ * If <code>source</code> is {@code null}, <code>aPoint</code> is assumed to be in <code>destination</code>'s
165+ * root component coordinate system.
166+ * If <code>destination</code> is {@code null}, <code>aPoint</code> will be converted to <code>source</code>'s
167+ * root component coordinate system.
168+ * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aPoint</code>
169+ * without any conversion.
170+ */
171+ public static Point convertPoint(Component source,Point aPoint,Component destination) {
172+ Point p;
173+
174+ if(source == null && destination == null)
175+ return aPoint;
176+ if(source == null) {
177+ source = getWindowAncestor(destination);
178+ if(source == null)
179+ throw new Error("Source component not connected to component tree hierarchy");
180+ }
181+ p = new Point(aPoint);
182+ convertPointToScreen(p,source);
183+ if(destination == null) {
184+ destination = getWindowAncestor(source);
185+ if(destination == null)
186+ throw new Error("Destination component not connected to component tree hierarchy");
187+ }
188+ convertPointFromScreen(p,destination);
189+ return p;
190+ }
191+
192+ /**
193+ * Convert the point <code>(x,y)</code> in <code>source</code> coordinate system to
194+ * <code>destination</code> coordinate system.
195+ * If <code>source</code> is {@code null}, <code>(x,y)</code> is assumed to be in <code>destination</code>'s
196+ * root component coordinate system.
197+ * If <code>destination</code> is {@code null}, <code>(x,y)</code> will be converted to <code>source</code>'s
198+ * root component coordinate system.
199+ * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>(x,y)</code>
200+ * without any conversion.
201+ */
202+ public static Point convertPoint(Component source,int x, int y,Component destination) {
203+ Point point = new Point(x,y);
204+ return convertPoint(source,point,destination);
205+ }
206+
207+ /**
208+ * Convert the rectangle <code>aRectangle</code> in <code>source</code> coordinate system to
209+ * <code>destination</code> coordinate system.
210+ * If <code>source</code> is {@code null}, <code>aRectangle</code> is assumed to be in <code>destination</code>'s
211+ * root component coordinate system.
212+ * If <code>destination</code> is {@code null}, <code>aRectangle</code> will be converted to <code>source</code>'s
213+ * root component coordinate system.
214+ * If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aRectangle</code>
215+ * without any conversion.
216+ */
217+ public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
218+ Point point = new Point(aRectangle.x,aRectangle.y);
219+ point = convertPoint(source,point,destination);
220+ return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
221+ }
222+
223+ /**
224+ * Convenience method for searching above <code>comp</code> in the
225+ * component hierarchy and returns the first object of class <code>c</code> it
226+ * finds. Can return {@code null}, if a class <code>c</code> cannot be found.
227+ */
228+ public static Container getAncestorOfClass(Class<?> c, Component comp)
229+ {
230+ if(comp == null || c == null)
231+ return null;
232+
233+ Container parent = comp.getParent();
234+ while(parent != null && !(c.isInstance(parent)))
235+ parent = parent.getParent();
236+ return parent;
237+ }
238+
239+ /**
240+ * Convenience method for searching above <code>comp</code> in the
241+ * component hierarchy and returns the first object of <code>name</code> it
242+ * finds. Can return {@code null}, if <code>name</code> cannot be found.
243+ */
244+ public static Container getAncestorNamed(String name, Component comp) {
245+ if(comp == null || name == null)
246+ return null;
247+
248+ Container parent = comp.getParent();
249+ while(parent != null && !(name.equals(parent.getName())))
250+ parent = parent.getParent();
251+ return parent;
252+ }
253+
254+ /**
255+ * Returns the deepest visible descendent Component of <code>parent</code>
256+ * that contains the location <code>x</code>, <code>y</code>.
257+ * If <code>parent</code> does not contain the specified location,
258+ * then <code>null</code> is returned. If <code>parent</code> is not a
259+ * container, or none of <code>parent</code>'s visible descendents
260+ * contain the specified location, <code>parent</code> is returned.
261+ *
262+ * @param parent the root component to begin the search
263+ * @param x the x target location
264+ * @param y the y target location
265+ */
266+ public static Component getDeepestComponentAt(Component parent, int x, int y) {
267+ if (!parent.contains(x, y)) {
268+ return null;
269+ }
270+ if (parent instanceof Container) {
271+ Component components[] = ((Container)parent).getComponents();
272+ for (Component comp : components) {
273+ if (comp != null && comp.isVisible()) {
274+ Point loc = comp.getLocation();
275+ if (comp instanceof Container) {
276+ comp = getDeepestComponentAt(comp, x - loc.x, y - loc.y);
277+ } else {
278+ comp = comp.getComponentAt(x - loc.x, y - loc.y);
279+ }
280+ if (comp != null && comp.isVisible()) {
281+ return comp;
282+ }
283+ }
284+ }
285+ }
286+ return parent;
287+ }
288+
289+
290+ /**
291+ * Returns a MouseEvent similar to <code>sourceEvent</code> except that its x
292+ * and y members have been converted to <code>destination</code>'s coordinate
293+ * system. If <code>source</code> is {@code null}, <code>sourceEvent</code> x and y members
294+ * are assumed to be into <code>destination</code>'s root component coordinate system.
295+ * If <code>destination</code> is <code>null</code>, the
296+ * returned MouseEvent will be in <code>source</code>'s coordinate system.
297+ * <code>sourceEvent</code> will not be changed. A new event is returned.
298+ * the <code>source</code> field of the returned event will be set
299+ * to <code>destination</code> if destination is non-{@code null}
300+ * use the translateMouseEvent() method to translate a mouse event from
301+ * one component to another without changing the source.
302+ */
303+ public static MouseEvent convertMouseEvent(Component source,
304+ MouseEvent sourceEvent,
305+ Component destination) {
306+ Point p = convertPoint(source,new Point(sourceEvent.getX(),
307+ sourceEvent.getY()),
308+ destination);
309+ Component newSource;
310+
311+ if(destination != null)
312+ newSource = destination;
313+ else
314+ newSource = source;
315+
316+ MouseEvent newEvent;
317+ if (sourceEvent instanceof MouseWheelEvent) {
318+ MouseWheelEvent sourceWheelEvent = (MouseWheelEvent)sourceEvent;
319+ newEvent = new MouseWheelEvent(newSource,
320+ sourceWheelEvent.getID(),
321+ sourceWheelEvent.getWhen(),
322+ sourceWheelEvent.getModifiers(),
323+ p.x,p.y,
324+ sourceWheelEvent.getXOnScreen(),
325+ sourceWheelEvent.getYOnScreen(),
326+ sourceWheelEvent.getClickCount(),
327+ sourceWheelEvent.isPopupTrigger(),
328+ sourceWheelEvent.getScrollType(),
329+ sourceWheelEvent.getScrollAmount(),
330+ sourceWheelEvent.getWheelRotation());
331+ }
332+ else if (sourceEvent instanceof MenuDragMouseEvent) {
333+ MenuDragMouseEvent sourceMenuDragEvent = (MenuDragMouseEvent)sourceEvent;
334+ newEvent = new MenuDragMouseEvent(newSource,
335+ sourceMenuDragEvent.getID(),
336+ sourceMenuDragEvent.getWhen(),
337+ sourceMenuDragEvent.getModifiers(),
338+ p.x,p.y,
339+ sourceMenuDragEvent.getXOnScreen(),
340+ sourceMenuDragEvent.getYOnScreen(),
341+ sourceMenuDragEvent.getClickCount(),
342+ sourceMenuDragEvent.isPopupTrigger(),
343+ sourceMenuDragEvent.getPath(),
344+ sourceMenuDragEvent.getMenuSelectionManager());
345+ }
346+ else {
347+ newEvent = new MouseEvent(newSource,
348+ sourceEvent.getID(),
349+ sourceEvent.getWhen(),
350+ sourceEvent.getModifiers(),
351+ p.x,p.y,
352+ sourceEvent.getXOnScreen(),
353+ sourceEvent.getYOnScreen(),
354+ sourceEvent.getClickCount(),
355+ sourceEvent.isPopupTrigger(),
356+ MouseEvent.NOBUTTON );
357+ }
358+ return newEvent;
359+ }
360+
361+
362+ /**
363+ * Convert a point from a component's coordinate system to
364+ * screen coordinates.
365+ *
366+ * @param p a Point object (converted to the new coordinate system)
367+ * @param c a Component object
368+ */
369+ public static void convertPointToScreen(Point p,Component c) {
370+ Rectangle b;
371+ int x,y;
372+
373+ do {
374+ if(c instanceof JComponent) {
375+ x = c.getX();
376+ y = c.getY();
377+ } else if(c instanceof java.applet.Applet ||
378+ c instanceof java.awt.Window) {
379+ try {
380+ Point pp = c.getLocationOnScreen();
381+ x = pp.x;
382+ y = pp.y;
383+ } catch (IllegalComponentStateException icse) {
384+ x = c.getX();
385+ y = c.getY();
386+ }
387+ } else {
388+ x = c.getX();
389+ y = c.getY();
390+ }
391+
392+ p.x += x;
393+ p.y += y;
394+
395+ if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
396+ break;
397+ c = c.getParent();
398+ } while(c != null);
399+ }
400+
401+ /**
402+ * Convert a point from a screen coordinates to a component's
403+ * coordinate system
404+ *
405+ * @param p a Point object (converted to the new coordinate system)
406+ * @param c a Component object
407+ */
408+ public static void convertPointFromScreen(Point p,Component c) {
409+ Rectangle b;
410+ int x,y;
411+
412+ do {
413+ if(c instanceof JComponent) {
414+ x = c.getX();
415+ y = c.getY();
416+ } else if(c instanceof java.applet.Applet ||
417+ c instanceof java.awt.Window) {
418+ try {
419+ Point pp = c.getLocationOnScreen();
420+ x = pp.x;
421+ y = pp.y;
422+ } catch (IllegalComponentStateException icse) {
423+ x = c.getX();
424+ y = c.getY();
425+ }
426+ } else {
427+ x = c.getX();
428+ y = c.getY();
429+ }
430+
431+ p.x -= x;
432+ p.y -= y;
433+
434+ if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
435+ break;
436+ c = c.getParent();
437+ } while(c != null);
438+ }
439+
440+ /**
441+ * Returns the first <code>Window </code> ancestor of <code>c</code>, or
442+ * {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
443+ * <p>
444+ * Note: This method provides the same functionality as
445+ * <code>getWindowAncestor</code>.
446+ *
447+ * @param c <code>Component</code> to get <code>Window</code> ancestor
448+ * of.
449+ * @return the first <code>Window </code> ancestor of <code>c</code>, or
450+ * {@code null} if <code>c</code> is not contained inside a
451+ * <code>Window</code>.
452+ */
453+ public static Window windowForComponent(Component c) {
454+ return getWindowAncestor(c);
455+ }
456+
457+ /**
458+ * Return <code>true</code> if a component <code>a</code> descends from a component <code>b</code>
459+ */
460+ public static boolean isDescendingFrom(Component a,Component b) {
461+ if(a == b)
462+ return true;
463+ for(Container p = a.getParent();p!=null;p=p.getParent())
464+ if(p == b)
465+ return true;
466+ return false;
467+ }
468+
469+
470+ /**
471+ * Convenience to calculate the intersection of two rectangles
472+ * without allocating a new rectangle.
473+ * If the two rectangles don't intersect,
474+ * then the returned rectangle begins at (0,0)
475+ * and has zero width and height.
476+ *
477+ * @param x the X coordinate of the first rectangle's top-left point
478+ * @param y the Y coordinate of the first rectangle's top-left point
479+ * @param width the width of the first rectangle
480+ * @param height the height of the first rectangle
481+ * @param dest the second rectangle
482+ *
483+ * @return <code>dest</code>, modified to specify the intersection
484+ */
485+ public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
486+ int x1 = (x > dest.x) ? x : dest.x;
487+ int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
488+ int y1 = (y > dest.y) ? y : dest.y;
489+ int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));
490+
491+ dest.x = x1;
492+ dest.y = y1;
493+ dest.width = x2 - x1;
494+ dest.height = y2 - y1;
495+
496+ // If rectangles don't intersect, return zero'd intersection.
497+ if (dest.width < 0 || dest.height < 0) {
498+ dest.x = dest.y = dest.width = dest.height = 0;
499+ }
500+
501+ return dest;
502+ }
503+
504+ /**
505+ * Convenience method that calculates the union of two rectangles
506+ * without allocating a new rectangle.
507+ *
508+ * @param x the x-coordinate of the first rectangle
509+ * @param y the y-coordinate of the first rectangle
510+ * @param width the width of the first rectangle
511+ * @param height the height of the first rectangle
512+ * @param dest the coordinates of the second rectangle; the union
513+ * of the two rectangles is returned in this rectangle
514+ * @return the <code>dest</code> <code>Rectangle</code>
515+ */
516+ public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
517+ int x1 = (x < dest.x) ? x : dest.x;
518+ int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
519+ int y1 = (y < dest.y) ? y : dest.y;
520+ int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);
521+
522+ dest.x = x1;
523+ dest.y = y1;
524+ dest.width = (x2 - x1);
525+ dest.height= (y2 - y1);
526+ return dest;
527+ }
528+
529+ /**
530+ * Convenience returning an array of rect representing the regions within
531+ * <code>rectA</code> that do not overlap with <code>rectB</code>. If the
532+ * two Rects do not overlap, returns an empty array
533+ */
534+ public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
535+ if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
536+ return new Rectangle[0];
537+ }
538+
539+ Rectangle t = new Rectangle();
540+ Rectangle a=null,b=null,c=null,d=null;
541+ Rectangle result[];
542+ int rectCount = 0;
543+
544+ /* rectA contains rectB */
545+ if (isRectangleContainingRectangle(rectA,rectB)) {
546+ t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
547+ if(t.width > 0 && t.height > 0) {
548+ a = new Rectangle(t);
549+ rectCount++;
550+ }
551+
552+ t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
553+ if(t.width > 0 && t.height > 0) {
554+ b = new Rectangle(t);
555+ rectCount++;
556+ }
557+
558+ t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width;
559+ t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
560+ if(t.width > 0 && t.height > 0) {
561+ c = new Rectangle(t);
562+ rectCount++;
563+ }
564+
565+ t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - (rectB.x + rectB.width);
566+ t.height = rectA.height;
567+ if(t.width > 0 && t.height > 0) {
568+ d = new Rectangle(t);
569+ rectCount++;
570+ }
571+ } else {
572+ /* 1 */
573+ if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
574+ if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
575+
576+ t.x = rectA.x; t.y = rectB.y + rectB.height;
577+ t.width = rectA.width; t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
578+ if(t.width > 0 && t.height > 0) {
579+ a = t;
580+ rectCount++;
581+ }
582+ } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
583+ t.setBounds((rectB.x + rectB.width), rectA.y,
584+ (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
585+ if(t.width > 0 && t.height > 0) {
586+ a = t;
587+ rectCount++;
588+ }
589+ } else {
590+ t.setBounds((rectB.x + rectB.width), rectA.y,
591+ (rectA.x + rectA.width) - (rectB.x + rectB.width),
592+ (rectB.y + rectB.height) - rectA.y);
593+ if(t.width > 0 && t.height > 0) {
594+ a = new Rectangle(t);
595+ rectCount++;
596+ }
597+
598+ t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
599+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
600+ if(t.width > 0 && t.height > 0) {
601+ b = new Rectangle(t);
602+ rectCount++;
603+ }
604+ }
605+ } else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
606+ if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
607+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
608+ if(t.width > 0 && t.height > 0) {
609+ a = t;
610+ rectCount++;
611+ }
612+ } else {
613+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
614+ if(t.width > 0 && t.height > 0) {
615+ a = new Rectangle(t);
616+ rectCount++;
617+ }
618+ t.setBounds((rectB.x + rectB.width), rectB.y,
619+ (rectA.x + rectA.width) - (rectB.x + rectB.width),
620+ (rectA.y + rectA.height) - rectB.y);
621+ if(t.width > 0 && t.height > 0) {
622+ b = new Rectangle(t);
623+ rectCount++;
624+ }
625+ }
626+ } else if (rectB.x <= rectA.x) {
627+ if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
628+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
629+ if(t.width>0 && t.height > 0) {
630+ a = new Rectangle(t);
631+ rectCount++;
632+ }
633+
634+ t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
635+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
636+ if(t.width > 0 && t.height > 0) {
637+ b = new Rectangle(t);
638+ rectCount++;
639+ }
640+ } else {
641+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
642+ if(t.width > 0 && t.height > 0) {
643+ a = new Rectangle(t);
644+ rectCount++;
645+ }
646+
647+ t.setBounds((rectB.x + rectB.width), rectB.y,
648+ (rectA.x + rectA.width) - (rectB.x + rectB.width),
649+ rectB.height);
650+ if(t.width > 0 && t.height > 0) {
651+ b = new Rectangle(t);
652+ rectCount++;
653+ }
654+
655+ t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
656+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
657+ if(t.width > 0 && t.height > 0) {
658+ c = new Rectangle(t);
659+ rectCount++;
660+ }
661+ }
662+ } else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
663+ if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
664+ t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
665+ if(t.width > 0 && t.height > 0) {
666+ a = t;
667+ rectCount++;
668+ }
669+ } else if (rectB.y <= rectA.y) {
670+ t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
671+ (rectB.y + rectB.height) - rectA.y);
672+ if(t.width > 0 && t.height > 0) {
673+ a = new Rectangle(t);
674+ rectCount++;
675+ }
676+
677+ t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
678+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
679+ if(t.width > 0 && t.height > 0) {
680+ b = new Rectangle(t);
681+ rectCount++;
682+ }
683+ } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
684+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
685+ if(t.width > 0 && t.height > 0) {
686+ a = new Rectangle(t);
687+ rectCount++;
688+ }
689+
690+ t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
691+ (rectA.y + rectA.height) - rectB.y);
692+ if(t.width > 0 && t.height > 0) {
693+ b = new Rectangle(t);
694+ rectCount++;
695+ }
696+ } else {
697+ t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
698+ if(t.width > 0 && t.height > 0) {
699+ a = new Rectangle(t);
700+ rectCount++;
701+ }
702+
703+ t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
704+ rectB.height);
705+ if(t.width > 0 && t.height > 0) {
706+ b = new Rectangle(t);
707+ rectCount++;
708+ }
709+
710+ t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
711+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
712+ if(t.width > 0 && t.height > 0) {
713+ c = new Rectangle(t);
714+ rectCount++;
715+ }
716+ }
717+ } else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
718+ if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
719+ t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
720+ if(t.width > 0 && t.height > 0) {
721+ a = new Rectangle(t);
722+ rectCount++;
723+ }
724+ t.setBounds((rectB.x + rectB.width), rectA.y,
725+ (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
726+ if(t.width > 0 && t.height > 0) {
727+ b = new Rectangle(t);
728+ rectCount++;
729+ }
730+ } else if (rectB.y <= rectA.y) {
731+ t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
732+ if(t.width > 0 && t.height > 0) {
733+ a = new Rectangle(t);
734+ rectCount++;
735+ }
736+
737+ t.setBounds(rectB.x, (rectB.y + rectB.height),
738+ rectB.width,
739+ (rectA.y + rectA.height) - (rectB.y + rectB.height));
740+ if(t.width > 0 && t.height > 0) {
741+ b = new Rectangle(t);
742+ rectCount++;
743+ }
744+
745+ t.setBounds((rectB.x + rectB.width), rectA.y,
746+ (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
747+ if(t.width > 0 && t.height > 0) {
748+ c = new Rectangle(t);
749+ rectCount++;
750+ }
751+ } else {
752+ t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
753+ if(t.width > 0 && t.height > 0) {
754+ a = new Rectangle(t);
755+ rectCount++;
756+ }
757+
758+ t.setBounds(rectB.x, rectA.y, rectB.width,
759+ rectB.y - rectA.y);
760+ if(t.width > 0 && t.height > 0) {
761+ b = new Rectangle(t);
762+ rectCount++;
763+ }
764+
765+ t.setBounds((rectB.x + rectB.width), rectA.y,
766+ (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
767+ if(t.width > 0 && t.height > 0) {
768+ c = new Rectangle(t);
769+ rectCount++;
770+ }
771+ }
772+ }
773+ }
774+
775+ result = new Rectangle[rectCount];
776+ rectCount = 0;
777+ if(a != null)
778+ result[rectCount++] = a;
779+ if(b != null)
780+ result[rectCount++] = b;
781+ if(c != null)
782+ result[rectCount++] = c;
783+ if(d != null)
784+ result[rectCount++] = d;
785+ return result;
786+ }
787+
788+ /**
789+ * Returns true if the mouse event specifies the left mouse button.
790+ *
791+ * @param anEvent a MouseEvent object
792+ * @return true if the left mouse button was active
793+ */
794+ public static boolean isLeftMouseButton(MouseEvent anEvent) {
795+ return ((anEvent.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+}