OSDN Git Service

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