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      */
getAccessibleName()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      */
getAccessibleRole()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      */
getSelectedText()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      */
getSelectionStart()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      */
getSelectionEnd()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      */
getCharacterAttribute(int index)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      */
getAtIndex(int part, int index)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      */
getAfterIndex(int part, int index)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      */
getBeforeIndex(int part, int index)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      */
getCaretPosition()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      */
getCharCount()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      */
getCharacterBounds(int index)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      */
getTextRectangle()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      */
getIndexAtPoint(Point point)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    */
JLabel()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    */
JLabel(Icon image)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    */
JLabel(Icon image, int horizontalAlignment)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    */
JLabel(String text)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    */
JLabel(String text, int horizontalAlignment)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    */
JLabel(String text, Icon icon, int horizontalAlignment)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    */
getUI()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    */
setUI(LabelUI ui)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    */
updateUI()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    */
getUIClassID()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    */
paramString()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    */
getText()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    */
setText(String newText)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    */
getIcon()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    */
setIcon(Icon newIcon)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    */
getDisabledIcon()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    */
setDisabledIcon(Icon newIcon)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    */
setDisplayedMnemonic(int mnemonic)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    */
setDisplayedMnemonic(char mnemonic)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    */
getDisplayedMnemonic()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    */
setDisplayedMnemonicIndex(int newIndex)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    */
getDisplayedMnemonicIndex()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    */
checkHorizontalKey(int key, String message)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    */
checkVerticalKey(int key, String message)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    */
getIconTextGap()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    */
setIconTextGap(int newGap)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    */
getVerticalAlignment()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    */
setVerticalAlignment(int alignment)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    */
getHorizontalAlignment()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    */
setHorizontalAlignment(int alignment)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    */
getVerticalTextPosition()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    */
setVerticalTextPosition(int textPosition)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    */
getHorizontalTextPosition()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    */
setHorizontalTextPosition(int textPosition)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    */
imageUpdate(Image img, int infoflags, int x, int y, int w, int h)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    */
getLabelFor()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    */
setLabelFor(Component c)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    */
setFont(Font f)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    */
getAccessibleContext()1116   public AccessibleContext getAccessibleContext()
1117   {
1118     if (accessibleContext == null)
1119       accessibleContext = new AccessibleJLabel();
1120     return accessibleContext;
1121   }
1122 }
1123