1 /* AWTUtilities.java -- Common utility methods for AWT and Swing.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java
.applet
.Applet
;
41 import java
.awt
.Component
;
42 import java
.awt
.Container
;
44 import java
.awt
.FontMetrics
;
45 import java
.awt
.Insets
;
46 import java
.awt
.Point
;
47 import java
.awt
.Rectangle
;
48 import java
.awt
.Toolkit
;
49 import java
.awt
.Window
;
50 import java
.awt
.event
.MouseEvent
;
51 import java
.util
.AbstractSequentialList
;
52 import java
.util
.List
;
53 import java
.util
.ListIterator
;
54 import java
.util
.NoSuchElementException
;
55 import java
.util
.WeakHashMap
;
56 import java
.lang
.reflect
.InvocationTargetException
;
59 * This class mirrors the javax.swing.SwingUtilities class. It
60 * provides commonly needed functionalities for AWT classes without
61 * the need to reference classes in the javax.swing package.
63 public class AWTUtilities
67 * This List implementation wraps the Component[] returned by
68 * {@link Container#getComponents()} and iterates over the visible Components
69 * in that array. This class is used in {@link #getVisibleChildren}.
71 static class VisibleComponentList
extends AbstractSequentialList
74 * The ListIterator for this List.
76 class VisibleComponentIterator
implements ListIterator
78 /** The current index in the Component[]. */
81 /** The index in the List of visible Components. */
85 * Creates a new VisibleComponentIterator that starts at the specified
86 * <code>listIndex</code>. The array of Components is searched from
87 * the beginning to find the matching array index.
89 * @param listIndex the index from where to begin iterating
91 VisibleComponentIterator(int listIndex
)
93 this.listIndex
= listIndex
;
94 int visibleComponentsFound
= 0;
95 for (index
= 0; visibleComponentsFound
!= listIndex
; index
++)
97 if (components
[index
].isVisible())
98 visibleComponentsFound
++;
103 * Returns <code>true</code> if there are more visible components in the
104 * array, <code>false</code> otherwise.
106 * @return <code>true</code> if there are more visible components in the
107 * array, <code>false</code> otherwise
109 public boolean hasNext()
111 boolean hasNext
= false;
112 for (int i
= index
; i
< components
.length
; i
++)
114 if (components
[i
].isVisible())
124 * Returns the next visible <code>Component</code> in the List.
126 * @return the next visible <code>Component</code> in the List
128 * @throws if there is no next element
133 for (; index
< components
.length
; index
++)
135 if (components
[index
].isVisible())
137 o
= components
[index
];
148 throw new NoSuchElementException();
152 * Returns <code>true</code> if there are more visible components in the
153 * array in the reverse direction, <code>false</code> otherwise.
155 * @return <code>true</code> if there are more visible components in the
156 * array in the reverse direction, <code>false</code> otherwise
158 public boolean hasPrevious()
160 boolean hasPrevious
= false;
161 for (int i
= index
- 1; i
>= 0; i
--)
163 if (components
[i
].isVisible())
173 * Returns the previous visible <code>Component</code> in the List.
175 * @return the previous visible <code>Component</code> in the List
177 * @throws NoSuchElementException if there is no previous element
179 public Object
previous()
182 for (index
--; index
>= 0; index
--)
184 if (components
[index
].isVisible())
186 o
= components
[index
];
196 throw new NoSuchElementException();
200 * Returns the index of the next element in the List.
202 * @return the index of the next element in the List
204 public int nextIndex()
206 return listIndex
+ 1;
210 * Returns the index of the previous element in the List.
212 * @return the index of the previous element in the List
214 public int previousIndex()
216 return listIndex
- 1;
220 * This operation is not supported because the List is immutable.
222 * @throws UnsupportedOperationException because the List is immutable
226 throw new UnsupportedOperationException
227 ("VisibleComponentList is immutable");
231 * This operation is not supported because the List is immutable.
233 * @param o not used here
235 * @throws UnsupportedOperationException because the List is immutable
237 public void set(Object o
)
239 throw new UnsupportedOperationException
240 ("VisibleComponentList is immutable");
244 * This operation is not supported because the List is immutable.
246 * @param o not used here
248 * @throws UnsupportedOperationException because the List is immutable
250 public void add(Object o
)
252 throw new UnsupportedOperationException
253 ("VisibleComponentList is immutable");
258 * The components over which we iterate. Only the visible components
259 * are returned by this List.
261 Component
[] components
;
264 * Creates a new instance of VisibleComponentList that wraps the specified
265 * <code>Component[]</code>.
267 * @param c the <code>Component[]</code> to be wrapped.
269 VisibleComponentList(Component
[] c
)
275 * Returns a {@link ListIterator} for iterating over this List.
277 * @return a {@link ListIterator} for iterating over this List
279 public ListIterator
listIterator(int index
)
281 return new VisibleComponentIterator(index
);
285 * Returns the number of visible components in the wrapped Component[].
287 * @return the number of visible components
291 int visibleComponents
= 0;
292 for (int i
= 0; i
< components
.length
; i
++)
293 if (components
[i
].isVisible())
295 return visibleComponents
;
300 * The cache for our List instances. We try to hold one instance of
301 * VisibleComponentList for each Component[] that is requested. Note
302 * that we use a WeakHashMap for caching, so that the cache itself
303 * does not keep the array or the List from beeing garbage collected
304 * if no other objects hold references to it.
306 static WeakHashMap visibleChildrenCache
= new WeakHashMap();
309 * Returns the visible children of a {@link Container}. This method is
310 * commonly needed in LayoutManagers, because they only have to layout
311 * the visible children of a Container.
313 * @param c the Container from which to extract the visible children
315 * @return the visible children of <code>c</code>
317 public static List
getVisibleChildren(Container c
)
319 Component
[] children
= c
.getComponents();
320 Object o
= visibleChildrenCache
.get(children
);
321 VisibleComponentList visibleChildren
= null;
324 visibleChildren
= new VisibleComponentList(children
);
325 visibleChildrenCache
.put(children
, visibleChildren
);
328 visibleChildren
= (VisibleComponentList
) o
;
330 return visibleChildren
;
334 * Calculates the portion of the base rectangle which is inside the
337 * @param base The rectangle to apply the insets to
338 * @param insets The insets to apply to the base rectangle
339 * @param ret A rectangle to use for storing the return value, or
342 * @return The calculated area inside the base rectangle and its insets,
343 * either stored in ret or a new Rectangle if ret is <code>null</code>
345 * @see #calculateInnerArea
347 public static Rectangle
calculateInsetArea(Rectangle base
, Insets insets
,
351 ret
= new Rectangle();
352 ret
.setBounds(base
.x
+ insets
.left
, base
.y
+ insets
.top
,
353 base
.width
- (insets
.left
+ insets
.right
),
354 base
.height
- (insets
.top
+ insets
.bottom
));
359 * Calculates the bounds of a component in the component's own coordinate
360 * space. The result has the same height and width as the component's
361 * bounds, but its location is set to (0,0).
363 * @param aComponent The component to measure
365 * @return The component's bounds in its local coordinate space
367 public static Rectangle
getLocalBounds(Component aComponent
)
369 Rectangle bounds
= aComponent
.getBounds();
370 return new Rectangle(0, 0, bounds
.width
, bounds
.height
);
374 * Returns the font metrics object for a given font. The metrics can be
375 * used to calculate crude bounding boxes and positioning information,
376 * for laying out components with textual elements.
378 * @param font The font to get metrics for
380 * @return The font's metrics
382 * @see java.awt.font.GlyphMetrics
384 public static FontMetrics
getFontMetrics(Font font
)
386 return Toolkit
.getDefaultToolkit().getFontMetrics(font
);
390 * Returns the least ancestor of <code>comp</code> which has the
393 * @param name The name to search for
394 * @param comp The component to search the ancestors of
396 * @return The nearest ancestor of <code>comp</code> with the given
397 * name, or <code>null</code> if no such ancestor exists
399 * @see java.awt.Component#getName
400 * @see #getAncestorOfClass
402 public static Container
getAncestorNamed(String name
, Component comp
)
404 while (comp
!= null && (comp
.getName() != name
))
405 comp
= comp
.getParent();
406 return (Container
) comp
;
410 * Returns the least ancestor of <code>comp</code> which is an instance
411 * of the specified class.
413 * @param c The class to search for
414 * @param comp The component to search the ancestors of
416 * @return The nearest ancestor of <code>comp</code> which is an instance
417 * of the given class, or <code>null</code> if no such ancestor exists
419 * @see #getAncestorOfClass
420 * @see #windowForComponent
424 public static Container
getAncestorOfClass(Class c
, Component comp
)
426 while (comp
!= null && (! c
.isInstance(comp
)))
427 comp
= comp
.getParent();
428 return (Container
) comp
;
432 * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>.
434 * @param comp The component to search for an ancestor window
436 * @return An ancestral window, or <code>null</code> if none exists
438 public static Window
windowForComponent(Component comp
)
440 return (Window
) getAncestorOfClass(Window
.class, comp
);
444 * Returns the "root" of the component tree containint <code>comp</code>
445 * The root is defined as either the <em>least</em> ancestor of
446 * <code>comp</code> which is a {@link Window}, or the <em>greatest</em>
447 * ancestor of <code>comp</code> which is a {@link Applet} if no {@link
448 * Window} ancestors are found.
450 * @param comp The component to search for a root
452 * @return The root of the component's tree, or <code>null</code>
454 public static Component
getRoot(Component comp
)
461 if (win
== null && comp
instanceof Window
)
463 else if (comp
instanceof Applet
)
465 comp
= comp
.getParent();
475 * Return true if a descends from b, in other words if b is an
478 * @param a The child to search the ancestry of
479 * @param b The potential ancestor to search for
481 * @return true if a is a descendent of b, false otherwise
483 public static boolean isDescendingFrom(Component a
, Component b
)
487 if (a
== null || b
== null)
496 * Returns the deepest descendent of parent which is both visible and
497 * contains the point <code>(x,y)</code>. Returns parent when either
498 * parent is not a container, or has no children which contain
499 * <code>(x,y)</code>. Returns <code>null</code> when either
500 * <code>(x,y)</code> is outside the bounds of parent, or parent is
503 * @param parent The component to search the descendents of
504 * @param x Horizontal coordinate to search for
505 * @param y Vertical coordinate to search for
507 * @return A component containing <code>(x,y)</code>, or
510 * @see java.awt.Container#findComponentAt
512 public static Component
getDeepestComponentAt(Component parent
, int x
, int y
)
514 if (parent
== null || (! parent
.contains(x
, y
)))
517 if (! (parent
instanceof Container
))
520 Container c
= (Container
) parent
;
521 return c
.findComponentAt(x
, y
);
525 * Converts a point from a component's local coordinate space to "screen"
526 * coordinates (such as the coordinate space mouse events are delivered
527 * in). This operation is equivalent to translating the point by the
528 * location of the component (which is the origin of its coordinate
531 * @param p The point to convert
532 * @param c The component which the point is expressed in terms of
534 * @see convertPointFromScreen
536 public static void convertPointToScreen(Point p
, Component c
)
538 Point c0
= c
.getLocationOnScreen();
539 p
.translate(c0
.x
, c0
.y
);
543 * Converts a point from "screen" coordinates (such as the coordinate
544 * space mouse events are delivered in) to a component's local coordinate
545 * space. This operation is equivalent to translating the point by the
546 * negation of the component's location (which is the origin of its
549 * @param p The point to convert
550 * @param c The component which the point should be expressed in terms of
552 public static void convertPointFromScreen(Point p
, Component c
)
554 Point c0
= c
.getLocationOnScreen();
555 p
.translate(-c0
.x
, -c0
.y
);
559 * Converts a point <code>(x,y)</code> from the coordinate space of one
560 * component to another. This is equivalent to converting the point from
561 * <code>source</code> space to screen space, then back from screen space
562 * to <code>destination</code> space. If exactly one of the two
563 * Components is <code>null</code>, it is taken to refer to the root
564 * ancestor of the other component. If both are <code>null</code>, no
565 * transformation is done.
567 * @param source The component which the point is expressed in terms of
568 * @param x Horizontal coordinate of point to transform
569 * @param y Vertical coordinate of point to transform
570 * @param destination The component which the return value will be
571 * expressed in terms of
573 * @return The point <code>(x,y)</code> converted from the coordinate
575 * source component to the coordinate space of the destination component
577 * @see #convertPointToScreen
578 * @see #convertPointFromScreen
579 * @see #convertRectangle
582 public static Point
convertPoint(Component source
, int x
, int y
,
583 Component destination
)
585 Point pt
= new Point(x
, y
);
587 if (source
== null && destination
== null)
591 source
= getRoot(destination
);
593 if (destination
== null)
594 destination
= getRoot(source
);
596 if (source
.isShowing() && destination
.isShowing())
598 convertPointToScreen(pt
, source
);
599 convertPointFromScreen(pt
, destination
);
607 * Converts a rectangle from the coordinate space of one component to
608 * another. This is equivalent to converting the rectangle from
609 * <code>source</code> space to screen space, then back from screen space
610 * to <code>destination</code> space. If exactly one of the two
611 * Components is <code>null</code>, it is taken to refer to the root
612 * ancestor of the other component. If both are <code>null</code>, no
613 * transformation is done.
615 * @param source The component which the rectangle is expressed in terms of
616 * @param rect The rectangle to convert
617 * @param destination The component which the return value will be
618 * expressed in terms of
620 * @return A new rectangle, equal in size to the input rectangle, but
621 * with its position converted from the coordinate space of the source
622 * component to the coordinate space of the destination component
624 * @see #convertPointToScreen
625 * @see #convertPointFromScreen
629 public static Rectangle
convertRectangle(Component source
, Rectangle rect
,
630 Component destination
)
632 Point pt
= convertPoint(source
, rect
.x
, rect
.y
, destination
);
633 return new Rectangle(pt
.x
, pt
.y
, rect
.width
, rect
.height
);
637 * Convert a mouse event which refrers to one component to another. This
638 * includes changing the mouse event's coordinate space, as well as the
639 * source property of the event. If <code>source</code> is
640 * <code>null</code>, it is taken to refer to <code>destination</code>'s
641 * root component. If <code>destination</code> is <code>null</code>, the
642 * new event will remain expressed in <code>source</code>'s coordinate
645 * @param source The component the mouse event currently refers to
646 * @param sourceEvent The mouse event to convert
647 * @param destination The component the new mouse event should refer to
649 * @return A new mouse event expressed in terms of the destination
650 * component's coordinate space, and with the destination component as
655 public static MouseEvent
convertMouseEvent(Component source
,
656 MouseEvent sourceEvent
,
657 Component destination
)
659 Point newpt
= convertPoint(source
, sourceEvent
.getX(), sourceEvent
.getY(),
662 return new MouseEvent(destination
, sourceEvent
.getID(),
663 sourceEvent
.getWhen(), sourceEvent
.getModifiers(),
664 newpt
.x
, newpt
.y
, sourceEvent
.getClickCount(),
665 sourceEvent
.isPopupTrigger(),
666 sourceEvent
.getButton());
671 * Calls {@link java.awt.EventQueue.invokeLater} with the
672 * specified {@link Runnable}.
674 public static void invokeLater(Runnable doRun
)
676 java
.awt
.EventQueue
.invokeLater(doRun
);
680 * Calls {@link java.awt.EventQueue.invokeAndWait} with the
681 * specified {@link Runnable}.
683 public static void invokeAndWait(Runnable doRun
)
684 throws InterruptedException
,
685 InvocationTargetException
687 java
.awt
.EventQueue
.invokeAndWait(doRun
);
691 * Calls {@link java.awt.EventQueue.isEventDispatchThread}.
693 public static boolean isEventDispatchThread()
695 return java
.awt
.EventQueue
.isDispatchThread();