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