1 /* SwingUtilities.java --
2    Copyright (C) 2002, 2004, 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 
39 package javax.swing;
40 
41 import java.applet.Applet;
42 import java.awt.Component;
43 import java.awt.ComponentOrientation;
44 import java.awt.Container;
45 import java.awt.FontMetrics;
46 import java.awt.Frame;
47 import java.awt.Graphics;
48 import java.awt.Insets;
49 import java.awt.KeyboardFocusManager;
50 import java.awt.Point;
51 import java.awt.Rectangle;
52 import java.awt.Shape;
53 import java.awt.Window;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.InputEvent;
56 import java.awt.event.KeyEvent;
57 import java.awt.event.MouseEvent;
58 import java.lang.reflect.InvocationTargetException;
59 
60 import javax.accessibility.Accessible;
61 import javax.accessibility.AccessibleStateSet;
62 import javax.swing.plaf.ActionMapUIResource;
63 import javax.swing.plaf.InputMapUIResource;
64 
65 /**
66  * A number of static utility functions which are
67  * useful when drawing swing components, dispatching events, or calculating
68  * regions which need painting.
69  *
70  * @author Graydon Hoare (graydon@redhat.com)
71  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
72  */
73 public class SwingUtilities
74   implements SwingConstants
75 {
76   /**
77    * This frame should be used as parent for JWindow or JDialog
78    * that doesn't an owner
79    */
80   private static OwnerFrame ownerFrame;
81 
SwingUtilities()82   private SwingUtilities()
83   {
84     // Do nothing.
85   }
86 
87   /**
88    * Calculates the portion of the base rectangle which is inside the
89    * insets.
90    *
91    * @param base The rectangle to apply the insets to
92    * @param insets The insets to apply to the base rectangle
93    * @param ret A rectangle to use for storing the return value, or
94    * <code>null</code>
95    *
96    * @return The calculated area inside the base rectangle and its insets,
97    * either stored in ret or a new Rectangle if ret is <code>null</code>
98    *
99    * @see #calculateInnerArea
100    */
calculateInsetArea(Rectangle base, Insets insets, Rectangle ret)101   public static Rectangle calculateInsetArea(Rectangle base, Insets insets,
102                                              Rectangle ret)
103   {
104     if (ret == null)
105       ret = new Rectangle();
106     ret.setBounds(base.x + insets.left, base.y + insets.top,
107                   base.width - (insets.left + insets.right),
108                   base.height - (insets.top + insets.bottom));
109     return ret;
110   }
111 
112   /**
113    * Calculates the portion of the component's bounds which is inside the
114    * component's border insets. This area is usually the area a component
115    * should confine its painting to. The coordinates are returned in terms
116    * of the <em>component's</em> coordinate system, where (0,0) is the
117    * upper left corner of the component's bounds.
118    *
119    * @param c The component to measure the bounds of
120    * @param r A Rectangle to store the return value in, or
121    * <code>null</code>
122    *
123    * @return The calculated area inside the component and its border
124    * insets
125    *
126    * @see #calculateInsetArea
127    */
calculateInnerArea(JComponent c, Rectangle r)128   public static Rectangle calculateInnerArea(JComponent c, Rectangle r)
129   {
130     Rectangle b = getLocalBounds(c);
131     return calculateInsetArea(b, c.getInsets(), r);
132   }
133 
134   /**
135    * Returns the focus owner or <code>null</code> if <code>comp</code> is not
136    * the focus owner or a parent of it.
137    *
138    * @param comp the focus owner or a parent of it
139    *
140    * @return the focus owner, or <code>null</code>
141    *
142    * @deprecated 1.4 Replaced by
143    * <code>KeyboardFocusManager.getFocusOwner()</code>.
144    */
findFocusOwner(Component comp)145   public static Component findFocusOwner(Component comp)
146   {
147     // Get real focus owner.
148     Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager()
149 					       .getFocusOwner();
150 
151     // Check if comp is the focus owner or a parent of it.
152     Component tmp = focusOwner;
153 
154     while (tmp != null)
155       {
156 	if (tmp == comp)
157 	  return focusOwner;
158 
159 	tmp = tmp.getParent();
160       }
161 
162     return null;
163   }
164 
165   /**
166    * Returns the <code>Accessible</code> child of the specified component
167    * which appears at the supplied <code>Point</code>.  If there is no
168    * child located at that particular pair of co-ordinates, null is returned
169    * instead.
170    *
171    * @param c the component whose children may be found at the specified
172    *          point.
173    * @param p the point at which to look for the existence of children
174    *          of the specified component.
175    * @return the <code>Accessible</code> child at the point, <code>p</code>,
176    *         or null if there is no child at this point.
177    * @see javax.accessibility.AccessibleComponent#getAccessibleAt
178    */
getAccessibleAt(Component c, Point p)179   public static Accessible getAccessibleAt(Component c, Point p)
180   {
181     return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p);
182   }
183 
184   /**
185    * <p>
186    * Returns the <code>Accessible</code> child of the specified component
187    * that has the supplied index within the parent component.  The indexing
188    * of the children is zero-based, making the first child have an index of
189    * 0.
190    * </p>
191    * <p>
192    * Caution is advised when using this method, as its operation relies
193    * on the behaviour of varying implementations of an abstract method.
194    * For greater surety, direct use of the AWT component implementation
195    * of this method is advised.
196    * </p>
197    *
198    * @param c the component whose child should be returned.
199    * @param i the index of the child within the parent component.
200    * @return the <code>Accessible</code> child at index <code>i</code>
201    *         in the component, <code>c</code>.
202    * @see javax.accessibility.AccessibleContext#getAccessibleChild
203    * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChild
204    */
getAccessibleChild(Component c, int i)205   public static Accessible getAccessibleChild(Component c, int i)
206   {
207     return c.getAccessibleContext().getAccessibleChild(i);
208   }
209 
210   /**
211    * <p>
212    * Returns the number of <code>Accessible</code> children within
213    * the supplied component.
214    * </p>
215    * <p>
216    * Caution is advised when using this method, as its operation relies
217    * on the behaviour of varying implementations of an abstract method.
218    * For greater surety, direct use of the AWT component implementation
219    * of this method is advised.
220    * </p>
221    *
222    * @param c the component whose children should be counted.
223    * @return the number of children belonging to the component,
224    *         <code>c</code>.
225    * @see javax.accessibility.AccessibleContext#getAccessibleChildrenCount
226    * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChildrenCount
227    */
getAccessibleChildrenCount(Component c)228   public static int getAccessibleChildrenCount(Component c)
229   {
230     return c.getAccessibleContext().getAccessibleChildrenCount();
231   }
232 
233   /**
234    * <p>
235    * Returns the zero-based index of the specified component
236    * within its parent.  If the component doesn't have a parent,
237    * -1 is returned.
238    * </p>
239    * <p>
240    * Caution is advised when using this method, as its operation relies
241    * on the behaviour of varying implementations of an abstract method.
242    * For greater surety, direct use of the AWT component implementation
243    * of this method is advised.
244    * </p>
245    *
246    * @param c the component whose parental index should be found.
247    * @return the index of the component within its parent, or -1
248    *         if the component doesn't have a parent.
249    * @see javax.accessibility.AccessibleContext#getAccessibleIndexInParent
250    * @see java.awt.Component.AccessibleAWTComponent#getAccessibleIndexInParent
251    */
getAccessibleIndexInParent(Component c)252   public static int getAccessibleIndexInParent(Component c)
253   {
254     return c.getAccessibleContext().getAccessibleIndexInParent();
255   }
256 
257   /**
258    * <p>
259    * Returns a set of <code>AccessibleState</code>s, which represent
260    * the state of the supplied component.
261    * </p>
262    * <p>
263    * Caution is advised when using this method, as its operation relies
264    * on the behaviour of varying implementations of an abstract method.
265    * For greater surety, direct use of the AWT component implementation
266    * of this method is advised.
267    * </p>
268    *
269    * @param c the component whose accessible state should be retrieved.
270    * @return a set of <code>AccessibleState</code> objects, which represent
271    *         the state of the supplied component.
272    * @see javax.accessibility.AccessibleContext#getAccessibleStateSet
273    * @see java.awt.Component.AccessibleAWTComponent#getAccessibleStateSet
274    */
getAccessibleStateSet(Component c)275   public static AccessibleStateSet getAccessibleStateSet(Component c)
276   {
277     return c.getAccessibleContext().getAccessibleStateSet();
278   }
279 
280   /**
281    * Calculates the bounds of a component in the component's own coordinate
282    * space. The result has the same height and width as the component's
283    * bounds, but its location is set to (0,0).
284    *
285    * @param aComponent The component to measure
286    *
287    * @return The component's bounds in its local coordinate space
288    */
getLocalBounds(Component aComponent)289   public static Rectangle getLocalBounds(Component aComponent)
290   {
291     Rectangle bounds = aComponent.getBounds();
292     return new Rectangle(0, 0, bounds.width, bounds.height);
293   }
294 
295   /**
296    * If <code>comp</code> is a RootPaneContainer, return its JRootPane.
297    * Otherwise call <code>getAncestorOfClass(JRootPane.class, a)</code>.
298    *
299    * @param comp The component to get the JRootPane of
300    *
301    * @return a suitable JRootPane for <code>comp</code>, or <code>null</code>
302    *
303    * @see javax.swing.RootPaneContainer#getRootPane
304    * @see #getAncestorOfClass
305    */
getRootPane(Component comp)306   public static JRootPane getRootPane(Component comp)
307   {
308     if (comp instanceof RootPaneContainer)
309       return ((RootPaneContainer)comp).getRootPane();
310     else
311       return (JRootPane) getAncestorOfClass(JRootPane.class, comp);
312   }
313 
314   /**
315    * Returns the least ancestor of <code>comp</code> which has the
316    * specified name.
317    *
318    * @param name The name to search for
319    * @param comp The component to search the ancestors of
320    *
321    * @return The nearest ancestor of <code>comp</code> with the given
322    * name, or <code>null</code> if no such ancestor exists
323    *
324    * @see java.awt.Component#getName
325    * @see #getAncestorOfClass
326    */
getAncestorNamed(String name, Component comp)327   public static Container getAncestorNamed(String name, Component comp)
328   {
329     while (comp != null && (comp.getName() != name))
330       comp = comp.getParent();
331     return (Container) comp;
332   }
333 
334   /**
335    * Returns the least ancestor of <code>comp</code> which is an instance
336    * of the specified class.
337    *
338    * @param c The class to search for
339    * @param comp The component to search the ancestors of
340    *
341    * @return The nearest ancestor of <code>comp</code> which is an instance
342    * of the given class, or <code>null</code> if no such ancestor exists
343    *
344    * @see #getAncestorOfClass
345    * @see #windowForComponent
346    */
getAncestorOfClass(Class c, Component comp)347   public static Container getAncestorOfClass(Class c, Component comp)
348   {
349     while (comp != null && (! c.isInstance(comp)))
350       comp = comp.getParent();
351     return (Container) comp;
352   }
353 
354   /**
355    * Returns the first ancestor of <code>comp</code> that is a {@link Window}
356    * or <code>null</code> if <code>comp</code> is not contained in a
357    * {@link Window}.
358    *
359    * This is equivalent to calling
360    * <code>getAncestorOfClass(Window, comp)</code> or
361    * <code>windowForComponent(comp)</code>.
362    *
363    * @param comp the component for which we are searching the ancestor Window
364    *
365    * @return the first ancestor Window of <code>comp</code> or
366    *     <code>null</code> if <code>comp</code> is not contained in a Window
367    */
getWindowAncestor(Component comp)368   public static Window getWindowAncestor(Component comp)
369   {
370     return (Window) getAncestorOfClass(Window.class, comp);
371   }
372 
373   /**
374    * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>.
375    *
376    * @param comp The component to search for an ancestor window
377    *
378    * @return An ancestral window, or <code>null</code> if none exists
379    */
windowForComponent(Component comp)380   public static Window windowForComponent(Component comp)
381   {
382     return (Window) getAncestorOfClass(Window.class, comp);
383   }
384 
385   /**
386    * Returns the "root" of the component tree containint <code>comp</code>
387    * The root is defined as either the <em>least</em> ancestor of
388    * <code>comp</code> which is a {@link Window}, or the <em>greatest</em>
389    * ancestor of <code>comp</code> which is a {@link Applet} if no {@link
390    * Window} ancestors are found.
391    *
392    * @param comp The component to search for a root
393    *
394    * @return The root of the component's tree, or <code>null</code>
395    */
getRoot(Component comp)396   public static Component getRoot(Component comp)
397   {
398     Applet app = null;
399     Window win = null;
400 
401     while (comp != null)
402       {
403         if (win == null && comp instanceof Window)
404           win = (Window) comp;
405         else if (comp instanceof Applet)
406           app = (Applet) comp;
407         comp = comp.getParent();
408       }
409 
410     if (win != null)
411       return win;
412     else
413       return app;
414   }
415 
416   /**
417    * Return true if a descends from b, in other words if b is an
418    * ancestor of a.
419    *
420    * @param a The child to search the ancestry of
421    * @param b The potential ancestor to search for
422    *
423    * @return true if a is a descendent of b, false otherwise
424    */
isDescendingFrom(Component a, Component b)425   public static boolean isDescendingFrom(Component a, Component b)
426   {
427     while (true)
428       {
429         if (a == null || b == null)
430           return false;
431         if (a == b)
432           return true;
433         a = a.getParent();
434       }
435   }
436 
437   /**
438    * Returns the deepest descendent of parent which is both visible and
439    * contains the point <code>(x,y)</code>. Returns parent when either
440    * parent is not a container, or has no children which contain
441    * <code>(x,y)</code>. Returns <code>null</code> when either
442    * <code>(x,y)</code> is outside the bounds of parent, or parent is
443    * <code>null</code>.
444    *
445    * @param parent The component to search the descendents of
446    * @param x Horizontal coordinate to search for
447    * @param y Vertical coordinate to search for
448    *
449    * @return A component containing <code>(x,y)</code>, or
450    * <code>null</code>
451    *
452    * @see java.awt.Container#findComponentAt(int, int)
453    */
getDeepestComponentAt(Component parent, int x, int y)454   public static Component getDeepestComponentAt(Component parent, int x, int y)
455   {
456     if (parent == null || (! parent.contains(x, y)))
457       return null;
458 
459     if (! (parent instanceof Container))
460       return parent;
461 
462     Container c = (Container) parent;
463     return c.findComponentAt(x, y);
464   }
465 
466   /**
467    * Converts a point from a component's local coordinate space to "screen"
468    * coordinates (such as the coordinate space mouse events are delivered
469    * in). This operation is equivalent to translating the point by the
470    * location of the component (which is the origin of its coordinate
471    * space).
472    *
473    * @param p The point to convert
474    * @param c The component which the point is expressed in terms of
475    *
476    * @see #convertPointFromScreen
477    */
convertPointToScreen(Point p, Component c)478   public static void convertPointToScreen(Point p, Component c)
479   {
480     Point c0 = c.getLocationOnScreen();
481     p.translate(c0.x, c0.y);
482   }
483 
484   /**
485    * Converts a point from "screen" coordinates (such as the coordinate
486    * space mouse events are delivered in) to a component's local coordinate
487    * space. This operation is equivalent to translating the point by the
488    * negation of the component's location (which is the origin of its
489    * coordinate space).
490    *
491    * @param p The point to convert
492    * @param c The component which the point should be expressed in terms of
493    */
convertPointFromScreen(Point p, Component c)494   public static void convertPointFromScreen(Point p, Component c)
495   {
496     Point c0 = c.getLocationOnScreen();
497     p.translate(-c0.x, -c0.y);
498   }
499 
500   /**
501    * Converts a point <code>(x,y)</code> from the coordinate space of one
502    * component to another. This is equivalent to converting the point from
503    * <code>source</code> space to screen space, then back from screen space
504    * to <code>destination</code> space. If exactly one of the two
505    * Components is <code>null</code>, it is taken to refer to the root
506    * ancestor of the other component. If both are <code>null</code>, no
507    * transformation is done.
508    *
509    * @param source The component which the point is expressed in terms of
510    * @param x Horizontal coordinate of point to transform
511    * @param y Vertical coordinate of point to transform
512    * @param destination The component which the return value will be
513    * expressed in terms of
514    *
515    * @return The point <code>(x,y)</code> converted from the coordinate space of the
516    * source component to the coordinate space of the destination component
517    *
518    * @see #convertPointToScreen
519    * @see #convertPointFromScreen
520    * @see #convertRectangle
521    * @see #getRoot
522    */
convertPoint(Component source, int x, int y, Component destination)523   public static Point convertPoint(Component source, int x, int y,
524                                    Component destination)
525   {
526     Point pt = new Point(x, y);
527 
528     if (source == null && destination == null)
529       return pt;
530 
531     if (source == null)
532       source = getRoot(destination);
533 
534     if (destination == null)
535       destination = getRoot(source);
536 
537     if (source.isShowing() && destination.isShowing())
538       {
539         convertPointToScreen(pt, source);
540         convertPointFromScreen(pt, destination);
541       }
542 
543     return pt;
544   }
545 
convertPoint(Component source, Point aPoint, Component destination)546   public static Point convertPoint(Component source, Point aPoint, Component destination)
547   {
548     return convertPoint(source, aPoint.x, aPoint.y, destination);
549   }
550 
551   /**
552    * Converts a rectangle from the coordinate space of one component to
553    * another. This is equivalent to converting the rectangle from
554    * <code>source</code> space to screen space, then back from screen space
555    * to <code>destination</code> space. If exactly one of the two
556    * Components is <code>null</code>, it is taken to refer to the root
557    * ancestor of the other component. If both are <code>null</code>, no
558    * transformation is done.
559    *
560    * @param source The component which the rectangle is expressed in terms of
561    * @param rect The rectangle to convert
562    * @param destination The component which the return value will be
563    * expressed in terms of
564    *
565    * @return A new rectangle, equal in size to the input rectangle, but
566    * with its position converted from the coordinate space of the source
567    * component to the coordinate space of the destination component
568    *
569    * @see #convertPointToScreen
570    * @see #convertPointFromScreen
571    * @see #convertPoint(Component, int, int, Component)
572    * @see #getRoot
573    */
convertRectangle(Component source, Rectangle rect, Component destination)574   public static Rectangle convertRectangle(Component source,
575                                            Rectangle rect,
576                                            Component destination)
577   {
578     Point pt = convertPoint(source, rect.x, rect.y, destination);
579     return new Rectangle(pt.x, pt.y, rect.width, rect.height);
580   }
581 
582   /**
583    * Convert a mouse event which refrers to one component to another.  This
584    * includes changing the mouse event's coordinate space, as well as the
585    * source property of the event. If <code>source</code> is
586    * <code>null</code>, it is taken to refer to <code>destination</code>'s
587    * root component. If <code>destination</code> is <code>null</code>, the
588    * new event will remain expressed in <code>source</code>'s coordinate
589    * system.
590    *
591    * @param source The component the mouse event currently refers to
592    * @param sourceEvent The mouse event to convert
593    * @param destination The component the new mouse event should refer to
594    *
595    * @return A new mouse event expressed in terms of the destination
596    * component's coordinate space, and with the destination component as
597    * its source
598    *
599    * @see #convertPoint(Component, int, int, Component)
600    */
convertMouseEvent(Component source, MouseEvent sourceEvent, Component destination)601   public static MouseEvent convertMouseEvent(Component source,
602                                              MouseEvent sourceEvent,
603                                              Component destination)
604   {
605     Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(),
606                                destination);
607 
608     return new MouseEvent(destination, sourceEvent.getID(),
609                           sourceEvent.getWhen(), sourceEvent.getModifiersEx(),
610                           newpt.x, newpt.y, sourceEvent.getClickCount(),
611                           sourceEvent.isPopupTrigger(), sourceEvent.getButton());
612   }
613 
614   /**
615    * Recursively walk the component tree under <code>comp</code> calling
616    * <code>updateUI</code> on each {@link JComponent} found. This causes
617    * the entire tree to re-initialize its UI delegates.
618    *
619    * @param comp The component to walk the children of, calling <code>updateUI</code>
620    */
updateComponentTreeUI(Component comp)621   public static void updateComponentTreeUI(Component comp)
622   {
623     if (comp == null)
624       return;
625 
626     if (comp instanceof Container)
627       {
628         Component[] children = ((Container)comp).getComponents();
629         for (int i = 0; i < children.length; ++i)
630           updateComponentTreeUI(children[i]);
631       }
632 
633     if (comp instanceof JComponent)
634       ((JComponent)comp).updateUI();
635   }
636 
637 
638   /**
639    * <p>Layout a "compound label" consisting of a text string and an icon
640    * which is to be placed near the rendered text. Once the text and icon
641    * are laid out, the text rectangle and icon rectangle parameters are
642    * altered to store the calculated positions.</p>
643    *
644    * <p>The size of the text is calculated from the provided font metrics
645    * object.  This object should be the metrics of the font you intend to
646    * paint the label with.</p>
647    *
648    * <p>The position values control where the text is placed relative to
649    * the icon. The horizontal position value should be one of the constants
650    * <code>LEADING</code>, <code>TRAILING</code>, <code>LEFT</code>,
651    * <code>RIGHT</code> or <code>CENTER</code>. The vertical position value
652    * should be one fo the constants <code>TOP</code>, <code>BOTTOM</code>
653    * or <code>CENTER</code>.</p>
654    *
655    * <p>The text-icon gap value controls the number of pixels between the
656    * icon and the text.</p>
657    *
658    * <p>The alignment values control where the text and icon are placed, as
659    * a combined unit, within the view rectangle. The horizontal alignment
660    * value should be one of the constants <code>LEADING</code>,
661    * <code>TRAILING</code>, <code>LEFT</code>, <code>RIGHT</code> or
662    * <code>CENTER</code>. The vertical alignment valus should be one of the
663    * constants <code>TOP</code>, <code>BOTTOM</code> or
664    * <code>CENTER</code>.</p>
665    *
666    * <p>If the <code>LEADING</code> or <code>TRAILING</code> constants are
667    * given for horizontal alignment or horizontal text position, they are
668    * interpreted relative to the provided component's orientation property,
669    * a constant in the {@link java.awt.ComponentOrientation} class. For
670    * example, if the component's orientation is <code>LEFT_TO_RIGHT</code>,
671    * then the <code>LEADING</code> value is a synonym for <code>LEFT</code>
672    * and the <code>TRAILING</code> value is a synonym for
673    * <code>RIGHT</code></p>
674    *
675    * <p>If the text and icon are equal to or larger than the view
676    * rectangle, the horizontal and vertical alignment values have no
677    * affect.</p>
678    *
679    * @param c A component used for its orientation value
680    * @param fm The font metrics used to measure the text
681    * @param text The text to place in the compound label
682    * @param icon The icon to place next to the text
683    * @param verticalAlignment The vertical alignment of the label relative
684    * to its component
685    * @param horizontalAlignment The horizontal alignment of the label
686    * relative to its component
687    * @param verticalTextPosition The vertical position of the label's text
688    * relative to its icon
689    * @param horizontalTextPosition The horizontal position of the label's
690    * text relative to its icon
691    * @param viewR The view rectangle, specifying the area which layout is
692    * constrained to
693    * @param iconR A rectangle which is modified to hold the laid-out
694    * position of the icon
695    * @param textR A rectangle which is modified to hold the laid-out
696    * position of the text
697    * @param textIconGap The distance between text and icon
698    *
699    * @return The string of characters, possibly truncated with an elipsis,
700    * which is laid out in this label
701    */
702 
layoutCompoundLabel(JComponent c, FontMetrics fm, String text, Icon icon, int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap)703   public static String layoutCompoundLabel(JComponent c,
704                                            FontMetrics fm,
705                                            String text,
706                                            Icon icon,
707                                            int verticalAlignment,
708                                            int horizontalAlignment,
709                                            int verticalTextPosition,
710                                            int horizontalTextPosition,
711                                            Rectangle viewR,
712                                            Rectangle iconR,
713                                            Rectangle textR,
714                                            int textIconGap)
715   {
716 
717     // Fix up the orientation-based horizontal positions.
718 
719     if (horizontalTextPosition == LEADING)
720       {
721         if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
722           horizontalTextPosition = RIGHT;
723         else
724           horizontalTextPosition = LEFT;
725       }
726     else if (horizontalTextPosition == TRAILING)
727       {
728         if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
729           horizontalTextPosition = LEFT;
730         else
731           horizontalTextPosition = RIGHT;
732       }
733 
734     // Fix up the orientation-based alignments.
735 
736     if (horizontalAlignment == LEADING)
737       {
738         if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
739           horizontalAlignment = RIGHT;
740         else
741           horizontalAlignment = LEFT;
742       }
743     else if (horizontalAlignment == TRAILING)
744       {
745         if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
746           horizontalAlignment = LEFT;
747         else
748           horizontalAlignment = RIGHT;
749       }
750 
751     return layoutCompoundLabel(fm, text, icon,
752                                verticalAlignment,
753                                horizontalAlignment,
754                                verticalTextPosition,
755                                horizontalTextPosition,
756                                viewR, iconR, textR, textIconGap);
757   }
758 
759   /**
760    * <p>Layout a "compound label" consisting of a text string and an icon
761    * which is to be placed near the rendered text. Once the text and icon
762    * are laid out, the text rectangle and icon rectangle parameters are
763    * altered to store the calculated positions.</p>
764    *
765    * <p>The size of the text is calculated from the provided font metrics
766    * object.  This object should be the metrics of the font you intend to
767    * paint the label with.</p>
768    *
769    * <p>The position values control where the text is placed relative to
770    * the icon. The horizontal position value should be one of the constants
771    * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The
772    * vertical position value should be one fo the constants
773    * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p>
774    *
775    * <p>The text-icon gap value controls the number of pixels between the
776    * icon and the text.</p>
777    *
778    * <p>The alignment values control where the text and icon are placed, as
779    * a combined unit, within the view rectangle. The horizontal alignment
780    * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or
781    * <code>CENTER</code>. The vertical alignment valus should be one of the
782    * constants <code>TOP</code>, <code>BOTTOM</code> or
783    * <code>CENTER</code>.</p>
784    *
785    * <p>If the text and icon are equal to or larger than the view
786    * rectangle, the horizontal and vertical alignment values have no
787    * affect.</p>
788    *
789    * <p>Note that this method does <em>not</em> know how to deal with
790    * horizontal alignments or positions given as <code>LEADING</code> or
791    * <code>TRAILING</code> values. Use the other overloaded variant of this
792    * method if you wish to use such values.
793    *
794    * @param fm The font metrics used to measure the text
795    * @param text The text to place in the compound label
796    * @param icon The icon to place next to the text
797    * @param verticalAlignment The vertical alignment of the label relative
798    * to its component
799    * @param horizontalAlignment The horizontal alignment of the label
800    * relative to its component
801    * @param verticalTextPosition The vertical position of the label's text
802    * relative to its icon
803    * @param horizontalTextPosition The horizontal position of the label's
804    * text relative to its icon
805    * @param viewR The view rectangle, specifying the area which layout is
806    * constrained to
807    * @param iconR A rectangle which is modified to hold the laid-out
808    * position of the icon
809    * @param textR A rectangle which is modified to hold the laid-out
810    * position of the text
811    * @param textIconGap The distance between text and icon
812    *
813    * @return The string of characters, possibly truncated with an elipsis,
814    * which is laid out in this label
815    */
816 
layoutCompoundLabel(FontMetrics fm, String text, Icon icon, int verticalAlignment, int horizontalAlignment, int verticalTextPosition, int horizontalTextPosition, Rectangle viewR, Rectangle iconR, Rectangle textR, int textIconGap)817   public static String layoutCompoundLabel(FontMetrics fm,
818                                            String text,
819                                            Icon icon,
820                                            int verticalAlignment,
821                                            int horizontalAlignment,
822                                            int verticalTextPosition,
823                                            int horizontalTextPosition,
824                                            Rectangle viewR,
825                                            Rectangle iconR,
826                                            Rectangle textR,
827                                            int textIconGap)
828   {
829 
830     // Work out basic height and width.
831 
832     if (icon == null)
833       {
834         textIconGap = 0;
835         iconR.width = 0;
836         iconR.height = 0;
837       }
838     else
839       {
840         iconR.width = icon.getIconWidth();
841         iconR.height = icon.getIconHeight();
842       }
843     if (text == null || text.equals(""))
844       {
845         textIconGap = 0;
846 	textR.width = 0;
847 	textR.height = 0;
848       }
849     else
850       {
851         int fromIndex = 0;
852         textR.width = fm.stringWidth(text);
853         textR.height = fm.getHeight();
854         while (text.indexOf('\n', fromIndex) != -1)
855           {
856             textR.height += fm.getHeight();
857             fromIndex = text.indexOf('\n', fromIndex) + 1;
858           }
859       }
860 
861     // Work out the position of text and icon, assuming the top-left coord
862     // starts at (0,0). We will fix that up momentarily, after these
863     // "position" decisions are made and we look at alignment.
864 
865     switch (horizontalTextPosition)
866       {
867       case LEFT:
868         textR.x = 0;
869         iconR.x = textR.width + textIconGap;
870         break;
871       case RIGHT:
872         iconR.x = 0;
873         textR.x = iconR.width + textIconGap;
874         break;
875       case CENTER:
876         int centerLine = Math.max(textR.width, iconR.width) / 2;
877         textR.x = centerLine - textR.width/2;
878         iconR.x = centerLine - iconR.width/2;
879         break;
880       }
881 
882     switch (verticalTextPosition)
883       {
884       case TOP:
885         textR.y = 0;
886         iconR.y = (horizontalTextPosition == CENTER
887                    ? textR.height + textIconGap : 0);
888         break;
889       case BOTTOM:
890         iconR.y = 0;
891         textR.y = (horizontalTextPosition == CENTER
892                    ? iconR.height + textIconGap
893                    : Math.max(iconR.height - textR.height, 0));
894         break;
895       case CENTER:
896         int centerLine = Math.max(textR.height, iconR.height) / 2;
897         textR.y = centerLine - textR.height/2;
898         iconR.y = centerLine - iconR.height/2;
899         break;
900       }
901     // The two rectangles are laid out correctly now, but only assuming
902     // that their upper left corner is at (0,0). If we have any alignment other
903     // than TOP and LEFT, we need to adjust them.
904 
905     Rectangle u = textR.union(iconR);
906     int horizontalAdjustment = viewR.x;
907     int verticalAdjustment = viewR.y;
908     switch (verticalAlignment)
909       {
910       case TOP:
911         break;
912       case BOTTOM:
913         verticalAdjustment += (viewR.height - u.height);
914         break;
915       case CENTER:
916         verticalAdjustment += ((viewR.height/2) - (u.height/2));
917         break;
918       }
919     switch (horizontalAlignment)
920       {
921       case LEFT:
922         break;
923       case RIGHT:
924         horizontalAdjustment += (viewR.width - u.width);
925         break;
926       case CENTER:
927         horizontalAdjustment += ((viewR.width/2) - (u.width/2));
928         break;
929       }
930 
931     iconR.x += horizontalAdjustment;
932     iconR.y += verticalAdjustment;
933 
934     textR.x += horizontalAdjustment;
935     textR.y += verticalAdjustment;
936 
937     return text;
938   }
939 
940   /**
941    * Calls {@link java.awt.EventQueue#invokeLater} with the
942    * specified {@link Runnable}.
943    */
invokeLater(Runnable doRun)944   public static void invokeLater(Runnable doRun)
945   {
946     java.awt.EventQueue.invokeLater(doRun);
947   }
948 
949   /**
950    * Calls {@link java.awt.EventQueue#invokeAndWait} with the
951    * specified {@link Runnable}.
952    */
invokeAndWait(Runnable doRun)953   public static void invokeAndWait(Runnable doRun)
954     throws InterruptedException,
955     InvocationTargetException
956   {
957     java.awt.EventQueue.invokeAndWait(doRun);
958   }
959 
960   /**
961    * Calls {@link java.awt.EventQueue#isDispatchThread()}.
962    *
963    * @return <code>true</code> if the current thread is the current AWT event
964    * dispatch thread.
965    */
isEventDispatchThread()966   public static boolean isEventDispatchThread()
967   {
968     return java.awt.EventQueue.isDispatchThread();
969   }
970 
971   /**
972    * This method paints the given component at the given position and size.
973    * The component will be reparented to the container given.
974    *
975    * @param g The Graphics object to draw with.
976    * @param c The Component to draw
977    * @param p The Container to reparent to.
978    * @param x The x coordinate to draw at.
979    * @param y The y coordinate to draw at.
980    * @param w The width of the drawing area.
981    * @param h The height of the drawing area.
982    */
paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h)983   public static void paintComponent(Graphics g, Component c, Container p,
984                                     int x, int y, int w, int h)
985   {
986     Container parent = c.getParent();
987     if (parent != null)
988       parent.remove(c);
989     if (p != null)
990       p.add(c);
991 
992     Shape savedClip = g.getClip();
993 
994     g.setClip(x, y, w, h);
995     g.translate(x, y);
996 
997     c.paint(g);
998 
999     g.translate(-x, -y);
1000     g.setClip(savedClip);
1001   }
1002 
1003   /**
1004    * This method paints the given component in the given rectangle.
1005    * The component will be reparented to the container given.
1006    *
1007    * @param g The Graphics object to draw with.
1008    * @param c The Component to draw
1009    * @param p The Container to reparent to.
1010    * @param r The rectangle that describes the drawing area.
1011    */
paintComponent(Graphics g, Component c, Container p, Rectangle r)1012   public static void paintComponent(Graphics g, Component c,
1013                                     Container p, Rectangle r)
1014   {
1015     paintComponent(g, c, p, r.x, r.y, r.width, r.height);
1016   }
1017 
1018   /**
1019    * This method returns the common Frame owner used in JDialogs or
1020    * JWindow when no owner is provided.
1021    *
1022    * @return The common Frame
1023    */
getOwnerFrame()1024   static Frame getOwnerFrame()
1025   {
1026     if (ownerFrame == null)
1027       ownerFrame = new OwnerFrame();
1028     return ownerFrame;
1029   }
1030 
1031   /**
1032    * Checks if left mouse button was clicked.
1033    *
1034    * @param event the event to check
1035    *
1036    * @return true if left mouse was clicked, false otherwise.
1037    */
isLeftMouseButton(MouseEvent event)1038   public static boolean isLeftMouseButton(MouseEvent event)
1039   {
1040     return ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK)
1041 	     == InputEvent.BUTTON1_DOWN_MASK);
1042   }
1043 
1044   /**
1045    * Checks if middle mouse button was clicked.
1046    *
1047    * @param event the event to check
1048    *
1049    * @return true if middle mouse was clicked, false otherwise.
1050    */
isMiddleMouseButton(MouseEvent event)1051   public static boolean isMiddleMouseButton(MouseEvent event)
1052   {
1053     return ((event.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK)
1054 	     == InputEvent.BUTTON2_DOWN_MASK);
1055   }
1056 
1057   /**
1058    * Checks if right mouse button was clicked.
1059    *
1060    * @param event the event to check
1061    *
1062    * @return true if right mouse was clicked, false otherwise.
1063    */
isRightMouseButton(MouseEvent event)1064   public static boolean isRightMouseButton(MouseEvent event)
1065   {
1066     return ((event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK)
1067 	     == InputEvent.BUTTON3_DOWN_MASK);
1068   }
1069 
1070   /**
1071    * This frame should be used when constructing a Window/JDialog without
1072    * a parent. In this case, we are forced to use this frame as a window's
1073    * parent, because we simply cannot pass null instead of parent to Window
1074    * constructor, since doing it will result in NullPointerException.
1075    */
1076   private static class OwnerFrame extends Frame
1077   {
setVisible(boolean b)1078     public void setVisible(boolean b)
1079     {
1080       // Do nothing here.
1081     }
1082 
isShowing()1083     public boolean isShowing()
1084     {
1085       return true;
1086     }
1087   }
1088 
notifyAction(Action action, KeyStroke ks, KeyEvent event, Object sender, int modifiers)1089   public static boolean notifyAction(Action action,
1090                                      KeyStroke ks,
1091                                      KeyEvent event,
1092                                      Object sender,
1093                                      int modifiers)
1094   {
1095     if (action != null && action.isEnabled())
1096       {
1097         String name = (String) action.getValue(Action.ACTION_COMMAND_KEY);
1098         if (name == null
1099             && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED)
1100           name = new String(new char[] {event.getKeyChar()});
1101         action.actionPerformed(new ActionEvent(sender,
1102                                                ActionEvent.ACTION_PERFORMED,
1103                                                name, modifiers));
1104         return true;
1105       }
1106     return false;
1107   }
1108 
1109   /**
1110    * <p>Change the shared, UI-managed {@link ActionMap} for a given
1111    * component. ActionMaps are arranged in a hierarchy, in order to
1112    * encourage sharing of common actions between components. The hierarchy
1113    * unfortunately places UI-managed ActionMaps at the <em>end</em> of the
1114    * parent-pointer chain, as illustrated:</p>
1115    *
1116    * <pre>
1117    *  [{@link javax.swing.JComponent#getActionMap()}]
1118    *          --&gt; [{@link javax.swing.ActionMap}]
1119    *     parent --&gt; [{@link javax.swing.text.JTextComponent.KeymapActionMap}]
1120    *       parent --&gt; [{@link javax.swing.plaf.ActionMapUIResource}]
1121    * </pre>
1122    *
1123    * <p>Our goal with this method is to replace the first ActionMap along
1124    * this chain which is an instance of {@link ActionMapUIResource}, since
1125    * these are the ActionMaps which are supposed to be shared between
1126    * components.</p>
1127    *
1128    * <p>If the provided ActionMap is <code>null</code>, we interpret the
1129    * call as a request to remove the UI-managed ActionMap from the
1130    * component's ActionMap parent chain.</p>
1131    */
replaceUIActionMap(JComponent component, ActionMap uiActionMap)1132   public static void replaceUIActionMap(JComponent component,
1133                                         ActionMap uiActionMap)
1134   {
1135     ActionMap child = component.getActionMap();
1136     if (child == null)
1137       component.setActionMap(uiActionMap);
1138     else
1139       {
1140         ActionMap parent = child.getParent();
1141         while(parent != null)
1142           {
1143             child = parent;
1144             parent = child.getParent();
1145           }
1146 
1147         if (child != null)
1148           child.setParent(uiActionMap);
1149       }
1150   }
1151 
1152   /**
1153    * <p>Change the shared, UI-managed {@link InputMap} for a given
1154    * component. InputMaps are arranged in a hierarchy, in order to
1155    * encourage sharing of common input mappings between components. The
1156    * hierarchy unfortunately places UI-managed InputMaps at the
1157    * <em>end</em> of the parent-pointer chain, as illustrated:</p>
1158    *
1159    * <pre>
1160    *  [{@link javax.swing.JComponent#getInputMap()}]
1161    *          --&gt; [{@link javax.swing.InputMap}]
1162    *     parent --&gt; [{@link javax.swing.text.JTextComponent.KeymapWrapper}]
1163    *       parent --&gt; [{@link javax.swing.plaf.InputMapUIResource}]
1164    * </pre>
1165    *
1166    * <p>Our goal with this method is to replace the first InputMap along
1167    * this chain which is an instance of {@link InputMapUIResource}, since
1168    * these are the InputMaps which are supposed to be shared between
1169    * components.</p>
1170    *
1171    * <p>If the provided InputMap is <code>null</code>, we interpret the
1172    * call as a request to remove the UI-managed InputMap from the
1173    * component's InputMap parent chain.</p>
1174    */
replaceUIInputMap(JComponent component, int condition, InputMap uiInputMap)1175   public static void replaceUIInputMap(JComponent component,
1176                                        int condition,
1177                                        InputMap uiInputMap)
1178   {
1179     InputMap child = component.getInputMap(condition);
1180     if (child == null)
1181       component.setInputMap(condition, uiInputMap);
1182     else
1183       {
1184         while(child.getParent() != null
1185               && !(child.getParent() instanceof InputMapUIResource))
1186           child = child.getParent();
1187         if (child != null)
1188           child.setParent(uiInputMap);
1189       }
1190   }
1191 
1192   /**
1193    * Subtracts a rectangle from another and return the area as an array
1194    * of rectangles.
1195    * Returns the areas of rectA which are not covered by rectB.
1196    * If the rectangles do not overlap, or if either parameter is
1197    * <code>null</code>, a zero-size array is returned.
1198    * @param rectA The first rectangle
1199    * @param rectB The rectangle to subtract from the first
1200    * @return An array of rectangles representing the area in rectA
1201    * not overlapped by rectB
1202    */
computeDifference(Rectangle rectA, Rectangle rectB)1203   public static Rectangle[] computeDifference(Rectangle rectA, Rectangle rectB)
1204   {
1205     if (rectA == null || rectB == null)
1206       return new Rectangle[0];
1207 
1208     Rectangle[] r = new Rectangle[4];
1209     int x1 = rectA.x;
1210     int y1 = rectA.y;
1211     int w1 = rectA.width;
1212     int h1 = rectA.height;
1213     int x2 = rectB.x;
1214     int y2 = rectB.y;
1215     int w2 = rectB.width;
1216     int h2 = rectB.height;
1217 
1218     // (outer box = rectA)
1219     // -------------
1220     // |_____0_____|
1221     // |  |rectB|  |
1222     // |_1|_____|_2|
1223     // |     3     |
1224     // -------------
1225     int H0 = (y2 > y1) ? y2 - y1 : 0; // height of box 0
1226     int H3 = (y2 + h2 < y1 + h1) ? y1 + h1 - y2 - h2 : 0; // height box 3
1227     int W1 = (x2 > x1) ? x2 - x1 : 0; // width box 1
1228     int W2 = (x1 + w1 > x2 + w2) ? x1 + w1 - x2 - w2 : 0; // w. box 2
1229     int H12 = (H0 + H3 < h1) ? h1 - H0 - H3 : 0; // height box 1 & 2
1230 
1231     if (H0 > 0)
1232       r[0] = new Rectangle(x1, y1, w1, H0);
1233     else
1234       r[0] = null;
1235 
1236     if (W1 > 0 && H12 > 0)
1237       r[1] = new Rectangle(x1, y1 + H0, W1, H12);
1238     else
1239       r[1] = null;
1240 
1241     if (W2 > 0 && H12 > 0)
1242       r[2] = new Rectangle(x2 + w2, y1 + H0, W2, H12);
1243     else
1244       r[2] = null;
1245 
1246     if (H3 > 0)
1247       r[3] = new Rectangle(x1, y1 + H0 + H12, w1, H3);
1248     else
1249       r[3] = null;
1250 
1251     // sort out null objects
1252     int n = 0;
1253     for (int i = 0; i < 4; i++)
1254       if (r[i] != null)
1255 	n++;
1256     Rectangle[] out = new Rectangle[n];
1257     for (int i = 3; i >= 0; i--)
1258       if (r[i] != null)
1259 	out[--n] = r[i];
1260 
1261     return out;
1262   }
1263 
1264   /**
1265    * Calculates the intersection of two rectangles.
1266    *
1267    * @param x upper-left x coodinate of first rectangle
1268    * @param y upper-left y coodinate of first rectangle
1269    * @param w width of first rectangle
1270    * @param h height of first rectangle
1271    * @param rect a Rectangle object of the second rectangle
1272    * @throws NullPointerException if rect is null.
1273    *
1274    * @return a rectangle corresponding to the intersection of the
1275    * two rectangles. A zero rectangle is returned if the rectangles
1276    * do not overlap.
1277    */
computeIntersection(int x, int y, int w, int h, Rectangle rect)1278   public static Rectangle computeIntersection(int x, int y, int w, int h,
1279                                               Rectangle rect)
1280   {
1281     int x2 = (int) rect.getX();
1282     int y2 = (int) rect.getY();
1283     int w2 = (int) rect.getWidth();
1284     int h2 = (int) rect.getHeight();
1285 
1286     int dx = (x > x2) ? x : x2;
1287     int dy = (y > y2) ? y : y2;
1288     int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
1289     int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
1290 
1291     if (dw >= 0 && dh >= 0)
1292       return new Rectangle(dx, dy, dw, dh);
1293 
1294     return new Rectangle(0, 0, 0, 0);
1295   }
1296 
1297   /**
1298    * Calculates the width of a given string.
1299    *
1300    * @param fm the <code>FontMetrics</code> object to use
1301    * @param str the string
1302    *
1303    * @return the width of the the string.
1304    */
computeStringWidth(FontMetrics fm, String str)1305   public static int computeStringWidth(FontMetrics fm, String str)
1306   {
1307     return fm.stringWidth(str);
1308   }
1309 
1310   /**
1311    * Calculates the union of two rectangles.
1312    *
1313    * @param x upper-left x coodinate of first rectangle
1314    * @param y upper-left y coodinate of first rectangle
1315    * @param w width of first rectangle
1316    * @param h height of first rectangle
1317    * @param rect a Rectangle object of the second rectangle
1318    * @throws NullPointerException if rect is null.
1319    *
1320    * @return a rectangle corresponding to the union of the
1321    * two rectangles. A rectangle encompassing both is returned if the
1322    * rectangles do not overlap.
1323    */
computeUnion(int x, int y, int w, int h, Rectangle rect)1324   public static Rectangle computeUnion(int x, int y, int w, int h,
1325                                        Rectangle rect)
1326   {
1327     int x2 = (int) rect.getX();
1328     int y2 = (int) rect.getY();
1329     int w2 = (int) rect.getWidth();
1330     int h2 = (int) rect.getHeight();
1331 
1332     int dx = (x < x2) ? x : x2;
1333     int dy = (y < y2) ? y : y2;
1334     int dw = (x + w > x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
1335     int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
1336 
1337     if (dw >= 0 && dh >= 0)
1338       return new Rectangle(dx, dy, dw, dh);
1339 
1340     return new Rectangle(0, 0, 0, 0);
1341   }
1342 
1343   /**
1344    * Tests if a rectangle contains another.
1345    * @param a first rectangle
1346    * @param b second rectangle
1347    * @return true if a contains b, false otherwise
1348    * @throws NullPointerException
1349    */
isRectangleContainingRectangle(Rectangle a, Rectangle b)1350   public static boolean isRectangleContainingRectangle(Rectangle a, Rectangle b)
1351   {
1352     // Note: zero-size rects inclusive, differs from Rectangle.contains()
1353     return b.width >= 0 && b.height >= 0 && b.width >= 0 && b.height >= 0
1354            && b.x >= a.x && b.x + b.width <= a.x + a.width && b.y >= a.y
1355            && b.y + b.height <= a.y + a.height;
1356   }
1357 
1358   /**
1359    * Returns the InputMap that is provided by the ComponentUI of
1360    * <code>component</code> for the specified condition.
1361    *
1362    * @param component the component for which the InputMap is returned
1363    * @param cond the condition that specifies which of the three input
1364    *     maps should be returned, may be
1365    *     {@link JComponent#WHEN_IN_FOCUSED_WINDOW},
1366    *     {@link JComponent#WHEN_FOCUSED} or
1367    *     {@link JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}
1368    *
1369    * @return The input map.
1370    */
getUIInputMap(JComponent component, int cond)1371   public static InputMap getUIInputMap(JComponent component, int cond)
1372   {
1373     if (UIManager.getUI(component) != null)
1374       // we assume here that the UI class sets the parent of the component's
1375       // InputMap, which is the correct behaviour. If it's not, then
1376       // this can be considered a bug
1377       return component.getInputMap(cond).getParent();
1378     else
1379       return null;
1380   }
1381 
1382   /**
1383    * Returns the ActionMap that is provided by the ComponentUI of
1384    * <code>component</code>.
1385    *
1386    * @param component the component for which the ActionMap is returned
1387    */
getUIActionMap(JComponent component)1388   public static ActionMap getUIActionMap(JComponent component)
1389   {
1390     if (UIManager.getUI(component) != null)
1391       // we assume here that the UI class sets the parent of the component's
1392       // ActionMap, which is the correct behaviour. If it's not, then
1393       // this can be considered a bug
1394       return component.getActionMap().getParent();
1395     else
1396       return null;
1397   }
1398 }
1399