Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: gnu/java/awt/AWTUtilities.java


1   /* AWTUtilities.java -- Common utility methods for AWT and Swing.
2      Copyright (C) 2005  Free Software Foundation, Inc.
3   
4   This file is part of GNU Classpath.
5   
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)
9   any later version.
10  
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.
15  
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
19  02110-1301 USA.
20  
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
24  combination.
25  
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. */
37  
38  package gnu.java.awt;
39  
40  import java.applet.Applet;
41  import java.awt.Component;
42  import java.awt.Container;
43  import java.awt.Font;
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;
57  
58  /**
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.
62   */
63  public class AWTUtilities
64  {
65  
66    /**
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}.
70     */
71    static class VisibleComponentList extends AbstractSequentialList
72    {
73      /**
74       * The ListIterator for this List.
75       */
76      class VisibleComponentIterator implements ListIterator
77      {
78        /** The current index in the Component[]. */
79        int index;
80  
81        /** The index in the List of visible Components. */
82        int listIndex;
83  
84        /**
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.
88         *
89         * @param listIndex the index from where to begin iterating
90         */
91        VisibleComponentIterator(int listIndex)
92        {
93    this.listIndex = listIndex;
94    int visibleComponentsFound = 0;
95    for (index = 0; visibleComponentsFound != listIndex; index++)
96      {
97        if (components[index].isVisible())
98          visibleComponentsFound++;
99      }
100       }
101 
102       /**
103        * Returns <code>true</code> if there are more visible components in the
104        * array, <code>false</code> otherwise.
105        *
106        * @return <code>true</code> if there are more visible components in the
107        *     array, <code>false</code> otherwise
108        */
109       public boolean hasNext()
110       {
111   boolean hasNext = false;
112   for (int i = index; i < components.length; i++)
113     {
114       if (components[i].isVisible())
115         {
116     hasNext = true;
117     break;
118         }
119     }
120   return hasNext;
121       }
122 
123       /**
124        * Returns the next visible <code>Component</code> in the List.
125        *
126        * @return the next visible <code>Component</code> in the List
127        *
128        * @throws if there is no next element
129        */
130       public Object next()
131       {
132   Object o = null;
133   for (; index < components.length; index++)
134     {
135       if (components[index].isVisible())
136         {
137     o = components[index];
138     break;
139         }
140     }
141   if (o != null)
142     {
143       index++;
144       listIndex++;
145       return o;
146     }
147   else
148     throw new NoSuchElementException();
149       }
150 
151       /**
152        * Returns <code>true</code> if there are more visible components in the
153        * array in the reverse direction, <code>false</code> otherwise.
154        *
155        * @return <code>true</code> if there are more visible components in the
156        *     array in the reverse direction, <code>false</code> otherwise
157        */
158       public boolean hasPrevious()
159       {
160   boolean hasPrevious = false;
161   for (int i = index - 1; i >= 0; i--)
162     {
163       if (components[i].isVisible())
164         {
165     hasPrevious = true;
166     break;
167         }
168     }
169   return hasPrevious;
170       }
171 
172       /**
173        * Returns the previous visible <code>Component</code> in the List.
174        *
175        * @return the previous visible <code>Component</code> in the List
176        *
177        * @throws NoSuchElementException if there is no previous element
178        */
179       public Object previous()
180       {
181   Object o = null;
182   for (index--; index >= 0; index--)
183     {
184       if (components[index].isVisible())
185         {
186     o = components[index];
187     break;
188         }
189     }
190   if (o != null)
191     {
192       listIndex--;
193       return o;
194     }
195   else
196     throw new NoSuchElementException();
197       }
198 
199       /**
200        * Returns the index of the next element in the List.
201        *
202        * @return the index of the next element in the List
203        */
204       public int nextIndex()
205       {
206   return listIndex + 1;
207       }
208 
209       /**
210        * Returns the index of the previous element in the List.
211        *
212        * @return the index of the previous element in the List
213        */
214       public int previousIndex()
215       {
216   return listIndex - 1;
217       }
218 
219       /**
220        * This operation is not supported because the List is immutable.
221        *
222        * @throws UnsupportedOperationException because the List is immutable
223        */
224       public void remove()
225       {
226   throw new UnsupportedOperationException
227     ("VisibleComponentList is immutable");
228       }
229 
230       /**
231        * This operation is not supported because the List is immutable.
232        *
233        * @param o not used here
234        *
235        * @throws UnsupportedOperationException because the List is immutable
236        */
237       public void set(Object o)
238       {
239   throw new UnsupportedOperationException
240     ("VisibleComponentList is immutable");
241       }
242 
243       /**
244        * This operation is not supported because the List is immutable.
245        *
246        * @param o not used here
247        *
248        * @throws UnsupportedOperationException because the List is immutable
249        */
250       public void add(Object o)
251       {
252   throw new UnsupportedOperationException
253     ("VisibleComponentList is immutable");
254       }
255     }
256 
257     /**
258      * The components over which we iterate. Only the visible components
259      * are returned by this List.
260      */
261     Component[] components;
262 
263     /**
264      * Creates a new instance of VisibleComponentList that wraps the specified
265      * <code>Component[]</code>.
266      *
267      * @param c the <code>Component[]</code> to be wrapped.
268      */
269     VisibleComponentList(Component[] c)
270     {
271       components = c;
272     }
273 
274     /**
275      * Returns a {@link ListIterator} for iterating over this List.
276      *
277      * @return a {@link ListIterator} for iterating over this List
278      */
279     public ListIterator listIterator(int index)
280     {
281       return new VisibleComponentIterator(index);
282     }
283 
284     /**
285      * Returns the number of visible components in the wrapped Component[].
286      *
287      * @return the number of visible components
288      */
289     public int size()
290     {
291       int visibleComponents = 0;
292       for (int i = 0; i < components.length; i++)
293   if (components[i].isVisible())
294     visibleComponents++;
295       return visibleComponents;
296     }
297   }
298 
299   /**
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.
305    */
306   static WeakHashMap visibleChildrenCache = new WeakHashMap();
307 
308   /**
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.
312    *
313    * @param c the Container from which to extract the visible children
314    *
315    * @return the visible children of <code>c</code>
316    */
317   public static List getVisibleChildren(Container c)
318   {
319     Component[] children = c.getComponents();
320     Object o = visibleChildrenCache.get(children);
321     VisibleComponentList visibleChildren = null;
322     if (o == null)
323       {
324   visibleChildren = new VisibleComponentList(children);
325   visibleChildrenCache.put(children, visibleChildren);
326       }
327     else
328       visibleChildren = (VisibleComponentList) o;
329 
330     return visibleChildren;
331   }
332 
333   /**
334    * Calculates the portion of the base rectangle which is inside the
335    * insets.
336    *
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
340    * <code>null</code>
341    *
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>
344    *
345    * @see #calculateInnerArea
346    */
347   public static Rectangle calculateInsetArea(Rectangle base, Insets insets,
348                                              Rectangle ret)
349   {
350     if (ret == null)
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));
355     return ret;
356   }
357 
358   /**
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).
362    *
363    * @param aComponent The component to measure
364    *
365    * @return The component's bounds in its local coordinate space
366    */
367   public static Rectangle getLocalBounds(Component aComponent)
368   {
369     Rectangle bounds = aComponent.getBounds();
370     return new Rectangle(0, 0, bounds.width, bounds.height);
371   }
372 
373   /**
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.
377    *
378    * @param font The font to get metrics for
379    *
380    * @return The font's metrics
381    *
382    * @see java.awt.font.GlyphMetrics
383    */
384   public static FontMetrics getFontMetrics(Font font)
385   {
386     return Toolkit.getDefaultToolkit().getFontMetrics(font);
387   }
388 
389   /**
390    * Returns the least ancestor of <code>comp</code> which has the
391    * specified name.
392    *
393    * @param name The name to search for
394    * @param comp The component to search the ancestors of
395    *
396    * @return The nearest ancestor of <code>comp</code> with the given
397    * name, or <code>null</code> if no such ancestor exists
398    *
399    * @see java.awt.Component#getName
400    * @see #getAncestorOfClass
401    */
402   public static Container getAncestorNamed(String name, Component comp)
403   {
404     while (comp != null && (comp.getName() != name))
405       comp = comp.getParent();
406     return (Container) comp;
407   }
408 
409   /**
410    * Returns the least ancestor of <code>comp</code> which is an instance
411    * of the specified class.
412    *
413    * @param c The class to search for
414    * @param comp The component to search the ancestors of
415    *
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
418    *
419    * @see #getAncestorOfClass
420    * @see #windowForComponent
421    * @see 
422    * 
423    */
424   public static Container getAncestorOfClass(Class c, Component comp)
425   {
426     while (comp != null && (! c.isInstance(comp)))
427       comp = comp.getParent();
428     return (Container) comp;
429   }
430 
431   /**
432    * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>.
433    *
434    * @param comp The component to search for an ancestor window 
435    *
436    * @return An ancestral window, or <code>null</code> if none exists
437    */
438   public static Window windowForComponent(Component comp)
439   {
440     return (Window) getAncestorOfClass(Window.class, comp);
441   }
442 
443   /**
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.
449    *
450    * @param comp The component to search for a root
451    *
452    * @return The root of the component's tree, or <code>null</code>
453    */
454   public static Component getRoot(Component comp)
455   {
456     Applet app = null;
457     Window win = null;
458 
459     while (comp != null)
460      {
461       if (win == null && comp instanceof Window)
462         win = (Window) comp;
463       else if (comp instanceof Applet)
464         app = (Applet) comp;
465       comp = comp.getParent();
466     }
467 
468     if (win != null)
469       return win;
470     else
471       return app;
472   }
473 
474   /**
475    * Return true if a descends from b, in other words if b is an
476    * ancestor of a.
477    *
478    * @param a The child to search the ancestry of
479    * @param b The potential ancestor to search for
480    *
481    * @return true if a is a descendent of b, false otherwise
482    */
483   public static boolean isDescendingFrom(Component a, Component b)
484   {
485     while (true)
486      {
487       if (a == null || b == null)
488         return false;
489       if (a == b)
490         return true;
491       a = a.getParent();
492     }
493   }
494 
495   /**
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
501    * <code>null</code>.
502    * 
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
506    *
507    * @return A component containing <code>(x,y)</code>, or
508    * <code>null</code>
509    *
510    * @see java.awt.Container#findComponentAt
511    */
512   public static Component getDeepestComponentAt(Component parent, int x, int y)
513   {
514     if (parent == null || (! parent.contains(x, y)))
515       return null;
516 
517     if (! (parent instanceof Container))
518       return parent;
519 
520     Container c = (Container) parent;
521     return c.findComponentAt(x, y);
522   }
523 
524   /**
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
529    * space).
530    *
531    * @param p The point to convert
532    * @param c The component which the point is expressed in terms of
533    *
534    * @see convertPointFromScreen
535    */
536   public static void convertPointToScreen(Point p, Component c)
537   {
538     Point c0 = c.getLocationOnScreen();
539     p.translate(c0.x, c0.y);
540   }
541 
542   /**
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
547    * coordinate space).
548    *
549    * @param p The point to convert
550    * @param c The component which the point should be expressed in terms of
551    */
552   public static void convertPointFromScreen(Point p, Component c)
553   {
554     Point c0 = c.getLocationOnScreen();
555     p.translate(-c0.x, -c0.y);
556   }
557 
558   /**
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.
566    *
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
572    *
573    * @return The point <code>(x,y)</code> converted from the coordinate
574    *         space of the
575    * source component to the coordinate space of the destination component
576    *
577    * @see #convertPointToScreen
578    * @see #convertPointFromScreen
579    * @see #convertRectangle
580    * @see #getRoot
581    */
582   public static Point convertPoint(Component source, int x, int y,
583                                    Component destination)
584   {
585     Point pt = new Point(x, y);
586 
587     if (source == null && destination == null)
588       return pt;
589 
590     if (source == null)
591       source = getRoot(destination);
592 
593     if (destination == null)
594       destination = getRoot(source);
595 
596     convertPointToScreen(pt, source);
597     convertPointFromScreen(pt, destination);
598 
599     return pt;
600   }
601 
602   
603   /**
604    * Converts a rectangle from the coordinate space of one component to
605    * another. This is equivalent to converting the rectangle from
606    * <code>source</code> space to screen space, then back from screen space
607    * to <code>destination</code> space. If exactly one of the two
608    * Components is <code>null</code>, it is taken to refer to the root
609    * ancestor of the other component. If both are <code>null</code>, no
610    * transformation is done.
611    *
612    * @param source The component which the rectangle is expressed in terms of
613    * @param rect The rectangle to convert
614    * @param destination The component which the return value will be
615    * expressed in terms of
616    *
617    * @return A new rectangle, equal in size to the input rectangle, but
618    * with its position converted from the coordinate space of the source
619    * component to the coordinate space of the destination component
620    *
621    * @see #convertPointToScreen
622    * @see #convertPointFromScreen
623    * @see #convertPoint
624    * @see #getRoot
625    */
626   public static Rectangle convertRectangle(Component source, Rectangle rect,
627                                            Component destination)
628   {
629     Point pt = convertPoint(source, rect.x, rect.y, destination);
630     return new Rectangle(pt.x, pt.y, rect.width, rect.height);
631   }
632 
633   /**
634    * Convert a mouse event which refrers to one component to another.  This
635    * includes changing the mouse event's coordinate space, as well as the
636    * source property of the event. If <code>source</code> is
637    * <code>null</code>, it is taken to refer to <code>destination</code>'s
638    * root component. If <code>destination</code> is <code>null</code>, the
639    * new event will remain expressed in <code>source</code>'s coordinate
640    * system.
641    *
642    * @param source The component the mouse event currently refers to
643    * @param sourceEvent The mouse event to convert
644    * @param destination The component the new mouse event should refer to
645    *
646    * @return A new mouse event expressed in terms of the destination
647    * component's coordinate space, and with the destination component as
648    * its source
649    *
650    * @see #convertPoint
651    */
652   public static MouseEvent convertMouseEvent(Component source,
653                                              MouseEvent sourceEvent,
654                                              Component destination)
655   {
656     Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(),
657                                destination);
658 
659     return new MouseEvent(destination, sourceEvent.getID(),
660                           sourceEvent.getWhen(), sourceEvent.getModifiers(),
661                           newpt.x, newpt.y, sourceEvent.getClickCount(),
662                           sourceEvent.isPopupTrigger(),
663                           sourceEvent.getButton());
664   }
665 
666 
667   /** 
668    * Calls {@link java.awt.EventQueue.invokeLater} with the
669    * specified {@link Runnable}. 
670    */
671   public static void invokeLater(Runnable doRun)
672   {
673     java.awt.EventQueue.invokeLater(doRun);
674   }
675 
676   /** 
677    * Calls {@link java.awt.EventQueue.invokeAndWait} with the
678    * specified {@link Runnable}. 
679    */
680   public static void invokeAndWait(Runnable doRun)
681   throws InterruptedException,
682   InvocationTargetException
683   {
684     java.awt.EventQueue.invokeAndWait(doRun);
685   }
686 
687   /** 
688    * Calls {@link java.awt.EventQueue.isEventDispatchThread}.
689    */
690   public static boolean isEventDispatchThread()
691   {
692     return java.awt.EventQueue.isDispatchThread();
693   }
694 }