KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > border > TitledBorder


1 /*
2  * @(#)TitledBorder.java 1.40 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.border;
8
9 import com.sun.java.swing.SwingUtilities2;
10
11 import java.awt.Graphics JavaDoc;
12 import java.awt.Insets JavaDoc;
13 import java.awt.Rectangle JavaDoc;
14 import java.awt.Color JavaDoc;
15 import java.awt.Font JavaDoc;
16 import java.awt.FontMetrics JavaDoc;
17 import java.awt.Point JavaDoc;
18 import java.awt.Toolkit JavaDoc;
19 import java.awt.Component JavaDoc;
20 import java.awt.Dimension JavaDoc;
21
22 import javax.swing.JComponent JavaDoc;
23 import javax.swing.UIManager JavaDoc;
24
25 /**
26  * A class which implements an arbitrary border
27  * with the addition of a String title in a
28  * specified position and justification.
29  * <p>
30  * If the border, font, or color property values are not
31  * specified in the constuctor or by invoking the appropriate
32  * set methods, the property values will be defined by the current
33  * look and feel, using the following property names in the
34  * Defaults Table:
35  * <ul>
36  * <li>&quot;TitledBorder.border&quot;
37  * <li>&quot;TitledBorder.font&quot;
38  * <li>&quot;TitledBorder.titleColor&quot;
39  * </ul>
40  * <p>
41  * <strong>Warning:</strong>
42  * Serialized objects of this class will not be compatible with
43  * future Swing releases. The current serialization support is
44  * appropriate for short term storage or RMI between applications running
45  * the same version of Swing. As of 1.4, support for long term storage
46  * of all JavaBeans<sup><font size="-2">TM</font></sup>
47  * has been added to the <code>java.beans</code> package.
48  * Please see {@link java.beans.XMLEncoder}.
49  *
50  * @version 1.40 12/19/03
51  * @author David Kloba
52  * @author Amy Fowler
53  */

