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