0001: /*
0002: * @(#)JideSwingUtilities.java
0003: *
0004: * Copyright 2002 JIDE Software. All rights reserved.
0005: */
0006: package com.jidesoft.swing;
0007:
0008: import com.jidesoft.dialog.ButtonPanel;
0009: import com.jidesoft.plaf.UIDefaultsLookup;
0010: import com.jidesoft.plaf.WindowsDesktopProperty;
0011: import com.jidesoft.plaf.basic.ThemePainter;
0012: import com.jidesoft.utils.SecurityUtils;
0013: import com.jidesoft.utils.SystemInfo;
0014:
0015: import javax.swing.*;
0016: import javax.swing.border.Border;
0017: import javax.swing.event.ChangeEvent;
0018: import javax.swing.event.ChangeListener;
0019: import javax.swing.event.EventListenerList;
0020: import javax.swing.plaf.FontUIResource;
0021: import javax.swing.plaf.UIResource;
0022: import javax.swing.table.DefaultTableModel;
0023: import javax.swing.text.JTextComponent;
0024: import javax.swing.text.View;
0025: import java.awt.*;
0026: import java.awt.event.*;
0027: import java.awt.image.BufferedImage;
0028: import java.beans.PropertyChangeEvent;
0029: import java.beans.PropertyChangeListener;
0030: import java.lang.reflect.Array;
0031: import java.lang.reflect.InvocationTargetException;
0032: import java.security.AccessControlException;
0033: import java.util.*;
0034:
0035: /**
0036: * A utilities class for Swing.
0037: */
0038: public class JideSwingUtilities implements SwingConstants {
0039: /**
0040: * Whether or not text is drawn anti-aliased. This is only used if
0041: * <code>AA_TEXT_DEFINED</code> is true.
0042: */
0043: private static final boolean AA_TEXT;
0044:
0045: /**
0046: * Whether or not the system property 'swing.aatext' is defined.
0047: */
0048: private static final boolean AA_TEXT_DEFINED;
0049:
0050: /**
0051: * Key used in client properties to indicate whether or not the component
0052: * should use aa text.
0053: */
0054: public static final Object AA_TEXT_PROPERTY_KEY = new StringBuffer(
0055: "AATextPropertyKey");
0056:
0057: static {
0058: Object aa = SecurityUtils.getProperty("swing.aatext", "false");
0059: AA_TEXT_DEFINED = (aa != null);
0060: AA_TEXT = "true".equals(aa);
0061: }
0062:
0063: /**
0064: * Create a Panel around a component so that
0065: * component aligns to left.
0066: *
0067: * @param object
0068: * @return a Panel
0069: */
0070: public static JPanel createLeftPanel(Component object) {
0071: JPanel ret = new NullPanel(new BorderLayout());
0072: ret.setOpaque(false);
0073: ret.add(object, BorderLayout.BEFORE_LINE_BEGINS);
0074: return ret;
0075: }
0076:
0077: /**
0078: * Create a Panel around a component so that
0079: * component aligns to right.
0080: *
0081: * @param object
0082: * @return a Panel
0083: */
0084: public static JPanel createRightPanel(Component object) {
0085: JPanel ret = new NullPanel(new BorderLayout());
0086: ret.setOpaque(false);
0087: ret.add(object, BorderLayout.AFTER_LINE_ENDS);
0088: return ret;
0089: }
0090:
0091: /**
0092: * Create a Panel around a component so that
0093: * component aligns to top.
0094: *
0095: * @param object
0096: * @return a Panel
0097: */
0098: public static JPanel createTopPanel(Component object) {
0099: JPanel ret = new NullPanel(new BorderLayout());
0100: ret.setOpaque(false);
0101: ret.add(object, BorderLayout.BEFORE_FIRST_LINE);
0102: return ret;
0103: }
0104:
0105: /**
0106: * Create a Panel around a component so that
0107: * component aligns to buttom.
0108: *
0109: * @param object
0110: * @return a Panel
0111: */
0112: public static JPanel createBottomPanel(Component object) {
0113: JPanel ret = new NullPanel(new BorderLayout());
0114: ret.setOpaque(false);
0115: ret.add(object, BorderLayout.AFTER_LAST_LINE);
0116: return ret;
0117: }
0118:
0119: /**
0120: * Create a Panel around a component so that
0121: * component is right in the middle.
0122: *
0123: * @param object
0124: * @return a Panel
0125: */
0126: public static JPanel createCenterPanel(Component object) {
0127: JPanel ret = new NullPanel(new GridBagLayout());
0128: ret.setOpaque(false);
0129: ret.add(object, new GridBagConstraints());
0130: return ret;
0131: }
0132:
0133: /**
0134: * Center the component to it's parent window.
0135: */
0136: public static void centerWindow(Window childToCenter) {
0137: childToCenter.setLocationRelativeTo(childToCenter.getParent());
0138: // Container parentWindow = childToCenter.getParent();
0139: //
0140: // int width = (parentWindow.getWidth() - childToCenter.getWidth()) >> 1;
0141: // int height = (parentWindow.getHeight() - childToCenter.getHeight()) >> 1;
0142: //
0143: // // according to javadoc of setLocation, it's relavent to parent window. but it's not the case.
0144: // Point location = parentWindow.getLocation();
0145: // width += location.x;
0146: // height += location.y;
0147: // childToCenter.setLocation(width, height);
0148: }
0149:
0150: /**
0151: * Center the window to the whole screen.
0152: */
0153: public static void globalCenterWindow(Window childToCenter) {
0154: childToCenter.setLocationRelativeTo(null);
0155: // Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
0156: //
0157: // // Get the bounds of the splash window
0158: // Rectangle frameDim = childToCenter.getBounds();
0159: //
0160: // // Compute the location of the window
0161: // childToCenter.setLocation((screenDim.width - frameDim.width) >> 1, (screenDim.height - frameDim.height) >> 1);
0162: }
0163:
0164: /**
0165: * Paints an arrow shape.
0166: *
0167: * @param g
0168: * @param color
0169: * @param startX
0170: * @param startY
0171: * @param width
0172: * @param orientation
0173: */
0174: public static void paintArrow(Graphics g, Color color, int startX,
0175: int startY, int width, int orientation) {
0176: Color oldColor = g.getColor();
0177: g.setColor(color);
0178: width = width / 2 * 2 + 1; // make sure it's odd
0179: if (orientation == HORIZONTAL) {
0180: for (int i = 0; i < (width + 1) / 2; i++) {
0181: g.drawLine(startX + i, startY + i, startX + width - i
0182: - 1, startY + i);
0183: }
0184: } else {
0185: for (int i = 0; i < (width + 1) / 2; i++) {
0186: g.drawLine(startX + i, startY + i, startX + i, startY
0187: + width - i - 1);
0188: }
0189: }
0190: g.setColor(oldColor);
0191: }
0192:
0193: /**
0194: * Paints a cross shape.
0195: *
0196: * @param g
0197: * @param color
0198: * @param centerX
0199: * @param centerY
0200: * @param size
0201: * @param width
0202: */
0203: public static void paintCross(Graphics g, Color color, int centerX,
0204: int centerY, int size, int width) {
0205: g.setColor(color);
0206: size = size / 2; // make sure it's odd
0207: for (int i = 0; i < width; i++) {
0208: g.drawLine(centerX - size, centerY - size, centerX + size,
0209: centerY + size);
0210: g.drawLine(centerX + size, centerY - size, centerX - size,
0211: centerY + size);
0212: centerX++;
0213: }
0214: }
0215:
0216: /**
0217: * Gets the top level Frame of the component.
0218: *
0219: * @param component
0220: * @return the top level Frame. Null if we didn't find an ancestor which is instance of Frame.
0221: */
0222: public static Frame getFrame(Component component) {
0223: if (component == null)
0224: return null;
0225:
0226: if (component instanceof Frame)
0227: return (Frame) component;
0228:
0229: // Find framel
0230: Container p = component.getParent();
0231: while (p != null) {
0232: if (p instanceof Frame) {
0233: return (Frame) p;
0234: }
0235: p = p.getParent();
0236: }
0237: return null;
0238: }
0239:
0240: /**
0241: * Toggles between RTL and LTR.
0242: *
0243: * @param topContainer
0244: */
0245: public static void toggleRTLnLTR(Component topContainer) {
0246: ComponentOrientation co = topContainer
0247: .getComponentOrientation();
0248: if (co == ComponentOrientation.RIGHT_TO_LEFT)
0249: co = ComponentOrientation.LEFT_TO_RIGHT;
0250: else
0251: co = ComponentOrientation.RIGHT_TO_LEFT;
0252: topContainer.applyComponentOrientation(co);
0253: }
0254:
0255: /**
0256: * @param view1
0257: * @param view2
0258: * @param orientation
0259: * @deprecated there is a typo. Use {@link #synchronizeView(javax.swing.JViewport,javax.swing.JViewport,int)}.
0260: */
0261: public static void synchonizeView(final JViewport view1,
0262: final JViewport view2, final int orientation) {
0263: synchronizeView(view1, view2, orientation);
0264: }
0265:
0266: /**
0267: * Synchonizes the two viewports. The view position in one view changes, the other view's view position will change too.
0268: * Generally speaking, if you want the two viewports to synchronize vertically, they should have the same height.
0269: * If horizonally, the same width.
0270: *
0271: * @param view1 the first viewport
0272: * @param view2 the second viewport
0273: * @param orientation the orientation. It could be either SwingConstants.HORIZONTAL or SwingConstants.VERTICAL.
0274: */
0275: public static void synchronizeView(final JViewport view1,
0276: final JViewport view2, final int orientation) {
0277: final ChangeListener c1 = new ChangeListener() {
0278: public void stateChanged(ChangeEvent e) {
0279: if (orientation == HORIZONTAL) {
0280: Point v1 = view1.getViewPosition();
0281: Point v2 = view2.getViewPosition();
0282: if (v1.x != v2.x) {
0283: view2.setViewPosition(new Point(v1.x, v2.y));
0284: }
0285: } else if (orientation == VERTICAL) {
0286: Point v1 = view1.getViewPosition();
0287: Point v2 = view2.getViewPosition();
0288: if (v1.y != v2.y) {
0289: view2.setViewPosition(new Point(v2.x, v1.y));
0290: }
0291: }
0292: }
0293: };
0294:
0295: final ChangeListener c2 = new ChangeListener() {
0296: public void stateChanged(ChangeEvent e) {
0297: if (orientation == HORIZONTAL) {
0298: Point v1 = view1.getViewPosition();
0299: Point v2 = view2.getViewPosition();
0300: if (v1.x != v2.x) {
0301: view1.setViewPosition(new Point(v2.x, v1.y));
0302: }
0303: } else if (orientation == VERTICAL) {
0304: Point v1 = view1.getViewPosition();
0305: Point v2 = view2.getViewPosition();
0306: if (v1.y != v2.y) {
0307: view1.setViewPosition(new Point(v1.x, v2.y));
0308: }
0309: }
0310: }
0311: };
0312:
0313: view1.addChangeListener(c1);
0314: view2.addChangeListener(c2);
0315: }
0316:
0317: public static int getButtonState(AbstractButton b) {
0318: ButtonModel model = b.getModel();
0319: if (!model.isEnabled()) {
0320: if (model.isSelected()) {
0321: return ThemePainter.STATE_DISABLE_SELECTED;
0322: } else {
0323: return ThemePainter.STATE_DISABLE;
0324: }
0325: } else if (b.hasFocus() && b.isFocusPainted()) {
0326: if (model.isSelected()) {
0327: return ThemePainter.STATE_PRESSED;
0328: } else {
0329: return ThemePainter.STATE_ROLLOVER;
0330: }
0331: } else if (model.isPressed() && model.isArmed()) {
0332: if (model.isRollover()) {
0333: return ThemePainter.STATE_PRESSED;
0334: }
0335: } else if (b.isRolloverEnabled() && model.isRollover()) {
0336: if (model.isSelected()) {
0337: return ThemePainter.STATE_PRESSED; // should be rollover selected
0338: } else {
0339: return ThemePainter.STATE_ROLLOVER;
0340: }
0341: } else if (model.isSelected()) {
0342: return ThemePainter.STATE_SELECTED;
0343: }
0344: return ThemePainter.STATE_DEFAULT;
0345: }
0346:
0347: public static int[] getButtonState(JideSplitButton b) {
0348: int[] states = new int[2];
0349: SplitButtonModel model = (SplitButtonModel) b.getModel();
0350: if (!model.isEnabled()) {
0351: if (model.isButtonSelected()) {
0352: states[0] = ThemePainter.STATE_DISABLE_SELECTED;
0353: } else {
0354: states[0] = ThemePainter.STATE_DISABLE;
0355: }
0356: } else if (b.hasFocus() && b.isFocusPainted()) {
0357: if (model.isButtonSelected()) {
0358: states[0] = ThemePainter.STATE_SELECTED;
0359: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0360: } else if (model.isSelected()) {
0361: states[0] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0362: states[1] = ThemePainter.STATE_SELECTED;
0363: } else {
0364: states[0] = ThemePainter.STATE_ROLLOVER;
0365: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0366: }
0367: } else if (model.isPressed() && model.isArmed()) {
0368: if (model.isButtonRollover()) {
0369: states[0] = ThemePainter.STATE_PRESSED;
0370: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0371: } else if (model.isRollover()) {
0372: states[0] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0373: states[1] = ThemePainter.STATE_ROLLOVER;
0374: }
0375: } else if (b.isRolloverEnabled() && model.isButtonRollover()) {
0376: if (model.isButtonSelected()) {
0377: states[0] = ThemePainter.STATE_PRESSED;
0378: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0379: } else if (model.isSelected()) {
0380: states[0] = ThemePainter.STATE_ROLLOVER;
0381: states[1] = ThemePainter.STATE_PRESSED;
0382: } else {
0383: states[0] = ThemePainter.STATE_ROLLOVER;
0384: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0385: }
0386: } else if (b.isRolloverEnabled() && model.isRollover()) {
0387: if (model.isButtonSelected()) {
0388: states[0] = ThemePainter.STATE_PRESSED;
0389: states[1] = ThemePainter.STATE_ROLLOVER;
0390: } else if (model.isSelected()) {
0391: states[0] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0392: states[1] = ThemePainter.STATE_PRESSED;
0393: } else {
0394: states[0] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0395: states[1] = ThemePainter.STATE_ROLLOVER;
0396: }
0397: } else if (model.isButtonSelected()) {
0398: states[0] = ThemePainter.STATE_SELECTED;
0399: states[1] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0400: } else if (model.isSelected()) {
0401: states[0] = ThemePainter.STATE_INACTIVE_ROLLOVER;
0402: states[1] = ThemePainter.STATE_SELECTED;
0403: } else {
0404: states[0] = ThemePainter.STATE_DEFAULT;
0405: states[1] = ThemePainter.STATE_DEFAULT;
0406: }
0407: return states;
0408: }
0409:
0410: /**
0411: * Checks if the two objects equal. If both are null, they are equal. If o1 and o2 both are Comparable, we will
0412: * use compareTo method to see if it equals 0.
0413: * At last, we will use <code>o1.equals(o2)</code> to compare.
0414: * If none of the above conditions match, we return false.
0415: *
0416: * @param o1 the first object to compare
0417: * @param o2 the second object to compare
0418: * @return true if the two objects are equal. Otherwise false.
0419: */
0420: public static boolean equals(Object o1, Object o2) {
0421: return equals(o1, o2, false);
0422: }
0423:
0424: /**
0425: * Checks if the two objects equal. If both are null, they are equal. If o1 and o2 both are Comparable, we will
0426: * use compareTo method to see if it equals 0. If considerArray is true and o1 and o2 are both array, we will compare each element in the array.
0427: * At last, we will use <code>o1.equals(o2)</code> to compare.
0428: * If none of the above conditions match, we return false.
0429: *
0430: * @param o1 the first object to compare
0431: * @param o2 the second object to compare
0432: * @param considerArray If true, and if o1 and o2 are both array, we will compare each element in the array instead of just compare the two array objects.
0433: * @return true if the two objects are equal. Otherwise false.
0434: */
0435: public static boolean equals(Object o1, Object o2,
0436: boolean considerArray) {
0437: if (o1 == null && o2 == null) {
0438: return true;
0439: } else if (o1 != null && o2 == null) {
0440: return false;
0441: } else if (o1 == null) {
0442: return false;
0443: } else if (o1 instanceof Comparable && o2 instanceof Comparable
0444: && o1.getClass().isAssignableFrom(o2.getClass())) {
0445: return ((Comparable) o1).compareTo(o2) == 0;
0446: } else if (o1 instanceof Comparable && o2 instanceof Comparable
0447: && o2.getClass().isAssignableFrom(o1.getClass())) {
0448: return ((Comparable) o2).compareTo(o1) == 0;
0449: } else {
0450: if (considerArray && o1.getClass().isArray()
0451: && o2.getClass().isArray()) {
0452: int length1 = Array.getLength(o1);
0453: int length2 = Array.getLength(o2);
0454: if (length1 != length2) {
0455: return false;
0456: }
0457: for (int i = 0; i < length1; i++) {
0458: boolean equals = equals(Array.get(o1, i), Array
0459: .get(o1, i));
0460: if (!equals) {
0461: return false;
0462: }
0463: }
0464: return true;
0465: } else {
0466: return o1.equals(o2);
0467: }
0468: }
0469: }
0470:
0471: /**
0472: * Convenience method that returns a scaled instance of the
0473: * provided BufferedImage.
0474: *
0475: * @param img the original image to be scaled
0476: * @param targetWidth the desired width of the scaled instance,
0477: * in pixels
0478: * @param targetHeight the desired height of the scaled instance,
0479: * in pixels
0480: * @param hint one of the rendering hints that corresponds to
0481: * RenderingHints.KEY_INTERPOLATION (e.g.
0482: * RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
0483: * RenderingHints.VALUE_INTERPOLATION_BILINEAR,
0484: * RenderingHints.VALUE_INTERPOLATION_BICUBIC)
0485: * @param progressiveBilinear if true, this method will use a multi-step
0486: * scaling technique that provides higher quality than the usual
0487: * one-step technique (only useful in down-scaling cases, where
0488: * targetWidth or targetHeight is
0489: * smaller than the original dimensions)
0490: * @return a scaled version of the original BufferedImage
0491: */
0492: public static BufferedImage getFasterScaledInstance(
0493: BufferedImage img, int targetWidth, int targetHeight,
0494: Object hint, boolean progressiveBilinear) {
0495: int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB
0496: : BufferedImage.TYPE_INT_ARGB;
0497: BufferedImage ret = img;
0498: BufferedImage scratchImage = null;
0499: Graphics2D g2 = null;
0500: int w, h;
0501: int prevW = ret.getWidth();
0502: int prevH = ret.getHeight();
0503: boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;
0504:
0505: if (progressiveBilinear) {
0506: // Use multi-step technique: start with original size, then
0507: // scale down in multiple passes with drawImage()
0508: // until the target size is reached
0509: w = img.getWidth();
0510: h = img.getHeight();
0511: } else {
0512: // Use one-step technique: scale directly from original
0513: // size to target size with a single drawImage() call
0514: w = targetWidth;
0515: h = targetHeight;
0516: }
0517:
0518: do {
0519: if (progressiveBilinear && w > targetWidth) {
0520: w /= 2;
0521: if (w < targetWidth) {
0522: w = targetWidth;
0523: }
0524: }
0525:
0526: if (progressiveBilinear && h > targetHeight) {
0527: h /= 2;
0528: if (h < targetHeight) {
0529: h = targetHeight;
0530: }
0531: }
0532:
0533: if (scratchImage == null || isTranslucent) {
0534: // Use a single scratch buffer for all iterations
0535: // and then copy to the final, correctly-sized image
0536: // before returning
0537: scratchImage = new BufferedImage(w, h, type);
0538: g2 = scratchImage.createGraphics();
0539: }
0540: g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
0541: g2.drawImage(ret, 0, 0, w, h, 0, 0, prevW, prevH, null);
0542: prevW = w;
0543: prevH = h;
0544:
0545: ret = scratchImage;
0546: } while (w != targetWidth || h != targetHeight);
0547:
0548: if (g2 != null) {
0549: g2.dispose();
0550: }
0551:
0552: // If we used a scratch buffer that is larger than our target size,
0553: // create an image of the right size and copy the results into it
0554: if (targetWidth != ret.getWidth()
0555: || targetHeight != ret.getHeight()) {
0556: scratchImage = new BufferedImage(targetWidth, targetHeight,
0557: type);
0558: g2 = scratchImage.createGraphics();
0559: g2.drawImage(ret, 0, 0, null);
0560: g2.dispose();
0561: ret = scratchImage;
0562: }
0563:
0564: return ret;
0565: }
0566:
0567: private static class GetPropertyAction implements
0568: java.security.PrivilegedAction {
0569: private String theProp;
0570: private String defaultVal;
0571:
0572: /**
0573: * Constructor that takes the name of the system property whose
0574: * string value needs to be determined.
0575: *
0576: * @param theProp the name of the system property.
0577: */
0578: public GetPropertyAction(String theProp) {
0579: this .theProp = theProp;
0580: }
0581:
0582: /**
0583: * Constructor that takes the name of the system property and the default
0584: * value of that property.
0585: *
0586: * @param theProp the name of the system property.
0587: * @param defaultVal the default value.
0588: */
0589: public GetPropertyAction(String theProp, String defaultVal) {
0590: this .theProp = theProp;
0591: this .defaultVal = defaultVal;
0592: }
0593:
0594: /**
0595: * Determines the string value of the system property whose
0596: * name was specified in the constructor.
0597: *
0598: * @return the string value of the system property,
0599: * or the default value if there is no property with that key.
0600: */
0601: public Object run() {
0602: String value = System.getProperty(theProp);
0603: return (value == null) ? defaultVal : value;
0604: }
0605: }
0606:
0607: /**
0608: * In JDK1.4, it uses a wrong font for Swing component in Windows L&F which
0609: * is actually one big reason for people to think Swing application ugly.
0610: * To address this issue, we changed the code to force to use Tahoma font
0611: * for all the fonts in L&F instead of using the system font.
0612: * <p/>
0613: * However this is a downside to this. Tahoma cannot display unicode characters
0614: * such as Chinese, Japanese and Korean. So if the locale is CJK ({@link SystemInfo#isCJKLocale()},
0615: * we shouldn't use Tahoma. If you are on JDK 1.5 and above, you shouldn't force to use Tahoma either
0616: * because JDK fixed it in 1.5 and above.
0617: * <p/>
0618: * There are also a few system properties you can set to control
0619: * if system font should be used. "swing.useSystemFontSettings"
0620: * is the one for all Swing applications. "Application.useSystemFontSettings" is the
0621: * one for a particular Swing application.
0622: * <p/>
0623: * This method considers all the cases above. If JDK is 1.5 and above, this method will return true.
0624: * If you are on Chinese, Japanese or Korean locale, it will return true. If "swing.useSystemFontSettings" property us true,
0625: * it will return true. If "Application.useSystemFontSettings" property is true, it will return true. Otherwise,
0626: * it will return false. All JIDE L&F considered the returned value and decide if Tahoma font should be used or not.
0627: *
0628: * @return true if the L&F should use system font.
0629: */
0630: public static boolean shouldUseSystemFont() {
0631: if (SystemInfo.isJdk15Above() || SystemInfo.isCJKLocale()) {
0632: return true;
0633: }
0634:
0635: String systemFonts = null;
0636: try {
0637: systemFonts = (String) java.security.AccessController
0638: .doPrivileged(new GetPropertyAction(
0639: "swing.useSystemFontSettings"));
0640: } catch (AccessControlException e) {
0641: // ignore
0642: }
0643:
0644: boolean useSystemFontSettings = (systemFonts != null && Boolean
0645: .valueOf(systemFonts));
0646:
0647: if (useSystemFontSettings) {
0648: Object value = UIDefaultsLookup
0649: .get("Application.useSystemFontSettings");
0650:
0651: useSystemFontSettings = (value != null || Boolean.TRUE
0652: .equals(value));
0653: }
0654:
0655: return "true".equals(SecurityUtils.getProperty("defaultFont",
0656: "false"))
0657: || useSystemFontSettings;
0658: }
0659:
0660: public static void printUIDefaults() {
0661: Enumeration e = UIManager.getDefaults().keys();
0662: java.util.List list = new ArrayList();
0663:
0664: System.out.println("Non-string keys ---");
0665: while (e.hasMoreElements()) {
0666: Object key = e.nextElement();
0667: if (key instanceof String) {
0668: list.add(key);
0669: } else {
0670: System.out.println(key + " => "
0671: + UIDefaultsLookup.get(key));
0672: }
0673: }
0674:
0675: System.out.println();
0676:
0677: Object[] array = list.toArray(new Object[list.size()]);
0678: Arrays.sort(array);
0679: System.out.println("String keys ---");
0680: for (int i = 0; i < array.length; i++) {
0681: Object key = array[i];
0682: System.out
0683: .println(key + " => " + UIDefaultsLookup.get(key));
0684: }
0685: }
0686:
0687: /**
0688: * A simple handler used by setRecursively.
0689: * <pre>
0690: * if ( condition() ) {
0691: * action();
0692: * }
0693: * postAction();
0694: * </pre>.
0695: */
0696: public interface Handler {
0697: /**
0698: * If true, it will call {@link #action(java.awt.Component)} on this component.
0699: *
0700: * @param c the component
0701: * @return true or false.
0702: */
0703: boolean condition(Component c);
0704:
0705: /**
0706: * The action you want to perform on this component. This method will only be called
0707: * if {@link #condition(java.awt.Component)} returns true.
0708: *
0709: * @param c the component
0710: */
0711: void action(Component c);
0712:
0713: /**
0714: * The actino you want to perform to any components. If action(c) is called, this action is after it.
0715: *
0716: * @param c the component.
0717: */
0718: void postAction(Component c);
0719:
0720: }
0721:
0722: /**
0723: * A simple handler used by setRecursively.
0724: * <pre>
0725: * if ( condition() ) {
0726: * action();
0727: * }
0728: * postAction();
0729: * </pre>.
0730: */
0731: public interface ConditionHandler extends Handler {
0732: /**
0733: * If this method returns true, the recursive call will stop at the component and will not call to its children.
0734: *
0735: * @param c the component
0736: * @return true or false.
0737: */
0738: boolean stopCondition(Component c);
0739: }
0740:
0741: /**
0742: * A simple handler used by getRecursively.
0743: * <code><pre>
0744: * if ( condition() ) {
0745: * return action();
0746: * }
0747: * </pre></code>.
0748: * Here is an example to get the first child of the specified type.
0749: * <code><pre>
0750: * public static Component getFirstChildOf(final Class clazz, Component c) {
0751: * return getRecursively(c, new GetHandler() {
0752: * public boolean condition(Component c) {
0753: * return clazz.isAssignableFrom(c.getClass());
0754: * }
0755: * public Component action(Component c) {
0756: * return c;
0757: * }
0758: * });
0759: * }
0760: * </pre></code>
0761: */
0762: public interface GetHandler {
0763: /**
0764: * If true, it will call {@link #action(java.awt.Component)} on this component.
0765: *
0766: * @param c the component
0767: * @return true or false.
0768: */
0769: boolean condition(Component c);
0770:
0771: /**
0772: * The action you want to perform on this component. This method will only be called
0773: * if {@link #condition(java.awt.Component)} returns true.
0774: *
0775: * @param c the component
0776: * @return the component that will be returned from {@link com.jidesoft.swing.JideSwingUtilities#getRecursively(java.awt.Component,com.jidesoft.swing.JideSwingUtilities.GetHandler)}.
0777: */
0778: Component action(Component c);
0779: }
0780:
0781: /**
0782: * Calls the handler recursively on a component.
0783: *
0784: * @param c component
0785: * @param handler handler to be called
0786: */
0787: public static void setRecursively(final Component c,
0788: final Handler handler) {
0789: setRecursively0(c, handler);
0790: handler.postAction(c);
0791: }
0792:
0793: private static void setRecursively0(final Component c,
0794: final Handler handler) {
0795: if (handler.condition(c)) {
0796: handler.action(c);
0797: }
0798:
0799: if (handler instanceof ConditionHandler
0800: && ((ConditionHandler) handler).stopCondition(c)) {
0801: return;
0802: }
0803:
0804: Component[] children = null;
0805:
0806: if (c instanceof JMenu) {
0807: children = ((JMenu) c).getMenuComponents();
0808: } else if (c instanceof JTabbedPane) {
0809: JTabbedPane tabbedPane = (JTabbedPane) c;
0810: children = new Component[tabbedPane.getTabCount()];
0811: for (int i = 0; i < children.length; i++) {
0812: children[i] = tabbedPane.getComponentAt(i);
0813: }
0814: } else if (c instanceof Container) {
0815: children = ((Container) c).getComponents();
0816: }
0817: if (children != null) {
0818: for (Component child : children) {
0819: setRecursively0(child, handler);
0820: }
0821: }
0822: }
0823:
0824: /**
0825: * Gets to a child of a component recursively based on certain condition.
0826: *
0827: * @param c component
0828: * @param handler handler to be called
0829: */
0830: public static Component getRecursively(final Component c,
0831: final GetHandler handler) {
0832: return getRecursively0(c, handler);
0833: }
0834:
0835: private static Component getRecursively0(final Component c,
0836: final GetHandler handler) {
0837: if (handler.condition(c)) {
0838: return handler.action(c);
0839: }
0840:
0841: Component[] children = null;
0842:
0843: if (c instanceof JMenu) {
0844: children = ((JMenu) c).getMenuComponents();
0845: } else if (c instanceof Container) {
0846: children = ((Container) c).getComponents();
0847: }
0848:
0849: if (children != null) {
0850: for (int i = 0; i < children.length; i++) {
0851: Component result = getRecursively0(children[i], handler);
0852: if (result != null) {
0853: return result;
0854: }
0855: }
0856: }
0857: return null;
0858: }
0859:
0860: /**
0861: * Calls setEnabled method recursively on component. <code>Component</code> c is usually a <code>Container</code>
0862: *
0863: * @param c component
0864: * @param enabled true if enable; false otherwise
0865: */
0866: public static void setEnabledRecursively(final Component c,
0867: final boolean enabled) {
0868: setRecursively(c, new Handler() {
0869: public boolean condition(Component c) {
0870: return true;
0871: }
0872:
0873: public void action(Component c) {
0874: c.setEnabled(enabled);
0875: }
0876:
0877: public void postAction(Component c) {
0878: }
0879: });
0880: }
0881:
0882: /**
0883: * Calls setRequestFocusEnabled method recursively on component. <code>Component</code> c is usually a <code>Container</code>
0884: *
0885: * @param c component
0886: * @param enabled true if setRequestFocusEnabled to true; false otherwise
0887: */
0888: public static void setRequestFocusEnabledRecursively(
0889: final Component c, final boolean enabled) {
0890: setRecursively(c, new Handler() {
0891: public boolean condition(Component c) {
0892: return true;
0893: }
0894:
0895: public void action(Component c) {
0896: if (c instanceof JComponent)
0897: ((JComponent) c).setRequestFocusEnabled(enabled);
0898: }
0899:
0900: public void postAction(Component c) {
0901: }
0902: });
0903: }
0904:
0905: private static PropertyChangeListener _setOpaqueTrueListener = new PropertyChangeListener() {
0906: public void propertyChange(PropertyChangeEvent evt) {
0907: if (evt.getSource() instanceof JComponent) {
0908: ((JComponent) evt.getSource()).setOpaque(true);
0909: }
0910: }
0911: };
0912:
0913: private static PropertyChangeListener _setOpaqueFalseListener;
0914: private static final String OPAQUE_LISTENER = "setOpaqueRecursively.opaqueListener";
0915:
0916: /**
0917: * setOpaqueRecursively method will make all child components opaque true or false. But if you call
0918: * jcomponent.putClientProperty(SET_OPAQUE_RECURSIVELY_EXCLUDED, Boolean.TRUE), we will not touch
0919: * this particular component when setOpaqueRecursively.
0920: */
0921: public static final String SET_OPAQUE_RECURSIVELY_EXCLUDED = "setOpaqueRecursively.excluded";
0922:
0923: /**
0924: * Calls setOpaque method recursively on each component except
0925: * for JButton, JComboBox and JTextComponent.
0926: * <code>Component</code> c is usually a <code>Container</code>.
0927: * If you would like certain child component not affected by this call, you can
0928: * call jcomponent.putClientProperty(SET_OPAQUE_RECURSIVELY_EXCLUDED, Boolean.TRUE) before calling this method.
0929: *
0930: * @param c component
0931: * @param opaque true if setOpaque to true; false otherwise
0932: */
0933: public static void setOpaqueRecursively(final Component c,
0934: final boolean opaque) {
0935: setRecursively(c, new Handler() {
0936: public boolean condition(Component c) {
0937: return !(c instanceof JComboBox || c instanceof JButton || c instanceof JTextComponent);
0938: }
0939:
0940: public void action(Component c) {
0941: if (c instanceof JComponent) {
0942: JComponent jc = (JComponent) c;
0943: if (Boolean.TRUE
0944: .equals(jc
0945: .getClientProperty(SET_OPAQUE_RECURSIVELY_EXCLUDED))) {
0946: return;
0947: }
0948:
0949: jc.setOpaque(opaque);
0950: if (jc.getClientProperty(OPAQUE_LISTENER) == null) {
0951: if (opaque) {
0952: if (_setOpaqueTrueListener == null) {
0953: _setOpaqueTrueListener = new PropertyChangeListener() {
0954: public void propertyChange(
0955: PropertyChangeEvent evt) {
0956: if (evt.getSource() instanceof JComponent) {
0957: ((JComponent) evt
0958: .getSource())
0959: .setOpaque(true);
0960: }
0961: }
0962: };
0963: }
0964: jc.addPropertyChangeListener("opaque",
0965: _setOpaqueTrueListener);
0966: jc.putClientProperty("opaqueListener",
0967: _setOpaqueTrueListener);
0968: } else {
0969: if (_setOpaqueFalseListener == null) {
0970: _setOpaqueFalseListener = new PropertyChangeListener() {
0971: public void propertyChange(
0972: PropertyChangeEvent evt) {
0973: if (evt.getSource() instanceof JComponent) {
0974: ((JComponent) evt
0975: .getSource())
0976: .setOpaque(false);
0977: }
0978: }
0979: };
0980: }
0981: jc.addPropertyChangeListener("opaque",
0982: _setOpaqueFalseListener);
0983: jc.putClientProperty(OPAQUE_LISTENER,
0984: _setOpaqueFalseListener);
0985: }
0986: }
0987: }
0988: }
0989:
0990: public void postAction(Component c) {
0991: }
0992: });
0993: }
0994:
0995: public static Dimension getPreferredButtonSize(AbstractButton b,
0996: int textIconGap, boolean isHorizontal) {
0997: if (b.getComponentCount() > 0) {
0998: return null;
0999: }
1000:
1001: Icon icon = (Icon) b.getIcon();
1002: String text = b.getText();
1003:
1004: Font font = b.getFont();
1005: FontMetrics fm = b.getFontMetrics(font);
1006:
1007: Rectangle iconR = new Rectangle();
1008: Rectangle textR = new Rectangle();
1009: Rectangle viewR = new Rectangle(Short.MAX_VALUE,
1010: Short.MAX_VALUE);
1011:
1012: layoutCompoundLabel((JComponent) b, fm, text, icon,
1013: isHorizontal, b.getVerticalAlignment(), b
1014: .getHorizontalAlignment(), b
1015: .getVerticalTextPosition(), b
1016: .getHorizontalTextPosition(), viewR, iconR,
1017: textR, (text == null ? 0 : textIconGap));
1018:
1019: /* The preferred size of the button is the size of
1020: * the text and icon rectangles plus the buttons insets.
1021: */
1022:
1023: Rectangle r = iconR.union(textR);
1024:
1025: Insets insets = b.getInsets();
1026: r.width += insets.left + insets.right;
1027: r.height += insets.top + insets.bottom;
1028:
1029: return r.getSize();
1030: }
1031:
1032: /**
1033: * Compute and return the location of the icons origin, the
1034: * location of origin of the text baseline, and a possibly clipped
1035: * version of the compound labels string. Locations are computed
1036: * relative to the viewR rectangle.
1037: * The JComponents orientation (LEADING/TRAILING) will also be taken
1038: * into account and translated into LEFT/RIGHT values accordingly.
1039: */
1040: public static String layoutCompoundLabel(JComponent c,
1041: FontMetrics fm, String text, Icon icon,
1042: boolean isHorizontal, int verticalAlignment,
1043: int horizontalAlignment, int verticalTextPosition,
1044: int horizontalTextPosition, Rectangle viewR,
1045: Rectangle iconR, Rectangle textR, int textIconGap) {
1046: boolean orientationIsLeftToRight = true;
1047: int hAlign = horizontalAlignment;
1048: int hTextPos = horizontalTextPosition;
1049:
1050: if (c != null) {
1051: if (!(c.getComponentOrientation().isLeftToRight())) {
1052: orientationIsLeftToRight = false;
1053: }
1054: }
1055:
1056: // Translate LEADING/TRAILING values in horizontalAlignment
1057: // to LEFT/RIGHT values depending on the components orientation
1058: switch (horizontalAlignment) {
1059: case LEADING:
1060: hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
1061: break;
1062: case TRAILING:
1063: hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
1064: break;
1065: }
1066:
1067: // Translate LEADING/TRAILING values in horizontalTextPosition
1068: // to LEFT/RIGHT values depending on the components orientation
1069: switch (horizontalTextPosition) {
1070: case LEADING:
1071: hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
1072: break;
1073: case TRAILING:
1074: hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
1075: break;
1076: }
1077:
1078: return layoutCompoundLabelImpl(c, fm, text, icon, isHorizontal,
1079: verticalAlignment, hAlign, verticalTextPosition,
1080: hTextPos, viewR, iconR, textR, textIconGap);
1081: }
1082:
1083: /**
1084: * Compute and return the location of the icons origin, the
1085: * location of origin of the text baseline, and a possibly clipped
1086: * version of the compound labels string. Locations are computed
1087: * relative to the viewR rectangle.
1088: * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
1089: * values in horizontalTextPosition (they will default to RIGHT) and in
1090: * horizontalAlignment (they will default to CENTER).
1091: * Use the other version of layoutCompoundLabel() instead.
1092: */
1093: public static String layoutCompoundLabel(FontMetrics fm,
1094: String text, Icon icon, boolean isHorizontal,
1095: int verticalAlignment, int horizontalAlignment,
1096: int verticalTextPosition, int horizontalTextPosition,
1097: Rectangle viewR, Rectangle iconR, Rectangle textR,
1098: int textIconGap) {
1099: return layoutCompoundLabelImpl(null, fm, text, icon,
1100: isHorizontal, verticalAlignment, horizontalAlignment,
1101: verticalTextPosition, horizontalTextPosition, viewR,
1102: iconR, textR, textIconGap);
1103: }
1104:
1105: /**
1106: * Compute and return the location of the icons origin, the
1107: * location of origin of the text baseline, and a possibly clipped
1108: * version of the compound labels string. Locations are computed
1109: * relative to the viewR rectangle.
1110: * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
1111: * values in horizontalTextPosition (they will default to RIGHT) and in
1112: * horizontalAlignment (they will default to CENTER).
1113: * Use the other version of layoutCompoundLabel() instead.
1114: */
1115: private static String layoutCompoundLabelImpl(JComponent c,
1116: FontMetrics fm, String text, Icon icon,
1117: boolean isHorizontal, int verticalAlignment,
1118: int horizontalAlignment, int verticalTextPosition,
1119: int horizontalTextPosition, Rectangle viewR,
1120: Rectangle iconR, Rectangle textR, int textIconGap) {
1121: /* Initialize the icon bounds rectangle iconR.
1122: */
1123: if (isHorizontal)
1124: return layoutCompoundLabelImplHorizontal(c, fm, text, icon,
1125: verticalAlignment, horizontalAlignment,
1126: verticalTextPosition, horizontalTextPosition,
1127: viewR, iconR, textR, textIconGap);
1128: else
1129: return layoutCompoundLabelImplVertical(c, fm, text, icon,
1130: verticalAlignment, horizontalAlignment,
1131: verticalTextPosition, horizontalTextPosition,
1132: viewR, iconR, textR, textIconGap);
1133:
1134: }
1135:
1136: private static String getMaxLengthWord(String text) {
1137: if (text.indexOf(' ') == -1) {
1138: return text;
1139: } else {
1140: int minDiff = text.length();
1141: int minPos = -1;
1142: int mid = text.length() / 2;
1143:
1144: int pos = -1;
1145: while (true) {
1146: pos = text.indexOf(' ', pos + 1);
1147: if (pos == -1) {
1148: break;
1149: }
1150: int diff = Math.abs(pos - mid);
1151: if (diff < minDiff) {
1152: minDiff = diff;
1153: minPos = pos;
1154: }
1155: }
1156: return minPos >= mid ? text.substring(0, minPos) : text
1157: .substring(minPos + 1);
1158: }
1159: }
1160:
1161: private static String layoutCompoundLabelImplHorizontal(
1162: JComponent c, FontMetrics fm, String text, Icon icon,
1163: int verticalAlignment, int horizontalAlignment,
1164: int verticalTextPosition, int horizontalTextPosition,
1165: Rectangle viewR, Rectangle iconR, Rectangle textR,
1166: int textIconGap) {
1167: /* Initialize the icon bounds rectangle iconR.
1168: */
1169:
1170: if (icon != null) {
1171: iconR.width = icon.getIconWidth();
1172: iconR.height = icon.getIconHeight();
1173: } else {
1174: iconR.width = iconR.height = 0;
1175: }
1176:
1177: /* Initialize the text bounds rectangle textR. If a null
1178: * or and empty String was specified we substitute "" here
1179: * and use 0,0,0,0 for textR.
1180: */
1181:
1182: boolean textIsEmpty = (text == null) || text.equals("");
1183:
1184: View v = null;
1185: if (textIsEmpty) {
1186: textR.width = textR.height = 0;
1187: text = "";
1188: } else {
1189: v = (c != null) ? (View) c.getClientProperty("html") : null;
1190: if (v != null) {
1191: textR.width = (int) v.getPreferredSpan(View.X_AXIS);
1192: textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
1193: } else {
1194: if (false) { // TODO: debug switch
1195: boolean wrapText = false;
1196: if (verticalTextPosition == BOTTOM
1197: && horizontalTextPosition == CENTER) { // in this case, we will wrap the text into two lines
1198: wrapText = true;
1199: }
1200:
1201: if (wrapText) {
1202: textR.width = SwingUtilities
1203: .computeStringWidth(fm,
1204: getMaxLengthWord(text));
1205: textR.height = fm.getHeight() + fm.getAscent()
1206: + 2; // gap between the two lines is 2.
1207: } else {
1208: textR.width = SwingUtilities
1209: .computeStringWidth(fm, text) + 1; // add an extra pixel at the end of the text
1210: textR.height = fm.getHeight();
1211: }
1212: } else {
1213: textR.width = SwingUtilities.computeStringWidth(fm,
1214: text); // add an extra pixel at the end of the text
1215: textR.height = fm.getHeight();
1216: }
1217: }
1218: }
1219:
1220: /* Unless both text and icon are non-null, we effectively ignore
1221: * the value of textIconGap. The code that follows uses the
1222: * value of gap instead of textIconGap.
1223: */
1224:
1225: int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
1226:
1227: if (!textIsEmpty) {
1228:
1229: /* If the label text string is too wide to fit within the available
1230: * space "..." and as many characters as will fit will be
1231: * displayed instead.
1232: */
1233:
1234: int availTextWidth;
1235:
1236: if (horizontalTextPosition == CENTER) {
1237: availTextWidth = viewR.width;
1238: } else {
1239: availTextWidth = viewR.width - (iconR.width + gap);
1240: }
1241:
1242: if (textR.width > availTextWidth) {
1243: if (v != null) {
1244: textR.width = availTextWidth;
1245: } else {
1246: String clipString = "...";
1247: int totalWidth = SwingUtilities.computeStringWidth(
1248: fm, clipString);
1249: int nChars;
1250: for (nChars = 0; nChars < text.length(); nChars++) {
1251: totalWidth += fm.charWidth(text.charAt(nChars));
1252: if (totalWidth > availTextWidth) {
1253: break;
1254: }
1255: }
1256: text = text.substring(0, nChars) + clipString;
1257: textR.width = SwingUtilities.computeStringWidth(fm,
1258: text);
1259: }
1260: }
1261: }
1262:
1263: /* Compute textR.x,y given the verticalTextPosition and
1264: * horizontalTextPosition properties
1265: */
1266:
1267: if (verticalTextPosition == TOP) {
1268: if (horizontalTextPosition != CENTER) {
1269: textR.y = 0;
1270: } else {
1271: textR.y = -(textR.height + gap);
1272: }
1273: } else if (verticalTextPosition == CENTER) {
1274: textR.y = (iconR.height >> 1) - (textR.height >> 1);
1275: } else { // (verticalTextPosition == BOTTOM)
1276: if (horizontalTextPosition != CENTER) {
1277: textR.y = iconR.height - textR.height;
1278: } else {
1279: textR.y = (iconR.height + gap);
1280: }
1281: }
1282:
1283: if (horizontalTextPosition == LEFT) {
1284: textR.x = -(textR.width + gap);
1285: } else if (horizontalTextPosition == CENTER) {
1286: textR.x = (iconR.width >> 1) - (textR.width >> 1);
1287: } else { // (horizontalTextPosition == RIGHT)
1288: textR.x = (iconR.width + gap);
1289: }
1290:
1291: /* labelR is the rectangle that contains iconR and textR.
1292: * Move it to its proper position given the labelAlignment
1293: * properties.
1294: *
1295: * To avoid actually allocating a Rectangle, Rectangle.union
1296: * has been inlined below.
1297: */
1298: int labelR_x = Math.min(iconR.x, textR.x);
1299: int labelR_width = Math.max(iconR.x + iconR.width, textR.x
1300: + textR.width)
1301: - labelR_x;
1302: int labelR_y = Math.min(iconR.y, textR.y);
1303: int labelR_height = Math.max(iconR.y + iconR.height, textR.y
1304: + textR.height)
1305: - labelR_y;
1306:
1307: int dx, dy;
1308:
1309: if (verticalAlignment == TOP) {
1310: dy = viewR.y - labelR_y;
1311: } else if (verticalAlignment == CENTER) {
1312: dy = (viewR.y + (viewR.height >> 1))
1313: - (labelR_y + (labelR_height >> 1));
1314: } else { // (verticalAlignment == BOTTOM)
1315: dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
1316: }
1317:
1318: if (horizontalAlignment == LEFT) {
1319: dx = viewR.x - labelR_x;
1320: } else if (horizontalAlignment == RIGHT) {
1321: dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
1322: } else { // (horizontalAlignment == CENTER)
1323: dx = (viewR.x + (viewR.width >> 1))
1324: - (labelR_x + (labelR_width >> 1));
1325: }
1326:
1327: /* Translate textR and glypyR by dx,dy.
1328: */
1329:
1330: textR.x += dx;
1331: textR.y += dy;
1332:
1333: iconR.x += dx;
1334: iconR.y += dy;
1335:
1336: return text;
1337: }
1338:
1339: private static String layoutCompoundLabelImplVertical(JComponent c,
1340: FontMetrics fm, String text, Icon icon,
1341: int verticalAlignment, int horizontalAlignment,
1342: int verticalTextPosition, int horizontalTextPosition,
1343: Rectangle viewR, Rectangle iconR, Rectangle textR,
1344: int textIconGap) {
1345: /* Initialize the icon bounds rectangle iconR.
1346: */
1347:
1348: if (icon != null) {
1349: iconR.width = icon.getIconWidth();
1350: iconR.height = icon.getIconHeight();
1351: } else {
1352: iconR.width = iconR.height = 0;
1353: }
1354:
1355: /* Initialize the text bounds rectangle textR. If a null
1356: * or and empty String was specified we substitute "" here
1357: * and use 0,0,0,0 for textR.
1358: */
1359:
1360: boolean textIsEmpty = (text == null) || text.equals("");
1361:
1362: View v = null;
1363: if (textIsEmpty) {
1364: textR.width = textR.height = 0;
1365: text = "";
1366: } else {
1367: v = (c != null) ? (View) c.getClientProperty("html") : null;
1368: if (v != null) {
1369: textR.height = (int) v.getPreferredSpan(View.X_AXIS);
1370: textR.width = (int) v.getPreferredSpan(View.Y_AXIS);
1371: } else {
1372: textR.height = SwingUtilities.computeStringWidth(fm,
1373: text);
1374: textR.width = fm.getHeight();
1375: }
1376: }
1377:
1378: /* Unless both text and icon are non-null, we effectively ignore
1379: * the value of textIconGap. The code that follows uses the
1380: * value of gap instead of textIconGap.
1381: */
1382:
1383: int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
1384:
1385: if (!textIsEmpty) {
1386:
1387: /* If the label text string is too wide to fit within the available
1388: * space "..." and as many characters as will fit will be
1389: * displayed instead.
1390: */
1391:
1392: int availTextHeight;
1393:
1394: if (horizontalTextPosition == CENTER) {
1395: availTextHeight = viewR.height;
1396: } else {
1397: availTextHeight = viewR.height - (iconR.height + gap);
1398: }
1399:
1400: if (textR.height > availTextHeight) {
1401: if (v != null) {
1402: textR.height = availTextHeight;
1403: } else {
1404: String clipString = "...";
1405: int totalHeight = SwingUtilities
1406: .computeStringWidth(fm, clipString);
1407: int nChars;
1408: for (nChars = 0; nChars < text.length(); nChars++) {
1409: totalHeight += fm
1410: .charWidth(text.charAt(nChars));
1411: if (totalHeight > availTextHeight) {
1412: break;
1413: }
1414: }
1415: text = text.substring(0, nChars) + clipString;
1416: textR.height = SwingUtilities.computeStringWidth(
1417: fm, text);
1418: }
1419: }
1420: }
1421:
1422: /* Compute textR.x,y given the verticalTextPosition and
1423: * horizontalTextPosition properties
1424: */
1425:
1426: if (verticalTextPosition == TOP) {
1427: if (horizontalTextPosition != CENTER) {
1428: textR.x = 0;
1429: } else {
1430: textR.x = -(textR.width + gap);
1431: }
1432: } else if (verticalTextPosition == CENTER) {
1433: textR.y = (iconR.width >> 1) - (textR.width >> 1);
1434: } else { // (verticalTextPosition == BOTTOM)
1435: if (horizontalTextPosition != CENTER) {
1436: textR.x = iconR.width - textR.width;
1437: } else {
1438: textR.x = (iconR.width + gap);
1439: }
1440: }
1441:
1442: if (horizontalTextPosition == LEFT) {
1443: textR.y = -(textR.height + gap);
1444: } else if (horizontalTextPosition == CENTER) {
1445: textR.y = (iconR.height >> 1) - (textR.height >> 1);
1446: } else { // (horizontalTextPosition == RIGHT)
1447: textR.y = (iconR.height + gap);
1448: }
1449:
1450: /* labelR is the rectangle that contains iconR and textR.
1451: * Move it to its proper position given the labelAlignment
1452: * properties.
1453: *
1454: * To avoid actually allocating a Rectangle, Rectangle.union
1455: * has been inlined below.
1456: */
1457: int labelR_x = Math.min(iconR.y, textR.y);
1458: int labelR_width = Math.max(iconR.y + iconR.height, textR.y
1459: + textR.height)
1460: - labelR_x;
1461: int labelR_y = Math.min(iconR.x, textR.x);
1462: int labelR_height = Math.max(iconR.x + iconR.width, textR.x
1463: + textR.width)
1464: - labelR_y;
1465:
1466: int dx, dy;
1467: int dIcony; // because we will retate icon, so the position will
1468: // be different from text. However after transform, they will be same
1469:
1470: if (verticalAlignment == TOP) {
1471: dy = viewR.x - labelR_y;
1472: dIcony = (viewR.x + viewR.width)
1473: - (labelR_y + labelR_height);
1474: } else if (verticalAlignment == CENTER) {
1475: dy = (viewR.x + (viewR.width >> 1))
1476: - (labelR_y + (labelR_height >> 1));
1477: dIcony = dy;
1478: } else { // (verticalAlignment == BOTTOM)
1479: dy = (viewR.x + viewR.width) - (labelR_y + labelR_height);
1480: dIcony = viewR.x - labelR_y;
1481: }
1482:
1483: if (horizontalAlignment == LEFT) {
1484: dx = viewR.y - labelR_x;
1485: } else if (horizontalAlignment == RIGHT) {
1486: dx = (viewR.y + viewR.height) - (labelR_x + labelR_width);
1487: } else { // (horizontalAlignment == CENTER)
1488: dx = (viewR.y + (viewR.height >> 1))
1489: - (labelR_x + (labelR_width >> 1));
1490: }
1491:
1492: /* Translate textR and iconR by dx,dy.
1493: */
1494:
1495: textR.y += dx;
1496: textR.x += dy;
1497:
1498: iconR.y += dx;
1499: iconR.x += dIcony;
1500:
1501: return text;
1502: }
1503:
1504: public static int getOrientationOf(Component component) {
1505: if (component instanceof Alignable) {
1506: return ((Alignable) component).getOrientation();
1507: } else if (component instanceof JComponent) {
1508: Integer value = (Integer) ((JComponent) component)
1509: .getClientProperty(Alignable.PROPERTY_ORIENTATION);
1510: if (value != null)
1511: return value;
1512: }
1513: return HORIZONTAL;
1514: }
1515:
1516: public static void setOrientationOf(Component component,
1517: int orientation) {
1518: int old = getOrientationOf(component);
1519: if (orientation != old) {
1520: if (component instanceof Alignable) {
1521: ((Alignable) component).setOrientation(orientation);
1522: } else if (component instanceof JComponent) {
1523: ((JComponent) component).putClientProperty(
1524: Alignable.PROPERTY_ORIENTATION, orientation);
1525: }
1526: }
1527: }
1528:
1529: public static void setChildrenOrientationOf(Container c,
1530: int orientation) {
1531: Component[] components = c.getComponents();
1532: for (int i = 0; i < components.length; ++i) {
1533: Component component = components[i];
1534: setOrientationOf(component, orientation);
1535: }
1536: }
1537:
1538: /**
1539: * Disables the double buffered flag of the component and its children. The return map contains
1540: * the components that were double buffered. After this call, you can then restore the double buffered flag
1541: * using {@link #restoreDoubleBuffered(java.awt.Component,java.util.Map)} using the map that is returned from
1542: * this method.
1543: *
1544: * @param c the parent container.
1545: * @return the map that contains all components that were double buffered.
1546: */
1547: public static Map<Component, Boolean> disableDoubleBuffered(
1548: final Component c) {
1549: final Map<Component, Boolean> map = new HashMap();
1550: if (c instanceof JComponent) {
1551: JideSwingUtilities.setRecursively(c,
1552: new JideSwingUtilities.Handler() {
1553: public boolean condition(Component c) {
1554: return c instanceof JComponent
1555: && ((JComponent) c)
1556: .isDoubleBuffered();
1557: }
1558:
1559: public void action(Component c) {
1560: map.put(c, Boolean.TRUE);
1561: ((JComponent) c).setDoubleBuffered(false);
1562: }
1563:
1564: public void postAction(Component c) {
1565:
1566: }
1567: });
1568: }
1569: return map;
1570: }
1571:
1572: /**
1573: * Enables the double buffered flag of the component and its children. The return map contains
1574: * the components that weren't double buffered. After this call, you can then restore the double buffered flag
1575: * using {@link #restoreDoubleBuffered(java.awt.Component,java.util.Map)} using the map that is returned from
1576: * this method.
1577: *
1578: * @param c the parent container.
1579: * @return the map that contains all components that weren't double buffered.
1580: */
1581: public static Map<Component, Boolean> enableDoubleBuffered(
1582: final Component c) {
1583: final Map<Component, Boolean> map = new HashMap();
1584: if (c instanceof JComponent) {
1585: JideSwingUtilities.setRecursively(c,
1586: new JideSwingUtilities.Handler() {
1587: public boolean condition(Component c) {
1588: return c instanceof JComponent
1589: && !c.isDoubleBuffered();
1590: }
1591:
1592: public void action(Component c) {
1593: map.put(c, Boolean.FALSE);
1594: ((JComponent) c).setDoubleBuffered(true);
1595: }
1596:
1597: public void postAction(Component c) {
1598:
1599: }
1600: });
1601: }
1602: return map;
1603: }
1604:
1605: /**
1606: * Restores the double buffered flag of the component and its children. Only components that are in the map will be changed.
1607: *
1608: * @param c the parent container.
1609: * @param map a map maps from component to a boolean. If the boolean is true, it means the component was double buffered bore.
1610: * Otherwise, not double buffered.
1611: */
1612: public static void restoreDoubleBuffered(final Component c,
1613: final Map<Component, Boolean> map) {
1614: JideSwingUtilities.setRecursively(c,
1615: new JideSwingUtilities.Handler() {
1616: public boolean condition(Component c) {
1617: return c instanceof JComponent;
1618: }
1619:
1620: public void action(Component c) {
1621: Boolean value = map.get(c);
1622: if (value != null) {
1623: ((JComponent) c)
1624: .setDoubleBuffered(Boolean.TRUE
1625: .equals(value));
1626: }
1627: }
1628:
1629: public void postAction(Component c) {
1630: }
1631: });
1632: }
1633:
1634: public static void paintBackground(Graphics g, Rectangle rect,
1635: Color border, Color bk) {
1636: Color old = g.getColor();
1637: g.setColor(bk);
1638: g.fillRect(rect.x + 1, rect.y + 1, rect.width - 2,
1639: rect.height - 2);
1640: g.setColor(border);
1641: g.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
1642: g.setColor(old);
1643: }
1644:
1645: public static void paintBackground(Graphics2D g2d, Rectangle rect,
1646: Color border, Paint paint) {
1647: Color old = g2d.getColor();
1648: g2d.setPaint(paint);
1649: g2d.fillRect(rect.x + 1, rect.y + 1, rect.width - 2,
1650: rect.height - 2);
1651: g2d.setColor(border);
1652: g2d.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
1653: g2d.setColor(old);
1654: }
1655:
1656: /**
1657: * Returns whether or not text should be drawn antialiased.
1658: *
1659: * @param c JComponent to test.
1660: * @return Whether or not text should be drawn antialiased for the
1661: * specified component.
1662: */
1663: private static boolean drawTextAntialiased(Component c) {
1664: if (!AA_TEXT_DEFINED) {
1665: if (c != null) {
1666: // Check if the component wants aa text
1667: if (c instanceof JComponent) {
1668: Boolean aaProperty = (Boolean) ((JComponent) c)
1669: .getClientProperty(AA_TEXT_PROPERTY_KEY);
1670: return aaProperty != null ? aaProperty : false;
1671: } else {
1672: return false;
1673: }
1674: }
1675: // No component, assume aa is off
1676: return false;
1677: }
1678: // 'swing.aatext' was defined, use its value.
1679: return AA_TEXT;
1680: }
1681:
1682: /**
1683: * Returns whether or not text should be drawn antialiased.
1684: *
1685: * @param aaText Whether or not aa text has been turned on for the
1686: * component.
1687: * @return Whether or not text should be drawn antialiased.
1688: */
1689: public static boolean drawTextAntialiased(boolean aaText) {
1690: if (!AA_TEXT_DEFINED) {
1691: // 'swing.aatext' wasn't defined, use the components aa text value.
1692: return aaText;
1693: }
1694: // 'swing.aatext' was defined, use its value.
1695: return AA_TEXT;
1696: }
1697:
1698: public static void drawStringUnderlineCharAt(JComponent c,
1699: Graphics g, String text, int underlinedIndex, int x, int y) {
1700: drawString(c, g, text, x, y);
1701:
1702: if (underlinedIndex >= 0 && underlinedIndex < text.length()) {
1703: FontMetrics fm = g.getFontMetrics();
1704: int underlineRectX = x
1705: + fm
1706: .stringWidth(text.substring(0,
1707: underlinedIndex));
1708: int underlineRectY = y;
1709: int underlineRectWidth = fm.charWidth(text
1710: .charAt(underlinedIndex));
1711: int underlineRectHeight = 1;
1712: g.fillRect(underlineRectX, underlineRectY + fm.getDescent()
1713: - 1, underlineRectWidth, underlineRectHeight);
1714: }
1715: }
1716:
1717: static RenderingHints renderingHints = null;
1718:
1719: static {
1720: if (SystemInfo.isJdk6Above()) {
1721: Toolkit tk = Toolkit.getDefaultToolkit();
1722: renderingHints = (RenderingHints) (tk
1723: .getDesktopProperty("awt.font.desktophints"));
1724: tk.addPropertyChangeListener("awt.font.desktophints",
1725: new PropertyChangeListener() {
1726: public void propertyChange(
1727: PropertyChangeEvent evt) {
1728: if (evt.getNewValue() instanceof RenderingHints) {
1729: renderingHints = (RenderingHints) evt
1730: .getNewValue();
1731: }
1732: }
1733: });
1734: }
1735: }
1736:
1737: /**
1738: * Get rendering hints from a Graphics instance.
1739: * "hintsToSave" is a Map of RenderingHint key-values.
1740: * For each hint key present in that map, the value of that
1741: * hint is obtained from the Graphics and stored as the value
1742: * for the key in savedHints.
1743: */
1744: private static RenderingHints getRenderingHints(Graphics2D g2d,
1745: RenderingHints hintsToSave, RenderingHints savedHints) {
1746: if (savedHints == null) {
1747: savedHints = new RenderingHints(null);
1748: } else {
1749: savedHints.clear();
1750: }
1751: if (hintsToSave == null || hintsToSave.size() == 0) {
1752: return savedHints;
1753: }
1754: /* RenderingHints.keySet() returns Set*/
1755: Set objects = hintsToSave.keySet();
1756: for (Iterator iterator = objects.iterator(); iterator.hasNext();) {
1757: Object o = iterator.next();
1758: RenderingHints.Key key = (RenderingHints.Key) o;
1759: Object value = g2d.getRenderingHint(key);
1760: savedHints.put(key, value);
1761: }
1762:
1763: return savedHints;
1764: }
1765:
1766: public static void drawString(JComponent c, Graphics g,
1767: String text, int x, int y) {
1768: if (SystemInfo.isJdk6Above()) {
1769: Graphics2D g2d = (Graphics2D) g;
1770: RenderingHints oldHints = null;
1771: if (renderingHints != null) {
1772: oldHints = getRenderingHints(g2d, renderingHints, null);
1773: g2d.addRenderingHints(renderingHints);
1774: }
1775: g2d.drawString(text, x, y);
1776: if (oldHints != null) {
1777: g2d.addRenderingHints(oldHints);
1778: }
1779: } else {
1780: // If we get here we're not printing
1781: if (drawTextAntialiased(c) && (g instanceof Graphics2D)) {
1782: Graphics2D g2 = (Graphics2D) g;
1783: Object oldAAValue = g2
1784: .getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
1785: g2.setRenderingHint(
1786: RenderingHints.KEY_TEXT_ANTIALIASING,
1787: RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1788: g2.drawString(text, x, y);
1789: g2.setRenderingHint(
1790: RenderingHints.KEY_TEXT_ANTIALIASING,
1791: oldAAValue);
1792: } else {
1793: g.drawString(text, x, y);
1794: }
1795: }
1796: }
1797:
1798: /**
1799: * Setups the graphics to draw text using anti-alias.
1800: * <p/>
1801: * Under JDK1.4 and JDK5, this method will use a system property "swing.aatext" to determine if anti-alias is used.
1802: * Under JDK6, we will read the system setting. For example, on Windows XP, there is a check box to turn on clear type anti-alias.
1803: * We will use the same settings.
1804: *
1805: * @param c
1806: * @param g
1807: * @return the old hints. You will need this value as the third parameter in {@link #restoreAntialiasing(java.awt.Component,java.awt.Graphics,Object)}.
1808: */
1809: public static Object setupAntialiasing(Component c, Graphics g) {
1810: Graphics2D g2d = (Graphics2D) g;
1811: Object oldHints = null;
1812: if (SystemInfo.isJdk6Above()) {
1813: oldHints = getRenderingHints(g2d, renderingHints, null);
1814: if (renderingHints != null) {
1815: g2d.addRenderingHints(renderingHints);
1816: }
1817: } else {
1818: oldHints = g2d
1819: .getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING);
1820: if (drawTextAntialiased(c)) {
1821: g2d.setRenderingHint(
1822: RenderingHints.KEY_TEXT_ANTIALIASING,
1823: RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
1824: }
1825: }
1826: return oldHints;
1827: }
1828:
1829: /**
1830: * Restores the old setting for text anti-alias.
1831: *
1832: * @param c
1833: * @param g
1834: * @param oldHints the value returned from {@link #setupAntialiasing(java.awt.Component,java.awt.Graphics)}.
1835: */
1836: public static void restoreAntialiasing(Component c, Graphics g,
1837: Object oldHints) {
1838: Graphics2D g2d = (Graphics2D) g;
1839: if (SystemInfo.isJdk6Above()) {
1840: if (oldHints != null) {
1841: g2d.addRenderingHints((RenderingHints) oldHints);
1842: }
1843: } else {
1844: g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
1845: oldHints);
1846: }
1847: }
1848:
1849: /**
1850: * Setups the graphics to draw shape using anti-alias.
1851: *
1852: * @param g
1853: * @return the old hints. You will need this value as the third parameter in {@link #restoreShapeAntialiasing(java.awt.Graphics,Object)}.
1854: */
1855: public static Object setupShapeAntialiasing(Graphics g) {
1856: Graphics2D g2d = (Graphics2D) g;
1857: Object oldHints = g2d
1858: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
1859: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1860: RenderingHints.VALUE_ANTIALIAS_ON);
1861: return oldHints;
1862: }
1863:
1864: /**
1865: * Restores the old setting for shape anti-alias.
1866: *
1867: * @param g
1868: * @param oldHints the value returned from {@link #setupShapeAntialiasing(java.awt.Graphics)}.
1869: */
1870: public static void restoreShapeAntialiasing(Graphics g,
1871: Object oldHints) {
1872: Graphics2D g2d = (Graphics2D) g;
1873: g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldHints);
1874: }
1875:
1876: public static void drawGrip(Graphics g, Rectangle rectangle,
1877: int maxLength, int maxThickness) {
1878: drawGrip(g, rectangle, maxLength, maxThickness, true);
1879: }
1880:
1881: public static void drawGrip(Graphics g, Rectangle rectangle,
1882: int maxLength, int maxThickness, boolean isSelected) {
1883: if (rectangle.width > rectangle.height) {
1884: int count = maxLength;
1885: if (maxLength * 3 > rectangle.width) {
1886: count = rectangle.width / 3;
1887: }
1888: int startX = rectangle.x
1889: + ((rectangle.width - (count * 3)) >> 1);
1890: int startY = rectangle.y
1891: + ((rectangle.height - (maxThickness * 3)) >> 1);
1892: for (int i = 0; i < maxThickness; i++) {
1893: for (int j = 0; j < count; j++) {
1894: if (isSelected) {
1895: g.setColor(UIDefaultsLookup
1896: .getColor("controlLtHighlight"));
1897: g.drawLine(startX + j * 3, startY + i * 3,
1898: startX + j * 3, startY + i * 3);
1899: }
1900: g.setColor(UIDefaultsLookup
1901: .getColor("controlShadow"));
1902: g.drawLine(startX + j * 3 + 1, startY + i * 3 + 1,
1903: startX + j * 3 + 1, startY + i * 3 + 1);
1904: }
1905: }
1906: } else {
1907: int count = maxLength;
1908: if (maxLength * 3 > rectangle.height) {
1909: count = rectangle.height / 3;
1910: }
1911: int startX = rectangle.x
1912: + ((rectangle.width - (maxThickness * 3)) >> 1);
1913: int startY = rectangle.y
1914: + ((rectangle.height - (count * 3)) >> 1);
1915: for (int i = 0; i < maxThickness; i++) {
1916: for (int j = 0; j < count; j++) {
1917: if (isSelected) {
1918: g.setColor(UIDefaultsLookup
1919: .getColor("controlLtHighlight"));
1920: g.drawLine(startX + i * 3, startY + j * 3,
1921: startX + i * 3, startY + j * 3);
1922: }
1923: g.setColor(UIDefaultsLookup
1924: .getColor("controlShadow"));
1925: g.drawLine(startX + i * 3 + 1, startY + j * 3 + 1,
1926: startX + i * 3 + 1, startY + j * 3 + 1);
1927: }
1928: }
1929: }
1930: }
1931:
1932: /**
1933: * Register the tab key with the container.
1934: *
1935: * @param container
1936: */
1937: public static void registerTabKey(Container container) {
1938: if (container instanceof JComponent) {
1939: ((JComponent) container).registerKeyboardAction(
1940: new AbstractAction() {
1941: public void actionPerformed(ActionEvent e) {
1942: // JDK 1.3 Porting Hint
1943: // comment out for now
1944: DefaultKeyboardFocusManager
1945: .getCurrentKeyboardFocusManager()
1946: .focusNextComponent();
1947: }
1948: }, KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0),
1949: JComponent.WHEN_FOCUSED);
1950: } else {
1951: for (int i = 0; i < container.getComponentCount(); i++) {
1952: Component c = container.getComponent(i);
1953: // JDK 1.3 Porting Hint
1954: // change to isFocusTraversable()
1955: if (c instanceof JComponent && c.isFocusable()) {
1956: ((JComponent) container).registerKeyboardAction(
1957: new AbstractAction() {
1958: public void actionPerformed(
1959: ActionEvent e) {
1960: // JDK 1.3 Porting Hint
1961: // comment out for now
1962: DefaultKeyboardFocusManager
1963: .getCurrentKeyboardFocusManager()
1964: .focusNextComponent();
1965: }
1966: }, KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
1967: 0), JComponent.WHEN_FOCUSED);
1968: }
1969: }
1970: }
1971: }
1972:
1973: public static void fillGradient(Graphics g, Rectangle rect,
1974: int orientation) {
1975: Graphics2D g2d = (Graphics2D) g;
1976: // paint upper gradient
1977: Color col1 = new Color(255, 255, 255, 0);
1978: Color col2 = new Color(255, 255, 255, 48);
1979: Color col3 = new Color(0, 0, 0, 0);
1980: Color col4 = new Color(0, 0, 0, 32);
1981:
1982: if (orientation == SwingConstants.HORIZONTAL) {
1983: // paint upper gradient
1984: fillGradient(g2d, new Rectangle(rect.x, rect.y, rect.width,
1985: rect.height >> 1), col2, col1, true);
1986:
1987: // paint lower gradient
1988: fillGradient(g2d,
1989: new Rectangle(rect.x, rect.y + (rect.height >> 1),
1990: rect.width, rect.height >> 1), col3, col4,
1991: true);
1992: } else {
1993: // paint left gradient
1994: fillGradient(g2d, new Rectangle(rect.x, rect.y,
1995: rect.width >> 1, rect.height), col2, col1, false);
1996:
1997: // paint right gradient
1998: fillGradient(g2d, new Rectangle(rect.x + (rect.width >> 1),
1999: rect.y, rect.width >> 1, rect.height), col3, col4,
2000: false);
2001: }
2002: }
2003:
2004: public static void fillSingleGradient(Graphics g, Rectangle rect,
2005: int orientation) {
2006: fillSingleGradient(g, rect, orientation, 127);
2007: }
2008:
2009: public static void fillSingleGradient(Graphics g, Rectangle rect,
2010: int orientation, int level) {
2011: Graphics2D g2d = (Graphics2D) g;
2012: Color col1 = new Color(255, 255, 255, 0);
2013: Color col2 = new Color(255, 255, 255, level);
2014:
2015: if (orientation == SwingConstants.SOUTH) {
2016: fillGradient(g2d, new Rectangle(rect.x, rect.y, rect.width,
2017: rect.height), col2, col1, true);
2018: } else if (orientation == SwingConstants.NORTH) {
2019: fillGradient(g2d, new Rectangle(rect.x, rect.y, rect.width,
2020: rect.height), col1, col2, true);
2021: } else if (orientation == SwingConstants.EAST) {
2022: fillGradient(g2d, new Rectangle(rect.x, rect.y, rect.width,
2023: rect.height), col2, col1, false);
2024: } else if (orientation == SwingConstants.WEST) {
2025: fillGradient(g2d, new Rectangle(rect.x, rect.y, rect.width,
2026: rect.height), col1, col2, false);
2027: }
2028: }
2029:
2030: /**
2031: * containerContainsFocus, does the specified container contain the current
2032: * focusOwner?
2033: *
2034: * @param cont the specified container
2035: * @return Is the current focusOwner a descendent of the specified
2036: * container, or the container itself?
2037: */
2038: public static boolean containerContainsFocus(Container cont) {
2039: Component focusOwner = KeyboardFocusManager
2040: .getCurrentKeyboardFocusManager().getFocusOwner();
2041: Component permFocusOwner = KeyboardFocusManager
2042: .getCurrentKeyboardFocusManager()
2043: .getPermanentFocusOwner();
2044: boolean focusOwned = false;
2045: focusOwned = ((focusOwner != null) && SwingUtilities
2046: .isDescendingFrom(focusOwner, cont));
2047: if (!focusOwned) {
2048: focusOwned = ((permFocusOwner != null) && SwingUtilities
2049: .isDescendingFrom(permFocusOwner, cont));
2050: }
2051: return focusOwned;
2052: }
2053:
2054: //<syd_0002>
2055:
2056: public static boolean componentIsPermanentFocusOwner(Component comp) {
2057: return ((comp != null) && (KeyboardFocusManager
2058: .getCurrentKeyboardFocusManager()
2059: .getPermanentFocusOwner() == comp));
2060: }
2061:
2062: //</syd_0002>
2063:
2064: public static void installColorsAndFont(Component c,
2065: Color background, Color foreground, Font font) {
2066: installFont(c, font);
2067: installColors(c, background, foreground);
2068: }
2069:
2070: public static void installFont(Component c, Font font) {
2071: Font f = c.getFont();
2072: if (f == null || f instanceof UIResource) {
2073: c.setFont(font);
2074: }
2075: }
2076:
2077: public static void installColors(Component c, Color background,
2078: Color foreground) {
2079: Color bg = c.getBackground();
2080: if (background != null
2081: && (bg == null || bg instanceof UIResource)) {
2082: c.setBackground(background);
2083: }
2084:
2085: Color fg = c.getForeground();
2086: if (foreground != null
2087: && (fg == null || fg instanceof UIResource)) {
2088: c.setForeground(foreground);
2089: }
2090: }
2091:
2092: public static void installBorder(JComponent c, Border defaultBorder) {
2093: Border border = c.getBorder();
2094: if (border == null || border instanceof UIResource) {
2095: c.setBorder(defaultBorder);
2096: }
2097: }
2098:
2099: public static void fillNormalGradient(Graphics2D g2d, Shape s,
2100: Color startColor, Color endColor, boolean isVertical) {
2101: Rectangle rect = s.getBounds();
2102: GradientPaint paint = null;
2103: if (isVertical) {
2104: paint = new GradientPaint(rect.x, rect.y, startColor,
2105: rect.x, rect.height + rect.y, endColor, true); // turn cyclic to true will be faster
2106: } else {
2107: paint = new GradientPaint(rect.x, rect.y, startColor,
2108: rect.width + rect.x, rect.y, endColor, true); // turn cyclic to true will be faster
2109: }
2110: Paint old = g2d.getPaint();
2111: g2d.setPaint(paint);
2112: g2d.fill(s);
2113: g2d.setPaint(old);
2114: }
2115:
2116: /**
2117: * Fills a gradient using the startColor and endColor specified. This is a fast version of fill gradient
2118: * which will not only leverage hardware acceleration, but also cache GradientPaint and reuse it.
2119: * <p/>
2120: * We also leave an option to use the normal GradientPaint to paint the gradient. To do so, just set a system property
2121: * "normalGradientPaint" to "false".
2122: *
2123: * @param g2d
2124: * @param s
2125: * @param startColor
2126: * @param endColor
2127: * @param isVertical
2128: */
2129: public static void fillGradient(Graphics2D g2d, Shape s,
2130: Color startColor, Color endColor, boolean isVertical) {
2131: if ("true".equals(SecurityUtils.getProperty(
2132: "normalGradientPaint", "false"))) {
2133: fillNormalGradient(g2d, s, startColor, endColor, isVertical);
2134: } else {
2135: FastGradientPainter.drawGradient(g2d, s, startColor,
2136: endColor, isVertical);
2137: }
2138: }
2139:
2140: /**
2141: * Gets the top modal dialog of current window.
2142: *
2143: * @param w
2144: * @return the top modal dialog of current window.
2145: */
2146: public static Window getTopModalDialog(Window w) {
2147: Window[] ws = w.getOwnedWindows();
2148: for (int i = 0; i < ws.length; i++) {
2149: if (ws[i].isVisible() && ws[i] instanceof Dialog
2150: && ((Dialog) ws[i]).isModal()) {
2151: return (getTopModalDialog(ws[i]));
2152: }
2153: }
2154: return w;
2155: }
2156:
2157: /**
2158: * For internal usage only.
2159: */
2160: public static void traceFocus() {
2161: PropertyChangeListener listener = new PropertyChangeListener() {
2162: public void propertyChange(PropertyChangeEvent evt) {
2163: String oldName = evt.getOldValue() == null ? "null"
2164: : evt.getOldValue().getClass().getName();
2165: System.out.println(evt.getPropertyName()
2166: + ": "
2167: + oldName
2168: + " ==> "
2169: + (evt.getNewValue() == null ? "null" : evt
2170: .getNewValue().getClass().getName()));
2171: }
2172: };
2173: DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager()
2174: .addPropertyChangeListener("focusOwner", listener);
2175: DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager()
2176: .addPropertyChangeListener("permanentFocusOwner",
2177: listener);
2178: DefaultKeyboardFocusManager.getCurrentKeyboardFocusManager()
2179: .addPropertyChangeListener("activeWindow", listener);
2180: }
2181:
2182: /**
2183: * For internal usage only.
2184: */
2185: public static JPanel createTableModelModifier(
2186: final DefaultTableModel tableModel) {
2187: JPanel tableModelPanel = new JPanel(new BorderLayout(6, 6));
2188: final JTable table = new JTable(tableModel);
2189: tableModelPanel.add(new JScrollPane(table));
2190: ButtonPanel buttonPanel = new ButtonPanel();
2191:
2192: JButton insert = new JButton("Insert");
2193: insert.addActionListener(new AbstractAction() {
2194: public void actionPerformed(ActionEvent e) {
2195: Vector rowData = tableModel.getDataVector();
2196: int index = table.getSelectedRow();
2197: if (index != -1) {
2198: Vector v = (Vector) rowData.get(index);
2199: Vector clone = new Vector();
2200: for (int i = 0; i < v.size(); i++) {
2201: if (i == 0) {
2202: clone.add((int) (Math.random() * 10));
2203: } else {
2204: clone.add("" + v.get(i));
2205: }
2206: }
2207: tableModel.insertRow(index, clone);
2208: }
2209: }
2210: });
2211:
2212: JButton delete = new JButton("Delete");
2213: delete.addActionListener(new AbstractAction() {
2214: public void actionPerformed(ActionEvent e) {
2215: int[] rows = table.getSelectedRows();
2216: for (int i = rows.length - 1; i >= 0; i--) {
2217: int row = rows[i];
2218: tableModel.removeRow(row);
2219: }
2220: }
2221: });
2222:
2223: JButton clear = new JButton("Clear");
2224: clear.addActionListener(new AbstractAction() {
2225: public void actionPerformed(ActionEvent e) {
2226: for (int i = 0; i < tableModel.getRowCount(); i++) {
2227: tableModel.removeRow(0);
2228: }
2229: }
2230: });
2231:
2232: buttonPanel.add(insert);
2233: buttonPanel.add(delete);
2234: buttonPanel.add(clear);
2235: tableModelPanel.add(buttonPanel, BorderLayout.AFTER_LAST_LINE);
2236: return tableModelPanel;
2237: }
2238:
2239: /**
2240: * Find some subcomponent of the specified container that will accept focus.
2241: * <p/>
2242: * Note that this doesn't do something smart like trying to walk the
2243: * hierarchy horizontally at each level so that the focused subcomponent is
2244: * as high as possible. Rather, it drills vertically. It's just a safety
2245: * valve so that focus can be requested somewhere rather than being lost.
2246: *
2247: * @param container
2248: * @return a focusable subcomponent
2249: */
2250: public static Component findSomethingFocusable(Container container) {
2251: if (passesFocusabilityTest(container)) {
2252: container.requestFocusInWindow();
2253: return container;
2254: }
2255: Component[] comps;
2256: Component comp;
2257: comps = container.getComponents();
2258: for (int i = 0; i < comps.length; i++) {
2259: if (passesFocusabilityTest(comps[i])) {
2260: container.requestFocusInWindow();
2261: return container;
2262: } else if (comps[i] instanceof Container) {
2263: comp = findSomethingFocusable((Container) (comps[i]));
2264: if (comp != null) {
2265: return comp;
2266: }
2267: }
2268: }
2269: return null;
2270: }
2271:
2272: /**
2273: * There are four standard tests which determine if Swing will be able to
2274: * request focus for a component. Test them.
2275: *
2276: * @param comp
2277: * @return does the specified component pass the four focusability tests
2278: */
2279: public static boolean passesFocusabilityTest(Component comp) {
2280: return ((comp != null) && comp.isEnabled()
2281: && comp.isDisplayable() && comp.isVisible() && comp
2282: .isFocusable());
2283: }
2284:
2285: /**
2286: * Ignore the exception. This method does nothing. However it's a
2287: * good practice to use this method so that we can easily find
2288: * out the place that ignoring exception. In development phase,
2289: * we can log a message in this method so that we can verify if it
2290: * makes sense to ignore.
2291: *
2292: * @param e
2293: */
2294: public static void ignoreException(Exception e) {
2295: }
2296:
2297: /**
2298: * Prints out the message of the exception.
2299: *
2300: * @param e
2301: */
2302: public static void printException(Exception e) {
2303: System.err.println(e.getLocalizedMessage());
2304: }
2305:
2306: /**
2307: * Throws the exception. If the exception is RuntimeException, just throw it. Otherwise,
2308: * wrap it in RuntimeException and throw it.
2309: *
2310: * @param e
2311: */
2312: public static void throwException(Exception e) {
2313: if (e instanceof RuntimeException) {
2314: throw (RuntimeException) e;
2315: } else {
2316: throw new RuntimeException(e);
2317: }
2318: }
2319:
2320: /**
2321: * Throws the InvocationTargetException. Usually InvocationTargetException
2322: * has a nested exception as target exception. If the target exception is a RuntimeException
2323: * or Error, we will throw it. Otherwise, we will wrap it inside RuntimeException and throw it.
2324: *
2325: * @param e
2326: */
2327: public static void throwInvocationTargetException(
2328: InvocationTargetException e) {
2329: // in most cases, target exception will be RuntimeException
2330: // but to be on saferside(it may be Error) we explicitly check it
2331: if (e.getTargetException() instanceof RuntimeException) {
2332: throw (RuntimeException) e.getTargetException();
2333: } else if (e.getTargetException() instanceof Error) {
2334: throw (Error) e.getTargetException();
2335: } else {
2336: throw new RuntimeException(e.getTargetException());
2337: }
2338: }
2339:
2340: public static int findDisplayedMnemonicIndex(String text,
2341: int mnemonic) {
2342: if (text == null || mnemonic == '\0') {
2343: return -1;
2344: }
2345:
2346: char uc = Character.toUpperCase((char) mnemonic);
2347: char lc = Character.toLowerCase((char) mnemonic);
2348:
2349: int uci = text.indexOf(uc);
2350: int lci = text.indexOf(lc);
2351:
2352: if (uci == -1) {
2353: return lci;
2354: } else if (lci == -1) {
2355: return uci;
2356: } else {
2357: return (lci < uci) ? lci : uci;
2358: }
2359: }
2360:
2361: /**
2362: * Gets the first occurence of the component with specified type in the container. It used deep-first searching
2363: * to find it.
2364: *
2365: * @param c
2366: * @param container
2367: * @return the first occurence of the component with specified type in the container. Null if nothing is found.
2368: */
2369: public static Component getDescendantOfClass(Class c,
2370: Container container) {
2371: if (container == null || c == null)
2372: return null;
2373:
2374: Component[] components = container.getComponents();
2375:
2376: for (int i = 0; i < components.length; i++) {
2377: Component component = components[i];
2378: if (c.isInstance(component)) {
2379: return component;
2380: }
2381: if (component instanceof Container) {
2382: Component found = getDescendantOfClass(c,
2383: (Container) component);
2384: if (found != null) {
2385: return found;
2386: }
2387: }
2388: }
2389: return null;
2390: }
2391:
2392: public static float getDefaultFontSize() {
2393: // read the font size from system property.
2394: String fontSize = SecurityUtils.getProperty("jide.fontSize",
2395: null);
2396: float defaultFontSize = -1f;
2397: try {
2398: if (fontSize != null) {
2399: defaultFontSize = Float.parseFloat(fontSize);
2400: }
2401: } catch (NumberFormatException e) {
2402: }
2403:
2404: return defaultFontSize;
2405: }
2406:
2407: public static Object getMenuFont(Toolkit toolkit, UIDefaults table) {
2408: Object menuFont = null;
2409: // read the font size from system property.
2410: float defaultFontSize = getDefaultFontSize();
2411:
2412: if (JideSwingUtilities.shouldUseSystemFont()) {
2413: if (defaultFontSize == -1/* || SystemInfo.isCJKLocale()*/) {
2414: menuFont = table.getFont("ToolBar.font");
2415: } else {
2416: menuFont = new WindowsDesktopProperty("win.menu.font",
2417: table.getFont("ToolBar.font"), toolkit,
2418: defaultFontSize);
2419: }
2420: } else {
2421: menuFont = SecurityUtils
2422: .createFontUIResource(
2423: "Tahoma",
2424: Font.PLAIN,
2425: defaultFontSize != -1f ? (int) defaultFontSize
2426: : 11);
2427: }
2428:
2429: if (menuFont == null) {
2430: return getControlFont(toolkit, table);
2431: } else {
2432: return menuFont;
2433: }
2434: }
2435:
2436: public static Object getControlFont(Toolkit toolkit,
2437: UIDefaults table) {
2438: Object controlFont = null;
2439: // read the font size from system property.
2440: float defaultFontSize = getDefaultFontSize();
2441:
2442: if (JideSwingUtilities.shouldUseSystemFont()) {
2443: Font font = table.getFont("Label.font");
2444: if (font == null) {
2445: font = new Font("Tahoma", Font.PLAIN, 12); // use default font
2446: }
2447: if (defaultFontSize == -1/* || SystemInfo.isCJKLocale()*/) {
2448: controlFont = font;
2449: } else {
2450: controlFont = new WindowsDesktopProperty(
2451: "win.defaultGUI.font", font, toolkit,
2452: defaultFontSize);
2453: }
2454: } else {
2455: controlFont = SecurityUtils
2456: .createFontUIResource(
2457: "Tahoma",
2458: Font.PLAIN,
2459: defaultFontSize != -1f ? (int) defaultFontSize
2460: : 11);
2461: }
2462:
2463: return controlFont;
2464: }
2465:
2466: public static Object getBoldFont(Toolkit toolkit, UIDefaults table) {
2467: if (SystemInfo.isCJKLocale()) {
2468: return getControlFont(toolkit, table);
2469: } else {
2470: Object boldFont = null;
2471: // read the font size from system property.
2472: float defaultFontSize = getDefaultFontSize();
2473:
2474: if (JideSwingUtilities.shouldUseSystemFont()) {
2475: Font font = table.getFont("Label.font");
2476: if (font == null) {
2477: font = new Font("Tahoma", Font.PLAIN, 12); // use default font
2478: }
2479: if (defaultFontSize == -1) {
2480: boldFont = new FontUIResource(font
2481: .deriveFont(Font.BOLD));
2482: } else {
2483: boldFont = new WindowsDesktopProperty(
2484: "win.defaultGUI.font", font, toolkit,
2485: defaultFontSize, Font.BOLD);
2486: }
2487: } else {
2488: boldFont = SecurityUtils.createFontUIResource("Tahoma",
2489: Font.BOLD,
2490: defaultFontSize != -1f ? (int) defaultFontSize
2491: : 11);
2492: }
2493: return boldFont;
2494: }
2495: }
2496:
2497: public static void drawShadow(Graphics g, Component c, int x,
2498: int y, int w, int h) {
2499: ShadowFactory factory = new ShadowFactory(6, 0.7f, Color.GRAY);
2500: BufferedImage temp = new BufferedImage(w, h,
2501: BufferedImage.TYPE_INT_ARGB);
2502: Graphics2D g2 = temp.createGraphics();
2503: g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
2504: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
2505: g2.setColor(Color.BLACK);
2506: g2.fillRect(0, 0, temp.getWidth(), temp.getHeight());
2507: g2.dispose();
2508: BufferedImage shadow = factory.createShadow(temp);
2509: g.drawImage(shadow, x, y, c);
2510: }
2511:
2512: static {
2513: Font.getFont("defaultFont");
2514: Font.getFont("emphasizedFont");
2515: }
2516:
2517: /**
2518: * Draws a border based on an image. The image can be divided into nine different areas. Each area size is determined
2519: * by the insets.
2520: */
2521: public static void drawImageBorder(Graphics g, ImageIcon img,
2522: Rectangle rect, Insets ins, boolean drawCenter) {
2523: int left = ins.left;
2524: int right = ins.right;
2525: int top = ins.top;
2526: int bottom = ins.bottom;
2527: int x = rect.x;
2528: int y = rect.y;
2529: int w = rect.width;
2530: int h = rect.height;
2531:
2532: // top
2533: g.drawImage(img.getImage(), x, y, x + left, y + top, 0, 0,
2534: left, top, null);
2535: g
2536: .drawImage(img.getImage(), x + left, y, x + w - right,
2537: y + top, left, 0, img.getIconWidth() - right,
2538: top, null);
2539: g.drawImage(img.getImage(), x + w - right, y, x + w, y + top,
2540: img.getIconWidth() - right, 0, img.getIconWidth(), top,
2541: null);
2542:
2543: // middle
2544: g.drawImage(img.getImage(), x, y + top, x + left, y + h
2545: - bottom, 0, top, left, img.getIconHeight() - bottom,
2546: null);
2547: g.drawImage(img.getImage(), x + left, y + top, x + w - right, y
2548: + h - bottom, left, top, img.getIconWidth() - right,
2549: img.getIconHeight() - bottom, null);
2550: g.drawImage(img.getImage(), x + w - right, y + top, x + w, y
2551: + h - bottom, img.getIconWidth() - right, top, img
2552: .getIconWidth(), img.getIconHeight() - bottom, null);
2553:
2554: // bottom
2555: g.drawImage(img.getImage(), x, y + h - bottom, x + left, y + h,
2556: 0, img.getIconHeight() - bottom, left, img
2557: .getIconHeight(), null);
2558: g.drawImage(img.getImage(), x + left, y + h - bottom, x + w
2559: - right, y + h, left, img.getIconHeight() - bottom, img
2560: .getIconWidth()
2561: - right, img.getIconHeight(), null);
2562: g
2563: .drawImage(img.getImage(), x + w - right, y + h
2564: - bottom, x + w, y + h, img.getIconWidth()
2565: - right, img.getIconHeight() - bottom, img
2566: .getIconWidth(), img.getIconHeight(), null);
2567:
2568: if (drawCenter) {
2569: g.drawImage(img.getImage(), x + left, y + top, x + w
2570: - right, y + h - bottom, left, top, img
2571: .getIconWidth()
2572: - right, img.getIconHeight() - bottom, null);
2573: }
2574: }
2575:
2576: /**
2577: * Copied from BasicLookAndFeel as the method is package local.
2578: *
2579: * @param component
2580: * @return if request focus is success or not.
2581: */
2582: public static boolean compositeRequestFocus(Component component) {
2583: if (component instanceof Container) {
2584: Container container = (Container) component;
2585: if (container.isFocusCycleRoot()) {
2586: FocusTraversalPolicy policy = container
2587: .getFocusTraversalPolicy();
2588: Component comp = policy.getDefaultComponent(container);
2589: if (comp != null) {
2590: comp.requestFocus();
2591: return true;
2592: }
2593: }
2594: Container rootAncestor = container
2595: .getFocusCycleRootAncestor();
2596: if (rootAncestor != null) {
2597: FocusTraversalPolicy policy = rootAncestor
2598: .getFocusTraversalPolicy();
2599: Component comp = policy.getComponentAfter(rootAncestor,
2600: container);
2601:
2602: if (comp != null
2603: && SwingUtilities.isDescendingFrom(comp,
2604: container)) {
2605: comp.requestFocus();
2606: return true;
2607: }
2608: }
2609: }
2610: if (component.isFocusable()) {
2611: component.requestFocus();
2612: return true;
2613: }
2614: return false;
2615: }
2616:
2617: public static boolean isAncestorOfFocusOwner(Component component) {
2618: boolean hasFocus = false;
2619: Component focusOwner = KeyboardFocusManager
2620: .getCurrentKeyboardFocusManager().getFocusOwner();
2621: if (component == focusOwner
2622: || (component instanceof Container && ((Container) component)
2623: .isAncestorOf(focusOwner))) {
2624: hasFocus = true;
2625: }
2626: return hasFocus;
2627: }
2628:
2629: /**
2630: * Gets the top level Window of the component.
2631: *
2632: * @param component
2633: * @return the top level Frame. Null if we didn't find an ancestor which is instance of Frame.
2634: * @deprecated Please use {@link #getWindowForComponent(java.awt.Component)} instead. getWindowForComponent
2635: * method is the same as the same name method in JOptionPane. We have to copy it here because it's not public.
2636: * getWindowForComponent is better than this method is because it will give you a shared root frame even when parentComponent is null.
2637: * You can refer to {@link javax.swing.JOptionPane#getRootFrame()} for more information.
2638: */
2639: public static Window getWindow(Component component) {
2640: if (component == null)
2641: return null;
2642:
2643: if (component instanceof Window)
2644: return (Window) component;
2645:
2646: // Find framel
2647: Container p = component.getParent();
2648: while (p != null) {
2649: if (p instanceof Window) {
2650: return (Window) p;
2651: }
2652: p = p.getParent();
2653: }
2654: return null;
2655: }
2656:
2657: public static Window getWindowForComponent(Component parentComponent)
2658: throws HeadlessException {
2659: if (parentComponent == null)
2660: return JOptionPane.getRootFrame();
2661: if (parentComponent instanceof Frame
2662: || parentComponent instanceof Dialog)
2663: return (Window) parentComponent;
2664: return getWindowForComponent(parentComponent.getParent());
2665: }
2666:
2667: /**
2668: * Checks if the key listener is already registerd on the component.
2669: *
2670: * @param component the component
2671: * @param l the listener
2672: * @return true if already registered. Otherwise false.
2673: */
2674: public static boolean isKeyListenerRegistered(Component component,
2675: KeyListener l) {
2676: KeyListener[] listeners = component.getKeyListeners();
2677: for (KeyListener listener : listeners) {
2678: if (listener == l) {
2679: return true;
2680: }
2681: }
2682: return false;
2683: }
2684:
2685: /**
2686: * Inserts the key listener at the particular index in the listeners' chain.
2687: *
2688: * @param component
2689: * @param l
2690: * @param index
2691: */
2692: public static void insertKeyListener(Component component,
2693: KeyListener l, int index) {
2694: KeyListener[] listeners = component.getKeyListeners();
2695: for (KeyListener listener : listeners) {
2696: component.removeKeyListener(listener);
2697: }
2698: for (int i = 0; i < listeners.length; i++) {
2699: KeyListener listener = listeners[i];
2700: if (index == i) {
2701: component.addKeyListener(l);
2702: }
2703: component.addKeyListener(listener);
2704: }
2705: // inex is too large, add to the end.
2706: if (index > listeners.length - 1) {
2707: component.addKeyListener(l);
2708: }
2709: }
2710:
2711: /**
2712: * Checks if the mouse listener is already registerd on the component.
2713: *
2714: * @param component the component
2715: * @param l the listener
2716: * @return true if already registered. Otherwise false.
2717: */
2718: public static boolean isMouseListenerRegistered(
2719: Component component, MouseListener l) {
2720: MouseListener[] listeners = component.getMouseListeners();
2721: for (MouseListener listener : listeners) {
2722: if (listener == l) {
2723: return true;
2724: }
2725: }
2726: return false;
2727: }
2728:
2729: /**
2730: * Inserts the mouse listener at the particular index in the listeners' chain.
2731: *
2732: * @param component
2733: * @param l
2734: * @param index
2735: */
2736: public static void insertMouseListener(Component component,
2737: MouseListener l, int index) {
2738: MouseListener[] listeners = component.getMouseListeners();
2739: for (MouseListener listener : listeners) {
2740: component.removeMouseListener(listener);
2741: }
2742: for (int i = 0; i < listeners.length; i++) {
2743: MouseListener listener = listeners[i];
2744: if (index == i) {
2745: component.addMouseListener(l);
2746: }
2747: component.addMouseListener(listener);
2748: }
2749: // inex is too large, add to the end.
2750: if (index > listeners.length - 1) {
2751: component.addMouseListener(l);
2752: }
2753: }
2754:
2755: /**
2756: * Checks if the mouse motion listener is already registerd on the component.
2757: *
2758: * @param component the component
2759: * @param l the listener
2760: * @return true if already registered. Otherwise false.
2761: */
2762: public static boolean isMouseMotionListenerRegistered(
2763: Component component, MouseMotionListener l) {
2764: MouseMotionListener[] listeners = component
2765: .getMouseMotionListeners();
2766: for (MouseMotionListener listener : listeners) {
2767: if (listener == l) {
2768: return true;
2769: }
2770: }
2771: return false;
2772: }
2773:
2774: /**
2775: * Inserts the mouse motion listener at the particular index in the listeners' chain.
2776: *
2777: * @param component
2778: * @param l
2779: * @param index
2780: */
2781: public static void insertMouseMotionListener(Component component,
2782: MouseMotionListener l, int index) {
2783: MouseMotionListener[] listeners = component
2784: .getMouseMotionListeners();
2785: for (MouseMotionListener listener : listeners) {
2786: component.removeMouseMotionListener(listener);
2787: }
2788: for (int i = 0; i < listeners.length; i++) {
2789: MouseMotionListener listener = listeners[i];
2790: if (index == i) {
2791: component.addMouseMotionListener(l);
2792: }
2793: component.addMouseMotionListener(listener);
2794: }
2795: // inex is too large, add to the end.
2796: if (index > listeners.length - 1) {
2797: component.addMouseMotionListener(l);
2798: }
2799: }
2800:
2801: /**
2802: * Gets the scroll pane around the component.
2803: *
2804: * @param innerComponent
2805: * @return the scroll pane. Null if the component is not in any JScrollPane.
2806: */
2807: public static Component getScrollPane(Component innerComponent) {
2808: Component component = innerComponent;
2809: if (component.getParent() != null
2810: && component.getParent().getParent() != null
2811: && component.getParent().getParent() instanceof JScrollPane) {
2812: component = (JComponent) component.getParent().getParent();
2813: return component;
2814: } else {
2815: return null;
2816: }
2817: }
2818:
2819: /**
2820: * Checks if the listener is always registered to the EventListenerList to avoid duplicated registration of the same listener
2821: *
2822: * @param list the EventListenerList to register the listener.
2823: * @param t the type of the EventListener.
2824: * @param l the listener.
2825: * @return true if already registered. Otherwise false.
2826: */
2827: public static boolean isListenerRegistered(EventListenerList list,
2828: Class t, EventListener l) {
2829: Object[] objects = list.getListenerList();
2830: return isListenerRegistered(objects, t, l);
2831: }
2832:
2833: /**
2834: * Checks if the listener is always registered to the Component to avoid duplicated registration of the same listener
2835: *
2836: * @param component the component that you want to register the listener.
2837: * @param t the type of the EventListener.
2838: * @param l the listener.
2839: * @return true if already registered. Otherwise false.
2840: */
2841: public static boolean isListenerRegistered(Component component,
2842: Class t, EventListener l) {
2843: Object[] objects = component.getListeners(t);
2844: return isListenerRegistered(objects, t, l);
2845: }
2846:
2847: private static boolean isListenerRegistered(Object[] objects,
2848: Class t, EventListener l) {
2849: for (int i = 0; i < objects.length; i++) {
2850: Object listener = objects[i];
2851: if (t.isAssignableFrom(listener.getClass())
2852: && listener == l) {
2853: return true;
2854: }
2855: }
2856: return false;
2857: }
2858:
2859: /**
2860: * Gets the first child of the component that is the specified type.
2861: *
2862: * @param clazz
2863: * @param c
2864: * @return the first child of the component that is the specified type.
2865: */
2866: public static Component getFirstChildOf(final Class clazz,
2867: Component c) {
2868: return getRecursively(c, new GetHandler() {
2869: public boolean condition(Component c) {
2870: return clazz.isAssignableFrom(c.getClass());
2871: }
2872:
2873: public Component action(Component c) {
2874: return c;
2875: }
2876: });
2877: }
2878:
2879: public static Vector convertDefaultComboBoxModelToVector(
2880: DefaultComboBoxModel model) {
2881: Vector v = new Vector();
2882: for (int i = 0; i < model.getSize(); i++) {
2883: v.add(model.getElementAt(i));
2884: }
2885: return v;
2886:
2887: }
2888:
2889: /**
2890: * To make sure the row is visible. If the table's horizontal scroll bar is visible, the method will
2891: * not change the horizontal scroll bar's position.
2892: *
2893: * @param table
2894: * @param row
2895: */
2896: public static void ensureRowVisible(JTable table, int row) {
2897: Rectangle r = table.getVisibleRect();
2898: // Hack! make above and below visible if necessary
2899: // TODO: how to center it or make it the first?
2900: Rectangle rMid = table.getCellRect(row, 0, true);
2901: Rectangle rBefore = null, rAfter = null;
2902: if (row < table.getModel().getRowCount() - 1)
2903: rAfter = table.getCellRect(row + 1, 0, true);
2904: if (row > 0)
2905: rBefore = table.getCellRect(row - 1, 0, true);
2906:
2907: int yLow = (int) rMid.getMinY();
2908: int yHi = (int) rMid.getMaxY();
2909: int xLow = r.x;
2910: int xHi = r.x + r.width;
2911:
2912: if (rBefore != null)
2913: yLow = (int) rBefore.getMinY();
2914:
2915: if (rAfter != null) {
2916: yHi = (int) rAfter.getMaxY();
2917: }
2918:
2919: Rectangle rScrollTo = new Rectangle(xLow, yLow, xHi - xLow, yHi
2920: - yLow);
2921: if (!r.contains(rScrollTo) && rScrollTo.height != 0) {
2922: table.scrollRectToVisible(rScrollTo);
2923: }
2924: }
2925:
2926: public static void retargetMouseEvent(int id, MouseEvent e,
2927: Component target) {
2928: if (target == null || target == e.getSource()) {
2929: return;
2930: }
2931: if (e.isConsumed()) {
2932: return;
2933: }
2934:
2935: // fix for bug #4202966 -- hania
2936: // When retargetting a mouse event, we need to translate
2937: // the event's coordinates relative to the target.
2938:
2939: Point p = SwingUtilities.convertPoint(
2940: (Component) e.getSource(), e.getX(), e.getY(), target);
2941: MouseEvent retargeted = new MouseEvent(target, id, e.getWhen(),
2942: e.getModifiersEx() | e.getModifiers(), p.x, p.y, e
2943: .getClickCount(), e.isPopupTrigger());
2944: target.dispatchEvent(retargeted);
2945: }
2946:
2947: /**
2948: * If c is a JRootPane descendant return its outermost JRootPane ancestor.
2949: * If c is a RootPaneContainer then return its JRootPane.
2950: *
2951: * @return the outermost JRootPane for Component c or {@code null}.
2952: */
2953: public static JRootPane getOutermostRootPane(Component c) {
2954: if (c instanceof RootPaneContainer && c.getParent() == null) {
2955: return ((RootPaneContainer) c).getRootPane();
2956: }
2957: JRootPane lastRootPane = null;
2958: for (; c != null; c = SwingUtilities.getRootPane(c)) {
2959: if (c instanceof JRootPane) {
2960: lastRootPane = (JRootPane) c;
2961: if (c.getParent().getParent() == null) {
2962: return lastRootPane;
2963: }
2964: c = c.getParent();
2965: }
2966: }
2967: return null;
2968: }
2969: }
|