54 public class TitledBorder extends AbstractBorder JavaDoc
55 {
56     protected String JavaDoc title;
57     protected Border JavaDoc border;
58     protected int titlePosition;
59     protected int titleJustification;
60     protected Font JavaDoc titleFont;
61     protected Color JavaDoc titleColor;
62
63     private Point JavaDoc textLoc = new Point JavaDoc();
64
65     /**
66      * Use the default vertical orientation for the title text.
67      */

68     static public final int DEFAULT_POSITION = 0;
69     /** Position the title above the border's top line. */
70     static public final int ABOVE_TOP = 1;
71     /** Position the title in the middle of the border's top line. */
72     static public final int TOP = 2;
73     /** Position the title below the border's top line. */
74     static public final int BELOW_TOP = 3;
75     /** Position the title above the border's bottom line. */
76     static public final int ABOVE_BOTTOM = 4;
77     /** Position the title in the middle of the border's bottom line. */
78     static public final int BOTTOM = 5;
79     /** Position the title below the border's bottom line. */
80     static public final int BELOW_BOTTOM = 6;
81
82     /**
83      * Use the default justification for the title text.
84      */

85     static public final int DEFAULT_JUSTIFICATION = 0;
86     /** Position title text at the left side of the border line. */
87     static public final int LEFT = 1;
88     /** Position title text in the center of the border line. */
89     static public final int CENTER = 2;
90     /** Position title text at the right side of the border line. */
91     static public final int RIGHT = 3;
92     /** Position title text at the left side of the border line
93      * for left to right orientation, at the right side of the
94      * border line for right to left orientation.
95      */

96     static public final int LEADING = 4;
97     /** Position title text at the right side of the border line
98      * for left to right orientation, at the left side of the
99      * border line for right to left orientation.
100      */

101     static public final int TRAILING = 5;
102
103     // Space between the border and the component's edge
104
static protected final int EDGE_SPACING = 2;
105
106     // Space between the border and text
107
static protected final int TEXT_SPACING = 2;
108
109     // Horizontal inset of text that is left or right justified
110
static protected final int TEXT_INSET_H = 5;
111
112     /**
113      * Creates a TitledBorder instance.
114      *
115      * @param title the title the border should display
116      */

117     public TitledBorder(String JavaDoc title) {
118         this(null, title, LEADING, TOP, null, null);
119     }
120
121     /**
122      * Creates a TitledBorder instance with the specified border
123      * and an empty title.
124      *
125      * @param border the border
126      */

127     public TitledBorder(Border JavaDoc border) {
128         this(border, "", LEADING, TOP, null, null);
129     }
130
131     /**
132      * Creates a TitledBorder instance with the specified border
133      * and title.
134      *
135      * @param border the border
136      * @param title the title the border should display
137      */

138     public TitledBorder(Border JavaDoc border, String JavaDoc title) {
139         this(border, title, LEADING, TOP, null, null);
140     }
141
142     /**
143      * Creates a TitledBorder instance with the specified border,
144      * title, title-justification, and title-position.
145      *
146      * @param border the border
147      * @param title the title the border should display
148      * @param titleJustification the justification for the title
149      * @param titlePosition the position for the title
150      */

151     public TitledBorder(Border JavaDoc border,
152                         String JavaDoc title,
153                         int titleJustification,
154                         int titlePosition) {
155         this(border, title, titleJustification,
156                         titlePosition, null, null);
157     }
158
159     /**
160      * Creates a TitledBorder instance with the specified border,
161      * title, title-justification, title-position, and title-font.
162      *
163      * @param border the border
164      * @param title the title the border should display
165      * @param titleJustification the justification for the title
166      * @param titlePosition the position for the title
167      * @param titleFont the font for rendering the title
168      */

169     public TitledBorder(Border JavaDoc border,
170                         String JavaDoc title,
171                         int titleJustification,
172                         int titlePosition,
173                         Font JavaDoc titleFont) {
174         this(border, title, titleJustification,
175                         titlePosition, titleFont, null);
176     }
177
178     /**
179      * Creates a TitledBorder instance with the specified border,
180      * title, title-justification, title-position, title-font, and
181      * title-color.
182      *
183      * @param border the border
184      * @param title the title the border should display
185      * @param titleJustification the justification for the title
186      * @param titlePosition the position for the title
187      * @param titleFont the font of the title
188      * @param titleColor the color of the title
189      */

190     public TitledBorder(Border JavaDoc border,
191                         String JavaDoc title,
192                         int titleJustification,
193                         int titlePosition,
194                         Font JavaDoc titleFont,
195                         Color JavaDoc titleColor) {
196         this.title = title;
197         this.border = border;
198         this.titleFont = titleFont;
199         this.titleColor = titleColor;
200
201         setTitleJustification(titleJustification);
202         setTitlePosition(titlePosition);
203     }
204
205     /**
206      * Paints the border for the specified component with the
207      * specified position and size.
208      * @param c the component for which this border is being painted
209      * @param g the paint graphics
210      * @param x the x position of the painted border
211      * @param y the y position of the painted border
212      * @param width the width of the painted border
213      * @param height the height of the painted border
214      */

215     public void paintBorder(Component JavaDoc c, Graphics JavaDoc g, int x, int y, int width, int height) {
216
217         Border JavaDoc border = getBorder();
218
219         if (getTitle() == null || getTitle().equals("")) {
220             if (border != null) {
221                 border.paintBorder(c, g, x, y, width, height);
222             }
223             return;
224         }
225
226         Rectangle JavaDoc grooveRect = new Rectangle JavaDoc(x + EDGE_SPACING, y + EDGE_SPACING,
227                                              width - (EDGE_SPACING * 2),
228                                              height - (EDGE_SPACING * 2));
229         Font JavaDoc font = g.getFont();
230         Color JavaDoc color = g.getColor();
231
232         g.setFont(getFont(c));
233
234         JComponent JavaDoc jc = (c instanceof JComponent JavaDoc) ? (JComponent JavaDoc)c : null;
235         FontMetrics JavaDoc fm = SwingUtilities2.getFontMetrics(jc, g);
236         int fontHeight = fm.getHeight();
237         int descent = fm.getDescent();
238         int ascent = fm.getAscent();
239         int diff;
240         int stringWidth = SwingUtilities2.stringWidth(jc, fm,
241                                                               getTitle());
242         Insets JavaDoc insets;
243
244         if (border != null) {
245             insets = border.getBorderInsets(c);
246         } else {
247             insets = new Insets JavaDoc(0, 0, 0, 0);
248         }
249
250         int titlePos = getTitlePosition();
251         switch (titlePos) {
252             case ABOVE_TOP:
253                 diff = ascent + descent + (Math.max(EDGE_SPACING,
254                                  TEXT_SPACING*2) - EDGE_SPACING);
255                 grooveRect.y += diff;
256                 grooveRect.height -= diff;
257                 textLoc.y = grooveRect.y - (descent + TEXT_SPACING);
258                 break;
259             case TOP:
260             case DEFAULT_POSITION:
261                 diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING);
262                 grooveRect.y += diff;
263                 grooveRect.height -= diff;
264                 textLoc.y = (grooveRect.y - descent) +
265                 (insets.top + ascent + descent)/2;
266                 break;
267             case BELOW_TOP:
268                 textLoc.y = grooveRect.y + insets.top + ascent + TEXT_SPACING;
269                 break;
270             case ABOVE_BOTTOM:
271                 textLoc.y = (grooveRect.y + grooveRect.height) -
272                 (insets.bottom + descent + TEXT_SPACING);
273                 break;
274             case BOTTOM:
275                 grooveRect.height -= fontHeight/2;
276                 textLoc.y = ((grooveRect.y + grooveRect.height) - descent) +
277                         ((ascent + descent) - insets.bottom)/2;
278                 break;
279             case BELOW_BOTTOM:
280                 grooveRect.height -= fontHeight;
281                 textLoc.y = grooveRect.y + grooveRect.height + ascent +
282                         TEXT_SPACING;
283                 break;
284         }
285
286     int justification = getTitleJustification();
287     if(isLeftToRight(c)) {
288         if(justification==LEADING ||
289            justification==DEFAULT_JUSTIFICATION) {
290             justification = LEFT;
291         }
292         else if(justification==TRAILING) {
293             justification = RIGHT;
294         }
295     }
296     else {
297         if(justification==LEADING ||
298            justification==DEFAULT_JUSTIFICATION) {
299             justification = RIGHT;
300         }
301         else if(justification==TRAILING) {
302             justification = LEFT;
303         }
304     }
305
306         switch (justification) {
307             case LEFT:
308                 textLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
309                 break;
310             case RIGHT:
311                 textLoc.x = (grooveRect.x + grooveRect.width) -
312                         (stringWidth + TEXT_INSET_H + insets.right);
313                 break;
314             case CENTER:
315                 textLoc.x = grooveRect.x +
316                         ((grooveRect.width - stringWidth) / 2);
317                 break;
318         }
319
320         // If title is positioned in middle of border AND its fontsize
321
// is greater than the border's thickness, we'll need to paint
322
// the border in sections to leave space for the component's background
323
// to show through the title.
324
//
325
if (border != null) {
326             if (((titlePos == TOP || titlePos == DEFAULT_POSITION) &&
327           (grooveRect.y > textLoc.y - ascent)) ||
328          (titlePos == BOTTOM &&
329           (grooveRect.y + grooveRect.height < textLoc.y + descent))) {
330           
331                 Rectangle JavaDoc clipRect = new Rectangle JavaDoc();
332                 
333                 // save original clip
334
Rectangle JavaDoc saveClip = g.getClipBounds();
335
336                 // paint strip left of text
337
clipRect.setBounds(saveClip);
338                 if (computeIntersection(clipRect, x, y, textLoc.x-1-x, height)) {
339                     g.setClip(clipRect);
340                     border.paintBorder(c, g, grooveRect.x, grooveRect.y,
341                                   grooveRect.width, grooveRect.height);
342                 }
343
344                 // paint strip right of text
345
clipRect.setBounds(saveClip);
346                 if (computeIntersection(clipRect, textLoc.x+stringWidth+1, y,
347                                x+width-(textLoc.x+stringWidth+1), height)) {
348                     g.setClip(clipRect);
349                     border.paintBorder(c, g, grooveRect.x, grooveRect.y,
350                                   grooveRect.width, grooveRect.height);
351                 }
352
353                 if (titlePos == TOP || titlePos == DEFAULT_POSITION) {
354                     // paint strip below text
355
clipRect.setBounds(saveClip);
356                     if (computeIntersection(clipRect, textLoc.x-1, textLoc.y+descent,
357                                         stringWidth+2, y+height-textLoc.y-descent)) {
358                         g.setClip(clipRect);
359                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
360                                   grooveRect.width, grooveRect.height);
361                     }
362
363                 } else { // titlePos == BOTTOM
364
// paint strip above text
365
clipRect.setBounds(saveClip);
366                     if (computeIntersection(clipRect, textLoc.x-1, y,
367                           stringWidth+2, textLoc.y - ascent - y)) {
368                         g.setClip(clipRect);
369                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
370                                   grooveRect.width, grooveRect.height);
371                     }
372                 }
373
374                 // restore clip
375
g.setClip(saveClip);
376
377             } else {
378                 border.paintBorder(c, g, grooveRect.x, grooveRect.y,
379                                   grooveRect.width, grooveRect.height);
380             }
381         }
382
383         g.setColor(getTitleColor());
384         SwingUtilities2.drawString(jc, g, getTitle(), textLoc.x, textLoc.y);
385
386         g.setFont(font);
387         g.setColor(color);
388     }
389
390     /**
391      * Returns the insets of the border.
392      * @param c the component for which this border insets value applies
393      */

