OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [SwingUtilities.java] - Blame information for rev 772

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.