Frames | No Frames |
1: /* BasicLabelUI.java 2: Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing.plaf.basic; 39: 40: import java.awt.Color; 41: import java.awt.Component; 42: import java.awt.Dimension; 43: import java.awt.FontMetrics; 44: import java.awt.Graphics; 45: import java.awt.Insets; 46: import java.awt.Rectangle; 47: import java.awt.event.ActionEvent; 48: import java.awt.event.KeyEvent; 49: import java.beans.PropertyChangeEvent; 50: import java.beans.PropertyChangeListener; 51: 52: import javax.swing.AbstractAction; 53: import javax.swing.ActionMap; 54: import javax.swing.Icon; 55: import javax.swing.InputMap; 56: import javax.swing.JComponent; 57: import javax.swing.JLabel; 58: import javax.swing.KeyStroke; 59: import javax.swing.LookAndFeel; 60: import javax.swing.SwingUtilities; 61: import javax.swing.plaf.ComponentUI; 62: import javax.swing.plaf.LabelUI; 63: import javax.swing.text.View; 64: 65: /** 66: * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI 67: * object is used to paint all JLabels that utilize the Basic Look and Feel. 68: */ 69: public class BasicLabelUI extends LabelUI implements PropertyChangeListener 70: { 71: /** The labelUI that is shared by all labels. */ 72: protected static BasicLabelUI labelUI; 73: 74: /** 75: * These fields hold the rectangles for the whole label, 76: * the icon and the text. 77: */ 78: private Rectangle vr; 79: private Rectangle ir; 80: private Rectangle tr; 81: 82: /** 83: * Creates a new BasicLabelUI object. 84: */ 85: public BasicLabelUI() 86: { 87: super(); 88: vr = new Rectangle(); 89: ir = new Rectangle(); 90: tr = new Rectangle(); 91: } 92: 93: /** 94: * Creates and returns a UI for the label. Since one UI is shared by all 95: * labels, this means creating only if necessary and returning the shared 96: * UI. 97: * 98: * @param c The {@link JComponent} that a UI is being created for. 99: * 100: * @return A label UI for the Basic Look and Feel. 101: */ 102: public static ComponentUI createUI(JComponent c) 103: { 104: if (labelUI == null) 105: labelUI = new BasicLabelUI(); 106: return labelUI; 107: } 108: 109: /** 110: * Returns the preferred size of this component as calculated by the 111: * {@link #layoutCL(JLabel, FontMetrics, String, Icon, Rectangle, Rectangle, 112: * Rectangle)} method. 113: * 114: * @param c This {@link JComponent} to get a preferred size for. 115: * 116: * @return The preferred size. 117: */ 118: public Dimension getPreferredSize(JComponent c) 119: { 120: JLabel lab = (JLabel) c; 121: Insets insets = lab.getInsets(); 122: FontMetrics fm = lab.getFontMetrics(lab.getFont()); 123: layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); 124: Rectangle cr = SwingUtilities.computeUnion(tr.x, tr.y, tr.width, tr.height, 125: ir); 126: return new Dimension(insets.left + cr.width + insets.right, insets.top 127: + cr.height + insets.bottom); 128: 129: } 130: 131: /** 132: * This method returns the minimum size of the {@link JComponent} given. If 133: * this method returns null, then it is up to the Layout Manager to give 134: * this component a minimum size. 135: * 136: * @param c The {@link JComponent} to get a minimum size for. 137: * 138: * @return The minimum size. 139: */ 140: public Dimension getMinimumSize(JComponent c) 141: { 142: return getPreferredSize(c); 143: } 144: 145: /** 146: * This method returns the maximum size of the {@link JComponent} given. If 147: * this method returns null, then it is up to the Layout Manager to give 148: * this component a maximum size. 149: * 150: * @param c The {@link JComponent} to get a maximum size for. 151: * 152: * @return The maximum size. 153: */ 154: public Dimension getMaximumSize(JComponent c) 155: { 156: return getPreferredSize(c); 157: } 158: 159: /** 160: * The method that paints the label according to its current state. 161: * 162: * @param g The {@link Graphics} object to paint with. 163: * @param c The {@link JComponent} to paint. 164: */ 165: public void paint(Graphics g, JComponent c) 166: { 167: JLabel b = (JLabel) c; 168: FontMetrics fm = g.getFontMetrics(); 169: vr = SwingUtilities.calculateInnerArea(c, vr); 170: 171: if (vr.width < 0) 172: vr.width = 0; 173: if (vr.height < 0) 174: vr.height = 0; 175: 176: Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); 177: 178: String text = layoutCL(b, fm, b.getText(), icon, vr, ir, tr); 179: 180: if (icon != null) 181: icon.paintIcon(b, g, ir.x, ir.y); 182: 183: Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey); 184: if (htmlRenderer == null) 185: { 186: if (text != null && !text.equals("")) 187: { 188: if (b.isEnabled()) 189: paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); 190: else 191: paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); 192: } 193: } 194: else 195: { 196: ((View) htmlRenderer).paint(g, tr); 197: } 198: } 199: 200: /** 201: * This method is simply calls SwingUtilities's layoutCompoundLabel. 202: * 203: * @param label The label to lay out. 204: * @param fontMetrics The FontMetrics for the font used. 205: * @param text The text to paint. 206: * @param icon The icon to draw. 207: * @param viewR The entire viewable rectangle. 208: * @param iconR The icon bounds rectangle. 209: * @param textR The text bounds rectangle. 210: * 211: * @return A possibly clipped version of the text. 212: */ 213: protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, 214: Icon icon, Rectangle viewR, Rectangle iconR, Rectangle textR) 215: { 216: return SwingUtilities.layoutCompoundLabel(label, fontMetrics, text, icon, 217: label.getVerticalAlignment(), label.getHorizontalAlignment(), label 218: .getVerticalTextPosition(), label.getHorizontalTextPosition(), 219: viewR, iconR, textR, label.getIconTextGap()); 220: } 221: 222: /** 223: * Paints the text if the label is disabled. By default, this paints the 224: * clipped text returned by layoutCompoundLabel using the 225: * background.brighter() color. It also paints the same text using the 226: * background.darker() color one pixel to the right and one pixel down. 227: * 228: * @param l The {@link JLabel} being painted. 229: * @param g The {@link Graphics} object to paint with. 230: * @param s The String to paint. 231: * @param textX The x coordinate of the start of the baseline. 232: * @param textY The y coordinate of the start of the baseline. 233: */ 234: protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, 235: int textY) 236: { 237: Color saved_color = g.getColor(); 238: 239: g.setColor(l.getBackground().brighter()); 240: 241: int mnemIndex = l.getDisplayedMnemonicIndex(); 242: 243: if (mnemIndex != -1) 244: BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, 245: textY); 246: else 247: g.drawString(s, textX, textY); 248: 249: g.setColor(l.getBackground().darker()); 250: if (mnemIndex != -1) 251: BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX + 1, 252: textY + 1); 253: else 254: g.drawString(s, textX + 1, textY + 1); 255: 256: g.setColor(saved_color); 257: } 258: 259: /** 260: * Paints the text if the label is enabled. The text is painted using the 261: * foreground color. 262: * 263: * @param l The {@link JLabel} being painted. 264: * @param g The {@link Graphics} object to paint with. 265: * @param s The String to paint. 266: * @param textX The x coordinate of the start of the baseline. 267: * @param textY The y coordinate of the start of the baseline. 268: */ 269: protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, 270: int textY) 271: { 272: Color saved_color = g.getColor(); 273: g.setColor(l.getForeground()); 274: 275: int mnemIndex = l.getDisplayedMnemonicIndex(); 276: 277: if (mnemIndex != -1) 278: BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, 279: textY); 280: else 281: g.drawString(s, textX, textY); 282: 283: g.setColor(saved_color); 284: } 285: 286: /** 287: * This method installs the UI for the given {@link JComponent}. This 288: * method will install the component, defaults, listeners, and keyboard 289: * actions. 290: * 291: * @param c The {@link JComponent} that this UI is being installed on. 292: */ 293: public void installUI(JComponent c) 294: { 295: super.installUI(c); 296: if (c instanceof JLabel) 297: { 298: JLabel l = (JLabel) c; 299: 300: installComponents(l); 301: installDefaults(l); 302: installListeners(l); 303: installKeyboardActions(l); 304: } 305: } 306: 307: /** 308: * This method uninstalls the UI for the given {@link JComponent}. This 309: * method will uninstall the component, defaults, listeners, and keyboard 310: * actions. 311: * 312: * @param c The {@link JComponent} that this UI is being installed on. 313: */ 314: public void uninstallUI(JComponent c) 315: { 316: super.uninstallUI(c); 317: if (c instanceof JLabel) 318: { 319: JLabel l = (JLabel) c; 320: 321: uninstallKeyboardActions(l); 322: uninstallListeners(l); 323: uninstallDefaults(l); 324: uninstallComponents(l); 325: } 326: } 327: 328: /** 329: * This method installs the components for this {@link JLabel}. 330: * 331: * @param c The {@link JLabel} to install components for. 332: */ 333: protected void installComponents(JLabel c) 334: { 335: BasicHTML.updateRenderer(c, c.getText()); 336: } 337: 338: /** 339: * This method uninstalls the components for this {@link JLabel}. 340: * 341: * @param c The {@link JLabel} to uninstall components for. 342: */ 343: protected void uninstallComponents(JLabel c) 344: { 345: c.putClientProperty(BasicHTML.propertyKey, null); 346: c.putClientProperty(BasicHTML.documentBaseKey, null); 347: } 348: 349: /** 350: * This method installs the defaults that are defined in the Basic look and 351: * feel for this {@link JLabel}. 352: * 353: * @param c The {@link JLabel} to install defaults for. 354: */ 355: protected void installDefaults(JLabel c) 356: { 357: LookAndFeel.installColorsAndFont(c, "Label.background", "Label.foreground", 358: "Label.font"); 359: //XXX: There are properties we don't use called disabledForeground 360: //and disabledShadow. 361: } 362: 363: /** 364: * This method uninstalls the defaults that are defined in the Basic look 365: * and feel for this {@link JLabel}. 366: * 367: * @param c The {@link JLabel} to uninstall defaults for. 368: */ 369: protected void uninstallDefaults(JLabel c) 370: { 371: c.setForeground(null); 372: c.setBackground(null); 373: c.setFont(null); 374: } 375: 376: /** 377: * Installs the keyboard actions for the given {@link JLabel}. 378: * 379: * @param l The {@link JLabel} to install keyboard actions for. 380: */ 381: protected void installKeyboardActions(JLabel l) 382: { 383: Component c = l.getLabelFor(); 384: if (c != null) 385: { 386: int mnemonic = l.getDisplayedMnemonic(); 387: if (mnemonic > 0) 388: { 389: // add a keystroke for the given mnemonic mapping to 'press'; 390: InputMap keyMap = new InputMap(); 391: keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.VK_ALT), 392: "press"); 393: SwingUtilities.replaceUIInputMap(l, 394: JComponent.WHEN_IN_FOCUSED_WINDOW, keyMap); 395: 396: // add an action to focus the component when 'press' happens 397: ActionMap map = new ActionMap(); 398: map.put("press", new AbstractAction() { 399: public void actionPerformed(ActionEvent event) 400: { 401: JLabel label = (JLabel) event.getSource(); 402: Component c = label.getLabelFor(); 403: if (c != null) 404: c.requestFocus(); 405: } 406: }); 407: SwingUtilities.replaceUIActionMap(l, map); 408: } 409: } 410: } 411: 412: /** 413: * This method uninstalls the keyboard actions for the given {@link JLabel}. 414: * 415: * @param l The {@link JLabel} to uninstall keyboard actions for. 416: */ 417: protected void uninstallKeyboardActions(JLabel l) 418: { 419: SwingUtilities.replaceUIActionMap(l, null); 420: SwingUtilities.replaceUIInputMap(l, JComponent.WHEN_IN_FOCUSED_WINDOW, 421: null); 422: } 423: 424: /** 425: * This method installs the listeners for the given {@link JLabel}. The UI 426: * delegate only listens to the label. 427: * 428: * @param c The {@link JLabel} to install listeners for. 429: */ 430: protected void installListeners(JLabel c) 431: { 432: c.addPropertyChangeListener(this); 433: } 434: 435: /** 436: * This method uninstalls the listeners for the given {@link JLabel}. The UI 437: * delegate only listens to the label. 438: * 439: * @param c The {@link JLabel} to uninstall listeners for. 440: */ 441: protected void uninstallListeners(JLabel c) 442: { 443: c.removePropertyChangeListener(this); 444: } 445: 446: /** 447: * This method is called whenever any JLabel's that use this UI has one of 448: * their properties change. 449: * 450: * @param e The {@link PropertyChangeEvent} that describes the change. 451: */ 452: public void propertyChange(PropertyChangeEvent e) 453: { 454: if (e.getPropertyName().equals("text")) 455: { 456: String text = (String) e.getNewValue(); 457: JLabel l = (JLabel) e.getSource(); 458: BasicHTML.updateRenderer(l, text); 459: } 460: else if (e.getPropertyName().equals("displayedMnemonic")) 461: { 462: // update the key to action mapping 463: JLabel label = (JLabel) e.getSource(); 464: if (label.getLabelFor() != null) 465: { 466: int oldMnemonic = ((Integer) e.getOldValue()).intValue(); 467: int newMnemonic = ((Integer) e.getNewValue()).intValue(); 468: InputMap keyMap = label.getInputMap( 469: JComponent.WHEN_IN_FOCUSED_WINDOW); 470: keyMap.put(KeyStroke.getKeyStroke(oldMnemonic, 471: KeyEvent.ALT_DOWN_MASK), null); 472: keyMap.put(KeyStroke.getKeyStroke(newMnemonic, 473: KeyEvent.ALT_DOWN_MASK), "press"); 474: } 475: } 476: else if (e.getPropertyName().equals("labelFor")) 477: { 478: JLabel label = (JLabel) e.getSource(); 479: InputMap keyMap = label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 480: int mnemonic = label.getDisplayedMnemonic(); 481: if (mnemonic > 0) 482: keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.ALT_DOWN_MASK), 483: "press"); 484: } 485: } 486: }