Source for javax.swing.plaf.basic.BasicLabelUI

   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: }