From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001
From: upstream source tree
+ * Returns the
+ * 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.
+ *
+ * Returns the number of
+ * 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.
+ *
+ * Returns the zero-based index of the specified component
+ * within its parent. If the component doesn't have a parent,
+ * -1 is returned.
+ *
+ * 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.
+ *
+ * Returns a set of
+ * 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.
+ * 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. 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. The position values control where the text is placed relative to
+ * the icon. The horizontal position value should be one of the constants
+ * The text-icon gap value controls the number of pixels between the
+ * icon and the text. 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 If the If the text and icon are equal to or larger than the view
+ * rectangle, the horizontal and vertical alignment values have no
+ * affect. 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. 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. The position values control where the text is placed relative to
+ * the icon. The horizontal position value should be one of the constants
+ * The text-icon gap value controls the number of pixels between the
+ * icon and the text. 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 If the text and icon are equal to or larger than the view
+ * rectangle, the horizontal and vertical alignment values have no
+ * affect. Note that this method does not know how to deal with
+ * horizontal alignments or positions given as 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. 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. The position values control where the text is placed relative to
+ * the icon. The horizontal position value should be one of the constants
+ * The text-icon gap value controls the number of pixels between the
+ * icon and the text. 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 If the text and icon are equal to or larger than the view
+ * rectangle, the horizontal and vertical alignment values have no
+ * affect. Note that this method does not know how to deal with
+ * horizontal alignments or positions given as 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 end of the
+ * parent-pointer chain, as illustrated: 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. If the provided ActionMap is 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
+ * end of the parent-pointer chain, as illustrated: 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. If the provided InputMap is
+ * null
,
+ * this method returns null
).
+ * @param r a carrier to store the return value in (if null
, a
+ * new Rectangle
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 null
if comp
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 null
+ *
+ * @deprecated 1.4 Replaced by
+ * KeyboardFocusManager.getFocusOwner()
.
+ */
+ 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 Accessible
child of the specified component
+ * which appears at the supplied Point
. 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 Accessible
child at the point, p
,
+ * 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);
+ }
+
+ /**
+ * Accessible
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.
+ * Accessible
child at index i
+ * in the component, c
.
+ * @see javax.accessibility.AccessibleContext#getAccessibleChild
+ * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChild
+ */
+ public static Accessible getAccessibleChild(Component c, int i)
+ {
+ return c.getAccessibleContext().getAccessibleChild(i);
+ }
+
+ /**
+ * Accessible
children within
+ * the supplied component.
+ * c
.
+ * @see javax.accessibility.AccessibleContext#getAccessibleChildrenCount
+ * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChildrenCount
+ */
+ public static int getAccessibleChildrenCount(Component c)
+ {
+ return c.getAccessibleContext().getAccessibleChildrenCount();
+ }
+
+ /**
+ * AccessibleState
s, which represent
+ * the state of the supplied component.
+ * AccessibleState
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 comp
is a RootPaneContainer, return its JRootPane.
+ * Otherwise call getAncestorOfClass(JRootPane.class, a)
.
+ *
+ * @param comp The component to get the JRootPane of
+ *
+ * @return a suitable JRootPane for comp
, or null
+ *
+ * @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 comp
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 comp
with the given
+ * name, or null
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 comp
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 comp
which is an instance
+ * of the given class, or null
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 comp
that is a {@link Window}
+ * or null
if comp
is not contained in a
+ * {@link Window}.
+ *
+ * This is equivalent to calling
+ * getAncestorOfClass(Window, comp)
or
+ * windowForComponent(comp)
.
+ *
+ * @param comp the component for which we are searching the ancestor Window
+ *
+ * @return the first ancestor Window of comp
or
+ * null
if comp
is not contained in a Window
+ */
+ public static Window getWindowAncestor(Component comp)
+ {
+ return (Window) getAncestorOfClass(Window.class, comp);
+ }
+
+ /**
+ * Equivalent to calling getAncestorOfClass(Window, comp)
.
+ *
+ * @param comp The component to search for an ancestor window
+ *
+ * @return An ancestral window, or null
if none exists
+ */
+ public static Window windowForComponent(Component comp)
+ {
+ return (Window) getAncestorOfClass(Window.class, comp);
+ }
+
+ /**
+ * Returns the "root" of the component tree containint comp
+ * The root is defined as either the least ancestor of
+ * comp
which is a {@link Window}, or the greatest
+ * ancestor of comp
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 null
+ */
+ 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 (x,y)
. Returns parent when either
+ * parent is not a container, or has no children which contain
+ * (x,y)
. Returns null
when either
+ * (x,y)
is outside the bounds of parent, or parent is
+ * null
.
+ *
+ * @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 (x,y)
, or
+ * null
+ *
+ * @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 (x,y)
from the coordinate space of one
+ * component to another. This is equivalent to converting the point from
+ * source
space to screen space, then back from screen space
+ * to destination
space. If exactly one of the two
+ * Components is null
, it is taken to refer to the root
+ * ancestor of the other component. If both are null
, 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 (x,y)
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
+ * source
space to screen space, then back from screen space
+ * to destination
space. If exactly one of the two
+ * Components is null
, it is taken to refer to the root
+ * ancestor of the other component. If both are null
, 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 source
is
+ * null
, it is taken to refer to destination
's
+ * root component. If destination
is null
, the
+ * new event will remain expressed in source
'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 comp
calling
+ * updateUI
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 updateUI
+ */
+ 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]);
+ }
+ }
+
+ /**
+ * LEADING
, TRAILING
, LEFT
,
+ * RIGHT
or CENTER
. The vertical position value
+ * should be one fo the constants TOP
, BOTTOM
+ * or CENTER
.LEADING
,
+ * TRAILING
, LEFT
, RIGHT
or
+ * CENTER
. The vertical alignment valus should be one of the
+ * constants TOP
, BOTTOM
or
+ * CENTER
.LEADING
or TRAILING
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 LEFT_TO_RIGHT
,
+ * then the LEADING
value is a synonym for LEFT
+ * and the TRAILING
value is a synonym for
+ * RIGHT
LEFT
, RIGHT
or CENTER
. The
+ * vertical position value should be one fo the constants
+ * TOP
, BOTTOM
or CENTER
.LEFT
, RIGHT
or
+ * CENTER
. The vertical alignment valus should be one of the
+ * constants TOP
, BOTTOM
or
+ * CENTER
.LEADING
or
+ * TRAILING
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);
+ }
+
+ /**
+ * LEFT
, RIGHT
or CENTER
. The
+ * vertical position value should be one fo the constants
+ * TOP
, BOTTOM
or CENTER
.LEFT
, RIGHT
or
+ * CENTER
. The vertical alignment valus should be one of the
+ * constants TOP
, BOTTOM
or
+ * CENTER
.LEADING
or
+ * TRAILING
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 true
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;
+ }
+
+ /**
+ *
+ * [{@link javax.swing.JComponent#getActionMap()}]
+ * --> [{@link javax.swing.ActionMap}]
+ * parent --> [{@link javax.swing.text.JTextComponent.KeymapActionMap}]
+ * parent --> [{@link javax.swing.plaf.ActionMapUIResource}]
+ *
+ *
+ * null
, we interpret the
+ * call as a request to remove the UI-managed ActionMap from the
+ * component's ActionMap parent chain.
+ * [{@link javax.swing.JComponent#getInputMap()}]
+ * --> [{@link javax.swing.InputMap}]
+ * parent --> [{@link javax.swing.text.JTextComponent.KeymapWrapper}]
+ * parent --> [{@link javax.swing.plaf.InputMapUIResource}]
+ *
+ *
+ * null
, we interpret the
+ * call as a request to remove the UI-managed InputMap from the
+ * component's InputMap parent chain.null
, 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 rect
. 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
+ * rect
.
+ *
+ * @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 FontMetrics
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
+ * rect
. 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
+ * rect
.
+ *
+ * @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
+ * component
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
+ * component
.
+ *
+ * @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 JComponent
that has a binding
+ * for the key event in the WHEN_IN_FOCUSED_WINDOW scope.
+ *
+ * @param ev the key event
+ *
+ * @return true
if a binding has been found and processed,
+ * false
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:
+ *
+ *
+ *
+ *
+ * Code: Returned String:
+ *
+ *
+ * {@link SwingConstants#CENTER}
+ *
+ * "CENTER"
+ *
+ * {@link SwingConstants#LEFT}
+ *
+ * "LEFT"
+ *
+ * {@link SwingConstants#RIGHT}
+ *
+ * "RIGHT"
+ *
+ * {@link SwingConstants#LEADING}
+ *
+ * "LEADING"
+ *
+ * {@link SwingConstants#TRAILING}
+ *
+ * "TRAILING"
+ *
Code: | Returned String: | + *
---|---|
{@link SwingConstants#CENTER} | + *"CENTER" |
+ *
{@link SwingConstants#TOP} | + *"TOP" |
+ *
{@link SwingConstants#BOTTOM} | + *"BOTTOM" |
+ *
+ *
Code: | Returned String: | + *
---|---|
{@link WindowConstants#DO_NOTHING_ON_CLOSE} | + *"DO_NOTHING_ON_CLOSE" |
+ *
{@link WindowConstants#HIDE_ON_CLOSE} | + *"HIDE_ON_CLOSE" |
+ *
{@link WindowConstants#DISPOSE_ON_CLOSE} | + *"DISPOSE_ON_CLOSE" |
+ *
{@link WindowConstants#EXIT_ON_CLOSE} | + *"EXIT_ON_CLOSE" |
+ *