Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / swing / border / TitledBorder.java
blob8d3ee13d4bb973243a5bb80d7561f9e4e5f1baff
1 /* TitledBorder.java --
2 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.border;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Dimension;
44 import java.awt.Font;
45 import java.awt.FontMetrics;
46 import java.awt.Graphics;
47 import java.awt.Insets;
48 import java.awt.Shape;
49 import java.awt.font.FontRenderContext;
50 import java.awt.font.LineMetrics;
51 import java.awt.geom.AffineTransform;
53 import javax.swing.UIManager;
56 /**
57 * A border that paints a title on top of another border.
59 * @author Sascha Brawer (brawer@dandelis.ch)
61 public class TitledBorder extends AbstractBorder
63 /**
64 * A value for the <code>titlePosition</code> property that vertically
65 * positions the title text at the default vertical position, which
66 * is in the middle of the top line of the border.
68 * @see #getTitlePosition()
69 * @see #setTitlePosition(int)
71 public static final int DEFAULT_POSITION = 0;
74 /**
75 * A value for the <code>titlePosition</code> property that vertically
76 * positions the title text above the top line of the border.
78 * @see #getTitlePosition()
79 * @see #setTitlePosition(int)
81 public static final int ABOVE_TOP = 1;
84 /**
85 * A value for the <code>titlePosition</code> property that vertically
86 * positions the title text at the middle of the top line
87 * of the border.
89 * @see #getTitlePosition()
90 * @see #setTitlePosition(int)
92 public static final int TOP = 2;
95 /**
96 * A value for the <code>titlePosition</code> property that vertically
97 * positions the title text below the top line of the border.
99 * @see #getTitlePosition()
100 * @see #setTitlePosition(int)
102 public static final int BELOW_TOP = 3;
106 * A value for the <code>titlePosition</code> property that vertically
107 * positions the title text above the bottom line of the border.
109 * @see #getTitlePosition()
110 * @see #setTitlePosition(int)
112 public static final int ABOVE_BOTTOM = 4;
116 * A value for the <code>titlePosition</code> property that vertically
117 * positions the title text at the center of the bottom line
118 * of the border.
120 * @see #getTitlePosition()
121 * @see #setTitlePosition(int)
123 public static final int BOTTOM = 5;
127 * A value for the <code>titlePosition</code> property that vertically
128 * positions the title text below the bottom line of the border.
130 * @see #getTitlePosition()
131 * @see #setTitlePosition(int)
133 public static final int BELOW_BOTTOM = 6;
137 * A value for the <code>titleJustification</code> property that
138 * horizontally aligns the title text with either the left or the
139 * right edge of the border, depending on the orientation of the
140 * component nested into the border. If the component orientation
141 * is left-to-right, the title text is aligned with the left edge;
142 * otherwise, it is aligned with the right edge. This is the same
143 * behavior as with {@link #LEADING}.
145 * @see #getTitleJustification()
146 * @see #setTitleJustification(int)
147 * @see java.awt.ComponentOrientation#isLeftToRight()
149 public static final int DEFAULT_JUSTIFICATION = 0;
153 * A value for the <code>titleJustification</code> property that
154 * horizontally aligns the title text with the left-hand edge of
155 * the border.
157 * @see #getTitleJustification()
158 * @see #setTitleJustification(int)
160 public static final int LEFT = 1;
164 * A value for the <code>titleJustification</code> property that
165 * horizontally aligns the title text with the center of the border.
167 * @see #getTitleJustification()
168 * @see #setTitleJustification(int)
170 public static final int CENTER = 2;
174 * A value for the <code>titleJustification</code> property that
175 * horizontally aligns the title text with the right-hand edge of
176 * the border.
178 * @see #getTitleJustification()
179 * @see #setTitleJustification(int)
181 public static final int RIGHT = 3;
185 * A value for the <code>titleJustification</code> property that
186 * horizontally aligns the title text with either the left or the
187 * right edge of the border, depending on the orientation of the
188 * component nested into the border. If the component orientation
189 * is left-to-right, the title text is aligned with the left edge;
190 * otherwise, it is aligned with the right edge. This is the same
191 * behavior as with {@link #DEFAULT_JUSTIFICATION}.
193 * @see #getTitleJustification()
194 * @see #setTitleJustification(int)
195 * @see java.awt.ComponentOrientation#isLeftToRight()
197 public static final int LEADING = 4;
201 * A value for the <code>titleJustification</code> property that
202 * horizontally aligns the title text with either the right or the
203 * left edge of the border, depending on the orientation of the
204 * component nested into the border. If the component orientation
205 * is left-to-right, the title text is aligned with the right edge;
206 * otherwise, it is aligned with the left edge.
208 * @see #getTitleJustification()
209 * @see #setTitleJustification(int)
210 * @see java.awt.ComponentOrientation#isLeftToRight()
212 public static final int TRAILING = 5;
216 * The number of pixels between the inside of {@link #border}
217 * and the bordered component.
219 protected static final int EDGE_SPACING = 2;
223 * The number of pixels between the outside of this TitledBorder
224 * and the beginning (if left-aligned) or end (if right-aligned)
225 * of the title text.
227 protected static final int TEXT_INSET_H = 5;
231 * The number of pixels between the title text and {@link #border}.
232 * This value is only relevant if the title text does not intersect
233 * {@link #border}. No intersection occurs if {@link #titlePosition}
234 * is one of {@link #ABOVE_TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM},
235 * or {@link #BELOW_BOTTOM}.
237 protected static final int TEXT_SPACING = 2;
241 * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1
242 * on MacOS X 10.1.5.
244 static final long serialVersionUID = 8012999415147721601L;
248 * The title, or <code>null</code> to display no title.
250 protected String title;
254 * The border underneath the title. If this value is
255 * <code>null</code>, the border will be retrieved from the {@link
256 * javax.swing.UIManager}&#x2019;s defaults table using the key
257 * <code>TitledBorder.border</code>.
259 protected Border border;
263 * The vertical position of the title text relative to the border,
264 * which is one of {@link #ABOVE_TOP}, {@link #TOP}, {@link
265 * #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link
266 * #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}.
268 protected int titlePosition;
272 * The horizontal alignment of the title text in relation to the
273 * border, which is one of {@link #LEFT}, {@link #CENTER}, {@link
274 * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link
275 * #DEFAULT_JUSTIFICATION}.
277 protected int titleJustification;
281 * The font for displaying the title text. If this value is
282 * <code>null</code>, the font will be retrieved from the {@link
283 * javax.swing.UIManager}&#x2019;s defaults table using the key
284 * <code>TitledBorder.font</code>.
286 protected Font titleFont;
290 * The color for displaying the title text. If this value is
291 * <code>null</code>, the color will be retrieved from the {@link
292 * javax.swing.UIManager}&#x2019;s defaults table using the key
293 * <code>TitledBorder.titleColor</code>.
295 protected Color titleColor;
299 * Constructs a TitledBorder given the text of its title.
301 * @param title the title text, or <code>null</code> to use no title text.
303 public TitledBorder(String title)
305 this(/* border */ null,
306 title, LEADING, TOP,
307 /* titleFont */ null, /* titleColor */ null);
312 * Constructs an initially untitled TitledBorder given another border.
314 * @param border the border underneath the title, or <code>null</code>
315 * to use a default from the current look and feel.
317 public TitledBorder(Border border)
319 this(border, /* title */ "", LEADING, TOP,
320 /* titleFont */ null, /* titleColor */ null);
325 * Constructs a TitledBorder given its border and title text.
327 * @param border the border underneath the title, or <code>null</code>
328 * to use a default from the current look and feel.
330 * @param title the title text, or <code>null</code> to use no title
331 * text.
333 public TitledBorder(Border border, String title)
335 this(border, title, LEADING, TOP,
336 /* titleFont */ null, /* titleColor */ null);
341 * Constructs a TitledBorder given its border, title text, horizontal
342 * alignment, and vertical position.
344 * @param border the border underneath the title, or <code>null</code>
345 * to use a default from the current look and feel.
347 * @param title the title text, or <code>null</code> to use no title
348 * text.
350 * @param titleJustification the horizontal alignment of the title
351 * text in relation to the border. The value must be one of
352 * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
353 * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
355 * @param titlePosition the vertical position of the title text
356 * in relation to the border. The value must be one of
357 * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
358 * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
359 * or {@link #DEFAULT_POSITION}.
361 * @throws IllegalArgumentException if <code>titleJustification</code>
362 * or <code>titlePosition</code> have an unsupported value.
364 public TitledBorder(Border border, String title, int titleJustification,
365 int titlePosition)
367 this(border, title, titleJustification, titlePosition,
368 /* titleFont */ null, /* titleColor */ null);
373 * Constructs a TitledBorder given its border, title text, horizontal
374 * alignment, vertical position, and font.
376 * @param border the border underneath the title, or <code>null</code>
377 * to use a default from the current look and feel.
379 * @param title the title text, or <code>null</code> to use no title
380 * text.
382 * @param titleJustification the horizontal alignment of the title
383 * text in relation to the border. The value must be one of
384 * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
385 * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
387 * @param titlePosition the vertical position of the title text
388 * in relation to the border. The value must be one of
389 * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
390 * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
391 * or {@link #DEFAULT_POSITION}.
393 * @param titleFont the font for the title text, or <code>null</code>
394 * to use a default from the current look and feel.
396 * @throws IllegalArgumentException if <code>titleJustification</code>
397 * or <code>titlePosition</code> have an unsupported value.
399 public TitledBorder(Border border, String title, int titleJustification,
400 int titlePosition, Font titleFont)
402 this(border, title, titleJustification, titlePosition, titleFont,
403 /* titleColor */ null);
408 * Constructs a TitledBorder given its border, title text, horizontal
409 * alignment, vertical position, font, and color.
411 * @param border the border underneath the title, or <code>null</code>
412 * to use a default from the current look and feel.
414 * @param title the title text, or <code>null</code> to use no title
415 * text.
417 * @param titleJustification the horizontal alignment of the title
418 * text in relation to the border. The value must be one of
419 * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
420 * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
422 * @param titlePosition the vertical position of the title text
423 * in relation to the border. The value must be one of
424 * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP},
425 * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM},
426 * or {@link #DEFAULT_POSITION}.
428 * @param titleFont the font for the title text, or <code>null</code>
429 * to use a default from the current look and feel.
431 * @param titleColor the color for the title text, or <code>null</code>
432 * to use a default from the current look and feel.
434 * @throws IllegalArgumentException if <code>titleJustification</code>
435 * or <code>titlePosition</code> have an unsupported value.
437 public TitledBorder(Border border, String title, int titleJustification,
438 int titlePosition, Font titleFont, Color titleColor)
440 this.border = border;
441 this.title = title;
443 /* Invoking the setter methods ensures that the newly constructed
444 * TitledBorder has valid property values.
446 setTitleJustification(titleJustification);
447 setTitlePosition(titlePosition);
449 this.titleFont = titleFont;
450 this.titleColor = titleColor;
455 * Paints the border and the title text.
457 * @param c the component whose border is to be painted.
458 * @param g the graphics for painting.
459 * @param x the horizontal position for painting the border.
460 * @param y the vertical position for painting the border.
461 * @param width the width of the available area for painting the border.
462 * @param height the height of the available area for painting the border.
464 public void paintBorder(Component c, Graphics g,
465 int x, int y, int width, int height)
467 Measurements mes = getMeasurements(c);
468 Font oldFont = g.getFont();
469 Color oldColor = g.getColor();
472 * A local helper class for painting the border without changing
473 * any pixels inside the rectangle of the title text.
475 class BorderPainter
477 private Component c;
478 private Border b;
479 private int x, y, width, height;
482 * Constructs a BorderPainter.
484 * @param c the component whose border is being painted.
485 * @param b the border object.
486 * @param x the x coordinate of the rectangle delimiting the border.
487 * @param y the y coordinate of the rectangle delimiting the border.
488 * @param width the width of the rectangle delimiting the border.
489 * @param height the width of the rectangle delimiting the border.
491 public BorderPainter(Component c, Border b,
492 int x, int y, int width, int height)
494 this.c = c;
495 this.b = b;
496 this.x = x;
497 this.y = y;
498 this.width = width;
499 this.height = height;
504 * Paints the entire border.
506 public void paint(Graphics g)
508 if (b != null)
509 b.paintBorder(c, g, x, y, width, height);
514 * Paints the border, clipping the drawing operation to a
515 * given rectangular area.
517 private void paint(Graphics g,
518 int clipX, int clipY, int clipWidth, int clipHeight)
520 Shape oldClip = g.getClip();
523 g.clipRect(clipX, clipY, clipWidth, clipHeight);
524 paint(g);
526 finally
528 g.setClip(oldClip);
534 * Paints the border without affecting a given rectangular area.
535 * This is used for painting the border without drawing anything
536 * underneath the title text.
538 * <p>Since we do not want to introduce unnecessary dependencies
539 * on Java 2D, we perform the clipping without constructive geometry
540 * (provided by java.awt.geom.Area). Instead, the border&#x2019;s
541 * bounding rectangle is split into smaller parts, which are then
542 * clipped and painted individually.:
544 * <p><pre>
545 * +--------------------+ +--------------------+
546 * | | | 1 |
547 * | +--------+ | +---+--------+-------+
548 * | | hole | | |====> | 2 | hole | 3 |
549 * | +--------+ | |---+--------+-------+
550 * | | | 4 |
551 * +--------------------+ +--------------------+</pre>
554 public void paintExcept(Graphics g,
555 int holeX, int holeY, int holeWidth, int holeHeight)
557 int stripeHeight;
559 stripeHeight = holeY - y;
560 if (stripeHeight > 0)
561 paint(g, x, y, width, stripeHeight); // patch #1 in the image above
563 stripeHeight = holeHeight;
564 if (stripeHeight > 0)
566 paint(g, x, holeY, holeX - x, stripeHeight); // patches #2 and #3
567 paint(g, holeX + holeWidth, holeY, x + width - (holeX + holeWidth), stripeHeight);
570 stripeHeight = height - (holeY - y + holeHeight);
571 if (stripeHeight > 0)
572 paint(g, x, y + height - stripeHeight, width, stripeHeight); // #4
576 BorderPainter bp;
577 int textX, textY, borderWidth, borderHeight;
579 borderWidth = width - (mes.outerSpacing.left + mes.outerSpacing.right);
580 borderHeight = height - (mes.outerSpacing.top + mes.outerSpacing.bottom);
581 bp = new BorderPainter(c, getBorder(),
582 x + mes.outerSpacing.left, y + mes.outerSpacing.top,
583 borderWidth, borderHeight);
585 switch (getRealTitleJustification(c))
587 case LEFT:
588 textX = x + EDGE_SPACING + TEXT_INSET_H;
589 break;
591 case CENTER:
592 textX = x + (borderWidth - mes.textWidth) / 2;
593 break;
595 case RIGHT:
596 textX = x + borderWidth - (mes.textWidth + TEXT_INSET_H);
597 break;
599 default:
600 throw new IllegalStateException();
603 switch (titlePosition)
605 case ABOVE_TOP:
606 textY = y + EDGE_SPACING;
607 break;
609 case TOP:
610 case DEFAULT_POSITION:
611 default:
612 textY = y + mes.outerSpacing.top + mes.borderInsets.top - mes.textAscent
613 + mes.lineHeight;
614 break;
616 case BELOW_TOP:
617 textY = y + mes.outerSpacing.top + mes.borderInsets.top + TEXT_SPACING;
618 break;
620 case ABOVE_BOTTOM:
621 textY = y + height - mes.outerSpacing.bottom - mes.borderInsets.bottom
622 - TEXT_SPACING - (mes.textAscent + mes.textDescent);
623 break;
625 case BOTTOM:
626 case BELOW_BOTTOM:
627 textY = y + height - (mes.textAscent + mes.textDescent);
628 break;
631 if (mes.trimmedText == null)
632 bp.paint(g);
633 else
637 g.setFont(mes.font);
638 g.setColor(getTitleColor());
639 g.drawString(mes.trimmedText, textX, textY + mes.textAscent);
641 finally
643 g.setFont(oldFont);
644 g.setColor(oldColor);
646 bp.paintExcept(g, textX, textY,
647 mes.textWidth, mes.textAscent + mes.textDescent);
653 * Measures the width of this border.
655 * @param c the component whose border is to be measured.
657 * @return an Insets object whose <code>left</code>, <code>right</code>,
658 * <code>top</code> and <code>bottom</code> fields indicate the
659 * width of the border at the respective edge.
661 * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
663 public Insets getBorderInsets(Component c)
665 return getBorderInsets(c, new Insets(0, 0, 0, 0));
670 * Measures the width of this border, storing the results into a
671 * pre-existing Insets object.
673 * @param insets an Insets object for holding the result values.
674 * After invoking this method, the <code>left</code>,
675 * <code>right</code>, <code>top</code> and
676 * <code>bottom</code> fields indicate the width of the
677 * border at the respective edge.
679 * @return the same object that was passed for <code>insets</code>.
681 * @see #getBorderInsets(Component)
683 public Insets getBorderInsets(Component c, Insets insets)
685 return getMeasurements(c).getContentInsets(insets);
690 * Returns <code>false</code>, indicating that there are pixels inside
691 * the area of this border where the background shines through.
693 * @return <code>false</code>.
695 public boolean isBorderOpaque()
697 /* Note that the AbstractBorder.isBorderOpaque would also return
698 * false, so there is actually no need to override the inherited
699 * implementation. However, GNU Classpath strives for exact
700 * compatibility with the Sun reference implementation, which
701 * overrides isBorderOpaque for unknown reasons.
703 return false;
708 * Returns the text of the title.
710 * @return the title text, or <code>null</code> if no title is
711 * displayed.
713 public String getTitle()
715 return title;
720 * Retrieves the border underneath the title. If no border has been
721 * set, or if it has been set to<code>null</code>, the current
722 * {@link javax.swing.LookAndFeel} will be asked for a border
723 * using the key <code>TitledBorder.border</code>.
725 * @return a border, or <code>null</code> if the current LookAndFeel
726 * does not provide a border for the key
727 * <code>TitledBorder.border</code>.
729 * @see javax.swing.UIManager#getBorder(Object)
731 public Border getBorder()
733 if (border != null)
734 return border;
736 return UIManager.getBorder("TitledBorder.border");
741 * Returns the vertical position of the title text in relation
742 * to the border.
744 * @return one of the values {@link #ABOVE_TOP}, {@link #TOP},
745 * {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM},
746 * {@link #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}.
748 public int getTitlePosition()
750 return titlePosition;
755 * Returns the horizontal alignment of the title text in relation to
756 * the border.
758 * @return one of the values {@link #LEFT}, {@link #CENTER}, {@link
759 * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link
760 * #DEFAULT_JUSTIFICATION}.
762 public int getTitleJustification()
764 return titleJustification;
769 * Retrieves the font for displaying the title text. If no font has
770 * been set, or if it has been set to<code>null</code>, the current
771 * {@link javax.swing.LookAndFeel} will be asked for a font
772 * using the key <code>TitledBorder.font</code>.
774 * @return a font, or <code>null</code> if the current LookAndFeel
775 * does not provide a font for the key
776 * <code>TitledBorder.font</code>.
778 * @see javax.swing.UIManager#getFont(Object)
780 public Font getTitleFont()
782 if (titleFont != null)
783 return titleFont;
785 return UIManager.getFont("TitledBorder.font");
790 * Retrieves the color for displaying the title text. If no color has
791 * been set, or if it has been set to<code>null</code>, the current
792 * {@link javax.swing.LookAndFeel} will be asked for a color
793 * using the key <code>TitledBorder.titleColor</code>.
795 * @return a color, or <code>null</code> if the current LookAndFeel
796 * does not provide a color for the key
797 * <code>TitledBorder.titleColor</code>.
799 * @see javax.swing.UIManager#getColor(Object)
801 public Color getTitleColor()
803 if (titleColor != null)
804 return titleColor;
806 return UIManager.getColor("TitledBorder.titleColor");
811 * Sets the text of the title.
813 * @param title the new title text, or <code>null</code> for displaying
814 * no text at all.
816 public void setTitle(String title)
818 // Swing borders are not JavaBeans, thus no need to fire an event.
819 this.title = title;
824 * Sets the border underneath the title.
826 * @param border a border, or <code>null</code> to use the
827 * border that is supplied by the current LookAndFeel.
829 * @see #getBorder()
831 public void setBorder(Border border)
833 // Swing borders are not JavaBeans, thus no need to fire an event.
834 this.border = border;
839 * Sets the vertical position of the title text in relation
840 * to the border.
842 * @param titlePosition one of the values {@link #ABOVE_TOP},
843 * {@link #TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM},
844 * {@link #BOTTOM}, {@link #BELOW_BOTTOM},
845 * or {@link #DEFAULT_POSITION}.
847 * @throws IllegalArgumentException if an unsupported value is passed
848 * for <code>titlePosition</code>.
850 public void setTitlePosition(int titlePosition)
852 if ((titlePosition < DEFAULT_POSITION) || (titlePosition > BELOW_BOTTOM))
853 throw new IllegalArgumentException();
855 // Swing borders are not JavaBeans, thus no need to fire an event.
856 this.titlePosition = titlePosition;
861 * Sets the horizontal alignment of the title text in relation to the border.
863 * @param titleJustification the new alignment, which must be one of
864 * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING},
865 * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}.
867 * @throws IllegalArgumentException if an unsupported value is passed
868 * for <code>titleJustification</code>.
870 public void setTitleJustification(int titleJustification)
872 if ((titleJustification < DEFAULT_JUSTIFICATION)
873 || (titleJustification > TRAILING))
874 throw new IllegalArgumentException();
876 // Swing borders are not JavaBeans, thus no need to fire an event.
877 this.titleJustification = titleJustification;
882 * Sets the font for displaying the title text.
884 * @param titleFont the font, or <code>null</code> to use the font
885 * provided by the current {@link javax.swing.LookAndFeel}.
887 * @see #getTitleFont()
889 public void setTitleFont(Font titleFont)
891 // Swing borders are not JavaBeans, thus no need to fire an event.
892 this.titleFont = titleFont;
897 * Sets the color for displaying the title text.
899 * @param titleColor the color, or <code>null</code> to use the color
900 * provided by the current {@link javax.swing.LookAndFeel}.
902 * @see #getTitleColor()
904 public void setTitleColor(Color titleColor)
906 // Swing borders are not JavaBeans, thus no need to fire an event.
907 this.titleColor = titleColor;
912 * Calculates the minimum size needed for displaying the border
913 * and its title.
915 * @param c the Component for which this TitledBorder consitutes
916 * a border.
918 public Dimension getMinimumSize(Component c)
920 return getMeasurements(c).getMinimumSize();
925 * Returns the font that is used for displaying the title text for
926 * a given Component.
928 * @param c the Component for which this TitledBorder is the border.
930 * @return The font returned by {@link #getTitleFont()}, or a fallback
931 * if {@link #getTitleFont()} returned <code>null</code>.
933 protected Font getFont(Component c)
935 Font f;
937 f = getTitleFont();
938 if (f != null)
939 return f;
941 return new Font("Dialog", Font.PLAIN, 12);
946 * Returns the horizontal alignment of the title text in relation to
947 * the border, mapping the component-dependent alignment constants
948 * {@link #LEADING}, {@link #TRAILING} and {@link #DEFAULT_JUSTIFICATION}
949 * to the correct value according to the embedded component&#x2019;s
950 * orientation.
952 * @param c the Component for which this TitledBorder is the border.
954 * @return one of the values {@link #LEFT}, {@link #CENTER}, or {@link
955 * #RIGHT}.
957 private int getRealTitleJustification(Component c)
959 switch (titleJustification)
961 case DEFAULT_JUSTIFICATION:
962 case LEADING:
963 if ((c == null) || c.getComponentOrientation().isLeftToRight())
964 return LEFT;
965 else
966 return RIGHT;
968 case TRAILING:
969 if ((c == null) || c.getComponentOrientation().isLeftToRight())
970 return RIGHT;
971 else
972 return LEFT;
974 default:
975 return titleJustification;
981 * Performs various measurements for the current state of this TitledBorder
982 * and the given Component.
984 private Measurements getMeasurements(Component c)
986 Measurements m = new Measurements();
987 FontMetrics fmet;
989 m.font = getFont(c);
990 fmet = c.getFontMetrics(m.font);
991 m.border = getBorder();
992 if (m.border != null)
993 m.borderInsets = m.border.getBorderInsets(c);
994 else
995 m.borderInsets = new Insets(0, 0, 0, 0);
997 if (title != null)
999 m.trimmedText = title.trim();
1000 if (m.trimmedText.length() == 0)
1001 m.trimmedText = null;
1004 if (m.trimmedText != null)
1006 m.textAscent = fmet.getAscent();
1007 m.textDescent = fmet.getDescent() + fmet.getLeading();
1009 FontRenderContext frc = new FontRenderContext(new AffineTransform(),
1010 false, false);
1011 LineMetrics lmet = m.font.getLineMetrics(m.trimmedText, 0,
1012 m.trimmedText.length(), frc);
1013 m.lineHeight = (int) lmet.getStrikethroughOffset();
1015 // Fallback in case that LineMetrics is not available/working.
1016 if (m.lineHeight == 0)
1017 m.lineHeight = (int) (0.3333 * (double) m.textAscent);
1018 m.textWidth = fmet.stringWidth(m.trimmedText) + 3;
1020 else
1022 m.textAscent = 0;
1023 m.textDescent = 0;
1026 m.innerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING,
1027 EDGE_SPACING);
1028 m.outerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING,
1029 EDGE_SPACING);
1031 switch (titlePosition)
1033 case ABOVE_TOP:
1034 m.outerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING;
1035 break;
1037 case TOP:
1038 m.outerSpacing.top += m.textDescent + m.lineHeight;
1039 m.innerSpacing.top += m.textAscent - m.lineHeight;
1040 break;
1042 case BELOW_TOP:
1043 m.innerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING;
1044 break;
1046 case ABOVE_BOTTOM:
1047 m.innerSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING;
1048 break;
1050 case BOTTOM:
1051 m.innerSpacing.bottom += Math.max(m.textAscent - m.lineHeight, 0);
1052 m.outerSpacing.bottom += m.textDescent + m.lineHeight;
1053 break;
1055 case BELOW_BOTTOM:
1056 m.outerSpacing.bottom += m.textAscent + m.textDescent;
1057 break;
1059 default:
1060 m.outerSpacing.top += m.textAscent;
1063 return m;
1068 * A private helper class for holding the result of measuring the
1069 * distances of a TitledBorder. While it would be possible to cache
1070 * these objects, it does not seem to be worth the effort. Note that
1071 * invalidating the cache would be tricky, especially since there is
1072 * no notification mechanism that would inform the cache when
1073 * border has changed, so it would return different insets.
1075 private static class Measurements
1078 * The font used for displaying the title text. Note that it can
1079 * well be that the TitledBorder&#x2019;s font is <code>null</code>,
1080 * which means that the font is to be retrieved from the current
1081 * LookAndFeel. In this case, this <code>font</code> field will
1082 * contain the result of the retrieval. Therefore, it is safe
1083 * to assume that this <code>font</code> field will never have
1084 * a <code>null</code> value.
1086 Font font;
1090 * The number of pixels between the base line and the top of the
1091 * text box.
1093 int textAscent;
1097 * The number of pixels between the base line and the bottom of
1098 * the text box.
1100 int textDescent;
1103 * The number of pixels between the base line and the height where
1104 * a strike-through would be drawn.
1106 int lineHeight;
1109 * The title text after removing leading and trailing white space
1110 * characters. If the title consists only of white space, the
1111 * value of <code>trimmedText</code> will be <code>null</code>.
1113 String trimmedText;
1117 * The width of the trimmed title text in pixels.
1119 int textWidth;
1123 * The border that constitutes the interior border
1124 * underneath the title text.
1126 Border border;
1130 * The distance between the TitledBorder and the interior border.
1132 Insets outerSpacing;
1135 * The width of the interior border, as returned by
1136 * <code>border.getBorderInsets()</code>.
1138 Insets borderInsets;
1142 * The distance between the interior border and the nested
1143 * Component for which this TitledBorder is a border.
1145 Insets innerSpacing;
1149 * Determines the insets of the nested component when it has a
1150 * TitledBorder as its border. Used by {@link
1151 * TitledBorder#getBorderInsets(Component, Insets)}.
1153 * @param i an Insets object for storing the results into, or
1154 * <code>null</code> to cause the creation of a
1155 * new instance.
1157 * @return the <code>i</code> object, or a new Insets object
1158 * if <code>null</code> was passed for <code>i</code>.
1160 public Insets getContentInsets(Insets i)
1162 if (i == null)
1163 i = new Insets(0, 0, 0, 0);
1164 i.left = outerSpacing.left + borderInsets.left + innerSpacing.left;
1165 i.right = outerSpacing.right + borderInsets.right + innerSpacing.right;
1166 i.top = outerSpacing.top + borderInsets.top + innerSpacing.top;
1167 i.bottom = outerSpacing.bottom + borderInsets.bottom + innerSpacing.bottom;
1168 return i;
1173 * Calculates the minimum size needed for displaying the border
1174 * and its title. Used by {@link TitledBorder#getMinimumSize(Component)}.
1176 public Dimension getMinimumSize()
1178 int width;
1179 Insets insets;
1181 insets = getContentInsets(null);
1182 width = Math.max(insets.left + insets.right, textWidth + 2
1183 * TEXT_INSET_H);
1184 return new Dimension(width, insets.top + insets.bottom);