View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package javax.swing;
27  
28  import java.awt.Component;
29  import java.awt.Font;
30  import java.awt.Image;
31  import java.awt.*;
32  import java.text.*;
33  import java.awt.geom.*;
34  import java.beans.Transient;
35  
36  import java.io.ObjectOutputStream;
37  import java.io.ObjectInputStream;
38  import java.io.IOException;
39  
40  import javax.swing.plaf.LabelUI;
41  import javax.accessibility.*;
42  import javax.swing.text.*;
43  import javax.swing.text.html.*;
44  import javax.swing.plaf.basic.*;
45  import java.util.*;
46  
47  
48  /**
49   * A display area for a short text string or an image,
50   * or both.
51   * A label does not react to input events.
52   * As a result, it cannot get the keyboard focus.
53   * A label can, however, display a keyboard alternative
54   * as a convenience for a nearby component
55   * that has a keyboard alternative but can't display it.
56   * <p>
57   * A <code>JLabel</code> object can display
58   * either text, an image, or both.
59   * You can specify where in the label's display area
60   * the label's contents are aligned
61   * by setting the vertical and horizontal alignment.
62   * By default, labels are vertically centered
63   * in their display area.
64   * Text-only labels are leading edge aligned, by default;
65   * image-only labels are horizontally centered, by default.
66   * <p>
67   * You can also specify the position of the text
68   * relative to the image.
69   * By default, text is on the trailing edge of the image,
70   * with the text and image vertically aligned.
71   * <p>
72   * A label's leading and trailing edge are determined from the value of its
73   * {@link java.awt.ComponentOrientation} property.  At present, the default
74   * ComponentOrientation setting maps the leading edge to left and the trailing
75   * edge to right.
76   *
77   * <p>
78   * Finally, you can use the <code>setIconTextGap</code> method
79   * to specify how many pixels
80   * should appear between the text and the image.
81   * The default is 4 pixels.
82   * <p>
83   * See <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/label.html">How to Use Labels</a>
84   * in <em>The Java Tutorial</em>
85   * for further documentation.
86   * <p>
87   * <strong>Warning:</strong> Swing is not thread safe. For more
88   * information see <a
89   * href="package-summary.html#threading">Swing's Threading
90   * Policy</a>.
91   * <p>
92   * <strong>Warning:</strong>
93   * Serialized objects of this class will not be compatible with
94   * future Swing releases. The current serialization support is
95   * appropriate for short term storage or RMI between applications running
96   * the same version of Swing.  As of 1.4, support for long term storage
97   * of all JavaBeans&trade;
98   * has been added to the <code>java.beans</code> package.
99   * Please see {@link java.beans.XMLEncoder}.
100  *
101  * @beaninfo
102  *   attribute: isContainer false
103  * description: A component that displays a short string and an icon.
104  *
105  * @author Hans Muller
106  */
107 @SuppressWarnings("serial")
108 public class JLabel extends JComponent implements SwingConstants, Accessible
109 {
110     /**
111      * @see #getUIClassID
112      * @see #readObject
113      */
114     private static final String uiClassID = "LabelUI";
115 
116     private int mnemonic = '\0';
117     private int mnemonicIndex = -1;
118 
119     private String text = "";         // "" rather than null, for BeanBox
120     private Icon defaultIcon = null;
121     private Icon disabledIcon = null;
122     private boolean disabledIconSet = false;
123 
124     private int verticalAlignment = CENTER;
125     private int horizontalAlignment = LEADING;
126     private int verticalTextPosition = CENTER;
127     private int horizontalTextPosition = TRAILING;
128     private int iconTextGap = 4;
129 
130     protected Component labelFor = null;
131 
132     /**
133      * Client property key used to determine what label is labeling the
134      * component.  This is generally not used by labels, but is instead
135      * used by components such as text areas that are being labeled by
136      * labels.  When the labelFor property of a label is set, it will
137      * automatically set the LABELED_BY_PROPERTY of the component being
138      * labelled.
139      *
140      * @see #setLabelFor
141      */
142     static final String LABELED_BY_PROPERTY = "labeledBy";
143 
144     /**
145      * Creates a <code>JLabel</code> instance with the specified
146      * text, image, and horizontal alignment.
147      * The label is centered vertically in its display area.
148      * The text is on the trailing edge of the image.
149      *
150      * @param text  The text to be displayed by the label.
151      * @param icon  The image to be displayed by the label.
152      * @param horizontalAlignment  One of the following constants
153      *           defined in <code>SwingConstants</code>:
154      *           <code>LEFT</code>,
155      *           <code>CENTER</code>,
156      *           <code>RIGHT</code>,
157      *           <code>LEADING</code> or
158      *           <code>TRAILING</code>.
159      */
160     public JLabel(String text, Icon icon, int horizontalAlignment) {
161         setText(text);
162         setIcon(icon);
163         setHorizontalAlignment(horizontalAlignment);
164         updateUI();
165         setAlignmentX(LEFT_ALIGNMENT);
166     }
167 
168     /**
169      * Creates a <code>JLabel</code> instance with the specified
170      * text and horizontal alignment.
171      * The label is centered vertically in its display area.
172      *
173      * @param text  The text to be displayed by the label.
174      * @param horizontalAlignment  One of the following constants
175      *           defined in <code>SwingConstants</code>:
176      *           <code>LEFT</code>,
177      *           <code>CENTER</code>,
178      *           <code>RIGHT</code>,
179      *           <code>LEADING</code> or
180      *           <code>TRAILING</code>.
181      */
182     public JLabel(String text, int horizontalAlignment) {
183         this(text, null, horizontalAlignment);
184     }
185 
186     /**
187      * Creates a <code>JLabel</code> instance with the specified text.
188      * The label is aligned against the leading edge of its display area,
189      * and centered vertically.
190      *
191      * @param text  The text to be displayed by the label.
192      */
193     public JLabel(String text) {
194         this(text, null, LEADING);
195     }
196 
197     /**
198      * Creates a <code>JLabel</code> instance with the specified
199      * image and horizontal alignment.
200      * The label is centered vertically in its display area.
201      *
202      * @param image  The image to be displayed by the label.
203      * @param horizontalAlignment  One of the following constants
204      *           defined in <code>SwingConstants</code>:
205      *           <code>LEFT</code>,
206      *           <code>CENTER</code>,
207      *           <code>RIGHT</code>,
208      *           <code>LEADING</code> or
209      *           <code>TRAILING</code>.
210      */
211     public JLabel(Icon image, int horizontalAlignment) {
212         this(null, image, horizontalAlignment);
213     }
214 
215     /**
216      * Creates a <code>JLabel</code> instance with the specified image.
217      * The label is centered vertically and horizontally
218      * in its display area.
219      *
220      * @param image  The image to be displayed by the label.
221      */
222     public JLabel(Icon image) {
223         this(null, image, CENTER);
224     }
225 
226     /**
227      * Creates a <code>JLabel</code> instance with
228      * no image and with an empty string for the title.
229      * The label is centered vertically
230      * in its display area.
231      * The label's contents, once set, will be displayed on the leading edge
232      * of the label's display area.
233      */
234     public JLabel() {
235         this("", null, LEADING);
236     }
237 
238 
239     /**
240      * Returns the L&amp;F object that renders this component.
241      *
242      * @return LabelUI object
243      */
244     public LabelUI getUI() {
245         return (LabelUI)ui;
246     }
247 
248 
249     /**
250      * Sets the L&amp;F object that renders this component.
251      *
252      * @param ui  the LabelUI L&amp;F object
253      * @see UIDefaults#getUI
254      * @beaninfo
255      *        bound: true
256      *       hidden: true
257      *    attribute: visualUpdate true
258      *  description: The UI object that implements the Component's LookAndFeel.
259      */
260     public void setUI(LabelUI ui) {
261         super.setUI(ui);
262         // disabled icon is generated by LF so it should be unset here
263         if (!disabledIconSet && disabledIcon != null) {
264             setDisabledIcon(null);
265         }
266     }
267 
268 
269     /**
270      * Resets the UI property to a value from the current look and feel.
271      *
272      * @see JComponent#updateUI
273      */
274     public void updateUI() {
275         setUI((LabelUI)UIManager.getUI(this));
276     }
277 
278 
279     /**
280      * Returns a string that specifies the name of the l&amp;f class
281      * that renders this component.
282      *
283      * @return String "LabelUI"
284      *
285      * @see JComponent#getUIClassID
286      * @see UIDefaults#getUI
287      */
288     public String getUIClassID() {
289         return uiClassID;
290     }
291 
292 
293     /**
294      * Returns the text string that the label displays.
295      *
296      * @return a String
297      * @see #setText
298      */
299     public String getText() {
300         return text;
301     }
302 
303 
304     /**
305      * Defines the single line of text this component will display.  If
306      * the value of text is null or empty string, nothing is displayed.
307      * <p>
308      * The default value of this property is null.
309      * <p>
310      * This is a JavaBeans bound property.
311      *
312      * @see #setVerticalTextPosition
313      * @see #setHorizontalTextPosition
314      * @see #setIcon
315      * @beaninfo
316      *    preferred: true
317      *        bound: true
318      *    attribute: visualUpdate true
319      *  description: Defines the single line of text this component will display.
320      */
321     public void setText(String text) {
322 
323         String oldAccessibleName = null;
324         if (accessibleContext != null) {
325             oldAccessibleName = accessibleContext.getAccessibleName();
326         }
327 
328         String oldValue = this.text;
329         this.text = text;
330         firePropertyChange("text", oldValue, text);
331 
332         setDisplayedMnemonicIndex(
333                       SwingUtilities.findDisplayedMnemonicIndex(
334                                           text, getDisplayedMnemonic()));
335 
336         if ((accessibleContext != null)
337             && (accessibleContext.getAccessibleName() != oldAccessibleName)) {
338                 accessibleContext.firePropertyChange(
339                         AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
340                         oldAccessibleName,
341                         accessibleContext.getAccessibleName());
342         }
343         if (text == null || oldValue == null || !text.equals(oldValue)) {
344             revalidate();
345             repaint();
346         }
347     }
348 
349 
350     /**
351      * Returns the graphic image (glyph, icon) that the label displays.
352      *
353      * @return an Icon
354      * @see #setIcon
355      */
356     public Icon getIcon() {
357         return defaultIcon;
358     }
359 
360     /**
361      * Defines the icon this component will display.  If
362      * the value of icon is null, nothing is displayed.
363      * <p>
364      * The default value of this property is null.
365      * <p>
366      * This is a JavaBeans bound property.
367      *
368      * @see #setVerticalTextPosition
369      * @see #setHorizontalTextPosition
370      * @see #getIcon
371      * @beaninfo
372      *    preferred: true
373      *        bound: true
374      *    attribute: visualUpdate true
375      *  description: The icon this component will display.
376      */
377     public void setIcon(Icon icon) {
378         Icon oldValue = defaultIcon;
379         defaultIcon = icon;
380 
381         /* If the default icon has really changed and we had
382          * generated the disabled icon for this component
383          * (in other words, setDisabledIcon() was never called), then
384          * clear the disabledIcon field.
385          */
386         if ((defaultIcon != oldValue) && !disabledIconSet) {
387             disabledIcon = null;
388         }
389 
390         firePropertyChange("icon", oldValue, defaultIcon);
391 
392         if ((accessibleContext != null) && (oldValue != defaultIcon)) {
393                 accessibleContext.firePropertyChange(
394                         AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
395                         oldValue, defaultIcon);
396         }
397 
398         /* If the default icon has changed and the new one is
399          * a different size, then revalidate.   Repaint if the
400          * default icon has changed.
401          */
402         if (defaultIcon != oldValue) {
403             if ((defaultIcon == null) ||
404                 (oldValue == null) ||
405                 (defaultIcon.getIconWidth() != oldValue.getIconWidth()) ||
406                 (defaultIcon.getIconHeight() != oldValue.getIconHeight())) {
407                 revalidate();
408             }
409             repaint();
410         }
411     }
412 
413 
414     /**
415      * Returns the icon used by the label when it's disabled.
416      * If no disabled icon has been set this will forward the call to
417      * the look and feel to construct an appropriate disabled Icon.
418      * <p>
419      * Some look and feels might not render the disabled Icon, in which
420      * case they will ignore this.
421      *
422      * @return the <code>disabledIcon</code> property
423      * @see #setDisabledIcon
424      * @see javax.swing.LookAndFeel#getDisabledIcon
425      * @see ImageIcon
426      */
427     @Transient
428     public Icon getDisabledIcon() {
429         if (!disabledIconSet && disabledIcon == null && defaultIcon != null) {
430             disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, defaultIcon);
431             if (disabledIcon != null) {
432                 firePropertyChange("disabledIcon", null, disabledIcon);
433             }
434         }
435         return disabledIcon;
436     }
437 
438 
439     /**
440      * Set the icon to be displayed if this JLabel is "disabled"
441      * (JLabel.setEnabled(false)).
442      * <p>
443      * The default value of this property is null.
444      *
445      * @param disabledIcon the Icon to display when the component is disabled
446      * @see #getDisabledIcon
447      * @see #setEnabled
448      * @beaninfo
449      *        bound: true
450      *    attribute: visualUpdate true
451      *  description: The icon to display if the label is disabled.
452      */
453     public void setDisabledIcon(Icon disabledIcon) {
454         Icon oldValue = this.disabledIcon;
455         this.disabledIcon = disabledIcon;
456         disabledIconSet = (disabledIcon != null);
457         firePropertyChange("disabledIcon", oldValue, disabledIcon);
458         if (disabledIcon != oldValue) {
459             if (disabledIcon == null || oldValue == null ||
460                 disabledIcon.getIconWidth() != oldValue.getIconWidth() ||
461                 disabledIcon.getIconHeight() != oldValue.getIconHeight()) {
462                 revalidate();
463             }
464             if (!isEnabled()) {
465                 repaint();
466             }
467         }
468     }
469 
470 
471     /**
472      * Specify a keycode that indicates a mnemonic key.
473      * This property is used when the label is part of a larger component.
474      * If the labelFor property of the label is not null, the label will
475      * call the requestFocus method of the component specified by the
476      * labelFor property when the mnemonic is activated.
477      *
478      * @see #getLabelFor
479      * @see #setLabelFor
480      * @beaninfo
481      *        bound: true
482      *    attribute: visualUpdate true
483      *  description: The mnemonic keycode.
484      */
485     public void setDisplayedMnemonic(int key) {
486         int oldKey = mnemonic;
487         mnemonic = key;
488         firePropertyChange("displayedMnemonic", oldKey, mnemonic);
489 
490         setDisplayedMnemonicIndex(
491             SwingUtilities.findDisplayedMnemonicIndex(getText(), mnemonic));
492 
493         if (key != oldKey) {
494             revalidate();
495             repaint();
496         }
497     }
498 
499 
500     /**
501      * Specifies the displayedMnemonic as a char value.
502      *
503      * @param aChar  a char specifying the mnemonic to display
504      * @see #setDisplayedMnemonic(int)
505      */
506     public void setDisplayedMnemonic(char aChar) {
507         int vk = java.awt.event.KeyEvent.getExtendedKeyCodeForChar(aChar);
508         if (vk != java.awt.event.KeyEvent.VK_UNDEFINED) {
509             setDisplayedMnemonic(vk);
510         }
511     }
512 
513 
514     /**
515      * Return the keycode that indicates a mnemonic key.
516      * This property is used when the label is part of a larger component.
517      * If the labelFor property of the label is not null, the label will
518      * call the requestFocus method of the component specified by the
519      * labelFor property when the mnemonic is activated.
520      *
521      * @return int value for the mnemonic key
522      *
523      * @see #getLabelFor
524      * @see #setLabelFor
525      */
526     public int getDisplayedMnemonic() {
527         return mnemonic;
528     }
529 
530     /**
531      * Provides a hint to the look and feel as to which character in the
532      * text should be decorated to represent the mnemonic. Not all look and
533      * feels may support this. A value of -1 indicates either there is no
534      * mnemonic, the mnemonic character is not contained in the string, or
535      * the developer does not wish the mnemonic to be displayed.
536      * <p>
537      * The value of this is updated as the properties relating to the
538      * mnemonic change (such as the mnemonic itself, the text...).
539      * You should only ever have to call this if
540      * you do not wish the default character to be underlined. For example, if
541      * the text was 'Save As', with a mnemonic of 'a', and you wanted the 'A'
542      * to be decorated, as 'Save <u>A</u>s', you would have to invoke
543      * <code>setDisplayedMnemonicIndex(5)</code> after invoking
544      * <code>setDisplayedMnemonic(KeyEvent.VK_A)</code>.
545      *
546      * @since 1.4
547      * @param index Index into the String to underline
548      * @exception IllegalArgumentException will be thrown if <code>index</code>
549      *            is &gt;= length of the text, or &lt; -1
550      *
551      * @beaninfo
552      *        bound: true
553      *    attribute: visualUpdate true
554      *  description: the index into the String to draw the keyboard character
555      *               mnemonic at
556      */
557     public void setDisplayedMnemonicIndex(int index)
558                                              throws IllegalArgumentException {
559         int oldValue = mnemonicIndex;
560         if (index == -1) {
561             mnemonicIndex = -1;
562         } else {
563             String text = getText();
564             int textLength = (text == null) ? 0 : text.length();
565             if (index < -1 || index >= textLength) {  // index out of range
566                 throw new IllegalArgumentException("index == " + index);
567             }
568         }
569         mnemonicIndex = index;
570         firePropertyChange("displayedMnemonicIndex", oldValue, index);
571         if (index != oldValue) {
572             revalidate();
573             repaint();
574         }
575     }
576 
577     /**
578      * Returns the character, as an index, that the look and feel should
579      * provide decoration for as representing the mnemonic character.
580      *
581      * @since 1.4
582      * @return index representing mnemonic character
583      * @see #setDisplayedMnemonicIndex
584      */
585     public int getDisplayedMnemonicIndex() {
586         return mnemonicIndex;
587     }
588 
589     /**
590      * Verify that key is a legal value for the horizontalAlignment properties.
591      *
592      * @param key the property value to check
593      * @param message the IllegalArgumentException detail message
594      * @exception IllegalArgumentException if key isn't LEFT, CENTER, RIGHT,
595      * LEADING or TRAILING.
596      * @see #setHorizontalTextPosition
597      * @see #setHorizontalAlignment
598      */
599     protected int checkHorizontalKey(int key, String message) {
600         if ((key == LEFT) ||
601             (key == CENTER) ||
602             (key == RIGHT) ||
603             (key == LEADING) ||
604             (key == TRAILING)) {
605             return key;
606         }
607         else {
608             throw new IllegalArgumentException(message);
609         }
610     }
611 
612 
613     /**
614      * Verify that key is a legal value for the
615      * verticalAlignment or verticalTextPosition properties.
616      *
617      * @param key the property value to check
618      * @param message the IllegalArgumentException detail message
619      * @exception IllegalArgumentException if key isn't TOP, CENTER, or BOTTOM.
620      * @see #setVerticalAlignment
621      * @see #setVerticalTextPosition
622      */
623     protected int checkVerticalKey(int key, String message) {
624         if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
625             return key;
626         }
627         else {
628             throw new IllegalArgumentException(message);
629         }
630     }
631 
632 
633     /**
634      * Returns the amount of space between the text and the icon
635      * displayed in this label.
636      *
637      * @return an int equal to the number of pixels between the text
638      *         and the icon.
639      * @see #setIconTextGap
640      */
641     public int getIconTextGap() {
642         return iconTextGap;
643     }
644 
645 
646     /**
647      * If both the icon and text properties are set, this property
648      * defines the space between them.
649      * <p>
650      * The default value of this property is 4 pixels.
651      * <p>
652      * This is a JavaBeans bound property.
653      *
654      * @see #getIconTextGap
655      * @beaninfo
656      *        bound: true
657      *    attribute: visualUpdate true
658      *  description: If both the icon and text properties are set, this
659      *               property defines the space between them.
660      */
661     public void setIconTextGap(int iconTextGap) {
662         int oldValue = this.iconTextGap;
663         this.iconTextGap = iconTextGap;
664         firePropertyChange("iconTextGap", oldValue, iconTextGap);
665         if (iconTextGap != oldValue) {
666             revalidate();
667             repaint();
668         }
669     }
670 
671 
672 
673     /**
674      * Returns the alignment of the label's contents along the Y axis.
675      *
676      * @return   The value of the verticalAlignment property, one of the
677      *           following constants defined in <code>SwingConstants</code>:
678      *           <code>TOP</code>,
679      *           <code>CENTER</code>, or
680      *           <code>BOTTOM</code>.
681      *
682      * @see SwingConstants
683      * @see #setVerticalAlignment
684      */
685     public int getVerticalAlignment() {
686         return verticalAlignment;
687     }
688 
689 
690     /**
691      * Sets the alignment of the label's contents along the Y axis.
692      * <p>
693      * The default value of this property is CENTER.
694      *
695      * @param alignment One of the following constants
696      *           defined in <code>SwingConstants</code>:
697      *           <code>TOP</code>,
698      *           <code>CENTER</code> (the default), or
699      *           <code>BOTTOM</code>.
700      *
701      * @see SwingConstants
702      * @see #getVerticalAlignment
703      * @beaninfo
704      *        bound: true
705      *         enum: TOP    SwingConstants.TOP
706      *               CENTER SwingConstants.CENTER
707      *               BOTTOM SwingConstants.BOTTOM
708      *    attribute: visualUpdate true
709      *  description: The alignment of the label's contents along the Y axis.
710      */
711     public void setVerticalAlignment(int alignment) {
712         if (alignment == verticalAlignment) return;
713         int oldValue = verticalAlignment;
714         verticalAlignment = checkVerticalKey(alignment, "verticalAlignment");
715         firePropertyChange("verticalAlignment", oldValue, verticalAlignment);
716         repaint();
717     }
718 
719 
720     /**
721      * Returns the alignment of the label's contents along the X axis.
722      *
723      * @return   The value of the horizontalAlignment property, one of the
724      *           following constants defined in <code>SwingConstants</code>:
725      *           <code>LEFT</code>,
726      *           <code>CENTER</code>,
727      *           <code>RIGHT</code>,
728      *           <code>LEADING</code> or
729      *           <code>TRAILING</code>.
730      *
731      * @see #setHorizontalAlignment
732      * @see SwingConstants
733      */
734     public int getHorizontalAlignment() {
735         return horizontalAlignment;
736     }
737 
738     /**
739      * Sets the alignment of the label's contents along the X axis.
740      * <p>
741      * This is a JavaBeans bound property.
742      *
743      * @param alignment  One of the following constants
744      *           defined in <code>SwingConstants</code>:
745      *           <code>LEFT</code>,
746      *           <code>CENTER</code> (the default for image-only labels),
747      *           <code>RIGHT</code>,
748      *           <code>LEADING</code> (the default for text-only labels) or
749      *           <code>TRAILING</code>.
750      *
751      * @see SwingConstants
752      * @see #getHorizontalAlignment
753      * @beaninfo
754      *        bound: true
755      *         enum: LEFT     SwingConstants.LEFT
756      *               CENTER   SwingConstants.CENTER
757      *               RIGHT    SwingConstants.RIGHT
758      *               LEADING  SwingConstants.LEADING
759      *               TRAILING SwingConstants.TRAILING
760      *    attribute: visualUpdate true
761      *  description: The alignment of the label's content along the X axis.
762      */
763     public void setHorizontalAlignment(int alignment) {
764         if (alignment == horizontalAlignment) return;
765         int oldValue = horizontalAlignment;
766         horizontalAlignment = checkHorizontalKey(alignment,
767                                                  "horizontalAlignment");
768         firePropertyChange("horizontalAlignment",
769                            oldValue, horizontalAlignment);
770         repaint();
771     }
772 
773 
774     /**
775      * Returns the vertical position of the label's text,
776      * relative to its image.
777      *
778      * @return   One of the following constants
779      *           defined in <code>SwingConstants</code>:
780      *           <code>TOP</code>,
781      *           <code>CENTER</code>, or
782      *           <code>BOTTOM</code>.
783      *
784      * @see #setVerticalTextPosition
785      * @see SwingConstants
786      */
787     public int getVerticalTextPosition() {
788         return verticalTextPosition;
789     }
790 
791 
792     /**
793      * Sets the vertical position of the label's text,
794      * relative to its image.
795      * <p>
796      * The default value of this property is CENTER.
797      * <p>
798      * This is a JavaBeans bound property.
799      *
800      * @param textPosition  One of the following constants
801      *           defined in <code>SwingConstants</code>:
802      *           <code>TOP</code>,
803      *           <code>CENTER</code> (the default), or
804      *           <code>BOTTOM</code>.
805      *
806      * @see SwingConstants
807      * @see #getVerticalTextPosition
808      * @beaninfo
809      *        bound: true
810      *         enum: TOP    SwingConstants.TOP
811      *               CENTER SwingConstants.CENTER
812      *               BOTTOM SwingConstants.BOTTOM
813      *       expert: true
814      *    attribute: visualUpdate true
815      *  description: The vertical position of the text relative to it's image.
816      */
817     public void setVerticalTextPosition(int textPosition) {
818         if (textPosition == verticalTextPosition) return;
819         int old = verticalTextPosition;
820         verticalTextPosition = checkVerticalKey(textPosition,
821                                                 "verticalTextPosition");
822         firePropertyChange("verticalTextPosition", old, verticalTextPosition);
823         revalidate();
824         repaint();
825     }
826 
827 
828     /**
829      * Returns the horizontal position of the label's text,
830      * relative to its image.
831      *
832      * @return   One of the following constants
833      *           defined in <code>SwingConstants</code>:
834      *           <code>LEFT</code>,
835      *           <code>CENTER</code>,
836      *           <code>RIGHT</code>,
837      *           <code>LEADING</code> or
838      *           <code>TRAILING</code>.
839      *
840      * @see SwingConstants
841      */
842     public int getHorizontalTextPosition() {
843         return horizontalTextPosition;
844     }
845 
846 
847     /**
848      * Sets the horizontal position of the label's text,
849      * relative to its image.
850      *
851      * @param textPosition  One of the following constants
852      *           defined in <code>SwingConstants</code>:
853      *           <code>LEFT</code>,
854      *           <code>CENTER</code>,
855      *           <code>RIGHT</code>,
856      *           <code>LEADING</code>, or
857      *           <code>TRAILING</code> (the default).
858      * @exception IllegalArgumentException
859      *
860      * @see SwingConstants
861      * @beaninfo
862      *       expert: true
863      *        bound: true
864      *         enum: LEFT     SwingConstants.LEFT
865      *               CENTER   SwingConstants.CENTER
866      *               RIGHT    SwingConstants.RIGHT
867      *               LEADING  SwingConstants.LEADING
868      *               TRAILING SwingConstants.TRAILING
869      *    attribute: visualUpdate true
870      *  description: The horizontal position of the label's text,
871      *               relative to its image.
872      */
873     public void setHorizontalTextPosition(int textPosition) {
874         int old = horizontalTextPosition;
875         this.horizontalTextPosition = checkHorizontalKey(textPosition,
876                                                 "horizontalTextPosition");
877         firePropertyChange("horizontalTextPosition",
878                            old, horizontalTextPosition);
879         revalidate();
880         repaint();
881     }
882 
883 
884     /**
885      * This is overridden to return false if the current Icon's Image is
886      * not equal to the passed in Image <code>img</code>.
887      *
888      * @see     java.awt.image.ImageObserver
889      * @see     java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int, int)
890      */
891     public boolean imageUpdate(Image img, int infoflags,
892                                int x, int y, int w, int h) {
893         // Don't use getDisabledIcon, will trigger creation of icon if icon
894         // not set.
895         if (!isShowing() ||
896             !SwingUtilities.doesIconReferenceImage(getIcon(), img) &&
897             !SwingUtilities.doesIconReferenceImage(disabledIcon, img)) {
898 
899             return false;
900         }
901         return super.imageUpdate(img, infoflags, x, y, w, h);
902     }
903 
904 
905     /**
906      * See readObject() and writeObject() in JComponent for more
907      * information about serialization in Swing.
908      */
909     private void writeObject(ObjectOutputStream s) throws IOException {
910         s.defaultWriteObject();
911         if (getUIClassID().equals(uiClassID)) {
912             byte count = JComponent.getWriteObjCounter(this);
913             JComponent.setWriteObjCounter(this, --count);
914             if (count == 0 && ui != null) {
915                 ui.installUI(this);
916             }
917         }
918     }
919 
920 
921     /**
922      * Returns a string representation of this JLabel. This method
923      * is intended to be used only for debugging purposes, and the
924      * content and format of the returned string may vary between
925      * implementations. The returned string may be empty but may not
926      * be <code>null</code>.
927      *
928      * @return  a string representation of this JLabel.
929      */
930     protected String paramString() {
931         String textString = (text != null ?
932                              text : "");
933         String defaultIconString = ((defaultIcon != null)
934                                     && (defaultIcon != this)  ?
935                                     defaultIcon.toString() : "");
936         String disabledIconString = ((disabledIcon != null)
937                                      && (disabledIcon != this) ?
938                                      disabledIcon.toString() : "");
939         String labelForString = (labelFor  != null ?
940                                  labelFor.toString() : "");
941         String verticalAlignmentString;
942         if (verticalAlignment == TOP) {
943             verticalAlignmentString = "TOP";
944         } else if (verticalAlignment == CENTER) {
945             verticalAlignmentString = "CENTER";
946         } else if (verticalAlignment == BOTTOM) {
947             verticalAlignmentString = "BOTTOM";
948         } else verticalAlignmentString = "";
949         String horizontalAlignmentString;
950         if (horizontalAlignment == LEFT) {
951             horizontalAlignmentString = "LEFT";
952         } else if (horizontalAlignment == CENTER) {
953             horizontalAlignmentString = "CENTER";
954         } else if (horizontalAlignment == RIGHT) {
955             horizontalAlignmentString = "RIGHT";
956         } else if (horizontalAlignment == LEADING) {
957             horizontalAlignmentString = "LEADING";
958         } else if (horizontalAlignment == TRAILING) {
959             horizontalAlignmentString = "TRAILING";
960         } else horizontalAlignmentString = "";
961         String verticalTextPositionString;
962         if (verticalTextPosition == TOP) {
963             verticalTextPositionString = "TOP";
964         } else if (verticalTextPosition == CENTER) {
965             verticalTextPositionString = "CENTER";
966         } else if (verticalTextPosition == BOTTOM) {
967             verticalTextPositionString = "BOTTOM";
968         } else verticalTextPositionString = "";
969         String horizontalTextPositionString;
970         if (horizontalTextPosition == LEFT) {
971             horizontalTextPositionString = "LEFT";
972         } else if (horizontalTextPosition == CENTER) {
973             horizontalTextPositionString = "CENTER";
974         } else if (horizontalTextPosition == RIGHT) {
975             horizontalTextPositionString = "RIGHT";
976         } else if (horizontalTextPosition == LEADING) {
977             horizontalTextPositionString = "LEADING";
978         } else if (horizontalTextPosition == TRAILING) {
979             horizontalTextPositionString = "TRAILING";
980         } else horizontalTextPositionString = "";
981 
982         return super.paramString() +
983         ",defaultIcon=" + defaultIconString +
984         ",disabledIcon=" + disabledIconString +
985         ",horizontalAlignment=" + horizontalAlignmentString +
986         ",horizontalTextPosition=" + horizontalTextPositionString +
987         ",iconTextGap=" + iconTextGap +
988         ",labelFor=" + labelForString +
989         ",text=" + textString +
990         ",verticalAlignment=" + verticalAlignmentString +
991         ",verticalTextPosition=" + verticalTextPositionString;
992     }
993 
994     /**
995      * --- Accessibility Support ---
996      */
997 
998     /**
999      * Get the component this is labelling.
1000      *
1001      * @return the Component this is labelling.  Can be null if this
1002      * does not label a Component.  If the displayedMnemonic
1003      * property is set and the labelFor property is also set, the label
1004      * will call the requestFocus method of the component specified by the
1005      * labelFor property when the mnemonic is activated.
1006      *
1007      * @see #getDisplayedMnemonic
1008      * @see #setDisplayedMnemonic
1009      */
1010     public Component getLabelFor() {
1011         return labelFor;
1012     }
1013 
1014     /**
1015      * Set the component this is labelling.  Can be null if this does not
1016      * label a Component.  If the displayedMnemonic property is set
1017      * and the labelFor property is also set, the label will
1018      * call the requestFocus method of the component specified by the
1019      * labelFor property when the mnemonic is activated.
1020      *
1021      * @param c  the Component this label is for, or null if the label is
1022      *           not the label for a component
1023      *
1024      * @see #getDisplayedMnemonic
1025      * @see #setDisplayedMnemonic
1026      *
1027      * @beaninfo
1028      *        bound: true
1029      *  description: The component this is labelling.
1030      */
1031     public void setLabelFor(Component c) {
1032         Component oldC = labelFor;
1033         labelFor = c;
1034         firePropertyChange("labelFor", oldC, c);
1035 
1036         if (oldC instanceof JComponent) {
1037             ((JComponent)oldC).putClientProperty(LABELED_BY_PROPERTY, null);
1038         }
1039         if (c instanceof JComponent) {
1040             ((JComponent)c).putClientProperty(LABELED_BY_PROPERTY, this);
1041         }
1042     }
1043 
1044     /**
1045      * Get the AccessibleContext of this object
1046      *
1047      * @return the AccessibleContext of this object
1048      * @beaninfo
1049      *       expert: true
1050      *  description: The AccessibleContext associated with this Label.
1051      */
1052     public AccessibleContext getAccessibleContext() {
1053         if (accessibleContext == null) {
1054             accessibleContext = new AccessibleJLabel();
1055         }
1056         return accessibleContext;
1057     }
1058 
1059     /**
1060      * The class used to obtain the accessible role for this object.
1061      * <p>
1062      * <strong>Warning:</strong>
1063      * Serialized objects of this class will not be compatible with
1064      * future Swing releases. The current serialization support is
1065      * appropriate for short term storage or RMI between applications running
1066      * the same version of Swing.  As of 1.4, support for long term storage
1067      * of all JavaBeans&trade;
1068      * has been added to the <code>java.beans</code> package.
1069      * Please see {@link java.beans.XMLEncoder}.
1070      */
1071     @SuppressWarnings("serial")
1072     protected class AccessibleJLabel extends AccessibleJComponent
1073         implements AccessibleText, AccessibleExtendedComponent {
1074 
1075         /**
1076          * Get the accessible name of this object.
1077          *
1078          * @return the localized name of the object -- can be null if this
1079          * object does not have a name
1080          * @see AccessibleContext#setAccessibleName
1081          */
1082         public String getAccessibleName() {
1083             String name = accessibleName;
1084 
1085             if (name == null) {
1086                 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
1087             }
1088             if (name == null) {
1089                 name = JLabel.this.getText();
1090             }
1091             if (name == null) {
1092                 name = super.getAccessibleName();
1093             }
1094             return name;
1095         }
1096 
1097         /**
1098          * Get the role of this object.
1099          *
1100          * @return an instance of AccessibleRole describing the role of the
1101          * object
1102          * @see AccessibleRole
1103          */
1104         public AccessibleRole getAccessibleRole() {
1105             return AccessibleRole.LABEL;
1106         }
1107 
1108         /**
1109          * Get the AccessibleIcons associated with this object if one
1110          * or more exist.  Otherwise return null.
1111          * @since 1.3
1112          */
1113         public AccessibleIcon [] getAccessibleIcon() {
1114             Icon icon = getIcon();
1115             if (icon instanceof Accessible) {
1116                 AccessibleContext ac =
1117                 ((Accessible)icon).getAccessibleContext();
1118                 if (ac != null && ac instanceof AccessibleIcon) {
1119                     return new AccessibleIcon[] { (AccessibleIcon)ac };
1120                 }
1121             }
1122             return null;
1123         }
1124 
1125         /**
1126          * Get the AccessibleRelationSet associated with this object if one
1127          * exists.  Otherwise return null.
1128          * @see AccessibleRelation
1129          * @since 1.3
1130          */
1131         public AccessibleRelationSet getAccessibleRelationSet() {
1132             // Check where the AccessibleContext's relation
1133             // set already contains a LABEL_FOR relation.
1134             AccessibleRelationSet relationSet
1135                 = super.getAccessibleRelationSet();
1136 
1137             if (!relationSet.contains(AccessibleRelation.LABEL_FOR)) {
1138                 Component c = JLabel.this.getLabelFor();
1139                 if (c != null) {
1140                     AccessibleRelation relation
1141                         = new AccessibleRelation(AccessibleRelation.LABEL_FOR);
1142                     relation.setTarget(c);
1143                     relationSet.add(relation);
1144                 }
1145             }
1146             return relationSet;
1147         }
1148 
1149 
1150         /* AccessibleText ---------- */
1151 
1152         public AccessibleText getAccessibleText() {
1153             View view = (View)JLabel.this.getClientProperty("html");
1154             if (view != null) {
1155                 return this;
1156             } else {
1157                 return null;
1158             }
1159         }
1160 
1161         /**
1162          * Given a point in local coordinates, return the zero-based index
1163          * of the character under that Point.  If the point is invalid,
1164          * this method returns -1.
1165          *
1166          * @param p the Point in local coordinates
1167          * @return the zero-based index of the character under Point p; if
1168          * Point is invalid returns -1.
1169          * @since 1.3
1170          */
1171         public int getIndexAtPoint(Point p) {
1172             View view = (View) JLabel.this.getClientProperty("html");
1173             if (view != null) {
1174                 Rectangle r = getTextRectangle();
1175                 if (r == null) {
1176                     return -1;
1177                 }
1178                 Rectangle2D.Float shape =
1179                     new Rectangle2D.Float(r.x, r.y, r.width, r.height);
1180                 Position.Bias bias[] = new Position.Bias[1];
1181                 return view.viewToModel(p.x, p.y, shape, bias);
1182             } else {
1183                 return -1;
1184             }
1185         }
1186 
1187         /**
1188          * Returns the bounding box of the character at the given
1189          * index in the string.  The bounds are returned in local
1190          * coordinates. If the index is invalid, <code>null</code> is returned.
1191          *
1192          * @param i the index into the String
1193          * @return the screen coordinates of the character's bounding box.
1194          * If the index is invalid, <code>null</code> is returned.
1195          * @since 1.3
1196          */
1197         public Rectangle getCharacterBounds(int i) {
1198             View view = (View) JLabel.this.getClientProperty("html");
1199             if (view != null) {
1200                 Rectangle r = getTextRectangle();
1201         if (r == null) {
1202             return null;
1203         }
1204                 Rectangle2D.Float shape =
1205                     new Rectangle2D.Float(r.x, r.y, r.width, r.height);
1206                 try {
1207                     Shape charShape =
1208                         view.modelToView(i, shape, Position.Bias.Forward);
1209                     return charShape.getBounds();
1210                 } catch (BadLocationException e) {
1211                     return null;
1212                 }
1213             } else {
1214                 return null;
1215             }
1216         }
1217 
1218         /**
1219          * Return the number of characters (valid indicies)
1220          *
1221          * @return the number of characters
1222          * @since 1.3
1223          */
1224         public int getCharCount() {
1225             View view = (View) JLabel.this.getClientProperty("html");
1226             if (view != null) {
1227                 Document d = view.getDocument();
1228                 if (d instanceof StyledDocument) {
1229                     StyledDocument doc = (StyledDocument)d;
1230                     return doc.getLength();
1231                 }
1232             }
1233             return accessibleContext.getAccessibleName().length();
1234         }
1235 
1236         /**
1237          * Return the zero-based offset of the caret.
1238          *
1239          * Note: That to the right of the caret will have the same index
1240          * value as the offset (the caret is between two characters).
1241          * @return the zero-based offset of the caret.
1242          * @since 1.3
1243          */
1244         public int getCaretPosition() {
1245             // There is no caret.
1246             return -1;
1247         }
1248 
1249         /**
1250          * Returns the String at a given index.
1251          *
1252          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1253          * or AccessibleText.SENTENCE to retrieve
1254          * @param index an index within the text &gt;= 0
1255          * @return the letter, word, or sentence,
1256          *   null for an invalid index or part
1257          * @since 1.3
1258          */
1259         public String getAtIndex(int part, int index) {
1260             if (index < 0 || index >= getCharCount()) {
1261                 return null;
1262             }
1263             switch (part) {
1264             case AccessibleText.CHARACTER:
1265                 try {
1266                     return getText(index, 1);
1267                 } catch (BadLocationException e) {
1268                     return null;
1269                 }
1270             case AccessibleText.WORD:
1271                 try {
1272                     String s = getText(0, getCharCount());
1273                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
1274                     words.setText(s);
1275                     int end = words.following(index);
1276                     return s.substring(words.previous(), end);
1277                 } catch (BadLocationException e) {
1278                     return null;
1279                 }
1280             case AccessibleText.SENTENCE:
1281                 try {
1282                     String s = getText(0, getCharCount());
1283                     BreakIterator sentence =
1284                         BreakIterator.getSentenceInstance(getLocale());
1285                     sentence.setText(s);
1286                     int end = sentence.following(index);
1287                     return s.substring(sentence.previous(), end);
1288                 } catch (BadLocationException e) {
1289                     return null;
1290                 }
1291             default:
1292                 return null;
1293             }
1294         }
1295 
1296         /**
1297          * Returns the String after a given index.
1298          *
1299          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1300          * or AccessibleText.SENTENCE to retrieve
1301          * @param index an index within the text &gt;= 0
1302          * @return the letter, word, or sentence, null for an invalid
1303          *  index or part
1304          * @since 1.3
1305          */
1306         public String getAfterIndex(int part, int index) {
1307             if (index < 0 || index >= getCharCount()) {
1308                 return null;
1309             }
1310             switch (part) {
1311             case AccessibleText.CHARACTER:
1312                 if (index+1 >= getCharCount()) {
1313                    return null;
1314                 }
1315                 try {
1316                     return getText(index+1, 1);
1317                 } catch (BadLocationException e) {
1318                     return null;
1319                 }
1320             case AccessibleText.WORD:
1321                 try {
1322                     String s = getText(0, getCharCount());
1323                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
1324                     words.setText(s);
1325                     int start = words.following(index);
1326                     if (start == BreakIterator.DONE || start >= s.length()) {
1327                         return null;
1328                     }
1329                     int end = words.following(start);
1330                     if (end == BreakIterator.DONE || end >= s.length()) {
1331                         return null;
1332                     }
1333                     return s.substring(start, end);
1334                 } catch (BadLocationException e) {
1335                     return null;
1336                 }
1337             case AccessibleText.SENTENCE:
1338                 try {
1339                     String s = getText(0, getCharCount());
1340                     BreakIterator sentence =
1341                         BreakIterator.getSentenceInstance(getLocale());
1342                     sentence.setText(s);
1343                     int start = sentence.following(index);
1344                     if (start == BreakIterator.DONE || start > s.length()) {
1345                         return null;
1346                     }
1347                     int end = sentence.following(start);
1348                     if (end == BreakIterator.DONE || end > s.length()) {
1349                         return null;
1350                     }
1351                     return s.substring(start, end);
1352                 } catch (BadLocationException e) {
1353                     return null;
1354                 }
1355             default:
1356                 return null;
1357             }
1358         }
1359 
1360         /**
1361          * Returns the String before a given index.
1362          *
1363          * @param part the AccessibleText.CHARACTER, AccessibleText.WORD,
1364          *   or AccessibleText.SENTENCE to retrieve
1365          * @param index an index within the text &gt;= 0
1366          * @return the letter, word, or sentence, null for an invalid index
1367          *  or part
1368          * @since 1.3
1369          */
1370         public String getBeforeIndex(int part, int index) {
1371             if (index < 0 || index > getCharCount()-1) {
1372                 return null;
1373             }
1374             switch (part) {
1375             case AccessibleText.CHARACTER:
1376                 if (index == 0) {
1377                     return null;
1378                 }
1379                 try {
1380                     return getText(index-1, 1);
1381                 } catch (BadLocationException e) {
1382                     return null;
1383                 }
1384             case AccessibleText.WORD:
1385                 try {
1386                     String s = getText(0, getCharCount());
1387                     BreakIterator words = BreakIterator.getWordInstance(getLocale());
1388                     words.setText(s);
1389                     int end = words.following(index);
1390                     end = words.previous();
1391                     int start = words.previous();
1392                     if (start == BreakIterator.DONE) {
1393                         return null;
1394                     }
1395                     return s.substring(start, end);
1396                 } catch (BadLocationException e) {
1397                     return null;
1398                 }
1399             case AccessibleText.SENTENCE:
1400                 try {
1401                     String s = getText(0, getCharCount());
1402                     BreakIterator sentence =
1403                         BreakIterator.getSentenceInstance(getLocale());
1404                     sentence.setText(s);
1405                     int end = sentence.following(index);
1406                     end = sentence.previous();
1407                     int start = sentence.previous();
1408                     if (start == BreakIterator.DONE) {
1409                         return null;
1410                     }
1411                     return s.substring(start, end);
1412                 } catch (BadLocationException e) {
1413                     return null;
1414                 }
1415             default:
1416                 return null;
1417             }
1418         }
1419 
1420         /**
1421          * Return the AttributeSet for a given character at a given index
1422          *
1423          * @param i the zero-based index into the text
1424          * @return the AttributeSet of the character
1425          * @since 1.3
1426          */
1427         public AttributeSet getCharacterAttribute(int i) {
1428             View view = (View) JLabel.this.getClientProperty("html");
1429             if (view != null) {
1430                 Document d = view.getDocument();
1431                 if (d instanceof StyledDocument) {
1432                     StyledDocument doc = (StyledDocument)d;
1433                     Element elem = doc.getCharacterElement(i);
1434                     if (elem != null) {
1435                         return elem.getAttributes();
1436                     }
1437                 }
1438             }
1439             return null;
1440         }
1441 
1442         /**
1443          * Returns the start offset within the selected text.
1444          * If there is no selection, but there is
1445          * a caret, the start and end offsets will be the same.
1446          *
1447          * @return the index into the text of the start of the selection
1448          * @since 1.3
1449          */
1450         public int getSelectionStart() {
1451             // Text cannot be selected.
1452             return -1;
1453         }
1454 
1455         /**
1456          * Returns the end offset within the selected text.
1457          * If there is no selection, but there is
1458          * a caret, the start and end offsets will be the same.
1459          *
1460          * @return the index into the text of the end of the selection
1461          * @since 1.3
1462          */
1463         public int getSelectionEnd() {
1464             // Text cannot be selected.
1465             return -1;
1466         }
1467 
1468         /**
1469          * Returns the portion of the text that is selected.
1470          *
1471          * @return the String portion of the text that is selected
1472          * @since 1.3
1473          */
1474         public String getSelectedText() {
1475             // Text cannot be selected.
1476             return null;
1477         }
1478 
1479         /*
1480          * Returns the text substring starting at the specified
1481          * offset with the specified length.
1482          */
1483         private String getText(int offset, int length)
1484             throws BadLocationException {
1485 
1486             View view = (View) JLabel.this.getClientProperty("html");
1487             if (view != null) {
1488                 Document d = view.getDocument();
1489                 if (d instanceof StyledDocument) {
1490                     StyledDocument doc = (StyledDocument)d;
1491                     return doc.getText(offset, length);
1492                 }
1493             }
1494             return null;
1495         }
1496 
1497         /*
1498          * Returns the bounding rectangle for the component text.
1499          */
1500         private Rectangle getTextRectangle() {
1501 
1502             String text = JLabel.this.getText();
1503             Icon icon = (JLabel.this.isEnabled()) ? JLabel.this.getIcon() : JLabel.this.getDisabledIcon();
1504 
1505             if ((icon == null) && (text == null)) {
1506                 return null;
1507             }
1508 
1509             Rectangle paintIconR = new Rectangle();
1510             Rectangle paintTextR = new Rectangle();
1511             Rectangle paintViewR = new Rectangle();
1512             Insets paintViewInsets = new Insets(0, 0, 0, 0);
1513 
1514             paintViewInsets = JLabel.this.getInsets(paintViewInsets);
1515             paintViewR.x = paintViewInsets.left;
1516             paintViewR.y = paintViewInsets.top;
1517             paintViewR.width = JLabel.this.getWidth() - (paintViewInsets.left + paintViewInsets.right);
1518             paintViewR.height = JLabel.this.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
1519 
1520             String clippedText = SwingUtilities.layoutCompoundLabel(
1521                 (JComponent)JLabel.this,
1522                 getFontMetrics(getFont()),
1523                 text,
1524                 icon,
1525                 JLabel.this.getVerticalAlignment(),
1526                 JLabel.this.getHorizontalAlignment(),
1527                 JLabel.this.getVerticalTextPosition(),
1528                 JLabel.this.getHorizontalTextPosition(),
1529                 paintViewR,
1530                 paintIconR,
1531                 paintTextR,
1532                 JLabel.this.getIconTextGap());
1533 
1534             return paintTextR;
1535         }
1536 
1537         // ----- AccessibleExtendedComponent
1538 
1539         /**
1540          * Returns the AccessibleExtendedComponent
1541          *
1542          * @return the AccessibleExtendedComponent
1543          */
1544         AccessibleExtendedComponent getAccessibleExtendedComponent() {
1545             return this;
1546         }
1547 
1548         /**
1549          * Returns the tool tip text
1550          *
1551          * @return the tool tip text, if supported, of the object;
1552          * otherwise, null
1553          * @since 1.4
1554          */
1555         public String getToolTipText() {
1556             return JLabel.this.getToolTipText();
1557         }
1558 
1559         /**
1560          * Returns the titled border text
1561          *
1562          * @return the titled border text, if supported, of the object;
1563          * otherwise, null
1564          * @since 1.4
1565          */
1566         public String getTitledBorderText() {
1567             return super.getTitledBorderText();
1568         }
1569 
1570         /**
1571          * Returns key bindings associated with this object
1572          *
1573          * @return the key bindings, if supported, of the object;
1574          * otherwise, null
1575          * @see AccessibleKeyBinding
1576          * @since 1.4
1577          */
1578         public AccessibleKeyBinding getAccessibleKeyBinding() {
1579             int mnemonic = JLabel.this.getDisplayedMnemonic();
1580             if (mnemonic == 0) {
1581                 return null;
1582             }
1583             return new LabelKeyBinding(mnemonic);
1584         }
1585 
1586         class LabelKeyBinding implements AccessibleKeyBinding {
1587             int mnemonic;
1588 
1589             LabelKeyBinding(int mnemonic) {
1590                 this.mnemonic = mnemonic;
1591             }
1592 
1593             /**
1594              * Returns the number of key bindings for this object
1595              *
1596              * @return the zero-based number of key bindings for this object
1597              */
1598             public int getAccessibleKeyBindingCount() {
1599                 return 1;
1600             }
1601 
1602             /**
1603              * Returns a key binding for this object.  The value returned is an
1604              * java.lang.Object which must be cast to appropriate type depending
1605              * on the underlying implementation of the key.  For example, if the
1606              * Object returned is a javax.swing.KeyStroke, the user of this
1607              * method should do the following:
1608              * <nf><code>
1609              * Component c = <get the component that has the key bindings>
1610              * AccessibleContext ac = c.getAccessibleContext();
1611              * AccessibleKeyBinding akb = ac.getAccessibleKeyBinding();
1612              * for (int i = 0; i < akb.getAccessibleKeyBindingCount(); i++) {
1613              *     Object o = akb.getAccessibleKeyBinding(i);
1614              *     if (o instanceof javax.swing.KeyStroke) {
1615              *         javax.swing.KeyStroke keyStroke = (javax.swing.KeyStroke)o;
1616              *         <do something with the key binding>
1617              *     }
1618              * }
1619              * </code></nf>
1620              *
1621              * @param i zero-based index of the key bindings
1622              * @return a javax.lang.Object which specifies the key binding
1623              * @exception IllegalArgumentException if the index is
1624              * out of bounds
1625              * @see #getAccessibleKeyBindingCount
1626              */
1627             public java.lang.Object getAccessibleKeyBinding(int i) {
1628                 if (i != 0) {
1629                     throw new IllegalArgumentException();
1630                 }
1631                 return KeyStroke.getKeyStroke(mnemonic, 0);
1632             }
1633         }
1634 
1635     }  // AccessibleJComponent
1636 }