ch.randelshofer.quaqua.QuaquaUtilities Maven / Gradle / Ivy
Show all versions of Quaqua Show documentation
/*
* @(#)QuaquaUtilities.java
*
* Copyright (c) 2003-2010 Werner Randelshofer, Immensee, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package ch.randelshofer.quaqua;
import ch.randelshofer.quaqua.util.*;
import java.awt.*;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.event.*;
import java.awt.image.*;
import java.lang.reflect.Method;
import java.net.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
/**
* Utility class for the Quaqua LAF.
*
* @author Werner Randelshofer, Hausmatt 10, CH-6405 Immensee, Switzerland
* @version $Id: QuaquaUtilities.java 361 2010-11-21 11:19:20Z wrandelshofer $
*/
public class QuaquaUtilities extends BasicGraphicsUtils implements SwingConstants {
private final static boolean DEBUG = false;
/** Holds the class name of SwingUtilities2 once it has been resolved. */
private static String swingUtilities2;
/** Prevent instance creation. */
private QuaquaUtilities() {
}
/*
* Convenience function for determining ComponentOrientation. Helps us
* avoid having Munge directives throughout the code.
*/
public static boolean isLeftToRight(Component c) {
return c.getComponentOrientation().isLeftToRight();
}
/**
* Draw a string with the graphics g
at location
* (x
, y
)
* just like g.drawString
would.
* The character at index underlinedIndex
* in text will be underlined. If index
is beyond the
* bounds of text
(including < 0), nothing will be
* underlined.
*
* @param g Graphics to draw with
* @param text String to draw
* @param underlinedIndex Index of character in text to underline
* @param x x coordinate to draw at
* @param y y coordinate to draw at
* @since 1.4
*/
public static void drawStringUnderlineCharAt(Graphics g, String text,
int underlinedIndex, int x, int y) {
g.drawString(text, x, y);
if (underlinedIndex >= 0 && underlinedIndex < text.length()) {
FontMetrics fm = g.getFontMetrics();
int underlineRectX = x + fm.stringWidth(text.substring(0, underlinedIndex));
int underlineRectY = y;
int underlineRectWidth = fm.charWidth(text.charAt(underlinedIndex));
int underlineRectHeight = 1;
g.fillRect(underlineRectX, underlineRectY + fm.getDescent() - 1,
underlineRectWidth, underlineRectHeight);
}
}
/**
* Returns index of the first occurrence of mnemonic
* within string text
. Matching algorithm is not
* case-sensitive.
*
* @param text The text to search through, may be null
* @param mnemonic The mnemonic to find the character for.
* @return index into the string if exists, otherwise -1
*/
static int findDisplayedMnemonicIndex(String text, int mnemonic) {
if (text == null || mnemonic == '\0') {
return -1;
}
char uc = Character.toUpperCase((char) mnemonic);
char lc = Character.toLowerCase((char) mnemonic);
int uci = text.indexOf(uc);
int lci = text.indexOf(lc);
if (uci == -1) {
return lci;
} else if (lci == -1) {
return uci;
} else {
return (lci < uci) ? lci : uci;
}
}
/**
* Returns true if the component is on a Dialog or a Frame, which is active,
* or if it is on a Window, which is focused.
* Always returns true, if the component has no parent window.
*/
public static boolean isOnActiveWindow(Component c) {
return isOnActiveWindow(c, false);
}
/**
* Returns true if the component is on a Dialog or a Frame, which is active,
* or if it is on a Window, which is focused.
* Always returns true, if the component has no parent window.
*
* @param c The component.
* @param isActiveWhenSheetIsActive Set this to true, when the window should
* be considered as active when its sheet dialog is active.
*/
public static boolean isOnActiveWindow(Component c, boolean isActiveWhenSheetIsActive) {
// In the RootPaneUI, we set a client property on the whole component
// tree, if the ancestor Frame gets activated or deactivated.
if (c instanceof JComponent) {
Boolean value = (Boolean) ((JComponent) c).getClientProperty("Frame.active");
// Unfortunately, the value is not always reliable.
// Therefore we can only do a short circuit, if the value is true.
if (value != null && value.booleanValue()) {
return true;
//return value.booleanValue();
}
}
Window window = SwingUtilities.getWindowAncestor(c);
boolean isOnActiveWindow;
if (window == null) {
isOnActiveWindow = true;
} else if (window instanceof JWindow) {
isOnActiveWindow = window.isActive()
|| window.getName() == "###focusableSwingPopup###";// literal strings get interned
} else if ((window instanceof Frame) || (window instanceof Dialog)) {
isOnActiveWindow = window.isActive();
if (!isOnActiveWindow && isActiveWhenSheetIsActive) {
Window focusedWindow = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow();
isOnActiveWindow = focusedWindow != null && focusedWindow.getOwner() == window;
// we return here, because we don't want to change the "Frame.active"
// property.
return isOnActiveWindow;
}
} else {
if (window.getFocusableWindowState()) {
isOnActiveWindow = window.isFocused();
} else {
isOnActiveWindow = true;
}
}
// In case the activation property is true, we fix the value of the
// client property, so that we can do a short circuit next time.
if (isOnActiveWindow && (c instanceof JComponent)) {
((JComponent) c).putClientProperty("Frame.active", isOnActiveWindow);
}
return isOnActiveWindow;
}
/**
* Returns a Mac OS X specific String describing the modifier key(s),
* such as "Shift", or "Ctrl+Shift".
*
* @return string a text description of the combination of modifier
* keys that were held down during the event
*/
public static String getKeyModifiersText(int modifiers, boolean leftToRight) {
return getKeyModifiersUnicode(modifiers, leftToRight);
}
static String getKeyModifiersUnicode(int modifiers, boolean leftToRight) {
char[] cs = new char[4];
int count = 0;
if (leftToRight) {
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
cs[count++] = '\u2303';
} // Unicode: UP ARROWHEAD
if ((modifiers & (InputEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0) {
cs[count++] = '\u2325';
} // Unicode: OPTION KEY
if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
cs[count++] = '\u21e7';
} // Unicode: UPWARDS WHITE ARROW
if ((modifiers & InputEvent.META_MASK) != 0) {
cs[count++] = '\u2318';
} // Unicode: PLACE OF INTEREST SIGN
} else {
if ((modifiers & InputEvent.META_MASK) != 0) {
cs[count++] = '\u2318';
} // Unicode: PLACE OF INTEREST SIGN
if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
cs[count++] = '\u21e7';
} // Unicode: UPWARDS WHITE ARROW
if ((modifiers & (InputEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0) {
cs[count++] = '\u2325';
} // Unicode: OPTION KEY
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
cs[count++] = '\u2303';
} // Unicode: UP ARROWHEAD
}
return new String(cs, 0, count);
}
public static void repaintBorder(JComponent component) {
JComponent c = component;
Border border = null;
Container container = component.getParent();
if (container instanceof JViewport) {
c = (JComponent) container.getParent();
if (c != null) {
border = c.getBorder();
}
}
if (border == null) {
border = component.getBorder();
c = component;
}
if (border != null && c != null) {
int w = c.getWidth();
int h = c.getHeight();
Insets insets = c.getInsets();
c.repaint(0, 0, w, insets.top);
c.repaint(0, insets.top, insets.left, h - insets.bottom - insets.top);
c.repaint(0, h - insets.bottom, w, insets.bottom);
c.repaint(w - insets.right, insets.top, insets.right, h - insets.bottom - insets.top);
}
}
public static final Object beginGraphics(Graphics2D graphics2d) {
Object object = graphics2d.getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
/*
AffineTransform tx = graphics2d.getTransform();
AffineTransform savedTransform = (AffineTransform) tx.clone();
tx.scale(0.9,0.9);
graphics2d.setTransform(tx);
*/
graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
// RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
/*graphics2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);*/
//if (true) return savedTransform;
return object;
}
public static final void endGraphics(Graphics2D graphics2d, Object oldHints) {
/*
if (true) {
graphics2d.setTransform((AffineTransform) oldHints);
return;
}*/
if (oldHints != null) {
graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
oldHints);
}
}
/**
* Returns true, if the specified component is focus owner or permanent
* focus owner and if the component is on an the active window.
*/
public static final boolean isFocused(Component component) {
// When a component is used as a cell renderer, the focus can
// not be determined from the component itself.
if (component instanceof JComponent) {
if (((JComponent) component).getClientProperty("Quaqua.Component.cellRendererFor") != null) {
component = (Component) ((JComponent) component).getClientProperty("Quaqua.Component.cellRendererFor");
}
}
//---
try {
boolean isFocusOwner = ((Boolean) Methods.invoke(component, "isFocusOwner")).booleanValue();
Window ancestor = SwingUtilities.getWindowAncestor(component);
Object kfm = Methods.invokeStatic("java.awt.KeyboardFocusManager", "getCurrentKeyboardFocusManager");
return isFocusOwner
|| component == Methods.invoke(kfm, "getPermanentFocusOwner")
&& ancestor != null
&& Methods.invokeGetter(ancestor, "isFocused", false);
} catch (NoSuchMethodException e) {
return component.hasFocus();
}
}
static boolean isHeadless() {
return Methods.invokeStaticGetter(GraphicsEnvironment.class, "isHeadless", false);
}
/** Returns the class name of SwingUtilities2. */
private static String getSwingUtilities2() {
if (swingUtilities2 == null) {
// Location of SwingUtilities2 in J2SE6:
swingUtilities2 = "sun.swing.SwingUtilities2";
try {
Class.forName(swingUtilities2);
} catch (ClassNotFoundException ex) {
// Location of SwingUtilities2 in J2SE5:
swingUtilities2 = "com.sun.java.swing.SwingUtilities2";
try {
Class.forName(swingUtilities2);
} catch (ClassNotFoundException ex2) {
System.err.println("Warning QuaquaUtilities: Couldn't locate class " + swingUtilities2);
}
}
}
return swingUtilities2;
}
public static int getLeftSideBearing(Font f, String string) {
return ((Integer) Methods.invokeStatic(
getSwingUtilities2(), "getLeftSideBearing",
new Class[]{Font.class, String.class}, new Object[]{f, string},
0)).intValue();
}
/**
* Invoked when the user attempts an invalid operation,
* such as pasting into an uneditable JTextField
* that has focus. The default implementation beeps. Subclasses
* that wish different behavior should override this and provide
* the additional feedback.
*
* @param component Component the error occured in, may be null
* indicating the error condition is not directly
* associated with a Component
.
*/
static void provideErrorFeedback(Component component) {
Toolkit toolkit = null;
if (component != null) {
toolkit = component.getToolkit();
} else {
toolkit = Toolkit.getDefaultToolkit();
}
toolkit.beep();
} // provideErrorFeedback()
public static BufferedImage createBufferedImage(URL location) {
Image image = Toolkit.getDefaultToolkit().createImage(location);
BufferedImage buf;
if (image instanceof BufferedImage) {
buf = (BufferedImage) image;
} else {
loadImage(image);
//buf = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
buf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(image.getWidth(null), image.getHeight(null), Transparency.OPAQUE);
Graphics g = buf.getGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
image.flush();
}
return buf;
}
public static TexturePaint createTexturePaint(URL location) {
BufferedImage texture = createBufferedImage(location);
TexturePaint paint = new TexturePaint(texture, new Rectangle(0, 0, texture.getWidth(), texture.getHeight()));
return paint;
}
/**
* Loads the image, returning only when the image is loaded.
* @param image the image
*/
private static void loadImage(Image image) {
Component component = new Component() {
};
MediaTracker tracker = new MediaTracker(component);
synchronized (tracker) {
int id = 0;
tracker.addImage(image, id);
try {
tracker.waitForID(id, 0);
} catch (InterruptedException e) {
if (DEBUG) {
System.out.println("INTERRUPTED while loading Image");
}
}
///int loadStatus = tracker.statusID(id, false);
tracker.removeImage(image, id);
}
}
/**
* Compute and return the location of the icons origin, the
* location of origin of the text baseline, and a possibly clipped
* version of the compound labels string. Locations are computed
* relative to the viewR rectangle.
* The JComponents orientation (LEADING/TRAILING) will also be taken
* into account and translated into LEFT/RIGHT values accordingly.
*/
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) {
boolean orientationIsLeftToRight = true;
int hAlign = horizontalAlignment;
int hTextPos = horizontalTextPosition;
if (c != null) {
if (!(c.getComponentOrientation().isLeftToRight())) {
orientationIsLeftToRight = false;
}
}
// Translate LEADING/TRAILING values in horizontalAlignment
// to LEFT/RIGHT values depending on the components orientation
switch (horizontalAlignment) {
case LEADING:
hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
break;
case TRAILING:
hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
break;
}
// Translate LEADING/TRAILING values in horizontalTextPosition
// to LEFT/RIGHT values depending on the components orientation
switch (horizontalTextPosition) {
case LEADING:
hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
break;
case TRAILING:
hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
break;
}
return layoutCompoundLabelImpl(c,
fm,
text,
icon,
verticalAlignment,
hAlign,
verticalTextPosition,
hTextPos,
viewR,
iconR,
textR,
textIconGap);
}
/**
* Compute and return the location of the icons origin, the
* location of origin of the text baseline, and a possibly clipped
* version of the compound labels string. Locations are computed
* relative to the viewR rectangle.
* This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
* values in horizontalTextPosition (they will default to RIGHT) and in
* horizontalAlignment (they will default to CENTER).
* Use the other version of layoutCompoundLabel() instead.
*/
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);
}
/**
* Compute and return the location of the icons origin, the
* location of origin of the text baseline, and a possibly clipped
* version of the compound labels string. Locations are computed
* relative to the viewR rectangle.
* This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
* values in horizontalTextPosition (they will default to RIGHT) and in
* horizontalAlignment (they will default to CENTER).
* Use the other version of layoutCompoundLabel() instead.
*
* This is the same as SwingUtilities.layoutCompoundLabelImpl, except for
* the algorithm for clipping the text. If a text is too long, "..." are
* inserted at the middle of the text instead of at the end.
*/
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) {
/* Initialize the icon bounds rectangle iconR.
*/
if (icon != null) {
iconR.width = icon.getIconWidth();
iconR.height = icon.getIconHeight();
} else {
iconR.width = iconR.height = 0;
}
/* Initialize the text bounds rectangle textR. If a null
* or and empty String was specified we substitute "" here
* and use 0,0,0,0 for textR.
*/
boolean textIsEmpty = (text == null) || text.equals("");
int lsb = 0;
View v = null;
if (textIsEmpty) {
textR.width = textR.height = 0;
text = "";
} else {
v = (c != null) ? (View) c.getClientProperty("html") : null;
if (v != null) {
textR.width = (int) v.getPreferredSpan(View.X_AXIS);
textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
} else {
textR.width = SwingUtilities.computeStringWidth(fm, text);
lsb = getLeftSideBearing(fm.getFont(), text);
if (lsb < 0) {
// If lsb is negative, add it to the width, the
// text bounds will later be adjusted accordingly.
textR.width -= lsb;
}
textR.height = fm.getHeight();
}
}
/* Unless both text and icon are non-null, we effectively ignore
* the value of textIconGap. The code that follows uses the
* value of gap instead of textIconGap.
*/
int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
if (!textIsEmpty) {
/* If the label text string is too wide to fit within the available
* space "..." and as many characters as will fit will be
* displayed instead.
*/
int availTextWidth;
if (horizontalTextPosition == CENTER) {
availTextWidth = viewR.width;
} else {
availTextWidth = viewR.width - (iconR.width + gap);
}
if (textR.width > availTextWidth) {
if (v != null) {
textR.width = availTextWidth;
} else {
String clipString = "...";
int totalWidth = SwingUtilities.computeStringWidth(fm, clipString);
int nChars;
int len = text.length();
for (nChars = 0; nChars < len; nChars++) {
int charIndex = (nChars % 2 == 0) ? nChars / 2 : len - 1 - nChars / 2;
totalWidth += fm.charWidth(text.charAt(charIndex));
if (totalWidth > availTextWidth) {
break;
}
}
text = text.substring(0, nChars / 2) + clipString + text.substring(len - nChars / 2);
textR.width = SwingUtilities.computeStringWidth(fm, text);
}
}
}
/* Compute textR.x,y given the verticalTextPosition and
* horizontalTextPosition properties
*/
if (verticalTextPosition == TOP) {
if (horizontalTextPosition != CENTER) {
textR.y = 0;
} else {
textR.y = -(textR.height + gap);
}
} else if (verticalTextPosition == CENTER) {
textR.y = (iconR.height / 2) - (textR.height / 2);
} else { // (verticalTextPosition == BOTTOM)
if (horizontalTextPosition != CENTER) {
textR.y = iconR.height - textR.height;
} else {
textR.y = (iconR.height + gap);
}
}
if (horizontalTextPosition == LEFT) {
textR.x = -(textR.width + gap);
} else if (horizontalTextPosition == CENTER) {
textR.x = (iconR.width / 2) - (textR.width / 2);
} else { // (horizontalTextPosition == RIGHT)
textR.x = (iconR.width + gap);
}
/* labelR is the rectangle that contains iconR and textR.
* Move it to its proper position given the labelAlignment
* properties.
*
* To avoid actually allocating a Rectangle, Rectangle.union
* has been inlined below.
*/
int labelR_x = Math.min(iconR.x, textR.x);
int labelR_width = Math.max(iconR.x + iconR.width,
textR.x + textR.width) - labelR_x;
int labelR_y = Math.min(iconR.y, textR.y);
int labelR_height = Math.max(iconR.y + iconR.height,
textR.y + textR.height) - labelR_y;
int dx, dy;
if (verticalAlignment == TOP) {
dy = viewR.y - labelR_y;
} else if (verticalAlignment == CENTER) {
dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
} else { // (verticalAlignment == BOTTOM)
dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
}
if (horizontalAlignment == LEFT) {
dx = viewR.x - labelR_x;
} else if (horizontalAlignment == RIGHT) {
dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
} else { // (horizontalAlignment == CENTER)
dx = (viewR.x + (viewR.width / 2))
- (labelR_x + (labelR_width / 2));
}
/* Translate textR and glypyR by dx,dy.
*/
textR.x += dx;
textR.y += dy;
iconR.x += dx;
iconR.y += dy;
if (lsb < 0) {
// lsb is negative. We previously adjusted the bounds by lsb,
// we now need to shift the x location so that the text is
// drawn at the right location. The result is textR does not
// line up with the actual bounds (on the left side), but we will
// have provided enough space for the text.
textR.width += lsb;
textR.x -= lsb;
}
return text;
}
public static void configureGraphics(Graphics gr) {
Graphics2D g = (Graphics2D) gr;
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
/*g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);*/
}
/**
* Uses some unsupported (dangerous) API calls on the native peers to make
* a window translucent. If the API is not found, this method leaves the
* window opaque.
*
* @param w The Window.
* @param value The alpha channel for the window.
*/
static final void setWindowAlpha(Window w, int value) {
if (w == null) {
return;
}
if (w instanceof RootPaneContainer) {
JRootPane rp = ((RootPaneContainer) w).getRootPane();
// Window alpha is for J2SE 5 on Mac OS X 10.5
// See: http://developer.apple.com/technotes/tn2007/tn2196.html#WINDOW_ALPHA
rp.putClientProperty("Window.alpha", new Float(value / 255f));
}
}
static final void setWindowAlphaOld(Window w, int value) {
if (w == null) {
return;
}
if (QuaquaManager.isOSX()) {
// Try Mac API
/*
// Platform neutral API
w.setBackground(new Color(0, 0, 0, value));
*/
// Java 1.4.2_05 does not support window alpha.
// Setting window alpha only sets the background color of the window
// to white.
if (w.getPeer() == null) {
w.pack();
}
java.awt.peer.ComponentPeer peer = w.getPeer();
try {
// Alpha API for Apple's Java 1.4 + 1.5 on Mac OS X 10.4 Tiger.
Methods.invoke(peer, "setAlpha", (float) (value / 255f));
// Platform neutral API
w.setBackground(new Color(255, 255, 255, value));
if (w instanceof RootPaneContainer) {
((RootPaneContainer) w).getContentPane().setBackground(new Color(255, 255, 255, 0));
}
} catch (Throwable e) {
// Alpha API for Apple's Java 1.3.
if (QuaquaManager.getProperty("java.version").startsWith("1.3")) {
try {
Methods.invoke(peer, "_setAlpha", value);
} catch (Throwable e2) {
// Platform neutral API
w.setBackground(new Color(255, 255, 255, value));
if (w instanceof RootPaneContainer) {
((RootPaneContainer) w).getContentPane().setBackground(new Color(255, 255, 255, 0));
}
}
}
}
} else {
// Try J2SE 6 Update 10 API on Windows
try {
Class clazz = Class.forName("com.sun.awt.AWTUtilities");
Method method =
clazz.getMethod("setWindowOpaque", new Class[]{java.awt.Window.class, Boolean.TYPE});
method.invoke(clazz, new Object[]{w, Boolean.FALSE});
} catch (Throwable e2) {
// silently ignore this exception.
}
}
}
/** Copied from BasicLookAndFeel.
*/
public static Component compositeRequestFocus(Component component) {
try {
if (component instanceof Container) {
Container container = (Container) component;
if (Methods.invokeGetter(container, "isFocusCycleRoot", false)) {
Object policy = Methods.invokeGetter(container, "getFocusTraversalPolicy", null);
Component comp = (Component) Methods.invoke(policy, "getDefaultComponent", Container.class, container);
if (comp != null) {
comp.requestFocus();
return comp;
}
}
Container rootAncestor = (Container) Methods.invokeGetter(container, "getFocusCycleRootAncestor", null);
if (rootAncestor != null) {
Object policy = Methods.invokeGetter(rootAncestor, "getFocusTraversalPolicy", null);
Component comp = (Component) Methods.invoke(policy, "getComponentAfter",
new Class[]{Container.class, Component.class},
new Object[]{rootAncestor, container});
if (comp != null && SwingUtilities.isDescendingFrom(comp, container)) {
comp.requestFocus();
return comp;
}
}
}
} catch (NoSuchMethodException e) {
// ignore
}
if (Methods.invokeGetter(component, "isFocusable", true)) {
component.requestFocus();
return component;
}
return null;
}
/**
* Convenience method for installing a property with the specified name
* and value on a component if that property has not already been set
* by the client program. This method is intended to be used by
* UI delegate instances that need to specify a default value for a
* property of primitive type (boolean, int, ..), but do not wish
* to override a value set by the client. Since primitive property
* values cannot be wrapped with the UIResource marker, this method
* uses private state to determine whether the property has been set
* by the client.
* @throws IllegalArgumentException if the specified property is not
* one which can be set using this method
* @throws ClassCastException may be thrown if the property value
* specified does not match the property's type
* @throws NullPointerException may be thrown if c or propertyValue is null
* @param c the target component for installing the property
* @param propertyName String containing the name of the property to be set
*/
public static void installProperty(JComponent c,
String propertyName, Object value) {
LookAndFeel.installProperty(c, propertyName, value);
}
/**
* Returns the ui that is of type klass
, or null if
* one can not be found.
*/
public static Object getUIOfType(ComponentUI ui, Class klass) {
if (klass.isInstance(ui)) {
return ui;
}
return null;
}
public static void adjustFocus(JComponent tree) {
try {
Methods.invokeStatic(getSwingUtilities2(), "adjustFocus", JComponent.class, tree);
} catch (NoSuchMethodException ex) {
tree.requestFocusInWindow();
}
}
static boolean shouldIgnore(MouseEvent e, JComponent tree) {
//return QuaquaUtilities2.shouldIgnore(e, tree);
try {
return ((Boolean) Methods.invokeStatic(getSwingUtilities2(), "shouldIgnore",
new Class[]{MouseEvent.class, JComponent.class},
new Object[]{e, tree})).booleanValue();
} catch (NoSuchMethodException ex) {
return false;
}
}
/**
* Returns true, if the component should use the small appearance.
* @param c
* @return true, , if the component should use the small appearance.
*/
public static boolean isSmallSizeVariant(JComponent c) {
Font f = c.getFont();
if (f != null && f.getSize() <= 11) {
return true;
}
String p = (String) c.getClientProperty("JComponent.sizeVariant");
return p != null && p.equals("small");
}
public static void applySizeVariant(JComponent c) {
String p = (String) c.getClientProperty("JComponent.sizeVariant");
if (p == null) {
} else if (p.equals("regular")) {
c.setFont(UIManager.getFont("SystemFont"));
} else if (p.equals("small")) {
c.setFont(UIManager.getFont("SmallSystemFont"));
} else if (p.equals("mini")) {
c.setFont(UIManager.getFont("MiniSystemFont"));
}
}
public static int getDragThreshold() {
try {
Integer value = (Integer) Methods.invokeStatic(DragSource.class, "getDragThreshold");
return value.intValue();
} catch (Throwable ex) {
//ex.printStackTrace();
return 5;
}
}
public static int mapDragOperationFromModifiers(MouseEvent me,
TransferHandler th) {
return convertModifiersToDropAction(me.getModifiersEx(), th.getSourceActions((JComponent) me.getSource()));
}
public static int convertModifiersToDropAction(final int modifiers,
final int supportedActions) {
int dropAction = DnDConstants.ACTION_NONE;
/*
* Fix for 4285634.
* Calculate the drop action to match Motif DnD behavior.
* If the user selects an operation (by pressing a modifier key),
* return the selected operation or ACTION_NONE if the selected
* operation is not supported by the drag source.
* If the user doesn't select an operation search the set of operations
* supported by the drag source for ACTION_MOVE, then for
* ACTION_COPY, then for ACTION_LINK and return the first operation
* found.
*/
switch (modifiers & (InputEvent.SHIFT_DOWN_MASK
| InputEvent.CTRL_DOWN_MASK)) {
case InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK:
dropAction = DnDConstants.ACTION_LINK;
break;
case InputEvent.CTRL_DOWN_MASK:
dropAction = DnDConstants.ACTION_COPY;
break;
case InputEvent.SHIFT_DOWN_MASK:
dropAction = DnDConstants.ACTION_MOVE;
break;
default:
if ((supportedActions & DnDConstants.ACTION_MOVE) != 0) {
dropAction = DnDConstants.ACTION_MOVE;
} else if ((supportedActions & DnDConstants.ACTION_COPY) != 0) {
dropAction = DnDConstants.ACTION_COPY;
} else if ((supportedActions & DnDConstants.ACTION_LINK) != 0) {
dropAction = DnDConstants.ACTION_LINK;
}
}
return dropAction & supportedActions;
}
/**
* Return the child Component
of the specified
* Component
that is the focus owner, if any.
*
* @param c the root of the Component
hierarchy to
* search for the focus owner
* @return the focus owner, or null
if there is no focus
* owner, or if the focus owner is not comp
, or a
* descendant of comp
*
* @see java.awt.KeyboardFocusManager#getFocusOwner
*/
public static Component findFocusOwner(Component c) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
// verify focusOwner is a descendant of c
for (Component temp = focusOwner; temp != null;
temp = (temp instanceof Window) ? null : temp.getParent()) {
if (temp == c) {
return focusOwner;
}
}
return null;
}
public static boolean isOnTexturedWindow(Component c) {
boolean isTextured;
JRootPane rootPane = SwingUtilities.getRootPane(c);
if (rootPane != null) {
isTextured = rootPane.getClientProperty("apple.awt.brushMetalLook") == Boolean.TRUE;
} else {
isTextured = false;
}
return isTextured;
}
}