394     public Insets JavaDoc getBorderInsets(Component JavaDoc c) {
395         return getBorderInsets(c, new Insets JavaDoc(0, 0, 0, 0));
396     }
397
398     /**
399      * Reinitialize the insets parameter with this Border's current Insets.
400      * @param c the component for which this border insets value applies
401      * @param insets the object to be reinitialized
402      */

403     public Insets JavaDoc getBorderInsets(Component JavaDoc c, Insets JavaDoc insets) {
404         FontMetrics JavaDoc fm;
405         int descent = 0;
406         int ascent = 16;
407     int height = 16;
408
409         Border JavaDoc border = getBorder();
410         if (border != null) {
411             if (border instanceof AbstractBorder JavaDoc) {
412                 ((AbstractBorder JavaDoc)border).getBorderInsets(c, insets);
413             } else {
414                 // Can't reuse border insets because the Border interface
415
// can't be enhanced.
416
Insets JavaDoc i = border.getBorderInsets(c);
417                 insets.top = i.top;
418                 insets.right = i.right;
419                 insets.bottom = i.bottom;
420                 insets.left = i.left;
421             }
422         } else {
423             insets.left = insets.top = insets.right = insets.bottom = 0;
424         }
425
426         insets.left += EDGE_SPACING + TEXT_SPACING;
427         insets.right += EDGE_SPACING + TEXT_SPACING;
428         insets.top += EDGE_SPACING + TEXT_SPACING;
429         insets.bottom += EDGE_SPACING + TEXT_SPACING;
430
431         if(c == null || getTitle() == null || getTitle().equals("")) {
432             return insets;
433         }
434
435         Font JavaDoc font = getFont(c);
436
437         fm = c.getFontMetrics(font);
438
439     if(fm != null) {
440        descent = fm.getDescent();
441        ascent = fm.getAscent();
442        height = fm.getHeight();
443     }
444
445         switch (getTitlePosition()) {
446           case ABOVE_TOP:
447               insets.top += ascent + descent
448                             + (Math.max(EDGE_SPACING, TEXT_SPACING*2)
449                             - EDGE_SPACING);
450               break;
451           case TOP:
452           case DEFAULT_POSITION:
453               insets.top += ascent + descent;
454               break;
455           case BELOW_TOP:
456               insets.top += ascent + descent + TEXT_SPACING;
457               break;
458           case ABOVE_BOTTOM:
459               insets.bottom += ascent + descent + TEXT_SPACING;
460               break;
461           case BOTTOM:
462               insets.bottom += ascent + descent;
463               break;
464           case BELOW_BOTTOM:
465               insets.bottom += height;
466               break;
467         }
468         return insets;
469     }
470
471     /**
472      * Returns whether or not the border is opaque.
473      */

