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