37 |
|
|
38 |
package gnu.java.awt; |
package gnu.java.awt; |
39 |
|
|
40 |
|
import java.applet.Applet; |
41 |
import java.awt.Component; |
import java.awt.Component; |
42 |
import java.awt.Container; |
import java.awt.Container; |
43 |
|
import java.awt.Font; |
44 |
|
import java.awt.FontMetrics; |
45 |
|
import java.awt.Insets; |
46 |
|
import java.awt.Point; |
47 |
|
import java.awt.Rectangle; |
48 |
|
import java.awt.Toolkit; |
49 |
|
import java.awt.Window; |
50 |
|
import java.awt.event.MouseEvent; |
51 |
import java.util.AbstractSequentialList; |
import java.util.AbstractSequentialList; |
52 |
import java.util.List; |
import java.util.List; |
53 |
import java.util.ListIterator; |
import java.util.ListIterator; |
54 |
import java.util.NoSuchElementException; |
import java.util.NoSuchElementException; |
55 |
import java.util.WeakHashMap; |
import java.util.WeakHashMap; |
56 |
|
import java.lang.reflect.InvocationTargetException; |
57 |
|
|
58 |
/** |
/** |
59 |
* This class provides utility methods that are commonly used in AWT |
* This class mirrors the javax.swing.SwingUtilities class. It |
60 |
* (and Swing). |
* provides commonly needed functionalities for AWT classes without |
61 |
|
* the need to reference classes in the javax.swing package. |
62 |
*/ |
*/ |
63 |
public class AWTUtilities |
public class AWTUtilities |
64 |
{ |
{ |
329 |
|
|
330 |
return visibleChildren; |
return visibleChildren; |
331 |
} |
} |
332 |
|
|
333 |
|
/** |
334 |
|
* Calculates the portion of the base rectangle which is inside the |
335 |
|
* insets. |
336 |
|
* |
337 |
|
* @param base The rectangle to apply the insets to |
338 |
|
* @param insets The insets to apply to the base rectangle |
339 |
|
* @param ret A rectangle to use for storing the return value, or |
340 |
|
* <code>null</code> |
341 |
|
* |
342 |
|
* @return The calculated area inside the base rectangle and its insets, |
343 |
|
* either stored in ret or a new Rectangle if ret is <code>null</code> |
344 |
|
* |
345 |
|
* @see #calculateInnerArea |
346 |
|
*/ |
347 |
|
public static Rectangle calculateInsetArea(Rectangle base, Insets insets, |
348 |
|
Rectangle ret) |
349 |
|
{ |
350 |
|
if (ret == null) |
351 |
|
ret = new Rectangle(); |
352 |
|
ret.setBounds(base.x + insets.left, base.y + insets.top, |
353 |
|
base.width - (insets.left + insets.right), |
354 |
|
base.height - (insets.top + insets.bottom)); |
355 |
|
return ret; |
356 |
|
} |
357 |
|
|
358 |
|
/** |
359 |
|
* Calculates the bounds of a component in the component's own coordinate |
360 |
|
* space. The result has the same height and width as the component's |
361 |
|
* bounds, but its location is set to (0,0). |
362 |
|
* |
363 |
|
* @param aComponent The component to measure |
364 |
|
* |
365 |
|
* @return The component's bounds in its local coordinate space |
366 |
|
*/ |
367 |
|
public static Rectangle getLocalBounds(Component aComponent) |
368 |
|
{ |
369 |
|
Rectangle bounds = aComponent.getBounds(); |
370 |
|
return new Rectangle(0, 0, bounds.width, bounds.height); |
371 |
|
} |
372 |
|
|
373 |
|
/** |
374 |
|
* Returns the font metrics object for a given font. The metrics can be |
375 |
|
* used to calculate crude bounding boxes and positioning information, |
376 |
|
* for laying out components with textual elements. |
377 |
|
* |
378 |
|
* @param font The font to get metrics for |
379 |
|
* |
380 |
|
* @return The font's metrics |
381 |
|
* |
382 |
|
* @see java.awt.font.GlyphMetrics |
383 |
|
*/ |
384 |
|
public static FontMetrics getFontMetrics(Font font) |
385 |
|
{ |
386 |
|
return Toolkit.getDefaultToolkit().getFontMetrics(font); |
387 |
|
} |
388 |
|
|
389 |
|
/** |
390 |
|
* Returns the least ancestor of <code>comp</code> which has the |
391 |
|
* specified name. |
392 |
|
* |
393 |
|
* @param name The name to search for |
394 |
|
* @param comp The component to search the ancestors of |
395 |
|
* |
396 |
|
* @return The nearest ancestor of <code>comp</code> with the given |
397 |
|
* name, or <code>null</code> if no such ancestor exists |
398 |
|
* |
399 |
|
* @see java.awt.Component#getName |
400 |
|
* @see #getAncestorOfClass |
401 |
|
*/ |
402 |
|
public static Container getAncestorNamed(String name, Component comp) |
403 |
|
{ |
404 |
|
while (comp != null && (comp.getName() != name)) |
405 |
|
comp = comp.getParent(); |
406 |
|
return (Container) comp; |
407 |
|
} |
408 |
|
|
409 |
|
/** |
410 |
|
* Returns the least ancestor of <code>comp</code> which is an instance |
411 |
|
* of the specified class. |
412 |
|
* |
413 |
|
* @param c The class to search for |
414 |
|
* @param comp The component to search the ancestors of |
415 |
|
* |
416 |
|
* @return The nearest ancestor of <code>comp</code> which is an instance |
417 |
|
* of the given class, or <code>null</code> if no such ancestor exists |
418 |
|
* |
419 |
|
* @see #getAncestorOfClass |
420 |
|
* @see #windowForComponent |
421 |
|
* @see |
422 |
|
* |
423 |
|
*/ |
424 |
|
public static Container getAncestorOfClass(Class c, Component comp) |
425 |
|
{ |
426 |
|
while (comp != null && (! c.isInstance(comp))) |
427 |
|
comp = comp.getParent(); |
428 |
|
return (Container) comp; |
429 |
|
} |
430 |
|
|
431 |
|
/** |
432 |
|
* Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>. |
433 |
|
* |
434 |
|
* @param comp The component to search for an ancestor window |
435 |
|
* |
436 |
|
* @return An ancestral window, or <code>null</code> if none exists |
437 |
|
*/ |
438 |
|
public static Window windowForComponent(Component comp) |
439 |
|
{ |
440 |
|
return (Window) getAncestorOfClass(Window.class, comp); |
441 |
|
} |
442 |
|
|
443 |
|
/** |
444 |
|
* Returns the "root" of the component tree containint <code>comp</code> |
445 |
|
* The root is defined as either the <em>least</em> ancestor of |
446 |
|
* <code>comp</code> which is a {@link Window}, or the <em>greatest</em> |
447 |
|
* ancestor of <code>comp</code> which is a {@link Applet} if no {@link |
448 |
|
* Window} ancestors are found. |
449 |
|
* |
450 |
|
* @param comp The component to search for a root |
451 |
|
* |
452 |
|
* @return The root of the component's tree, or <code>null</code> |
453 |
|
*/ |
454 |
|
public static Component getRoot(Component comp) |
455 |
|
{ |
456 |
|
Applet app = null; |
457 |
|
Window win = null; |
458 |
|
|
459 |
|
while (comp != null) |
460 |
|
{ |
461 |
|
if (win == null && comp instanceof Window) |
462 |
|
win = (Window) comp; |
463 |
|
else if (comp instanceof Applet) |
464 |
|
app = (Applet) comp; |
465 |
|
comp = comp.getParent(); |
466 |
|
} |
467 |
|
|
468 |
|
if (win != null) |
469 |
|
return win; |
470 |
|
else |
471 |
|
return app; |
472 |
|
} |
473 |
|
|
474 |
|
/** |
475 |
|
* Return true if a descends from b, in other words if b is an |
476 |
|
* ancestor of a. |
477 |
|
* |
478 |
|
* @param a The child to search the ancestry of |
479 |
|
* @param b The potential ancestor to search for |
480 |
|
* |
481 |
|
* @return true if a is a descendent of b, false otherwise |
482 |
|
*/ |
483 |
|
public static boolean isDescendingFrom(Component a, Component b) |
484 |
|
{ |
485 |
|
while (true) |
486 |
|
{ |
487 |
|
if (a == null || b == null) |
488 |
|
return false; |
489 |
|
if (a == b) |
490 |
|
return true; |
491 |
|
a = a.getParent(); |
492 |
|
} |
493 |
|
} |
494 |
|
|
495 |
|
/** |
496 |
|
* Returns the deepest descendent of parent which is both visible and |
497 |
|
* contains the point <code>(x,y)</code>. Returns parent when either |
498 |
|
* parent is not a container, or has no children which contain |
499 |
|
* <code>(x,y)</code>. Returns <code>null</code> when either |
500 |
|
* <code>(x,y)</code> is outside the bounds of parent, or parent is |
501 |
|
* <code>null</code>. |
502 |
|
* |
503 |
|
* @param parent The component to search the descendents of |
504 |
|
* @param x Horizontal coordinate to search for |
505 |
|
* @param y Vertical coordinate to search for |
506 |
|
* |
507 |
|
* @return A component containing <code>(x,y)</code>, or |
508 |
|
* <code>null</code> |
509 |
|
* |
510 |
|
* @see java.awt.Container#findComponentAt |
511 |
|
*/ |
512 |
|
public static Component getDeepestComponentAt(Component parent, int x, int y) |
513 |
|
{ |
514 |
|
if (parent == null || (! parent.contains(x, y))) |
515 |
|
return null; |
516 |
|
|
517 |
|
if (! (parent instanceof Container)) |
518 |
|
return parent; |
519 |
|
|
520 |
|
Container c = (Container) parent; |
521 |
|
return c.findComponentAt(x, y); |
522 |
|
} |
523 |
|
|
524 |
|
/** |
525 |
|
* Converts a point from a component's local coordinate space to "screen" |
526 |
|
* coordinates (such as the coordinate space mouse events are delivered |
527 |
|
* in). This operation is equivalent to translating the point by the |
528 |
|
* location of the component (which is the origin of its coordinate |
529 |
|
* space). |
530 |
|
* |
531 |
|
* @param p The point to convert |
532 |
|
* @param c The component which the point is expressed in terms of |
533 |
|
* |
534 |
|
* @see convertPointFromScreen |
535 |
|
*/ |
536 |
|
public static void convertPointToScreen(Point p, Component c) |
537 |
|
{ |
538 |
|
Point c0 = c.getLocationOnScreen(); |
539 |
|
p.translate(c0.x, c0.y); |
540 |
|
} |
541 |
|
|
542 |
|
/** |
543 |
|
* Converts a point from "screen" coordinates (such as the coordinate |
544 |
|
* space mouse events are delivered in) to a component's local coordinate |
545 |
|
* space. This operation is equivalent to translating the point by the |
546 |
|
* negation of the component's location (which is the origin of its |
547 |
|
* coordinate space). |
548 |
|
* |
549 |
|
* @param p The point to convert |
550 |
|
* @param c The component which the point should be expressed in terms of |
551 |
|
*/ |
552 |
|
public static void convertPointFromScreen(Point p, Component c) |
553 |
|
{ |
554 |
|
Point c0 = c.getLocationOnScreen(); |
555 |
|
p.translate(-c0.x, -c0.y); |
556 |
|
} |
557 |
|
|
558 |
|
/** |
559 |
|
* Converts a point <code>(x,y)</code> from the coordinate space of one |
560 |
|
* component to another. This is equivalent to converting the point from |
561 |
|
* <code>source</code> space to screen space, then back from screen space |
562 |
|
* to <code>destination</code> space. If exactly one of the two |
563 |
|
* Components is <code>null</code>, it is taken to refer to the root |
564 |
|
* ancestor of the other component. If both are <code>null</code>, no |
565 |
|
* transformation is done. |
566 |
|
* |
567 |
|
* @param source The component which the point is expressed in terms of |
568 |
|
* @param x Horizontal coordinate of point to transform |
569 |
|
* @param y Vertical coordinate of point to transform |
570 |
|
* @param destination The component which the return value will be |
571 |
|
* expressed in terms of |
572 |
|
* |
573 |
|
* @return The point <code>(x,y)</code> converted from the coordinate space of the |
574 |
|
* source component to the coordinate space of the destination component |
575 |
|
* |
576 |
|
* @see #convertPointToScreen |
577 |
|
* @see #convertPointFromScreen |
578 |
|
* @see #convertRectangle |
579 |
|
* @see #getRoot |
580 |
|
*/ |
581 |
|
public static Point convertPoint(Component source, int x, int y, |
582 |
|
Component destination) |
583 |
|
{ |
584 |
|
Point pt = new Point(x, y); |
585 |
|
|
586 |
|
if (source == null && destination == null) |
587 |
|
return pt; |
588 |
|
|
589 |
|
if (source == null) |
590 |
|
source = getRoot(destination); |
591 |
|
|
592 |
|
if (destination == null) |
593 |
|
destination = getRoot(source); |
594 |
|
|
595 |
|
convertPointToScreen(pt, source); |
596 |
|
convertPointFromScreen(pt, destination); |
597 |
|
|
598 |
|
return pt; |
599 |
|
} |
600 |
|
|
601 |
|
|
602 |
|
/** |
603 |
|
* Converts a rectangle from the coordinate space of one component to |
604 |
|
* another. This is equivalent to converting the rectangle from |
605 |
|
* <code>source</code> space to screen space, then back from screen space |
606 |
|
* to <code>destination</code> space. If exactly one of the two |
607 |
|
* Components is <code>null</code>, it is taken to refer to the root |
608 |
|
* ancestor of the other component. If both are <code>null</code>, no |
609 |
|
* transformation is done. |
610 |
|
* |
611 |
|
* @param source The component which the rectangle is expressed in terms of |
612 |
|
* @param rect The rectangle to convert |
613 |
|
* @param destination The component which the return value will be |
614 |
|
* expressed in terms of |
615 |
|
* |
616 |
|
* @return A new rectangle, equal in size to the input rectangle, but |
617 |
|
* with its position converted from the coordinate space of the source |
618 |
|
* component to the coordinate space of the destination component |
619 |
|
* |
620 |
|
* @see #convertPointToScreen |
621 |
|
* @see #convertPointFromScreen |
622 |
|
* @see #convertPoint |
623 |
|
* @see #getRoot |
624 |
|
*/ |
625 |
|
public static Rectangle convertRectangle(Component source, |
626 |
|
Rectangle rect, |
627 |
|
Component destination) |
628 |
|
{ |
629 |
|
Point pt = convertPoint(source, rect.x, rect.y, destination); |
630 |
|
return new Rectangle(pt.x, pt.y, rect.width, rect.height); |
631 |
|
} |
632 |
|
|
633 |
|
/** |
634 |
|
* Convert a mouse event which refrers to one component to another. This |
635 |
|
* includes changing the mouse event's coordinate space, as well as the |
636 |
|
* source property of the event. If <code>source</code> is |
637 |
|
* <code>null</code>, it is taken to refer to <code>destination</code>'s |
638 |
|
* root component. If <code>destination</code> is <code>null</code>, the |
639 |
|
* new event will remain expressed in <code>source</code>'s coordinate |
640 |
|
* system. |
641 |
|
* |
642 |
|
* @param source The component the mouse event currently refers to |
643 |
|
* @param sourceEvent The mouse event to convert |
644 |
|
* @param destination The component the new mouse event should refer to |
645 |
|
* |
646 |
|
* @return A new mouse event expressed in terms of the destination |
647 |
|
* component's coordinate space, and with the destination component as |
648 |
|
* its source |
649 |
|
* |
650 |
|
* @see #convertPoint |
651 |
|
*/ |
652 |
|
public static MouseEvent convertMouseEvent(Component source, |
653 |
|
MouseEvent sourceEvent, |
654 |
|
Component destination) |
655 |
|
{ |
656 |
|
Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), |
657 |
|
destination); |
658 |
|
|
659 |
|
return new MouseEvent(destination, sourceEvent.getID(), |
660 |
|
sourceEvent.getWhen(), sourceEvent.getModifiers(), |
661 |
|
newpt.x, newpt.y, sourceEvent.getClickCount(), |
662 |
|
sourceEvent.isPopupTrigger(), sourceEvent.getButton()); |
663 |
|
} |
664 |
|
|
665 |
|
|
666 |
|
/** |
667 |
|
* Calls {@link java.awt.EventQueue.invokeLater} with the |
668 |
|
* specified {@link Runnable}. |
669 |
|
*/ |
670 |
|
public static void invokeLater(Runnable doRun) |
671 |
|
{ |
672 |
|
java.awt.EventQueue.invokeLater(doRun); |
673 |
|
} |
674 |
|
|
675 |
|
/** |
676 |
|
* Calls {@link java.awt.EventQueue.invokeAndWait} with the |
677 |
|
* specified {@link Runnable}. |
678 |
|
*/ |
679 |
|
public static void invokeAndWait(Runnable doRun) |
680 |
|
throws InterruptedException, |
681 |
|
InvocationTargetException |
682 |
|
{ |
683 |
|
java.awt.EventQueue.invokeAndWait(doRun); |
684 |
|
} |
685 |
|
|
686 |
|
/** |
687 |
|
* Calls {@link java.awt.EventQueue.isEventDispatchThread}. |
688 |
|
*/ |
689 |
|
public static boolean isEventDispatchThread() |
690 |
|
{ |
691 |
|
return java.awt.EventQueue.isDispatchThread(); |
692 |
|
} |
693 |
} |
} |