Source for javax.swing.JLabel

   1: /* JLabel.java --
   2:    Copyright (C) 2002, 2004, 2005, 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: 
  39: package javax.swing;
  40: 
  41: import java.awt.Component;
  42: import java.awt.Font;
  43: import java.awt.FontMetrics;
  44: import java.awt.Image;
  45: import java.awt.Insets;
  46: import java.awt.Point;
  47: import java.awt.Rectangle;
  48: import java.awt.Shape;
  49: import java.awt.event.KeyEvent;
  50: import java.beans.PropertyChangeEvent;
  51: 
  52: import javax.accessibility.Accessible;
  53: import javax.accessibility.AccessibleContext;
  54: import javax.accessibility.AccessibleExtendedComponent;
  55: import javax.accessibility.AccessibleRole;
  56: import javax.accessibility.AccessibleText;
  57: import javax.swing.plaf.LabelUI;
  58: import javax.swing.plaf.basic.BasicHTML;
  59: import javax.swing.text.AttributeSet;
  60: import javax.swing.text.BadLocationException;
  61: import javax.swing.text.Position;
  62: import javax.swing.text.SimpleAttributeSet;
  63: import javax.swing.text.View;
  64: 
  65: /**
  66:  * A component that displays a static text message and/or an icon.
  67:  */
  68: public class JLabel extends JComponent implements Accessible, SwingConstants
  69: {
  70: 
  71:   /**
  72:    * Provides the accessibility features for the <code>JLabel</code>
  73:    * component.
  74:    */
  75:   protected class AccessibleJLabel
  76:     extends JComponent.AccessibleJComponent
  77:     implements AccessibleText, AccessibleExtendedComponent
  78:   {
  79:     
  80:     /**
  81:      * Returns the accessible name.
  82:      * 
  83:      * @return The accessible name.
  84:      */
  85:     public String getAccessibleName()
  86:     {
  87:       if (accessibleName != null)
  88:         return accessibleName;
  89:       if (text != null)
  90:         return text;
  91:       else
  92:         return super.getAccessibleName();
  93:     }
  94:     
  95:     /**
  96:      * Returns the accessible role for the <code>JLabel</code> component.
  97:      *
  98:      * @return {@link AccessibleRole#LABEL}.
  99:      */
 100:     public AccessibleRole getAccessibleRole()
 101:     {
 102:       return AccessibleRole.LABEL;
 103:     }
 104:     
 105:     /**
 106:      * Returns the selected text. This is null since JLabels
 107:      * are not selectable.
 108:      *
 109:      * @return <code>null</code> because JLabels cannot have selected text
 110:      */
 111:     public String getSelectedText()
 112:     {
 113:       // We return null here since JLabel's text is not selectable.
 114:       return null;
 115:     }
 116: 
 117:     /**
 118:      * Returns the start index of the selected text.
 119:      *
 120:      * @return the start index of the selected text
 121:      */
 122:     public int getSelectionStart()
 123:     {
 124:       // JLabel don't have selected text, so we return -1 here.
 125:       return -1;
 126:     }
 127: 
 128:     /**
 129:      * Returns the end index of the selected text.
 130:      *
 131:      * @return the end index of the selected text
 132:      */
 133:     public int getSelectionEnd()
 134:     {
 135:       // JLabel don't have selected text, so we return -1 here.
 136:       return -1;
 137:     }
 138: 
 139:     /**
 140:      * Returns an {@link AttributeSet} that reflects the text attributes of
 141:      * the specified character. We return an empty
 142:      * <code>AttributeSet</code> here, because JLabels don't support text
 143:      * attributes (at least not yet).
 144:      *
 145:      * @param index the index of the character
 146:      *
 147:      * @return an {@link AttributeSet} that reflects the text attributes of
 148:      *         the specified character
 149:      */
 150:     public AttributeSet getCharacterAttribute(int index)
 151:     {
 152:       // FIXME: Return null here for simple labels, and query the HTML
 153:       // view for HTML labels.
 154:       return new SimpleAttributeSet();
 155:     }
 156: 
 157:     /**
 158:      * Returns the character, word or sentence at the specified index. The
 159:      * <code>part</code> parameter determines what is returned, the character,
 160:      * word or sentence after the index.
 161:      *
 162:      * @param part one of {@link AccessibleText#CHARACTER},
 163:      *             {@link AccessibleText#WORD} or
 164:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 165:      * @param index the index
 166:      *
 167:      * @return the character, word or sentence after <code>index</code>
 168:      */
 169:     public String getAtIndex(int part, int index)
 170:     {
 171:       String result = "";
 172:       int startIndex = -1;
 173:       int endIndex = -1;
 174:       switch(part)
 175:         {
 176:         case AccessibleText.CHARACTER:
 177:           result = String.valueOf(text.charAt(index));
 178:           break;
 179:         case AccessibleText.WORD:
 180:           startIndex = text.lastIndexOf(' ', index);
 181:           endIndex = text.indexOf(' ', startIndex + 1);
 182:           if (endIndex == -1)
 183:             endIndex = startIndex + 1;
 184:           result = text.substring(startIndex + 1, endIndex);
 185:           break;
 186:         case AccessibleText.SENTENCE:
 187:         default:
 188:           startIndex = text.lastIndexOf('.', index);
 189:           endIndex = text.indexOf('.', startIndex + 1);
 190:           if (endIndex == -1)
 191:             endIndex = startIndex + 1;
 192:           result = text.substring(startIndex + 1, endIndex);
 193:           break;
 194:         }
 195:       return result;
 196:     }
 197: 
 198:     /**
 199:      * Returns the character, word or sentence after the specified index. The
 200:      * <code>part</code> parameter determines what is returned, the character,
 201:      * word or sentence after the index.
 202:      *
 203:      * @param part one of {@link AccessibleText#CHARACTER},
 204:      *             {@link AccessibleText#WORD} or
 205:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 206:      * @param index the index
 207:      *
 208:      * @return the character, word or sentence after <code>index</code>
 209:      */
 210:     public String getAfterIndex(int part, int index)
 211:     {
 212:       String result = "";
 213:       int startIndex = -1;
 214:       int endIndex = -1;
 215:       switch(part)
 216:         {
 217:         case AccessibleText.CHARACTER:
 218:           result = String.valueOf(text.charAt(index + 1));
 219:           break;
 220:         case AccessibleText.WORD:
 221:           startIndex = text.indexOf(' ', index);
 222:           endIndex = text.indexOf(' ', startIndex + 1);
 223:           if (endIndex == -1)
 224:             endIndex = startIndex + 1;
 225:           result = text.substring(startIndex + 1, endIndex);
 226:           break;
 227:         case AccessibleText.SENTENCE:
 228:         default:
 229:           startIndex = text.indexOf('.', index);
 230:           endIndex = text.indexOf('.', startIndex + 1);
 231:           if (endIndex == -1)
 232:             endIndex = startIndex + 1;
 233:           result = text.substring(startIndex + 1, endIndex);
 234:           break;
 235:         }
 236:       return result;
 237:     }
 238: 
 239:     /**
 240:      * Returns the character, word or sentence before the specified index. The
 241:      * <code>part</code> parameter determines what is returned, the character,
 242:      * word or sentence before the index.
 243:      *
 244:      * @param part one of {@link AccessibleText#CHARACTER},
 245:      *             {@link AccessibleText#WORD} or
 246:      *             {@link AccessibleText#SENTENCE}, specifying what is returned
 247:      * @param index the index
 248:      *
 249:      * @return the character, word or sentence before <code>index</code>
 250:      */
 251:     public String getBeforeIndex(int part, int index)
 252:     {
 253:       String result = "";
 254:       int startIndex = -1;
 255:       int endIndex = -1;
 256:       switch(part)
 257:         {
 258:         case AccessibleText.CHARACTER:
 259:           result = String.valueOf(text.charAt(index - 1));
 260:           break;
 261:         case AccessibleText.WORD:
 262:           endIndex = text.lastIndexOf(' ', index);
 263:           if (endIndex == -1)
 264:             endIndex = 0;
 265:           startIndex = text.lastIndexOf(' ', endIndex - 1);
 266:           result = text.substring(startIndex + 1, endIndex);
 267:           break;
 268:         case AccessibleText.SENTENCE:
 269:         default:
 270:           endIndex = text.lastIndexOf('.', index);
 271:           if (endIndex == -1)
 272:             endIndex = 0;
 273:           startIndex = text.lastIndexOf('.', endIndex - 1);
 274:           result = text.substring(startIndex + 1, endIndex);
 275:           break;
 276:         }
 277:       return result;
 278:     }
 279: 
 280:     /**
 281:      * Returns the caret position. This method returns -1 because JLabel don't
 282:      * have a caret.
 283:      *
 284:      * @return the caret position
 285:      */
 286:     public int getCaretPosition()
 287:     {
 288:       return -1;
 289:     }
 290: 
 291:     /**
 292:      * Returns the number of characters that are displayed by the JLabel.
 293:      *
 294:      * @return the number of characters that are displayed by the JLabel
 295:      */
 296:     public int getCharCount()
 297:     {
 298:       // FIXME: Query HTML view for HTML labels.
 299:       return text.length();
 300:     }
 301: 
 302:     /**
 303:      * Returns the bounding box of the character at the specified index.
 304:      *
 305:      * @param index the index of the character that we return the
 306:      *        bounds for
 307:      *
 308:      * @return the bounding box of the character at the specified index
 309:      */
 310:     public Rectangle getCharacterBounds(int index)
 311:     {
 312:       Rectangle bounds = null;
 313:       View view = (View) getClientProperty(BasicHTML.propertyKey);
 314:       if (view != null)
 315:         {
 316:           Rectangle textR = getTextRectangle();
 317:           try
 318:             {
 319:               Shape s = view.modelToView(index, textR, Position.Bias.Forward);
 320:               bounds = s.getBounds();
 321:             }
 322:           catch (BadLocationException ex)
 323:             {
 324:               // Can't return something reasonable in this case.
 325:             }
 326:         }
 327:       return bounds;
 328:     }
 329: 
 330:     /**
 331:      * Returns the rectangle inside the JLabel, in which the actual text is
 332:      * rendered. This method has been adopted from the Mauve testcase
 333:      * gnu.testlet.javax.swing.JLabel.AccessibleJLabel.getCharacterBounds.
 334:      *
 335:      * @return the rectangle inside the JLabel, in which the actual text is
 336:      *         rendered
 337:      */
 338:     private Rectangle getTextRectangle()
 339:     {
 340:       JLabel l = JLabel.this;
 341:       Rectangle textR = new Rectangle();
 342:       Rectangle iconR = new Rectangle();
 343:       Insets i = l.getInsets();
 344:       int w = l.getWidth();
 345:       int h = l.getHeight();
 346:       Rectangle viewR = new Rectangle(i.left, i.top, w - i.left - i.right,
 347:                                       h - i.top - i.bottom);
 348:       FontMetrics fm = l.getFontMetrics(l.getFont());
 349:       SwingUtilities.layoutCompoundLabel(l, fm, l.getText(), l.getIcon(),
 350:                                          l.getVerticalAlignment(),
 351:                                          l.getHorizontalAlignment(),
 352:                                          l.getVerticalTextPosition(),
 353:                                          l.getHorizontalTextPosition(),
 354:                                          viewR, iconR, textR,
 355:                                          l.getIconTextGap());
 356:       return textR;
 357:     }
 358: 
 359:     /**
 360:      * Returns the index of the character that is located at the specified
 361:      * point.
 362:      *
 363:      * @param point the location that we lookup the character for
 364:      *
 365:      * @return the index of the character that is located at the specified
 366:      *         point
 367:      */
 368:     public int getIndexAtPoint(Point point)
 369:     {
 370:       int index = -1;
 371:       View view = (View) getClientProperty(BasicHTML.propertyKey);
 372:       if (view != null)
 373:         {
 374:           Rectangle r = getTextRectangle();
 375:           index = view.viewToModel(point.x, point.y, r, new Position.Bias[0]);
 376:         }
 377:       return index;
 378:     }
 379:   }
 380: 
 381:   private static final long serialVersionUID = 5496508283662221534L;
 382: 
 383:   static final String LABEL_PROPERTY = "labeledBy";
 384: 
 385:   /**
 386:    * The Component the label will give focus to when its mnemonic is
 387:    * activated.
 388:    */
 389:   protected Component labelFor;
 390: 
 391:   /** The label's text. */
 392:   transient String text;
 393: 
 394:   /** Where the label will be positioned horizontally. */
 395:   private transient int horizontalAlignment = LEADING;
 396: 
 397:   /** Where the label text will be placed horizontally relative to the icon. */
 398:   private transient int horizontalTextPosition = TRAILING;
 399: 
 400:   /** Where the label will be positioned vertically. */
 401:   private transient int verticalAlignment = CENTER;
 402: 
 403:   /** Where the label text will be place vertically relative to the icon. */
 404:   private transient int verticalTextPosition = CENTER;
 405: 
 406:   /** The icon painted when the label is enabled. */
 407:   private transient Icon icon;
 408: 
 409:   /** The icon painted when the label is disabled. */
 410:   private transient Icon disabledIcon;
 411: 
 412:   /** The label's mnemnonic key. */
 413:   private transient int displayedMnemonic = KeyEvent.VK_UNDEFINED;
 414: 
 415:   /** The index of the mnemonic character in the text. */
 416:   private transient int displayedMnemonicIndex = -1;
 417: 
 418:   /** The gap between the icon and the text. */
 419:   private transient int iconTextGap = 4;
 420: 
 421:   /**
 422:    * Creates a new vertically centered, horizontally on the leading edge
 423:    * JLabel object with text and no icon.
 424:    */
 425:   public JLabel()
 426:   {
 427:     this("", null, LEADING);
 428:   }
 429: 
 430:   /**
 431:    * Creates a new vertically and horizontally centered
 432:    * JLabel object with no text and the given icon.
 433:    *
 434:    * @param image The icon to use with the label, <code>null</code> permitted.
 435:    */
 436:   public JLabel(Icon image)
 437:   {
 438:     this(null, image, CENTER);
 439:   }
 440: 
 441:   /**
 442:    * Creates a new vertically centered JLabel object with no text and the
 443:    * given icon and horizontal alignment. By default, the text is TRAILING
 444:    * the image.
 445:    *
 446:    * @param image The icon to use with the label, <code>null</code> premitted.
 447:    * @param horizontalAlignment The horizontal alignment of the label, must be
 448:    * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>,
 449:    * <code>LEADING</code> or <code>TRAILING</code>.
 450:    */
 451:   public JLabel(Icon image, int horizontalAlignment)
 452:   {
 453:     this(null, image, horizontalAlignment);
 454:   }
 455: 
 456:   /**
 457:    * Creates a new horizontally leading and vertically centered JLabel 
 458:    * object with no icon and the given text.
 459:    *
 460:    * @param text The text to use with the label, <code>null</code> permitted.
 461:    */
 462:   public JLabel(String text)
 463:   {
 464:     this(text, null, LEADING);
 465:   }
 466: 
 467:   /**
 468:    * Creates a new vertically centered JLabel object with no icon and the
 469:    * given text and horizontal alignment.
 470:    *
 471:    * @param text The text to use with the label, <code>null</code> permitted.
 472:    * @param horizontalAlignment The horizontal alignment of the label, must be
 473:    * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>,
 474:    * <code>LEADING</code> or <code>TRAILING</code>.
 475:    */
 476:   public JLabel(String text, int horizontalAlignment)
 477:   {
 478:     this(text, null, horizontalAlignment);
 479:   }
 480: 
 481:   /**
 482:    * Creates a new vertically centered JLabel object with the given text,
 483:    * icon, and horizontal alignment.
 484:    *
 485:    * @param text The text to use with the label, <code>null</code> permitted.
 486:    * @param icon The icon to use with the label, <code>null</code> premitted.
 487:    * @param horizontalAlignment The horizontal alignment of the label, must be
 488:    * either <code>CENTER</code>, <code>LEFT</code>, <code>RIGHT</code>,
 489:    * <code>LEADING</code> or <code>TRAILING</code>.
 490:    */
 491:   public JLabel(String text, Icon icon, int horizontalAlignment)
 492:   {
 493:     if (horizontalAlignment != SwingConstants.LEFT  
 494:         && horizontalAlignment != SwingConstants.RIGHT 
 495:         && horizontalAlignment != SwingConstants.CENTER 
 496:         && horizontalAlignment != SwingConstants.LEADING 
 497:         && horizontalAlignment != SwingConstants.TRAILING)
 498:       throw new IllegalArgumentException();
 499:     
 500:     this.text = text;
 501:     this.icon = icon;
 502:     this.horizontalAlignment = horizontalAlignment;
 503:     setAlignmentX(0.0F);
 504:     setInheritsPopupMenu(true);
 505:     updateUI();
 506:   }
 507: 
 508:   /**
 509:    * Returns the label's UI delegate.
 510:    *
 511:    * @return The label's UI delegate.
 512:    */
 513:   public LabelUI getUI()
 514:   {
 515:     return (LabelUI) ui;
 516:   }
 517: 
 518:   /**
 519:    * Sets the label's UI delegate.
 520:    *
 521:    * @param ui The label's UI delegate (<code>null</code> not permitted).
 522:    */
 523:   public void setUI(LabelUI ui)
 524:   {
 525:     super.setUI(ui);
 526:   }
 527: 
 528:   /**
 529:    * Resets the label's UI delegate to the default UI for the current look and 
 530:    * feel.
 531:    */
 532:   public void updateUI()
 533:   {
 534:     setUI((LabelUI) UIManager.getUI(this));
 535:   }
 536: 
 537:   /**
 538:    * Returns a name to identify which look and feel class will be
 539:    * the UI delegate for this label.
 540:    *
 541:    * @return <code>"LabelUI"</code>
 542:    */
 543:   public String getUIClassID()
 544:   {
 545:     return "LabelUI";
 546:   }
 547: 
 548:   /**
 549:    * Returns a string describing the attributes for the <code>JLabel</code>
 550:    * component, for use in debugging.  The return value is guaranteed to be 
 551:    * non-<code>null</code>, but the format of the string may vary between
 552:    * implementations.
 553:    *
 554:    * @return A string describing the attributes of the <code>JLabel</code>.
 555:    */
 556:   protected String paramString()
 557:   {
 558:     StringBuffer sb = new StringBuffer(super.paramString());
 559:     sb.append(",defaultIcon=");
 560:     if (icon != null)
 561:       sb.append(icon);
 562:     sb.append(",disabledIcon=");
 563:     if (disabledIcon != null)
 564:       sb.append(disabledIcon);
 565:     sb.append(",horizontalAlignment=");
 566:     sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString(
 567:         horizontalAlignment));
 568:     sb.append(",horizontalTextPosition=");
 569:     sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString(
 570:         horizontalTextPosition));
 571:     sb.append(",iconTextGap=").append(iconTextGap);
 572:     sb.append(",labelFor=");
 573:     if (labelFor != null)
 574:       sb.append(labelFor);
 575:     sb.append(",text=");
 576:     if (text != null)
 577:       sb.append(text);
 578:     sb.append(",verticalAlignment=");
 579:     sb.append(SwingUtilities.convertVerticalAlignmentCodeToString(
 580:         verticalAlignment));
 581:     sb.append(",verticalTextPosition=");
 582:     sb.append(SwingUtilities.convertVerticalAlignmentCodeToString(
 583:         verticalTextPosition));
 584:     return sb.toString();
 585:   }
 586: 
 587:   /**
 588:    * Returns the text displayed by the label.
 589:    *
 590:    * @return The label text (possibly <code>null</code>).
 591:    * 
 592:    * @see #setText(String)
 593:    */
 594:   public String getText()
 595:   {
 596:     return text;
 597:   }
 598: 
 599:   /**
 600:    * Sets the text for the label and sends a {@link PropertyChangeEvent} (with
 601:    * the name 'text') to all registered listeners.  This method will also 
 602:    * update the <code>displayedMnemonicIndex</code>, if necessary.
 603:    *
 604:    * @param newText The text (<code>null</code> permitted).
 605:    * 
 606:    * @see #getText()
 607:    * @see #getDisplayedMnemonicIndex()
 608:    */
 609:   public void setText(String newText)
 610:   {
 611:     if (text == null && newText == null)
 612:       return;
 613:     if (text != null && text.equals(newText))
 614:       return;
 615: 
 616:     String oldText = text;
 617:     text = newText;
 618:     firePropertyChange("text", oldText, newText);
 619: 
 620:     if (text != null)
 621:       setDisplayedMnemonicIndex(text.toUpperCase().indexOf(displayedMnemonic));
 622:     else
 623:       setDisplayedMnemonicIndex(-1);
 624:     revalidate();
 625:     repaint();
 626:   }
 627: 
 628:   /**
 629:    * Returns the active icon. The active icon is painted when the label is 
 630:    * enabled.
 631:    *
 632:    * @return The active icon.
 633:    * 
 634:    * @see #setIcon(Icon)
 635:    * @see #getDisabledIcon()
 636:    */
 637:   public Icon getIcon()
 638:   {
 639:     return icon;
 640:   }
 641: 
 642:   /**
 643:    * Sets the icon for the label (this is a bound property with the name 
 644:    * 'icon'). This icon will be displayed when the label is enabled.
 645:    *
 646:    * @param newIcon The icon (<code>null</code> permitted).
 647:    * 
 648:    * @see #getIcon()
 649:    * @see #setDisabledIcon(Icon)
 650:    */
 651:   public void setIcon(Icon newIcon)
 652:   {
 653:     if (icon != newIcon)
 654:       {
 655:         Icon oldIcon = icon;
 656:         icon = newIcon;
 657:         firePropertyChange("icon", oldIcon, newIcon);
 658:         repaint();
 659:       }
 660:   }
 661: 
 662:   /**
 663:    * Returns the disabled icon. The disabled icon is painted when the label is 
 664:    * disabled. If the disabled icon is <code>null</code> and the active icon
 665:    * is an {@link ImageIcon}, this method returns a grayed version of the icon. 
 666:    * The grayed version of the icon becomes the <code>disabledIcon</code>.
 667:    *
 668:    * @return The disabled icon.
 669:    * 
 670:    * @see #setDisabledIcon(Icon)
 671:    */
 672:   public Icon getDisabledIcon()
 673:   {
 674:     if (disabledIcon == null && icon instanceof ImageIcon)
 675:       disabledIcon = new ImageIcon(
 676:           GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()));
 677: 
 678:     return disabledIcon;
 679:   }
 680: 
 681:   /**
 682:    * Sets the icon displayed when the label is disabled (this is a bound
 683:    * property with the name 'disabledIcon').
 684:    *
 685:    * @param newIcon The disabled icon (<code>null</code> permitted).
 686:    * 
 687:    * @see #getDisabledIcon()
 688:    */
 689:   public void setDisabledIcon(Icon newIcon)
 690:   {
 691:     if (disabledIcon != newIcon)
 692:       {
 693:         Icon oldIcon = disabledIcon;
 694:         disabledIcon = newIcon;
 695:         firePropertyChange("disabledIcon", oldIcon, newIcon);
 696:       }
 697:   }
 698: 
 699:   /**
 700:    * Sets the keycode that will be the label's mnemonic (this is a bound
 701:    * property with the name 'displayedMnemonic').  If the label is used as a 
 702:    * label for another component, the label will give focus to that component 
 703:    * when the mnemonic is activated.
 704:    *
 705:    * @param mnemonic The keycode to use for the mnemonic.
 706:    * 
 707:    * @see #getDisplayedMnemonic()
 708:    */
 709:   public void setDisplayedMnemonic(int mnemonic)
 710:   {
 711:     if (displayedMnemonic != mnemonic)
 712:       {
 713:         int old = displayedMnemonic;
 714:         displayedMnemonic = mnemonic;
 715:         firePropertyChange("displayedMnemonic", old, displayedMnemonic);
 716:         if (text != null)
 717:           setDisplayedMnemonicIndex(text.toUpperCase().indexOf(mnemonic));
 718:       }
 719:   }
 720: 
 721:   /**
 722:    * Sets the character that will be the label's mnemonic. If the
 723:    * label is used as a label for another component, the label will give
 724:    * focus to that component when the mnemonic is activated via the keyboard.
 725:    *
 726:    * @param mnemonic The character to use for the mnemonic (this will be
 727:    *     converted to the equivalent upper case character).
 728:    *     
 729:    * @see #getDisplayedMnemonic()
 730:    */
 731:   public void setDisplayedMnemonic(char mnemonic)
 732:   {
 733:     setDisplayedMnemonic((int) Character.toUpperCase(mnemonic));
 734:   }
 735: 
 736:   /**
 737:    * Returns the keycode that is used for the label's mnemonic.
 738:    *
 739:    * @return The keycode that is used for the label's mnemonic.
 740:    * 
 741:    * @see #setDisplayedMnemonic(int)
 742:    */
 743:   public int getDisplayedMnemonic()
 744:   {
 745:     return displayedMnemonic;
 746:   }
 747: 
 748:   /**
 749:    * Sets the index of the character in the text that will be underlined to
 750:    * indicate that it is the mnemonic character for the label.  You only need
 751:    * to call this method if you wish to override the automatically calculated
 752:    * character index.  For instance, for a label "Find Next" with the mnemonic
 753:    * character 'n', you might wish to underline the second occurrence of 'n'
 754:    * rather than the first (which is the default).
 755:    * <br><br>
 756:    * Note that this method does not validate the character at the specified 
 757:    * index to ensure that it matches the key code returned by
 758:    * {@link #getDisplayedMnemonic()}.
 759:    *
 760:    * @param newIndex The index of the character to underline.
 761:    *
 762:    * @throws IllegalArgumentException If index less than -1 or index is greater
 763:    *         than or equal to the label length.
 764:    *         
 765:    * @see #getDisplayedMnemonicIndex()
 766:    * @since 1.4
 767:    */
 768:   public void setDisplayedMnemonicIndex(int newIndex)
 769:     throws IllegalArgumentException
 770:   {
 771:     int maxValid = -1;
 772:     if (text != null)
 773:       maxValid = text.length() - 1;
 774:     if (newIndex < -1 || newIndex > maxValid)
 775:       throw new IllegalArgumentException();
 776: 
 777:     if (newIndex != displayedMnemonicIndex)
 778:       {
 779:         int oldIndex = displayedMnemonicIndex;
 780:         displayedMnemonicIndex = newIndex;
 781:         firePropertyChange("displayedMnemonicIndex", oldIndex, newIndex);
 782:       }
 783:   }
 784: 
 785:   /**
 786:    * Returns the index of the character in the label's text that will be
 787:    * underlined (to indicate that it is the mnemonic character), or -1 if no
 788:    * character is to be underlined.
 789:    *
 790:    * @return The index of the character that will be underlined.
 791:    * 
 792:    * @see #setDisplayedMnemonicIndex(int)
 793:    * @since 1.4
 794:    */
 795:   public int getDisplayedMnemonicIndex()
 796:   {
 797:     return displayedMnemonicIndex;
 798:   }
 799: 
 800:   /**
 801:    * Checks the specified key to ensure that it is valid as a horizontal 
 802:    * alignment, throwing an {@link IllegalArgumentException} if the key is
 803:    * invalid.  Valid keys are {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, 
 804:    * {@link #LEADING} and {@link #TRAILING}.
 805:    *
 806:    * @param key The key to check.
 807:    * @param message The message of the exception to be thrown if the key is
 808:    *        invalid.
 809:    *
 810:    * @return The key if it is valid.
 811:    *
 812:    * @throws IllegalArgumentException If the key is invalid.
 813:    */
 814:   protected int checkHorizontalKey(int key, String message)
 815:   {
 816:     if (key != LEFT && key != CENTER && key != RIGHT && key != LEADING
 817:         && key != TRAILING)
 818:       throw new IllegalArgumentException(message);
 819:     else
 820:       return key;
 821:   }
 822: 
 823:   /**
 824:    * Checks the specified key to ensure that it is valid as a vertical 
 825:    * alignment, throwing an {@link IllegalArgumentException} if the key is
 826:    * invalid.  Valid keys are {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
 827:    *
 828:    * @param key The key to check.
 829:    * @param message The message of the exception to be thrown if the key is
 830:    *        invalid.
 831:    *
 832:    * @return The key if it is valid.
 833:    *
 834:    * @throws IllegalArgumentException If the key is invalid.
 835:    */
 836:   protected int checkVerticalKey(int key, String message)
 837:   {
 838:     if (key != TOP && key != BOTTOM && key != CENTER)
 839:       throw new IllegalArgumentException(message);
 840:     else
 841:       return key;
 842:   }
 843: 
 844:   /**
 845:    * Returns the gap between the icon and the text.
 846:    *
 847:    * @return The gap between the icon and the text.
 848:    * 
 849:    * @see #setIconTextGap(int)
 850:    */
 851:   public int getIconTextGap()
 852:   {
 853:     return iconTextGap;
 854:   }
 855: 
 856:   /**
 857:    * Sets the gap between the icon and the text, in the case that both are 
 858:    * visible (this is a bound property with the name 'iconTextGap'). 
 859:    *
 860:    * @param newGap The gap (in pixels).
 861:    * 
 862:    * @see #getIconTextGap()
 863:    */
 864:   public void setIconTextGap(int newGap)
 865:   {
 866:     if (iconTextGap != newGap)
 867:       {
 868:     firePropertyChange("iconTextGap", iconTextGap, newGap);
 869:     iconTextGap = newGap;
 870:       }
 871:   }
 872: 
 873:   /**
 874:    * Returns the vertical alignment of the label (one of
 875:    * {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}).  The default value
 876:    * depends on the installed look and feel, but is usually {@link #CENTER}.
 877:    *
 878:    * @return The vertical alignment.
 879:    * 
 880:    * @see #setVerticalAlignment(int)
 881:    */
 882:   public int getVerticalAlignment()
 883:   {
 884:     return verticalAlignment;
 885:   }
 886: 
 887:   /**
 888:    * Sets the vertical alignment for the label (this is a bound property with
 889:    * the name 'verticalAlignment').  The vertical alignment determines where 
 890:    * the label (icon and text) will be placed vertically within the component 
 891:    * bounds.  Valid alignment codes are {@link #TOP}, {@link #CENTER} and 
 892:    * {@link #BOTTOM}.
 893:    *
 894:    * @param alignment The vertical alignment of the label.
 895:    * 
 896:    * @throws IllegalArgumentException if <code>alignment</code> is not one of 
 897:    *     the specified values.
 898:    *     
 899:    * @see #getVerticalAlignment()
 900:    */
 901:   public void setVerticalAlignment(int alignment)
 902:   {
 903:     if (alignment == verticalAlignment)
 904:       return;
 905: 
 906:     int oldAlignment = verticalAlignment;
 907:     verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
 908:     firePropertyChange("verticalAlignment", oldAlignment, verticalAlignment);
 909:   }
 910: 
 911:   /**
 912:    * Returns the horizontal alignment of the label (one of {@link #LEFT}, 
 913:    * {@link #CENTER}, {@link #RIGHT}, {@link #LEADING} and {@link #TRAILING}).
 914:    * The default value depends on the installed look and feel, but is usually 
 915:    * {@link #LEFT}.
 916:    *
 917:    * @return The horizontal alignment.
 918:    * 
 919:    * @see #setHorizontalAlignment(int)
 920:    */
 921:   public int getHorizontalAlignment()
 922:   {
 923:     return horizontalAlignment;
 924:   }
 925: 
 926:   /**
 927:    * Sets the horizontal alignment for the label (this is a bound property with
 928:    * the name 'horizontalAlignment').  The horizontal alignment determines where 
 929:    * the label (icon and text) will be placed horizontally within the 
 930:    * component bounds.  Valid alignment codes are {@link #LEFT}, 
 931:    * {@link #CENTER}, {@link #RIGHT}, {@link #LEADING} and {@link #TRAILING}.
 932:    *
 933:    * @param alignment The horizontal alignment of the label.
 934:    * 
 935:    * @throws IllegalArgumentException if <code>alignment</code> is not one of 
 936:    *     the specified values.
 937:    *     
 938:    * @see #getHorizontalAlignment()
 939:    */
 940:   public void setHorizontalAlignment(int alignment)
 941:   {
 942:     if (horizontalAlignment == alignment)
 943:       return;
 944:     
 945:     int oldAlignment = horizontalAlignment;
 946:     horizontalAlignment = checkHorizontalKey(alignment, "horizontalAlignment");
 947:     firePropertyChange("horizontalAlignment", oldAlignment,
 948:                        horizontalAlignment);
 949:   }
 950: 
 951:   /**
 952:    * Returns the vertical position of the label's text relative to the icon. 
 953:    * This will be one of {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
 954:    * 
 955:    * @return The vertical position of the label's text relative to the icon.
 956:    * 
 957:    * @see #setVerticalTextPosition(int)
 958:    */
 959:   public int getVerticalTextPosition()
 960:   {
 961:     return verticalTextPosition;
 962:   }
 963: 
 964:   /**
 965:    * Sets the vertical position of the label's text relative to the icon (this
 966:    * is a bound property with the name 'verticalTextPosition').  Valid 
 967:    * positions are {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
 968:    *
 969:    * @param textPosition The vertical text position.
 970:    * 
 971:    * @throws IllegalArgumentException if <code>textPosition</code> is not one
 972:    *     of the specified values.
 973:    */
 974:   public void setVerticalTextPosition(int textPosition)
 975:   {
 976:     if (textPosition != verticalTextPosition)
 977:       {
 978:         int oldPos = verticalTextPosition;
 979:         verticalTextPosition = checkVerticalKey(textPosition,
 980:                                                 "verticalTextPosition");
 981:         firePropertyChange("verticalTextPosition", oldPos, 
 982:                            verticalTextPosition);
 983:       }
 984:   }
 985: 
 986:   /**
 987:    * Returns the horizontal position of the label's text relative to the icon. 
 988:    * This will be one of {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, 
 989:    * {@link #LEADING} and {@link #TRAILING}.
 990:    * 
 991:    * @return The horizontal position of the label's text relative to the icon.
 992:    * 
 993:    * @see #setHorizontalTextPosition(int)
 994:    */
 995:   public int getHorizontalTextPosition()
 996:   {
 997:     return horizontalTextPosition;
 998:   }
 999: 
