Frames | No Frames |
1: /* TitledBorder.java -- 2: Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.border; 40: 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.Point; 49: import java.awt.Rectangle; 50: 51: import javax.swing.SwingUtilities; 52: import javax.swing.UIManager; 53: 54: 55: /** 56: * A border that paints a title on top of another border. 57: * 58: * @author Sascha Brawer (brawer@dandelis.ch) 59: */ 60: public class TitledBorder extends AbstractBorder 61: { 62: /** 63: * A value for the <code>titlePosition</code> property that vertically 64: * positions the title text at the default vertical position, which 65: * is in the middle of the top line of the border. 66: * 67: * @see #getTitlePosition() 68: * @see #setTitlePosition(int) 69: */ 70: public static final int DEFAULT_POSITION = 0; 71: 72: 73: /** 74: * A value for the <code>titlePosition</code> property that vertically 75: * positions the title text above the top line of the border. 76: * 77: * @see #getTitlePosition() 78: * @see #setTitlePosition(int) 79: */ 80: public static final int ABOVE_TOP = 1; 81: 82: 83: /** 84: * A value for the <code>titlePosition</code> property that vertically 85: * positions the title text at the middle of the top line 86: * of the border. 87: * 88: * @see #getTitlePosition() 89: * @see #setTitlePosition(int) 90: */ 91: public static final int TOP = 2; 92: 93: 94: /** 95: * A value for the <code>titlePosition</code> property that vertically 96: * positions the title text below the top line of the border. 97: * 98: * @see #getTitlePosition() 99: * @see #setTitlePosition(int) 100: */ 101: public static final int BELOW_TOP = 3; 102: 103: 104: /** 105: * A value for the <code>titlePosition</code> property that vertically 106: * positions the title text above the bottom line of the border. 107: * 108: * @see #getTitlePosition() 109: * @see #setTitlePosition(int) 110: */ 111: public static final int ABOVE_BOTTOM = 4; 112: 113: 114: /** 115: * A value for the <code>titlePosition</code> property that vertically 116: * positions the title text at the center of the bottom line 117: * of the border. 118: * 119: * @see #getTitlePosition() 120: * @see #setTitlePosition(int) 121: */ 122: public static final int BOTTOM = 5; 123: 124: 125: /** 126: * A value for the <code>titlePosition</code> property that vertically 127: * positions the title text below the bottom line of the border. 128: * 129: * @see #getTitlePosition() 130: * @see #setTitlePosition(int) 131: */ 132: public static final int BELOW_BOTTOM = 6; 133: 134: 135: /** 136: * A value for the <code>titleJustification</code> property that 137: * horizontally aligns the title text with either the left or the 138: * right edge of the border, depending on the orientation of the 139: * component nested into the border. If the component orientation 140: * is left-to-right, the title text is aligned with the left edge; 141: * otherwise, it is aligned with the right edge. This is the same 142: * behavior as with {@link #LEADING}. 143: * 144: * @see #getTitleJustification() 145: * @see #setTitleJustification(int) 146: * @see java.awt.ComponentOrientation#isLeftToRight() 147: */ 148: public static final int DEFAULT_JUSTIFICATION = 0; 149: 150: 151: /** 152: * A value for the <code>titleJustification</code> property that 153: * horizontally aligns the title text with the left-hand edge of 154: * the border. 155: * 156: * @see #getTitleJustification() 157: * @see #setTitleJustification(int) 158: */ 159: public static final int LEFT = 1; 160: 161: 162: /** 163: * A value for the <code>titleJustification</code> property that 164: * horizontally aligns the title text with the center of the border. 165: * 166: * @see #getTitleJustification() 167: * @see #setTitleJustification(int) 168: */ 169: public static final int CENTER = 2; 170: 171: 172: /** 173: * A value for the <code>titleJustification</code> property that 174: * horizontally aligns the title text with the right-hand edge of 175: * the border. 176: * 177: * @see #getTitleJustification() 178: * @see #setTitleJustification(int) 179: */ 180: public static final int RIGHT = 3; 181: 182: 183: /** 184: * A value for the <code>titleJustification</code> property that 185: * horizontally aligns the title text with either the left or the 186: * right edge of the border, depending on the orientation of the 187: * component nested into the border. If the component orientation 188: * is left-to-right, the title text is aligned with the left edge; 189: * otherwise, it is aligned with the right edge. This is the same 190: * behavior as with {@link #DEFAULT_JUSTIFICATION}. 191: * 192: * @see #getTitleJustification() 193: * @see #setTitleJustification(int) 194: * @see java.awt.ComponentOrientation#isLeftToRight() 195: */ 196: public static final int LEADING = 4; 197: 198: 199: /** 200: * A value for the <code>titleJustification</code> property that 201: * horizontally aligns the title text with either the right or the 202: * left edge of the border, depending on the orientation of the 203: * component nested into the border. If the component orientation 204: * is left-to-right, the title text is aligned with the right edge; 205: * otherwise, it is aligned with the left edge. 206: * 207: * @see #getTitleJustification() 208: * @see #setTitleJustification(int) 209: * @see java.awt.ComponentOrientation#isLeftToRight() 210: */ 211: public static final int TRAILING = 5; 212: 213: 214: /** 215: * The number of pixels between the inside of {@link #border} 216: * and the bordered component. 217: */ 218: protected static final int EDGE_SPACING = 2; 219: 220: 221: /** 222: * The number of pixels between the outside of this TitledBorder 223: * and the beginning (if left-aligned) or end (if right-aligned) 224: * of the title text. 225: */ 226: protected static final int TEXT_INSET_H = 5; 227: 228: 229: /** 230: * The number of pixels between the title text and {@link #border}. 231: * This value is only relevant if the title text does not intersect 232: * {@link #border}. No intersection occurs if {@link #titlePosition} 233: * is one of {@link #ABOVE_TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, 234: * or {@link #BELOW_BOTTOM}. 235: */ 236: protected static final int TEXT_SPACING = 2; 237: 238: 239: /** 240: * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1 241: * on MacOS X 10.1.5. 242: */ 243: static final long serialVersionUID = 8012999415147721601L; 244: 245: 246: /** 247: * The title, or <code>null</code> to display no title. 248: */ 249: protected String title; 250: 251: 252: /** 253: * The border underneath the title. If this value is 254: * <code>null</code>, the border will be retrieved from the {@link 255: * javax.swing.UIManager}’s defaults table using the key 256: * <code>TitledBorder.border</code>. 257: */ 258: protected Border border; 259: 260: 261: /** 262: * The vertical position of the title text relative to the border, 263: * which is one of {@link #ABOVE_TOP}, {@link #TOP}, {@link 264: * #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link 265: * #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}. 266: */ 267: protected int titlePosition; 268: 269: 270: /** 271: * The horizontal alignment of the title text in relation to the 272: * border, which is one of {@link #LEFT}, {@link #CENTER}, {@link 273: * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link 274: * #DEFAULT_JUSTIFICATION}. 275: */ 276: protected int titleJustification; 277: 278: 279: /** 280: * The font for displaying the title text. If this value is 281: * <code>null</code>, the font will be retrieved from the {@link 282: * javax.swing.UIManager}’s defaults table using the key 283: * <code>TitledBorder.font</code>. 284: */ 285: protected Font titleFont; 286: 287: 288: /** 289: * The color for displaying the title text. If this value is 290: * <code>null</code>, the color will be retrieved from the {@link 291: * javax.swing.UIManager}’s defaults table using the key 292: * <code>TitledBorder.titleColor</code>. 293: */ 294: protected Color titleColor; 295: 296: 297: /** 298: * Constructs a TitledBorder given the text of its title. 299: * 300: * @param title the title text, or <code>null</code> to use no title text. 301: */ 302: public TitledBorder(String title) 303: { 304: this(/* border */ null, 305: title, LEADING, TOP, 306: /* titleFont */ null, /* titleColor */ null); 307: } 308: 309: 310: /** 311: * Constructs an initially untitled TitledBorder given another border. 312: * 313: * @param border the border underneath the title, or <code>null</code> 314: * to use a default from the current look and feel. 315: */ 316: public TitledBorder(Border border) 317: { 318: this(border, /* title */ "", LEADING, TOP, 319: /* titleFont */ null, /* titleColor */ null); 320: } 321: 322: 323: /** 324: * Constructs a TitledBorder given its border and title text. 325: * 326: * @param border the border underneath the title, or <code>null</code> 327: * to use a default from the current look and feel. 328: * 329: * @param title the title text, or <code>null</code> to use no title 330: * text. 331: */ 332: public TitledBorder(Border border, String title) 333: { 334: this(border, title, LEADING, TOP, 335: /* titleFont */ null, /* titleColor */ null); 336: } 337: 338: 339: /** 340: * Constructs a TitledBorder given its border, title text, horizontal 341: * alignment, and vertical position. 342: * 343: * @param border the border underneath the title, or <code>null</code> 344: * to use a default from the current look and feel. 345: * 346: * @param title the title text, or <code>null</code> to use no title 347: * text. 348: * 349: * @param titleJustification the horizontal alignment of the title 350: * text in relation to the border. The value must be one of 351: * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, 352: * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. 353: 354: * @param titlePosition the vertical position of the title text 355: * in relation to the border. The value must be one of 356: * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, 357: * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, 358: * or {@link #DEFAULT_POSITION}. 359: * 360: * @throws IllegalArgumentException if <code>titleJustification</code> 361: * or <code>titlePosition</code> have an unsupported value. 362: */ 363: public TitledBorder(Border border, String title, int titleJustification, 364: int titlePosition) 365: { 366: this(border, title, titleJustification, titlePosition, 367: /* titleFont */ null, /* titleColor */ null); 368: } 369: 370: 371: /** 372: * Constructs a TitledBorder given its border, title text, horizontal 373: * alignment, vertical position, and font. 374: * 375: * @param border the border underneath the title, or <code>null</code> 376: * to use a default from the current look and feel. 377: * 378: * @param title the title text, or <code>null</code> to use no title 379: * text. 380: * 381: * @param titleJustification the horizontal alignment of the title 382: * text in relation to the border. The value must be one of 383: * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, 384: * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. 385: * 386: * @param titlePosition the vertical position of the title text 387: * in relation to the border. The value must be one of 388: * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, 389: * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, 390: * or {@link #DEFAULT_POSITION}. 391: * 392: * @param titleFont the font for the title text, or <code>null</code> 393: * to use a default from the current look and feel. 394: * 395: * @throws IllegalArgumentException if <code>titleJustification</code> 396: * or <code>titlePosition</code> have an unsupported value. 397: */ 398: public TitledBorder(Border border, String title, int titleJustification, 399: int titlePosition, Font titleFont) 400: { 401: this(border, title, titleJustification, titlePosition, titleFont, 402: /* titleColor */ null); 403: } 404: 405: 406: /** 407: * Constructs a TitledBorder given its border, title text, horizontal 408: * alignment, vertical position, font, and color. 409: * 410: * @param border the border underneath the title, or <code>null</code> 411: * to use a default from the current look and feel. 412: * 413: * @param title the title text, or <code>null</code> to use no title 414: * text. 415: * 416: * @param titleJustification the horizontal alignment of the title 417: * text in relation to the border. The value must be one of 418: * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, 419: * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. 420: * 421: * @param titlePosition the vertical position of the title text 422: * in relation to the border. The value must be one of 423: * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, 424: * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, 425: * or {@link #DEFAULT_POSITION}. 426: * 427: * @param titleFont the font for the title text, or <code>null</code> 428: * to use a default from the current look and feel. 429: * 430: * @param titleColor the color for the title text, or <code>null</code> 431: * to use a default from the current look and feel. 432: * 433: * @throws IllegalArgumentException if <code>titleJustification</code> 434: * or <code>titlePosition</code> have an unsupported value. 435: */ 436: public TitledBorder(Border border, String title, int titleJustification, 437: int titlePosition, Font titleFont, Color titleColor) 438: { 439: this.border = border; 440: this.title = title; 441: 442: /* Invoking the setter methods ensures that the newly constructed 443: * TitledBorder has valid property values. 444: */ 445: setTitleJustification(titleJustification); 446: setTitlePosition(titlePosition); 447: 448: this.titleFont = titleFont; 449: this.titleColor = titleColor; 450: } 451: 452: 453: /** 454: * Paints the border and the title text. 455: * 456: * @param c the component whose border is to be painted. 457: * @param g the graphics for painting. 458: * @param x the horizontal position for painting the border. 459: * @param y the vertical position for painting the border. 460: * @param width the width of the available area for painting the border. 461: * @param height the height of the available area for painting the border. 462: */ 463: public void paintBorder(Component c, Graphics g, 464: int x, int y, int width, int height) 465: { 466: Rectangle borderRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, 467: width - (EDGE_SPACING * 2), 468: height - (EDGE_SPACING * 2)); 469: Point textLoc = new Point(); 470: 471: // Save color and font. 472: Color savedColor = g.getColor(); 473: Font savedFont = g.getFont(); 474: 475: // The font metrics. 476: Font font = getFont(c); 477: g.setFont(font); 478: FontMetrics fm = c.getFontMetrics(font); 479: 480: layoutBorderWithTitle(c, fm, borderRect, textLoc); 481: paintBorderWithTitle(c, g, x, y, width, height, borderRect, textLoc, fm); 482: 483: g.setColor(getTitleColor()); 484: g.drawString(getTitle(), textLoc.x, textLoc.y); 485: g.setFont(savedFont); 486: g.setColor(savedColor); 487: } 488: 489: /** 490: * Calculates the bounding box of the inner border and the location of the 491: * title string. 492: * 493: * @param c the component on which to paint the border 494: * @param fm the font metrics 495: * @param borderRect output parameter, holds the bounding box of the inner 496: * border on method exit 497: * @param textLoc output parameter, holds the location of the title text 498: * on method exit 499: */ 500: private void layoutBorderWithTitle(Component c, FontMetrics fm, 501: Rectangle borderRect, 502: Point textLoc) 503: { 504: Border b = getBorder(); 505: 506: // The font metrics. 507: int fontHeight = fm.getHeight(); 508: int fontDescent = fm.getDescent(); 509: int fontAscent = fm.getAscent(); 510: int titleWidth = fm.stringWidth(getTitle()); 511: 512: // The base insets. 513: Insets insets; 514: if (b == null) 515: insets = new Insets(0, 0, 0, 0); 516: else 517: insets = b.getBorderInsets(c); 518: 519: // The offset of the border rectangle, dependend on the title placement. 520: int offset; 521: 522: // Layout border and text vertically. 523: int titlePosition = getTitlePosition(); 524: switch (titlePosition) 525: { 526: case ABOVE_BOTTOM: 527: textLoc.y = borderRect.y + borderRect.height - insets.bottom 528: - fontDescent - TEXT_SPACING; 529: break; 530: case BOTTOM: 531: borderRect.height -= fontHeight / 2; 532: textLoc.y = borderRect.y + borderRect.height - fontDescent 533: + (fontAscent + fontDescent - insets.bottom) / 2; 534: break; 535: case BELOW_BOTTOM: 536: borderRect.height -= fontHeight; 537: textLoc.y = borderRect.y + borderRect.height + fontAscent 538: + TEXT_SPACING; 539: break; 540: case ABOVE_TOP: 541: offset = fontAscent + fontDescent 542: + Math.max(EDGE_SPACING, TEXT_SPACING * 2) - EDGE_SPACING; 543: borderRect.y += offset; 544: borderRect.height -= offset; 545: textLoc.y = borderRect.y - (fontDescent + TEXT_SPACING); 546: break; 547: case BELOW_TOP: 548: textLoc.y = borderRect.y + insets.top + fontAscent + TEXT_SPACING; 549: break; 550: case TOP: 551: case DEFAULT_POSITION: 552: default: 553: offset = Math.max(0, ((fontAscent / 2) + TEXT_SPACING) - EDGE_SPACING); 554: borderRect.y += offset; 555: borderRect.height -= offset; 556: textLoc.y = borderRect.y - fontDescent 557: + (insets.top + fontAscent + fontDescent) / 2; 558: break; 559: } 560: 561: // Layout border and text horizontally. 562: int justification = getTitleJustification(); 563: // Adjust justification for LEADING and TRAILING depending on the direction 564: // of the component. 565: if (c.getComponentOrientation().isLeftToRight()) 566: { 567: if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) 568: justification = LEFT; 569: else if (justification == TRAILING) 570: justification = RIGHT; 571: } 572: else 573: { 574: if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) 575: justification = RIGHT; 576: else if (justification == TRAILING) 577: justification = LEFT; 578: } 579: 580: switch (justification) 581: { 582: case CENTER: 583: textLoc.x = borderRect.x + (borderRect.width - titleWidth) / 2; 584: break; 585: case RIGHT: 586: textLoc.x = borderRect.x + borderRect.width - titleWidth 587: - TEXT_INSET_H - insets.right; 588: break; 589: case LEFT: 590: default: 591: textLoc.x = borderRect.x + TEXT_INSET_H + insets.left; 592: } 593: } 594: 595: /** 596: * Paints the border with the title. 597: * 598: * @param c the component to paint on 599: * @param g the graphics context used for paintin 600: * @param x the upper left corner of the whole border 601: * @param y the upper left corner of the whole border 602: * @param width the width of the whole border 603: * @param height the width of the whole border 604: * @param borderRect the bounding box of the inner border 605: * @param textLoc the location of the border title 606: * @param fm the font metrics of the title 607: */ 608: private void paintBorderWithTitle(Component c, Graphics g, int x, int y, 609: int width, int height, 610: Rectangle borderRect, Point textLoc, 611: FontMetrics fm) 612: { 613: Border b = getBorder(); 614: int fontDescent = fm.getDescent(); 615: int fontAscent = fm.getAscent(); 616: int titleWidth = fm.stringWidth(getTitle()); 617: 618: if (b != null) 619: { 620: // Paint border in segments, when the title is painted above the 621: // border. 622: if (((titlePosition == TOP || titlePosition == DEFAULT_POSITION) 623: && (borderRect.y > textLoc.y - fontAscent)) 624: || (titlePosition == BOTTOM 625: && borderRect.y + borderRect.height < textLoc.y + fontDescent)) 626: { 627: Rectangle clip = new Rectangle(); 628: Rectangle saved = g.getClipBounds(); 629: 630: // Paint border left from the text. 631: clip.setBounds(saved); 632: SwingUtilities.computeIntersection(x, y, textLoc.x - x - 1, 633: height, clip); 634: if (! clip.isEmpty()) 635: { 636: g.setClip(clip); 637: b.paintBorder(c, g, borderRect.x, borderRect.y, 638: borderRect.width, 639: borderRect.height); 640: } 641: // Paint border right from the text. 642: clip.setBounds(saved); 643: SwingUtilities.computeIntersection(textLoc.x + titleWidth + 1, y, 644: x + width - (textLoc.x + titleWidth + 1), height, clip); 645: if (! clip.isEmpty()) 646: { 647: g.setClip(clip); 648: b.paintBorder(c, g, borderRect.x, borderRect.y, 649: borderRect.width, 650: borderRect.height); 651: } 652: 653: if (titlePosition == TOP || titlePosition == DEFAULT_POSITION) 654: { 655: // Paint border below the text. 656: clip.setBounds(saved); 657: SwingUtilities.computeIntersection(textLoc.x - 1, 658: textLoc.y + fontDescent, 659: titleWidth + 2, 660: y + height - textLoc.y - fontDescent, 661: clip); 662: if (! clip.isEmpty()) 663: { 664: g.setClip(clip); 665: b.paintBorder(c, g, borderRect.x, borderRect.y, 666: borderRect.width, 667: borderRect.height); 668: } 669: 670: } 671: else 672: { 673: // Paint border above the text. 674: clip.setBounds(saved); 675: SwingUtilities.computeIntersection(textLoc.x - 1, y, 676: titleWidth + 2, 677: textLoc.y - fontDescent - y, 678: clip); 679: if (! clip.isEmpty()) 680: { 681: g.setClip(clip); 682: b.paintBorder(c, g, borderRect.x, borderRect.y, 683: borderRect.width, 684: borderRect.height); 685: } 686: 687: } 688: g.setClip(saved); 689: } 690: else 691: { 692: b.paintBorder(c, g, borderRect.x, borderRect.y, borderRect.width, 693: borderRect.height); 694: } 695: } 696: } 697: 698: /** 699: * Measures the width of this border. 700: * 701: * @param c the component whose border is to be measured. 702: * 703: * @return an Insets object whose <code>left</code>, <code>right</code>, 704: * <code>top</code> and <code>bottom</code> fields indicate the 705: * width of the border at the respective edge. 706: * 707: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 708: */ 709: public Insets getBorderInsets(Component c) 710: { 711: return getBorderInsets(c, new Insets(0, 0, 0, 0)); 712: } 713: 714: 715: /** 716: * Measures the width of this border, storing the results into a 717: * pre-existing Insets object. 718: * 719: * @param insets an Insets object for holding the result values. 720: * After invoking this method, the <code>left</code>, 721: * <code>right</code>, <code>top</code> and 722: * <code>bottom</code> fields indicate the width of the 723: * border at the respective edge. 724: * 725: * @return the same object that was passed for <code>insets</code>. 726: * 727: * @see #getBorderInsets(Component) 728: */ 729: public Insets getBorderInsets(Component c, Insets insets) 730: { 731: // Initialize insets with the insets from our border. 732: Border border = getBorder(); 733: if (border != null) 734: { 735: if (border instanceof AbstractBorder) 736: { 737: AbstractBorder aBorder = (AbstractBorder) border; 738: aBorder.getBorderInsets(c, insets); 739: } 740: else 741: { 742: Insets i = border.getBorderInsets(c); 743: insets.top = i.top; 744: insets.bottom = i.bottom; 745: insets.left = i.left; 746: insets.right = i.right; 747: } 748: } 749: else 750: { 751: insets.top = 0; 752: insets.bottom = 0; 753: insets.left = 0; 754: insets.right = 0; 755: } 756: 757: // Add spacing. 758: insets.top += EDGE_SPACING + TEXT_SPACING; 759: insets.bottom += EDGE_SPACING + TEXT_SPACING; 760: insets.left += EDGE_SPACING + TEXT_SPACING; 761: insets.right += EDGE_SPACING + TEXT_SPACING; 762: 763: String title = getTitle(); 764: if (c != null && title != null && !title.equals("")) 765: { 766: Font font = getFont(c); 767: FontMetrics fm = c.getFontMetrics(font); 768: int ascent = fm.getAscent(); 769: int descent = fm.getDescent(); 770: int height = fm.getHeight(); 771: switch (getTitlePosition()) 772: { 773: case ABOVE_BOTTOM: 774: insets.bottom += ascent + descent + TEXT_SPACING; 775: break; 776: case BOTTOM: 777: insets.bottom += ascent + descent; 778: break; 779: case BELOW_BOTTOM: 780: insets.bottom += height; 781: break; 782: case ABOVE_TOP: 783: insets.top += ascent + descent + 784: Math.max(EDGE_SPACING, TEXT_SPACING * 2) 785: - EDGE_SPACING; 786: break; 787: case BELOW_TOP: 788: insets.top += ascent + descent + TEXT_SPACING; 789: break; 790: case TOP: 791: case DEFAULT_POSITION: 792: default: 793: insets.top += ascent + descent; 794: } 795: } 796: return insets; 797: } 798: 799: 800: /** 801: * Returns <code>false</code>, indicating that there are pixels inside 802: * the area of this border where the background shines through. 803: * 804: * @return <code>false</code>. 805: */ 806: public boolean isBorderOpaque() 807: { 808: /* Note that the AbstractBorder.isBorderOpaque would also return 809: * false, so there is actually no need to override the inherited 810: * implementation. However, GNU Classpath strives for exact 811: * compatibility with the Sun reference implementation, which 812: * overrides isBorderOpaque for unknown reasons. 813: */ 814: return false; 815: } 816: 817: 818: /** 819: * Returns the text of the title. 820: * 821: * @return the title text, or <code>null</code> if no title is 822: * displayed. 823: */ 824: public String getTitle() 825: { 826: return title; 827: } 828: 829: 830: /** 831: * Retrieves the border underneath the title. If no border has been 832: * set, or if it has been set to<code>null</code>, the current 833: * {@link javax.swing.LookAndFeel} will be asked for a border 834: * using the key <code>TitledBorder.border</code>. 835: * 836: * @return a border, or <code>null</code> if the current LookAndFeel 837: * does not provide a border for the key 838: * <code>TitledBorder.border</code>. 839: * 840: * @see javax.swing.UIManager#getBorder(Object) 841: */ 842: public Border getBorder() 843: { 844: if (border != null) 845: return border; 846: 847: return UIManager.getBorder("TitledBorder.border"); 848: } 849: 850: 851: /** 852: * Returns the vertical position of the title text in relation 853: * to the border. 854: * 855: * @return one of the values {@link #ABOVE_TOP}, {@link #TOP}, 856: * {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, 857: * {@link #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}. 858: */ 859: public int getTitlePosition() 860: { 861: return titlePosition; 862: } 863: 864: 865: /** 866: * Returns the horizontal alignment of the title text in relation to 867: * the border. 868: * 869: * @return one of the values {@link #LEFT}, {@link #CENTER}, {@link 870: * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link 871: * #DEFAULT_JUSTIFICATION}. 872: */ 873: public int getTitleJustification() 874: { 875: return titleJustification; 876: } 877: 878: 879: /** 880: * Retrieves the font for displaying the title text. If no font has 881: * been set, or if it has been set to<code>null</code>, the current 882: * {@link javax.swing.LookAndFeel} will be asked for a font 883: * using the key <code>TitledBorder.font</code>. 884: * 885: * @return a font, or <code>null</code> if the current LookAndFeel 886: * does not provide a font for the key 887: * <code>TitledBorder.font</code>. 888: * 889: * @see javax.swing.UIManager#getFont(Object) 890: */ 891: public Font getTitleFont() 892: { 893: if (titleFont != null) 894: return titleFont; 895: 896: return UIManager.getFont("TitledBorder.font"); 897: } 898: 899: 900: /** 901: * Retrieves the color for displaying the title text. If no color has 902: * been set, or if it has been set to<code>null</code>, the current 903: * {@link javax.swing.LookAndFeel} will be asked for a color 904: * using the key <code>TitledBorder.titleColor</code>. 905: * 906: * @return a color, or <code>null</code> if the current LookAndFeel 907: * does not provide a color for the key 908: * <code>TitledBorder.titleColor</code>. 909: * 910: * @see javax.swing.UIManager#getColor(Object) 911: */ 912: public Color getTitleColor() 913: { 914: if (titleColor != null) 915: return titleColor; 916: 917: return UIManager.getColor("TitledBorder.titleColor"); 918: } 919: 920: 921: /** 922: * Sets the text of the title. 923: * 924: * @param title the new title text, or <code>null</code> for displaying 925: * no text at all. 926: */ 927: public void setTitle(String title) 928: { 929: // Swing borders are not JavaBeans, thus no need to fire an event. 930: this.title = title; 931: } 932: 933: 934: /** 935: * Sets the border underneath the title. 936: * 937: * @param border a border, or <code>null</code> to use the 938: * border that is supplied by the current LookAndFeel. 939: * 940: * @see #getBorder() 941: */ 942: public void setBorder(Border border) 943: { 944: // Swing borders are not JavaBeans, thus no need to fire an event. 945: this.border = border; 946: } 947: 948: 949: /** 950: * Sets the vertical position of the title text in relation 951: * to the border. 952: * 953: * @param titlePosition one of the values {@link #ABOVE_TOP}, 954: * {@link #TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, 955: * {@link #BOTTOM}, {@link #BELOW_BOTTOM}, 956: * or {@link #DEFAULT_POSITION}. 957: * 958: * @throws IllegalArgumentException if an unsupported value is passed 959: * for <code>titlePosition</code>. 960: */ 961: public void setTitlePosition(int titlePosition) 962: { 963: if ((titlePosition < DEFAULT_POSITION) || (titlePosition > BELOW_BOTTOM)) 964: throw new IllegalArgumentException(titlePosition 965: + " is not a valid title position."); 966: 967: // Swing borders are not JavaBeans, thus no need to fire an event. 968: this.titlePosition = titlePosition; 969: } 970: 971: 972: /** 973: * Sets the horizontal alignment of the title text in relation to the border. 974: * 975: * @param titleJustification the new alignment, which must be one of 976: * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, 977: * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. 978: * 979: * @throws IllegalArgumentException if an unsupported value is passed 980: * for <code>titleJustification</code>. 981: */ 982: public void setTitleJustification(int titleJustification) 983: { 984: if ((titleJustification < DEFAULT_JUSTIFICATION) 985: || (titleJustification > TRAILING)) 986: throw new IllegalArgumentException(titleJustification 987: + " is not a valid title justification."); 988: 989: // Swing borders are not JavaBeans, thus no need to fire an event. 990: this.titleJustification = titleJustification; 991: } 992: 993: 994: /** 995: * Sets the font for displaying the title text. 996: * 997: * @param titleFont the font, or <code>null</code> to use the font 998: * provided by the current {@link javax.swing.LookAndFeel}. 999: * 1000: * @see #getTitleFont() 1001: */ 1002: public void setTitleFont(Font titleFont) 1003: { 1004: // Swing borders are not JavaBeans, thus no need to fire an event. 1005: this.titleFont = titleFont; 1006: } 1007: 1008: 1009: /** 1010: * Sets the color for displaying the title text. 1011: * 1012: * @param titleColor the color, or <code>null</code> to use the color 1013: * provided by the current {@link javax.swing.LookAndFeel}. 1014: * 1015: * @see #getTitleColor() 1016: */ 1017: public void setTitleColor(Color titleColor) 1018: { 1019: // Swing borders are not JavaBeans, thus no need to fire an event. 1020: this.titleColor = titleColor; 1021: } 1022: 1023: 1024: /** 1025: * Calculates the minimum size needed for displaying the border 1026: * and its title. 1027: * 1028: * @param c the Component for which this TitledBorder constitutes 1029: * a border. 1030: * 1031: * @return The minimum size. 1032: */ 1033: public Dimension getMinimumSize(Component c) 1034: { 1035: Insets i = getBorderInsets(c); 1036: Dimension minSize = new Dimension(i.left + i.right, i.top + i.bottom); 1037: Font font = getFont(c); 1038: FontMetrics fm = c.getFontMetrics(font); 1039: int titleWidth = fm.stringWidth(getTitle()); 1040: switch (getTitlePosition()) 1041: { 1042: case ABOVE_TOP: 1043: case BELOW_BOTTOM: 1044: minSize.width = Math.max(minSize.width, titleWidth); 1045: break; 1046: case BELOW_TOP: 1047: case ABOVE_BOTTOM: 1048: case TOP: 1049: case BOTTOM: 1050: case DEFAULT_POSITION: 1051: default: 1052: minSize.width += titleWidth; 1053: } 1054: return minSize; 1055: } 1056: 1057: 1058: /** 1059: * Returns the font that is used for displaying the title text for 1060: * a given Component. 1061: * 1062: * @param c the Component for which this TitledBorder is the border. 1063: * 1064: * @return The font returned by {@link #getTitleFont()}, or a fallback 1065: * if {@link #getTitleFont()} returned <code>null</code>. 1066: */ 1067: protected Font getFont(Component c) 1068: { 1069: Font f; 1070: 1071: f = getTitleFont(); 1072: if (f != null) 1073: return f; 1074: 1075: return new Font("Dialog", Font.PLAIN, 12); 1076: } 1077: 1078: }