474     public boolean isBorderOpaque() { return false; }
475
476     /**
477      * Returns the title of the titled border.
478      */

479     public String JavaDoc getTitle() { return title; }
480
481     /**
482      * Returns the border of the titled border.
483      */

484     public Border JavaDoc getBorder() {
485         Border JavaDoc b = border;
486     if (b == null)
487         b = UIManager.getBorder("TitledBorder.border");
488         return b;
489     }
490
491     /**
492      * Returns the title-position of the titled border.
493      */

494     public int getTitlePosition() { return titlePosition; }
495
496     /**
497      * Returns the title-justification of the titled border.
498      */

499     public int getTitleJustification() { return titleJustification; }
500
501     /**
502      * Returns the title-font of the titled border.
503      */

504     public Font JavaDoc getTitleFont() {
505         Font JavaDoc f = titleFont;
506     if (f == null)
507         f = UIManager.getFont("TitledBorder.font");
508         return f;
509     }
510
511     /**
512      * Returns the title-color of the titled border.
513      */

514     public Color JavaDoc getTitleColor() {
515         Color JavaDoc c = titleColor;
516     if (c == null)
517         c = UIManager.getColor("TitledBorder.titleColor");
518         return c;
519     }
520
521
522     // REMIND(aim): remove all or some of these set methods?
523