1000:   /**
1001:    * Sets the horizontal position of the label's text relative to the icon (this
1002:    * is a bound property with the name 'horizontalTextPosition').  Valid 
1003:    * positions are {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, 
1004:    * {@link #LEADING} and {@link #TRAILING}.
1005:    *
1006:    * @param textPosition The horizontal text position.
1007:    * 
1008:    * @throws IllegalArgumentException if <code>textPosition</code> is not one
1009:    *     of the specified values.
1010:    */
1011:   public void setHorizontalTextPosition(int textPosition)
1012:   {
1013:     if (textPosition != horizontalTextPosition)
1014:       {
1015:         int oldPos = horizontalTextPosition;
1016:         horizontalTextPosition = checkHorizontalKey(textPosition,
1017:                                                     "horizontalTextPosition");
1018:         firePropertyChange("horizontalTextPosition", oldPos, 
1019:                            horizontalTextPosition);
1020:       }
1021:   }
1022: 
1023:   /**
1024:    * Returns false if the current icon image (current icon will depend on 
1025:    * whether the label is enabled) is not equal to the passed in image.
1026:    *
1027:    * @param img The image to check.
1028:    * @param infoflags The bitwise inclusive OR of ABORT, ALLBITS, ERROR,
1029:    *        FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, and WIDTH
1030:    * @param x The x position
1031:    * @param y The y position
1032:    * @param w The width
1033:    * @param h The height
1034:    *
1035:    * @return Whether the current icon image is equal to the image given.
1036:    */
1037:   public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
1038:                              int h)
1039:   {
1040:     Icon currIcon = isEnabled() ? icon : disabledIcon;
1041: 
1042:     // XXX: Is this the correct way to check for image equality?
1043:     if (currIcon != null && currIcon instanceof ImageIcon)
1044:       return (((ImageIcon) currIcon).getImage() == img);
1045: 
1046:     return false;
1047:   }
1048: 
1049:   /**
1050:    * Returns the component that this <code>JLabel</code> is providing the label
1051:    * for.  This component will typically receive the focus when the label's 
1052:    * mnemonic key is activated via the keyboard.
1053:    *
1054:    * @return The component (possibly <code>null</code>).
1055:    */
1056:   public Component getLabelFor()
1057:   {
1058:     return labelFor;
1059:   }
1060: 
1061:   /**
1062:    * Sets the component that this <code>JLabel</code> is providing the label
1063:    * for (this is a bound property with the name 'labelFor').  This component
1064:    * will typically receive the focus when the label's mnemonic key is 
1065:    * activated via the keyboard.
1066:    *
1067:    * @param c  the component (<code>null</code> permitted).
1068:    * 
1069:    * @see #getLabelFor()
1070:    */
1071:   public void setLabelFor(Component c)
1072:   {
1073:     if (c != labelFor)
1074:       {
1075:         Component oldLabelFor = labelFor;
1076:         labelFor = c;
1077:         firePropertyChange("labelFor", oldLabelFor, labelFor);
1078: 
1079:         // We put the label into the client properties for the labeled
1080:         // component so that it can be read by the AccessibleJComponent.
1081:         // The other option would be to reserve a default visible field
1082:         // in JComponent, but since this is relatively seldomly used, it
1083:         // would be unnecessary waste of memory to do so.
1084:         if (oldLabelFor instanceof JComponent)
1085:           {
1086:             ((JComponent) oldLabelFor).putClientProperty(LABEL_PROPERTY, null);
1087:           }
1088: 
1089:         if (labelFor instanceof JComponent)
1090:           {
1091:             ((JComponent) labelFor).putClientProperty(LABEL_PROPERTY, this);
1092:           }
1093: 
1094:       }
1095:   }
1096: 
1097:   /**
1098:    * Sets the font for the label (this a bound property with the name 'font').
1099:    *
1100:    * @param f The font (<code>null</code> permitted).
1101:    */
1102:   public void setFont(Font f)
1103:   {
1104:     super.setFont(f);
1105:     repaint();
1106:   }
1107: 
1108:   /**
1109:    * Returns the object that provides accessibility features for this
1110:    * <code>JLabel</code> component.
1111:    *
1112:    * @return The accessible context (an instance of {@link AccessibleJLabel}).
1113:    */
1114:   public AccessibleContext getAccessibleContext()
1115:   {
1116:     if (accessibleContext == null)
1117:       accessibleContext = new AccessibleJLabel();
1118:     return accessibleContext;
1119:   }
1120: }