diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/javax/swing/SwingUtilities.java | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/javax/swing/SwingUtilities.java')
-rw-r--r-- | libjava/classpath/javax/swing/SwingUtilities.java | 1754 |
1 files changed, 1754 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java new file mode 100644 index 000000000..61047323f --- /dev/null +++ b/libjava/classpath/javax/swing/SwingUtilities.java @@ -0,0 +1,1754 @@ +/* SwingUtilities.java -- + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.applet.Applet; +import java.awt.Component; +import java.awt.Container; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleStateSet; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.InputMapUIResource; +import javax.swing.plaf.basic.BasicHTML; +import javax.swing.text.View; + +/** + * A number of static utility functions which are + * useful when drawing swing components, dispatching events, or calculating + * regions which need painting. + * + * @author Graydon Hoare (graydon@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class SwingUtilities + implements SwingConstants +{ + /** + * This frame should be used as parent for JWindow or JDialog + * that doesn't an owner + */ + private static OwnerFrame ownerFrame; + + private SwingUtilities() + { + // Do nothing. + } + + /** + * Calculates the portion of the component's bounds which is inside the + * component's border insets. This area is usually the area a component + * should confine its painting to. The coordinates are returned in terms + * of the <em>component's</em> coordinate system, where (0,0) is the + * upper left corner of the component's bounds. + * + * @param c the component to measure the bounds of (if <code>null</code>, + * this method returns <code>null</code>). + * @param r a carrier to store the return value in (if <code>null</code>, a + * new <code>Rectangle</code> instance is created). + * + * @return The calculated area inside the component and its border insets. + */ + public static Rectangle calculateInnerArea(JComponent c, Rectangle r) + { + if (c == null) + return null; + r = c.getBounds(r); + Insets i = c.getInsets(); + r.x = i.left; + r.width = r.width - i.left - i.right; + r.y = i.top; + r.height = r.height - i.top - i.bottom; + return r; + } + + /** + * Returns the focus owner or <code>null</code> if <code>comp</code> is not + * the focus owner or a parent of it. + * + * @param comp the focus owner or a parent of it + * + * @return the focus owner, or <code>null</code> + * + * @deprecated 1.4 Replaced by + * <code>KeyboardFocusManager.getFocusOwner()</code>. + */ + public static Component findFocusOwner(Component comp) + { + // Get real focus owner. + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getFocusOwner(); + + // Check if comp is the focus owner or a parent of it. + Component tmp = focusOwner; + + while (tmp != null) + { + if (tmp == comp) + return focusOwner; + + tmp = tmp.getParent(); + } + + return null; + } + + /** + * Returns the <code>Accessible</code> child of the specified component + * which appears at the supplied <code>Point</code>. If there is no + * child located at that particular pair of co-ordinates, null is returned + * instead. + * + * @param c the component whose children may be found at the specified + * point. + * @param p the point at which to look for the existence of children + * of the specified component. + * @return the <code>Accessible</code> child at the point, <code>p</code>, + * or null if there is no child at this point. + * @see javax.accessibility.AccessibleComponent#getAccessibleAt + */ + public static Accessible getAccessibleAt(Component c, Point p) + { + return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p); + } + + /** + * <p> + * Returns the <code>Accessible</code> child of the specified component + * that has the supplied index within the parent component. The indexing + * of the children is zero-based, making the first child have an index of + * 0. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose child should be returned. + * @param i the index of the child within the parent component. + * @return the <code>Accessible</code> child at index <code>i</code> + * in the component, <code>c</code>. + * @see javax.accessibility.AccessibleContext#getAccessibleChild + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChild + */ + public static Accessible getAccessibleChild(Component c, int i) + { + return c.getAccessibleContext().getAccessibleChild(i); + } + + /** + * <p> + * Returns the number of <code>Accessible</code> children within + * the supplied component. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose children should be counted. + * @return the number of children belonging to the component, + * <code>c</code>. + * @see javax.accessibility.AccessibleContext#getAccessibleChildrenCount + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChildrenCount + */ + public static int getAccessibleChildrenCount(Component c) + { + return c.getAccessibleContext().getAccessibleChildrenCount(); + } + + /** + * <p> + * Returns the zero-based index of the specified component + * within its parent. If the component doesn't have a parent, + * -1 is returned. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose parental index should be found. + * @return the index of the component within its parent, or -1 + * if the component doesn't have a parent. + * @see javax.accessibility.AccessibleContext#getAccessibleIndexInParent + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleIndexInParent + */ + public static int getAccessibleIndexInParent(Component c) + { + return c.getAccessibleContext().getAccessibleIndexInParent(); + } + + /** + * <p> + * Returns a set of <code>AccessibleState</code>s, which represent + * the state of the supplied component. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose accessible state should be retrieved. + * @return a set of <code>AccessibleState</code> objects, which represent + * the state of the supplied component. + * @see javax.accessibility.AccessibleContext#getAccessibleStateSet + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleStateSet + */ + public static AccessibleStateSet getAccessibleStateSet(Component c) + { + return c.getAccessibleContext().getAccessibleStateSet(); + } + + /** + * Calculates the bounds of a component in the component's own coordinate + * space. The result has the same height and width as the component's + * bounds, but its location is set to (0,0). + * + * @param aComponent The component to measure + * + * @return The component's bounds in its local coordinate space + */ + public static Rectangle getLocalBounds(Component aComponent) + { + Rectangle bounds = aComponent.getBounds(); + return new Rectangle(0, 0, bounds.width, bounds.height); + } + + /** + * If <code>comp</code> is a RootPaneContainer, return its JRootPane. + * Otherwise call <code>getAncestorOfClass(JRootPane.class, a)</code>. + * + * @param comp The component to get the JRootPane of + * + * @return a suitable JRootPane for <code>comp</code>, or <code>null</code> + * + * @see javax.swing.RootPaneContainer#getRootPane + * @see #getAncestorOfClass + */ + public static JRootPane getRootPane(Component comp) + { + if (comp instanceof RootPaneContainer) + return ((RootPaneContainer)comp).getRootPane(); + else + return (JRootPane) getAncestorOfClass(JRootPane.class, comp); + } + + /** + * Returns the least ancestor of <code>comp</code> which has the + * specified name. + * + * @param name The name to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of <code>comp</code> with the given + * name, or <code>null</code> if no such ancestor exists + * + * @see java.awt.Component#getName + * @see #getAncestorOfClass + */ + public static Container getAncestorNamed(String name, Component comp) + { + while (comp != null && (comp.getName() != name)) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the least ancestor of <code>comp</code> which is an instance + * of the specified class. + * + * @param c The class to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of <code>comp</code> which is an instance + * of the given class, or <code>null</code> if no such ancestor exists + * + * @see #getAncestorOfClass + * @see #windowForComponent + */ + public static Container getAncestorOfClass(Class<?> c, Component comp) + { + while (comp != null && (! c.isInstance(comp))) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the first ancestor of <code>comp</code> that is a {@link Window} + * or <code>null</code> if <code>comp</code> is not contained in a + * {@link Window}. + * + * This is equivalent to calling + * <code>getAncestorOfClass(Window, comp)</code> or + * <code>windowForComponent(comp)</code>. + * + * @param comp the component for which we are searching the ancestor Window + * + * @return the first ancestor Window of <code>comp</code> or + * <code>null</code> if <code>comp</code> is not contained in a Window + */ + public static Window getWindowAncestor(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>. + * + * @param comp The component to search for an ancestor window + * + * @return An ancestral window, or <code>null</code> if none exists + */ + public static Window windowForComponent(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Returns the "root" of the component tree containint <code>comp</code> + * The root is defined as either the <em>least</em> ancestor of + * <code>comp</code> which is a {@link Window}, or the <em>greatest</em> + * ancestor of <code>comp</code> which is a {@link Applet} if no {@link + * Window} ancestors are found. + * + * @param comp The component to search for a root + * + * @return The root of the component's tree, or <code>null</code> + */ + public static Component getRoot(Component comp) + { + Applet app = null; + Window win = null; + + while (comp != null) + { + if (win == null && comp instanceof Window) + win = (Window) comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + if (win != null) + return win; + return app; + } + + /** + * Return true if a descends from b, in other words if b is an ancestor of a. + * + * @param a The child to search the ancestry of + * @param b The potential ancestor to search for + * @return true if a is a descendent of b, false otherwise + */ + public static boolean isDescendingFrom(Component a, Component b) + { + while (true) + { + if (a == null || b == null) + return false; + if (a == b) + return true; + a = a.getParent(); + } + } + + /** + * Returns the deepest descendent of parent which is both visible and + * contains the point <code>(x,y)</code>. Returns parent when either + * parent is not a container, or has no children which contain + * <code>(x,y)</code>. Returns <code>null</code> when either + * <code>(x,y)</code> is outside the bounds of parent, or parent is + * <code>null</code>. + * + * @param parent The component to search the descendents of + * @param x Horizontal coordinate to search for + * @param y Vertical coordinate to search for + * + * @return A component containing <code>(x,y)</code>, or + * <code>null</code> + * + * @see java.awt.Container#findComponentAt(int, int) + */ + public static Component getDeepestComponentAt(Component parent, int x, int y) + { + if (parent == null || (! parent.contains(x, y))) + return null; + + if (! (parent instanceof Container)) + return parent; + + Container c = (Container) parent; + return c.findComponentAt(x, y); + } + + /** + * Converts a point from a component's local coordinate space to "screen" + * coordinates (such as the coordinate space mouse events are delivered + * in). This operation is equivalent to translating the point by the + * location of the component (which is the origin of its coordinate + * space). + * + * @param p The point to convert + * @param c The component which the point is expressed in terms of + * + * @see #convertPointFromScreen + */ + public static void convertPointToScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(c0.x, c0.y); + } + + /** + * Converts a point from "screen" coordinates (such as the coordinate + * space mouse events are delivered in) to a component's local coordinate + * space. This operation is equivalent to translating the point by the + * negation of the component's location (which is the origin of its + * coordinate space). + * + * @param p The point to convert + * @param c The component which the point should be expressed in terms of + */ + public static void convertPointFromScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(-c0.x, -c0.y); + } + + /** + * Converts a point <code>(x,y)</code> from the coordinate space of one + * component to another. This is equivalent to converting the point from + * <code>source</code> space to screen space, then back from screen space + * to <code>destination</code> space. If exactly one of the two + * Components is <code>null</code>, it is taken to refer to the root + * ancestor of the other component. If both are <code>null</code>, no + * transformation is done. + * + * @param source The component which the point is expressed in terms of + * @param x Horizontal coordinate of point to transform + * @param y Vertical coordinate of point to transform + * @param destination The component which the return value will be + * expressed in terms of + * + * @return The point <code>(x,y)</code> converted from the coordinate space of the + * source component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertRectangle + * @see #getRoot + */ + public static Point convertPoint(Component source, int x, int y, + Component destination) + { + Point pt = new Point(x, y); + + if (source == null && destination == null) + return pt; + + if (source == null) + source = getRoot(destination); + + if (destination == null) + destination = getRoot(source); + + if (source.isShowing() && destination.isShowing()) + { + convertPointToScreen(pt, source); + convertPointFromScreen(pt, destination); + } + + return pt; + } + + public static Point convertPoint(Component source, Point aPoint, Component destination) + { + return convertPoint(source, aPoint.x, aPoint.y, destination); + } + + /** + * Converts a rectangle from the coordinate space of one component to + * another. This is equivalent to converting the rectangle from + * <code>source</code> space to screen space, then back from screen space + * to <code>destination</code> space. If exactly one of the two + * Components is <code>null</code>, it is taken to refer to the root + * ancestor of the other component. If both are <code>null</code>, no + * transformation is done. + * + * @param source The component which the rectangle is expressed in terms of + * @param rect The rectangle to convert + * @param destination The component which the return value will be + * expressed in terms of + * + * @return A new rectangle, equal in size to the input rectangle, but + * with its position converted from the coordinate space of the source + * component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertPoint(Component, int, int, Component) + * @see #getRoot + */ + public static Rectangle convertRectangle(Component source, + Rectangle rect, + Component destination) + { + Point pt = convertPoint(source, rect.x, rect.y, destination); + return new Rectangle(pt.x, pt.y, rect.width, rect.height); + } + + /** + * Convert a mouse event which refrers to one component to another. This + * includes changing the mouse event's coordinate space, as well as the + * source property of the event. If <code>source</code> is + * <code>null</code>, it is taken to refer to <code>destination</code>'s + * root component. If <code>destination</code> is <code>null</code>, the + * new event will remain expressed in <code>source</code>'s coordinate + * system. + * + * @param source The component the mouse event currently refers to + * @param sourceEvent The mouse event to convert + * @param destination The component the new mouse event should refer to + * + * @return A new mouse event expressed in terms of the destination + * component's coordinate space, and with the destination component as + * its source + * + * @see #convertPoint(Component, int, int, Component) + */ + public static MouseEvent convertMouseEvent(Component source, + MouseEvent sourceEvent, + Component destination) + { + Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), + destination); + + return new MouseEvent(destination, sourceEvent.getID(), + sourceEvent.getWhen(), sourceEvent.getModifiersEx(), + newpt.x, newpt.y, sourceEvent.getClickCount(), + sourceEvent.isPopupTrigger(), sourceEvent.getButton()); + } + + /** + * Recursively walk the component tree under <code>comp</code> calling + * <code>updateUI</code> on each {@link JComponent} found. This causes + * the entire tree to re-initialize its UI delegates. + * + * @param comp The component to walk the children of, calling <code>updateUI</code> + */ + public static void updateComponentTreeUI(Component comp) + { + updateComponentTreeUIImpl(comp); + if (comp instanceof JComponent) + { + JComponent jc = (JComponent) comp; + jc.revalidate(); + } + else + { + comp.invalidate(); + comp.validate(); + } + comp.repaint(); + } + + /** + * Performs the actual work for {@link #updateComponentTreeUI(Component)}. + * This calls updateUI() on c if it is a JComponent, and then walks down + * the component tree and calls this method on each child component. + * + * @param c the component to update the UI + */ + private static void updateComponentTreeUIImpl(Component c) + { + if (c instanceof JComponent) + { + JComponent jc = (JComponent) c; + jc.updateUI(); + } + + Component[] components = null; + if (c instanceof JMenu) + components = ((JMenu) c).getMenuComponents(); + else if (c instanceof Container) + components = ((Container) c).getComponents(); + if (components != null) + { + for (int i = 0; i < components.length; ++i) + updateComponentTreeUIImpl(components[i]); + } + } + + /** + * <p>Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.</p> + * + * <p>The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.</p> + * + * <p>The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * <code>LEADING</code>, <code>TRAILING</code>, <code>LEFT</code>, + * <code>RIGHT</code> or <code>CENTER</code>. The vertical position value + * should be one fo the constants <code>TOP</code>, <code>BOTTOM</code> + * or <code>CENTER</code>.</p> + * + * <p>The text-icon gap value controls the number of pixels between the + * icon and the text.</p> + * + * <p>The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants <code>LEADING</code>, + * <code>TRAILING</code>, <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. The vertical alignment valus should be one of the + * constants <code>TOP</code>, <code>BOTTOM</code> or + * <code>CENTER</code>.</p> + * + * <p>If the <code>LEADING</code> or <code>TRAILING</code> constants are + * given for horizontal alignment or horizontal text position, they are + * interpreted relative to the provided component's orientation property, + * a constant in the {@link java.awt.ComponentOrientation} class. For + * example, if the component's orientation is <code>LEFT_TO_RIGHT</code>, + * then the <code>LEADING</code> value is a synonym for <code>LEFT</code> + * and the <code>TRAILING</code> value is a synonym for + * <code>RIGHT</code></p> + * + * <p>If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.</p> + * + * @param c A component used for its orientation value + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + + public static String layoutCompoundLabel(JComponent c, + FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { + + // Fix up the orientation-based horizontal positions. + + boolean ltr = true; + if (c != null && ! c.getComponentOrientation().isLeftToRight()) + ltr = false; + + switch (horizontalTextPosition) + { + case LEADING: + horizontalTextPosition = ltr ? LEFT : RIGHT; + break; + case TRAILING: + horizontalTextPosition = ltr ? RIGHT : LEFT; + break; + default: + // Nothing to do in the other cases. + } + + // Fix up the orientation-based alignments. + switch (horizontalAlignment) + { + case LEADING: + horizontalAlignment = ltr ? LEFT : RIGHT; + break; + case TRAILING: + horizontalAlignment = ltr ? RIGHT : LEFT; + break; + default: + // Nothing to do in the other cases. + } + + return layoutCompoundLabelImpl(c, fm, text, icon, + verticalAlignment, + horizontalAlignment, + verticalTextPosition, + horizontalTextPosition, + viewR, iconR, textR, textIconGap); + } + + /** + * <p>Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.</p> + * + * <p>The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.</p> + * + * <p>The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The + * vertical position value should be one fo the constants + * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p> + * + * <p>The text-icon gap value controls the number of pixels between the + * icon and the text.</p> + * + * <p>The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. The vertical alignment valus should be one of the + * constants <code>TOP</code>, <code>BOTTOM</code> or + * <code>CENTER</code>.</p> + * + * <p>If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.</p> + * + * <p>Note that this method does <em>not</em> know how to deal with + * horizontal alignments or positions given as <code>LEADING</code> or + * <code>TRAILING</code> values. Use the other overloaded variant of this + * method if you wish to use such values. + * + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + + public static String layoutCompoundLabel(FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { + return layoutCompoundLabelImpl(null, fm, text, icon, verticalAlignment, + horizontalAlignment, verticalTextPosition, + horizontalTextPosition, viewR, iconR, textR, + textIconGap); + } + + /** + * <p>Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.</p> + * + * <p>The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.</p> + * + * <p>The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The + * vertical position value should be one fo the constants + * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p> + * + * <p>The text-icon gap value controls the number of pixels between the + * icon and the text.</p> + * + * <p>The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. The vertical alignment valus should be one of the + * constants <code>TOP</code>, <code>BOTTOM</code> or + * <code>CENTER</code>.</p> + * + * <p>If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.</p> + * + * <p>Note that this method does <em>not</em> know how to deal with + * horizontal alignments or positions given as <code>LEADING</code> or + * <code>TRAILING</code> values. Use the other overloaded variant of this + * method if you wish to use such values. + * + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + private static String layoutCompoundLabelImpl(JComponent c, + FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { + + // Work out basic height and width. + + if (icon == null) + { + textIconGap = 0; + iconR.width = 0; + iconR.height = 0; + } + else + { + iconR.width = icon.getIconWidth(); + iconR.height = icon.getIconHeight(); + } + + if (text == null || text.equals("")) + { + textIconGap = 0; + textR.width = 0; + textR.height = 0; + text = ""; + } + else + { + int availableWidth = viewR.width; + if (horizontalTextPosition != CENTER) + availableWidth -= iconR.width + textIconGap; + View html = c == null ? null + : (View) c.getClientProperty(BasicHTML.propertyKey); + if (html != null) + { + textR.width = (int) html.getPreferredSpan(View.X_AXIS); + textR.width = Math.min(availableWidth, textR.width); + textR.height = (int) html.getPreferredSpan(View.Y_AXIS); + } + else + { + int fromIndex = 0; + textR.width = fm.stringWidth(text); + textR.height = fm.getHeight(); + if (textR.width > availableWidth) + { + text = clipString(c, fm, text, availableWidth); + textR.width = fm.stringWidth(text); + } + } + } + + // Work out the position of text, assuming the top-left coord + // starts at (0,0). We will fix that up momentarily, after these + // "position" decisions are made and we look at alignment. + + switch (verticalTextPosition) + { + case TOP: + textR.y = horizontalTextPosition == CENTER ? + - textR.height - textIconGap : 0; + break; + case BOTTOM: + textR.y = horizontalTextPosition == CENTER ? + iconR.height + textIconGap : iconR.height - textR.height; + break; + case CENTER: + textR.y = iconR.height / 2 - textR.height / 2; + break; + } + + switch (horizontalTextPosition) + { + case LEFT: + textR.x = -(textR.width + textIconGap); + break; + case RIGHT: + textR.x = iconR.width + textIconGap; + break; + case CENTER: + textR.x = iconR.width / 2 - textR.width / 2; + break; + } + + // The two rectangles are laid out correctly now, but only assuming + // that their upper left corner is at (0,0). If we have any alignment other + // than TOP and LEFT, we need to adjust them. + + // These coordinates specify the rectangle that contains both the + // icon and text. Move it so that it fullfills the alignment properties. + int lx = Math.min(iconR.x, textR.x); + int lw = Math.max(iconR.x + iconR.width, textR.x + textR.width) - lx; + int ly = Math.min(iconR.y, textR.y); + int lh = Math.max(iconR.y + iconR.height, textR.y + textR.height) - ly; + int horizontalAdjustment = 0; + int verticalAdjustment = 0; + switch (verticalAlignment) + { + case TOP: + verticalAdjustment = viewR.y - ly; + break; + case BOTTOM: + verticalAdjustment = viewR.y + viewR.height - ly - lh; + break; + case CENTER: + verticalAdjustment = viewR.y + viewR.height / 2 - ly - lh / 2; + break; + } + switch (horizontalAlignment) + { + case LEFT: + horizontalAdjustment = viewR.x - lx; + break; + case RIGHT: + horizontalAdjustment = viewR.x + viewR.width - lx - lw; + break; + case CENTER: + horizontalAdjustment = (viewR.x + (viewR.width / 2)) - (lx + (lw / 2)); + break; + } + iconR.x += horizontalAdjustment; + iconR.y += verticalAdjustment; + + textR.x += horizontalAdjustment; + textR.y += verticalAdjustment; + + return text; + } + + /** + * The method clips the specified string so that it fits into the + * available width. It is only called when the text really doesn't fit, + * so we don't need to check that again. + * + * @param c the component + * @param fm the font metrics + * @param text the text + * @param availableWidth the available width + * + * @return the clipped string + */ + private static String clipString(JComponent c, FontMetrics fm, String text, + int availableWidth) + { + String dots = "..."; + int dotsWidth = fm.stringWidth(dots); + char[] string = text.toCharArray(); + int endIndex = string.length; + while (fm.charsWidth(string, 0, endIndex) + dotsWidth > availableWidth + && endIndex > 0) + endIndex--; + String clipped; + if (string.length >= endIndex + 3) + { + string[endIndex] = '.'; + string[endIndex + 1] = '.'; + string[endIndex + 2] = '.'; + clipped = new String(string, 0, endIndex + 3); + } + else + { + char[] clippedChars = new char[string.length + 3]; + System.arraycopy(string, 0, clippedChars, 0, string.length); + clippedChars[endIndex] = '.'; + clippedChars[endIndex + 1] = '.'; + clippedChars[endIndex + 2] = '.'; + clipped = new String(clippedChars, 0, endIndex + 3); + } + return clipped; + } + + /** + * Calls {@link java.awt.EventQueue#invokeLater} with the + * specified {@link Runnable}. + */ + public static void invokeLater(Runnable doRun) + { + java.awt.EventQueue.invokeLater(doRun); + } + + /** + * Calls {@link java.awt.EventQueue#invokeAndWait} with the + * specified {@link Runnable}. + */ + public static void invokeAndWait(Runnable doRun) + throws InterruptedException, + InvocationTargetException + { + java.awt.EventQueue.invokeAndWait(doRun); + } + + /** + * Calls {@link java.awt.EventQueue#isDispatchThread()}. + * + * @return <code>true</code> if the current thread is the current AWT event + * dispatch thread. + */ + public static boolean isEventDispatchThread() + { + return java.awt.EventQueue.isDispatchThread(); + } + + /** + * This method paints the given component at the given position and size. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param x The x coordinate to draw at. + * @param y The y coordinate to draw at. + * @param w The width of the drawing area. + * @param h The height of the drawing area. + */ + public static void paintComponent(Graphics g, Component c, Container p, + int x, int y, int w, int h) + { + Container parent = c.getParent(); + if (parent != null) + parent.remove(c); + if (p != null) + p.add(c); + + Shape savedClip = g.getClip(); + + g.setClip(x, y, w, h); + g.translate(x, y); + + c.paint(g); + + g.translate(-x, -y); + g.setClip(savedClip); + } + + /** + * This method paints the given component in the given rectangle. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param r The rectangle that describes the drawing area. + */ + public static void paintComponent(Graphics g, Component c, + Container p, Rectangle r) + { + paintComponent(g, c, p, r.x, r.y, r.width, r.height); + } + + /** + * This method returns the common Frame owner used in JDialogs or + * JWindow when no owner is provided. + * + * @return The common Frame + */ + static Window getOwnerFrame(Window owner) + { + Window result = owner; + if (result == null) + { + if (ownerFrame == null) + ownerFrame = new OwnerFrame(); + result = ownerFrame; + } + return result; + } + + /** + * Checks if left mouse button was clicked. + * + * @param event the event to check + * + * @return true if left mouse was clicked, false otherwise. + */ + public static boolean isLeftMouseButton(MouseEvent event) + { + return ((event.getModifiers() & InputEvent.BUTTON1_MASK) != 0); + } + + /** + * Checks if middle mouse button was clicked. + * + * @param event the event to check + * + * @return true if middle mouse was clicked, false otherwise. + */ + public static boolean isMiddleMouseButton(MouseEvent event) + { + return ((event.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) + == InputEvent.BUTTON2_DOWN_MASK); + } + + /** + * Checks if right mouse button was clicked. + * + * @param event the event to check + * + * @return true if right mouse was clicked, false otherwise. + */ + public static boolean isRightMouseButton(MouseEvent event) + { + return ((event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) + == InputEvent.BUTTON3_DOWN_MASK); + } + + /** + * This frame should be used when constructing a Window/JDialog without + * a parent. In this case, we are forced to use this frame as a window's + * parent, because we simply cannot pass null instead of parent to Window + * constructor, since doing it will result in NullPointerException. + */ + private static class OwnerFrame extends Frame + { + public void setVisible(boolean b) + { + // Do nothing here. + } + + public boolean isShowing() + { + return true; + } + } + + public static boolean notifyAction(Action action, + KeyStroke ks, + KeyEvent event, + Object sender, + int modifiers) + { + if (action != null && action.isEnabled()) + { + String name = (String) action.getValue(Action.ACTION_COMMAND_KEY); + if (name == null + && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) + name = new String(new char[] {event.getKeyChar()}); + action.actionPerformed(new ActionEvent(sender, + ActionEvent.ACTION_PERFORMED, + name, modifiers)); + return true; + } + return false; + } + + /** + * <p>Change the shared, UI-managed {@link ActionMap} for a given + * component. ActionMaps are arranged in a hierarchy, in order to + * encourage sharing of common actions between components. The hierarchy + * unfortunately places UI-managed ActionMaps at the <em>end</em> of the + * parent-pointer chain, as illustrated:</p> + * + * <pre> + * [{@link javax.swing.JComponent#getActionMap()}] + * --> [{@link javax.swing.ActionMap}] + * parent --> [{@link javax.swing.text.JTextComponent.KeymapActionMap}] + * parent --> [{@link javax.swing.plaf.ActionMapUIResource}] + * </pre> + * + * <p>Our goal with this method is to replace the first ActionMap along + * this chain which is an instance of {@link ActionMapUIResource}, since + * these are the ActionMaps which are supposed to be shared between + * components.</p> + * + * <p>If the provided ActionMap is <code>null</code>, we interpret the + * call as a request to remove the UI-managed ActionMap from the + * component's ActionMap parent chain.</p> + */ + public static void replaceUIActionMap(JComponent component, + ActionMap uiActionMap) + { + ActionMap child = component.getActionMap(); + if (child == null) + component.setActionMap(uiActionMap); + else + { + ActionMap parent = child.getParent(); + while (parent != null && !(parent instanceof ActionMapUIResource)) + { + child = parent; + parent = child.getParent(); + } + // Sanity check to avoid loops. + if (child != uiActionMap) + child.setParent(uiActionMap); + } + } + + /** + * <p>Change the shared, UI-managed {@link InputMap} for a given + * component. InputMaps are arranged in a hierarchy, in order to + * encourage sharing of common input mappings between components. The + * hierarchy unfortunately places UI-managed InputMaps at the + * <em>end</em> of the parent-pointer chain, as illustrated:</p> + * + * <pre> + * [{@link javax.swing.JComponent#getInputMap()}] + * --> [{@link javax.swing.InputMap}] + * parent --> [{@link javax.swing.text.JTextComponent.KeymapWrapper}] + * parent --> [{@link javax.swing.plaf.InputMapUIResource}] + * </pre> + * + * <p>Our goal with this method is to replace the first InputMap along + * this chain which is an instance of {@link InputMapUIResource}, since + * these are the InputMaps which are supposed to be shared between + * components.</p> + * + * <p>If the provided InputMap is <code>null</code>, we interpret the + * call as a request to remove the UI-managed InputMap from the + * component's InputMap parent chain.</p> + */ + public static void replaceUIInputMap(JComponent component, + int condition, + InputMap uiInputMap) + { + InputMap child = component.getInputMap(condition); + if (child == null) + component.setInputMap(condition, uiInputMap); + else + { + InputMap parent = child.getParent(); + while (parent != null && !(parent instanceof InputMapUIResource)) + { + child = parent; + parent = parent.getParent(); + } + // Sanity check to avoid loops. + if (child != uiInputMap) + child.setParent(uiInputMap); + } + } + + /** + * Subtracts a rectangle from another and return the area as an array + * of rectangles. + * Returns the areas of rectA which are not covered by rectB. + * If the rectangles do not overlap, or if either parameter is + * <code>null</code>, a zero-size array is returned. + * @param rectA The first rectangle + * @param rectB The rectangle to subtract from the first + * @return An array of rectangles representing the area in rectA + * not overlapped by rectB + */ + public static Rectangle[] computeDifference(Rectangle rectA, Rectangle rectB) + { + if (rectA == null || rectB == null) + return new Rectangle[0]; + + Rectangle[] r = new Rectangle[4]; + int x1 = rectA.x; + int y1 = rectA.y; + int w1 = rectA.width; + int h1 = rectA.height; + int x2 = rectB.x; + int y2 = rectB.y; + int w2 = rectB.width; + int h2 = rectB.height; + + // (outer box = rectA) + // ------------- + // |_____0_____| + // | |rectB| | + // |_1|_____|_2| + // | 3 | + // ------------- + int H0 = (y2 > y1) ? y2 - y1 : 0; // height of box 0 + int H3 = (y2 + h2 < y1 + h1) ? y1 + h1 - y2 - h2 : 0; // height box 3 + int W1 = (x2 > x1) ? x2 - x1 : 0; // width box 1 + int W2 = (x1 + w1 > x2 + w2) ? x1 + w1 - x2 - w2 : 0; // w. box 2 + int H12 = (H0 + H3 < h1) ? h1 - H0 - H3 : 0; // height box 1 & 2 + + if (H0 > 0) + r[0] = new Rectangle(x1, y1, w1, H0); + else + r[0] = null; + + if (W1 > 0 && H12 > 0) + r[1] = new Rectangle(x1, y1 + H0, W1, H12); + else + r[1] = null; + + if (W2 > 0 && H12 > 0) + r[2] = new Rectangle(x2 + w2, y1 + H0, W2, H12); + else + r[2] = null; + + if (H3 > 0) + r[3] = new Rectangle(x1, y1 + H0 + H12, w1, H3); + else + r[3] = null; + + // sort out null objects + int n = 0; + for (int i = 0; i < 4; i++) + if (r[i] != null) + n++; + Rectangle[] out = new Rectangle[n]; + for (int i = 3; i >= 0; i--) + if (r[i] != null) + out[--n] = r[i]; + + return out; + } + + /** + * Calculates the intersection of two rectangles. The result is stored + * in <code>rect</code>. This is basically the same + * like {@link Rectangle#intersection(Rectangle)}, only that it does not + * create new Rectangle instances. The tradeoff is that you loose any data in + * <code>rect</code>. + * + * @param x upper-left x coodinate of first rectangle + * @param y upper-left y coodinate of first rectangle + * @param w width of first rectangle + * @param h height of first rectangle + * @param rect a Rectangle object of the second rectangle + * + * @throws NullPointerException if rect is null + * + * @return a rectangle corresponding to the intersection of the + * two rectangles. An empty rectangle is returned if the rectangles + * do not overlap + */ + public static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } + + /** + * Calculates the width of a given string. + * + * @param fm the <code>FontMetrics</code> object to use + * @param str the string + * + * @return the width of the the string. + */ + public static int computeStringWidth(FontMetrics fm, String str) + { + return fm.stringWidth(str); + } + + /** + * Calculates the union of two rectangles. The result is stored in + * <code>rect</code>. This is basically the same as + * {@link Rectangle#union(Rectangle)} except that it avoids creation of new + * Rectangle objects. The tradeoff is that you loose any data in + * <code>rect</code>. + * + * @param x upper-left x coodinate of first rectangle + * @param y upper-left y coodinate of first rectangle + * @param w width of first rectangle + * @param h height of first rectangle + * @param rect a Rectangle object of the second rectangle + * + * @throws NullPointerException if rect is null + * + * @return a rectangle corresponding to the union of the + * two rectangles; a rectangle encompassing both is returned if the + * rectangles do not overlap + */ + public static Rectangle computeUnion(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.x; + int y2 = (int) rect.y; + int w2 = (int) rect.width; + int h2 = (int) rect.height; + + int dx = (x < x2) ? x : x2; + int dy = (y < y2) ? y : y2; + int dw = (x + w > x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + return rect; + } + + /** + * Tests if a rectangle contains another. + * @param a first rectangle + * @param b second rectangle + * @return true if a contains b, false otherwise + * @throws NullPointerException + */ + public static boolean isRectangleContainingRectangle(Rectangle a, Rectangle b) + { + // Note: zero-size rects inclusive, differs from Rectangle.contains() + return b.width >= 0 && b.height >= 0 && b.width >= 0 && b.height >= 0 + && b.x >= a.x && b.x + b.width <= a.x + a.width && b.y >= a.y + && b.y + b.height <= a.y + a.height; + } + + /** + * Returns the InputMap that is provided by the ComponentUI of + * <code>component</code> for the specified condition. + * + * @param component the component for which the InputMap is returned + * @param cond the condition that specifies which of the three input + * maps should be returned, may be + * {@link JComponent#WHEN_IN_FOCUSED_WINDOW}, + * {@link JComponent#WHEN_FOCUSED} or + * {@link JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT} + * + * @return The input map. + */ + public static InputMap getUIInputMap(JComponent component, int cond) + { + if (UIManager.getUI(component) != null) + // we assume here that the UI class sets the parent of the component's + // InputMap, which is the correct behaviour. If it's not, then + // this can be considered a bug + return component.getInputMap(cond).getParent(); + else + return null; + } + + /** + * Returns the ActionMap that is provided by the ComponentUI of + * <code>component</code>. + * + * @param component the component for which the ActionMap is returned + */ + public static ActionMap getUIActionMap(JComponent component) + { + if (UIManager.getUI(component) != null) + // we assume here that the UI class sets the parent of the component's + // ActionMap, which is the correct behaviour. If it's not, then + // this can be considered a bug + return component.getActionMap().getParent(); + else + return null; + } + + /** + * Processes key bindings for the component that is associated with the + * key event. Note that this method does not make sense for + * JComponent-derived components, except when + * {@link JComponent#processKeyEvent(KeyEvent)} is overridden and super is + * not called. + * + * This method searches through the component hierarchy of the component's + * top-level container to find a <code>JComponent</code> that has a binding + * for the key event in the WHEN_IN_FOCUSED_WINDOW scope. + * + * @param ev the key event + * + * @return <code>true</code> if a binding has been found and processed, + * <code>false</code> otherwise + * + * @since 1.4 + */ + public static boolean processKeyBindings(KeyEvent ev) + { + Component c = ev.getComponent(); + KeyStroke s = KeyStroke.getKeyStrokeForEvent(ev); + KeyboardManager km = KeyboardManager.getManager(); + return km.processKeyStroke(c, s, ev); + } + + /** + * Returns a string representing one of the horizontal alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEFT}</td> + * <td><code>"LEFT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#RIGHT}</td> + * <td><code>"RIGHT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEADING}</td> + * <td><code>"LEADING"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TRAILING}</td> + * <td><code>"TRAILING"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertHorizontalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.LEFT: + return "LEFT"; + case SwingConstants.RIGHT: + return "RIGHT"; + case SwingConstants.LEADING: + return "LEADING"; + case SwingConstants.TRAILING: + return "TRAILING"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the vertical alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TOP}</td> + * <td><code>"TOP"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#BOTTOM}</td> + * <td><code>"BOTTOM"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertVerticalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.TOP: + return "TOP"; + case SwingConstants.BOTTOM: + return "BOTTOM"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the default operation codes + * defined in the {@link WindowConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link WindowConstants#DO_NOTHING_ON_CLOSE}</td> + * <td><code>"DO_NOTHING_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#HIDE_ON_CLOSE}</td> + * <td><code>"HIDE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#DISPOSE_ON_CLOSE}</td> + * <td><code>"DISPOSE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#EXIT_ON_CLOSE}</td> + * <td><code>"EXIT_ON_CLOSE"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this method will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertWindowConstantToString(int code) + { + switch (code) + { + case WindowConstants.DO_NOTHING_ON_CLOSE: + return "DO_NOTHING_ON_CLOSE"; + case WindowConstants.HIDE_ON_CLOSE: + return "HIDE_ON_CLOSE"; + case WindowConstants.DISPOSE_ON_CLOSE: + return "DISPOSE_ON_CLOSE"; + case WindowConstants.EXIT_ON_CLOSE: + return "EXIT_ON_CLOSE"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Converts a rectangle in the coordinate system of a child component into + * a rectangle of one of it's Ancestors. The result is stored in the input + * rectangle. + * + * @param comp the child component + * @param r the rectangle to convert + * @param ancestor the ancestor component + */ + static void convertRectangleToAncestor(Component comp, Rectangle r, + Component ancestor) + { + if (comp == ancestor) + return; + + r.x += comp.getX(); + r.y += comp.getY(); + + Component parent = comp.getParent(); + if (parent != null && parent != ancestor) + convertRectangleToAncestor(parent, r, ancestor); + } +} |