524     /**
525      * Sets the title of the titled border.
526      * param title the title for the border
527      */

528     public void setTitle(String JavaDoc title) { this.title = title; }
529
530     /**
531      * Sets the border of the titled border.
532      * @param border the border
533      */

534     public void setBorder(Border JavaDoc border) { this.border = border; }
535
536     /**
537      * Sets the title-position of the titled border.
538      * @param titlePosition the position for the border
539      */

540     public void setTitlePosition(int titlePosition) {
541         switch (titlePosition) {
542           case ABOVE_TOP:
543           case TOP:
544           case BELOW_TOP:
545           case ABOVE_BOTTOM:
546           case BOTTOM:
547           case BELOW_BOTTOM:
548           case DEFAULT_POSITION:
549                 this.titlePosition = titlePosition;
550                 break;
551           default:
552             throw new IllegalArgumentException JavaDoc(titlePosition +
553                                         " is not a valid title position.");
554         }
555     }
556
557     /**
558      * Sets the title-justification of the titled border.
559      * @param titleJustification the justification for the border
560      */

561     public void setTitleJustification(int titleJustification) {
562         switch (titleJustification) {
563           case DEFAULT_JUSTIFICATION:
564           case LEFT:
565           case CENTER:
566           case RIGHT:
567       case LEADING:
568       case TRAILING:
569             this.titleJustification = titleJustification;
570             break;
571           default:
572             throw new IllegalArgumentException JavaDoc(titleJustification +
573                                         " is not a valid title justification.");
574         }
575     }
576
577     /**
578      * Sets the title-font of the titled border.
579      * @param titleFont the font for the border title
580      */

581     public void setTitleFont(Font JavaDoc titleFont) {
582         this.titleFont = titleFont;
583     }
584
585     /**
586      * Sets the title-color of the titled border.
587      * @param titleColor the color for the border title
588      */

589     public void setTitleColor(Color JavaDoc titleColor) {
590       this.titleColor = titleColor;
591     }
592
593     /**
594      * Returns the minimum dimensions this border requires
595      * in order to fully display the border and title.
596      * @param c the component where this border will be drawn
597      */

598     public Dimension JavaDoc getMinimumSize(Component JavaDoc c) {
599         Insets JavaDoc insets = getBorderInsets(c);
600         Dimension JavaDoc minSize = new Dimension JavaDoc(insets.right+insets.left,
601                                           insets.top+insets.bottom);
602         Font JavaDoc font = getFont(c);
603         FontMetrics JavaDoc fm = c.getFontMetrics(font);
604         JComponent JavaDoc jc = (c instanceof JComponent JavaDoc) ? (JComponent JavaDoc)c : null;
605         switch (titlePosition) {
606           case ABOVE_TOP:
607           case BELOW_BOTTOM:
608               minSize.width = Math.max(SwingUtilities2.stringWidth(jc, fm,
609                                        getTitle()), minSize.width);
610               break;
611           case BELOW_TOP:
612           case ABOVE_BOTTOM:
613           case TOP:
614           case BOTTOM:
615           case DEFAULT_POSITION:
616           default:
617               minSize.width += SwingUtilities2.stringWidth(jc, fm, getTitle());
618         }
619         return minSize;
620     }
621
622     protected Font JavaDoc getFont(Component JavaDoc c) {
623         Font JavaDoc font;
624         if ((font = getTitleFont()) != null) {
625             return font;
626         } else if (c != null && (font = c.getFont()) != null) {
627             return font;
628         }
629         return new Font JavaDoc("Dialog", Font.PLAIN, 12);
630     }
631
632     private static boolean computeIntersection(Rectangle JavaDoc dest,
633                                                int rx, int ry, int rw, int rh) {
634     int x1 = Math.max(rx, dest.x);
635     int x2 = Math.min(rx + rw, dest.x + dest.width);
636     int y1 = Math.max(ry, dest.y);
637     int y2 = Math.min(ry + rh, dest.y + dest.height);
638         dest.x = x1;
639         dest.y = y1;
640         dest.width = x2 - x1;
641         dest.height = y2 - y1;
642
643     if (dest.width <= 0 || dest.height <= 0) {
644         return false;
645     }
646         return true;
647     }
648 }
649
Popular Tags