| GNU Classpath (0.95) | |
| Frames | No Frames |
1: /* BasicBorders.java -- 2: Copyright (C) 2003, 2004, 2005 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.plaf.basic; 40: 41: import java.awt.Color; 42: import java.awt.Component; 43: import java.awt.Graphics; 44: import java.awt.Insets; 45: import java.awt.Rectangle; 46: import java.io.Serializable; 47: 48: import javax.swing.AbstractButton; 49: import javax.swing.ButtonModel; 50: import javax.swing.JButton; 51: import javax.swing.JPopupMenu; 52: import javax.swing.JSplitPane; 53: import javax.swing.JToolBar; 54: import javax.swing.UIManager; 55: import javax.swing.border.AbstractBorder; 56: import javax.swing.border.BevelBorder; 57: import javax.swing.border.Border; 58: import javax.swing.plaf.BorderUIResource; 59: import javax.swing.plaf.UIResource; 60: import javax.swing.text.JTextComponent; 61: 62: /** 63: * Provides various borders for the Basic look and feel. 64: * 65: * @author Sascha Brawer (brawer@dandelis.ch) 66: */ 67: public class BasicBorders 68: { 69: /** 70: * A MarginBorder that gets shared by multiple components. 71: * Created on demand by the private helper function {@link 72: * #getMarginBorder()}. 73: */ 74: private static MarginBorder sharedMarginBorder; 75: 76: 77: /** 78: * Returns a border for drawing push buttons. 79: * 80: * <p>The colors of the border are retrieved from the 81: * <code>UIDefaults</code> of the currently active look and feel 82: * using the keys <code>“Button.shadow”</code>, 83: * <code>“Button.darkShadow”</code>, 84: * <code>“Button.light”</code>, and 85: * <code>“Button.highlight”</code>. 86: * 87: * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" 88: * height="170" alt="[A screen shot of the returned border]" /> 89: * 90: * @return a {@link 91: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 92: * whose outer border is a {@link ButtonBorder} and whose 93: * inner border is a {@link MarginBorder}. 94: */ 95: public static Border getButtonBorder() 96: { 97: Border outer; 98: 99: /* The keys for UIDefaults have been determined by writing a 100: * test program that dumps the UIDefaults to stdout; that program 101: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 102: * the key "light" is usually called "highlight", and "highlight" 103: * is usually called "lightHighlight". 104: */ 105: outer = new ButtonBorder(UIManager.getColor("Button.shadow"), 106: UIManager.getColor("Button.darkShadow"), 107: UIManager.getColor("Button.light"), 108: UIManager.getColor("Button.highlight")); 109: 110: /* While the inner border is shared between multiple buttons, 111: * we do not share the outer border because ButtonBorders store 112: * their border colors. We cannot guarantee that the colors 113: * (which come from UIDefaults) are unchanged between invocations 114: * of getButtonBorder. We could store the last colors, and share 115: * the button border if the colors are the same as in the last 116: * invocation, but it probably is not worth the effort. 117: */ 118: return new BorderUIResource.CompoundBorderUIResource( 119: outer, 120: /* inner */ getMarginBorder()); 121: } 122: 123: 124: /** 125: * Returns a border for drawing radio buttons. 126: * 127: * <p>The colors of the border are retrieved from the 128: * <code>UIDefaults</code> of the currently active look and feel 129: * using the keys <code>“RadioButton.shadow”</code>, 130: * <code>“RadioButton.darkShadow”</code>, 131: * <code>“RadioButton.light”</code>, and 132: * <code>“RadioButton.highlight”</code>. 133: * 134: * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" 135: * height="135" alt="[A screen shot of the returned border]" /> 136: * 137: * @return a {@link 138: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 139: * whose outer border is a {@link RadioButtonBorder} and whose 140: * inner border is a {@link MarginBorder}. 141: */ 142: public static Border getRadioButtonBorder() 143: { 144: Border outer; 145: 146: /* The keys for UIDefaults have been determined by writing a 147: * test program that dumps the UIDefaults to stdout; that program 148: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 149: * the key "light" is usually called "highlight", and "highlight" 150: * is usually called "lightHighlight". 151: */ 152: outer = new RadioButtonBorder( 153: UIManager.getColor("RadioButton.shadow"), 154: UIManager.getColor("RadioButton.darkShadow"), 155: UIManager.getColor("RadioButton.light"), 156: UIManager.getColor("RadioButton.highlight")); 157: 158: /* While the inner border is shared between multiple buttons, we 159: * do not share the outer border because RadioButtonBorders, being 160: * ButtonBorders, store their border colors. We cannot guarantee 161: * that the colors (which come from UIDefaults) are unchanged 162: * between invocations of getButtonBorder. We could store the last 163: * colors, and share the button border if the colors are the same 164: * as in the last invocation, but it probably is not worth the 165: * effort. 166: */ 167: return new BorderUIResource.CompoundBorderUIResource( 168: outer, 169: /* inner */ getMarginBorder()); 170: } 171: 172: 173: /** 174: * Returns a border for drawing toggle buttons. 175: * 176: * <p>The colors of the border are retrieved from the 177: * <code>UIDefaults</code> of the currently active look and feel 178: * using the keys <code>“ToggleButton.shadow”</code>, 179: * <code>“ToggleButton.darkShadow”</code>, 180: * <code>“ToggleButton.light”</code>, and 181: * <code>“ToggleButton.highlight”</code>. 182: * 183: * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" width="270" 184: * height="135" alt="[A screen shot of the returned border]" /> 185: * 186: * @return a {@link 187: * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} 188: * whose outer border is a {@link ToggleButtonBorder} and whose 189: * inner border is a {@link MarginBorder}. 190: */ 191: public static Border getToggleButtonBorder() 192: { 193: Border outer; 194: 195: /* The keys for UIDefaults have been determined by writing a 196: * test program that dumps the UIDefaults to stdout; that program 197: * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, 198: * the key "light" is usually called "highlight", and "highlight" 199: * is usually called "lightHighlight". 200: */ 201: outer = new ToggleButtonBorder( 202: UIManager.getColor("ToggleButton.shadow"), 203: UIManager.getColor("ToggleButton.darkShadow"), 204: UIManager.getColor("ToggleButton.light"), 205: UIManager.getColor("ToggleButton.highlight")); 206: 207: /* While the inner border is shared between multiple buttons, we 208: * do not share the outer border because ToggleButtonBorders, being 209: * ButtonBorders, store their border colors. We cannot guarantee 210: * that the colors (which come from UIDefaults) are unchanged 211: * between invocations of getButtonBorder. We could store the last 212: * colors, and share the button border if the colors are the same 213: * as in the last invocation, but it probably is not worth the 214: * effort. 215: */ 216: return new BorderUIResource.CompoundBorderUIResource( 217: outer, 218: /* inner */ getMarginBorder()); 219: } 220: 221: 222: /** 223: * Returns a border for drawing a two-pixel thick separator line 224: * below menu bars. 225: * 226: * <p>The colors of the border are retrieved from the 227: * <code>UIDefaults</code> of the currently active look and feel 228: * using the keys <code>“MenuBar.shadow”</code> and 229: * <code>“MenuBar.highlight”</code>. 230: * 231: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 232: * height="140" alt="[A screen shot of a JMenuBar with this border]" /> 233: * 234: * @return a {@link MenuBarBorder}. 235: * 236: * @see javax.swing.JMenuBar 237: */ 238: public static Border getMenuBarBorder() 239: { 240: /* See comment in methods above for why this border is not shared. */ 241: return new MenuBarBorder(UIManager.getColor("MenuBar.shadow"), 242: UIManager.getColor("MenuBar.highlight")); 243: } 244: 245: 246: /** 247: * Returns a border for drawing a one-pixel thick border around 248: * split panes that are interrupted where the divider joins the 249: * border. 250: * 251: * <p>The colors of the border are retrieved from the 252: * <code>UIDefaults</code> of the currently active look and feel 253: * using the keys <code>“SplitPane.darkShadow”</code> and 254: * <code>“SplitPane.highlight”</code>. 255: * 256: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 257: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 258: * 259: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 260: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 261: * 262: * @return a {@link SplitPaneBorder}. 263: * 264: * @see javax.swing.JSplitPane 265: * @see #getSplitPaneDividerBorder() 266: */ 267: public static Border getSplitPaneBorder() 268: { 269: /* See comment in methods above for why this border is not shared. */ 270: return new SplitPaneBorder(UIManager.getColor("SplitPane.highlight"), 271: UIManager.getColor("SplitPane.darkShadow")); 272: } 273: 274: 275: /** 276: * Returns a border for drawing a one-pixel thick border around 277: * the divider of split panes. 278: * 279: * <p>The colors of the edges that are adjacent to the child components 280: * of the <code>JSplitPane</code> are retrieved from the 281: * <code>UIDefaults</code> of the currently active look and feel 282: * using the keys <code>“SplitPane.darkShadow”</code> and 283: * <code>“SplitPane.highlight”</code>. The color of the 284: * other two edges is the background color of the divider. 285: * 286: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 287: * width="520" height="200" alt= 288: * "[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 289: * 290: * @return an instance of <code>SplitPaneDividerBorder</code>, which is 291: * not a public API class of this package. 292: * 293: * @see javax.swing.JSplitPane 294: * @see javax.swing.plaf.basic.BasicSplitPaneDivider 295: * @see #getSplitPaneBorder() 296: * 297: * @since 1.3 298: */ 299: public static Border getSplitPaneDividerBorder() 300: { 301: /* See comment in methods above for why this border is not shared. */ 302: return new SplitPaneDividerBorder(); 303: } 304: 305: 306: /** 307: * Returns a border for drawing a border around a text field 308: * that makes the field appear as etched into the surface. 309: * 310: * <p>The colors of the border are retrieved from the 311: * <code>UIDefaults</code> of the currently active look and feel 312: * using the keys <code>“TextField.shadow”</code>, 313: * <code>“TextField.darkShadow”</code>, 314: * <code>“TextField.light”</code>, and 315: * <code>“TextField.highlight”</code>. 316: * 317: * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" 318: * height="200" alt="[A screen shot of a border returned by 319: * this method]" /> 320: * 321: * @return an instance of {@link FieldBorder}. 322: * 323: * @see javax.swing.JTextField 324: * @see javax.swing.text.JTextComponent 325: */ 326: public static Border getTextFieldBorder() 327: { 328: /* See comment in methods above for why this border is not shared. */ 329: return new FieldBorder( 330: UIManager.getColor("TextField.shadow"), 331: UIManager.getColor("TextField.darkShadow"), 332: UIManager.getColor("TextField.light"), 333: UIManager.getColor("TextField.highlight")); 334: } 335: 336: 337: /** 338: * Returns a two-pixel thick, green 339: * <code>LineBorderUIResource</code>. This is so ugly that look and 340: * feels better use different borders for their progress bars, or 341: * they will look really terrible. 342: * 343: * <p><img src="doc-files/BasicBorders-1.png" width="120" height="80" 344: * alt="[A screen shot of a border returned by this method]" /> 345: */ 346: public static Border getProgressBarBorder() 347: { 348: /* There does not seem to exist a way to parametrize the color 349: * or thickness of the border through UIDefaults. 350: */ 351: return new BorderUIResource.LineBorderUIResource(Color.green, 2); 352: } 353: 354: 355: /** 356: * Returns a border that is composed of a raised bevel border and a 357: * one-pixel thick line border. 358: * 359: * <p><img src="doc-files/BasicBorders-2.png" width="300" height="200" 360: * alt="[A screen shot of a border returned by this method]" /> 361: * 362: * <p>The colors of the border are retrieved from the 363: * <code>UIDefaults</code> of the currently active look and feel 364: * using the keys <code>“InternalFrame.borderShadow”</code>, 365: * <code>“InternalFrame.borderDarkShadow”</code>, 366: * <code>“InternalFrame.borderLight”</code>, 367: * <code>“InternalFrame.borderHighlight”</code>, and 368: * (for the inner one-pixel thick line) 369: * <code>“InternalFrame.borderColor”</code>. 370: */ 371: public static Border getInternalFrameBorder() 372: { 373: Color shadow, darkShadow, highlight, lightHighlight, line; 374: 375: /* See comment in methods above for why this border is not shared. */ 376: shadow = UIManager.getColor("InternalFrame.borderShadow"); 377: darkShadow = UIManager.getColor("InternalFrame.borderDarkShadow"); 378: highlight = UIManager.getColor("InternalFrame.borderLight"); 379: lightHighlight = UIManager.getColor("InternalFrame.borderHighlight"); 380: line = UIManager.getColor("InternalFrame.borderColor"); 381: 382: return new BorderUIResource.CompoundBorderUIResource( 383: /* outer border */ 384: new BorderUIResource.BevelBorderUIResource( 385: BevelBorder.RAISED, 386: (highlight != null) ? highlight : Color.lightGray, 387: (lightHighlight != null) ? lightHighlight : Color.white, 388: (darkShadow != null) ? darkShadow : Color.black, 389: (shadow != null) ? shadow : Color.gray), 390: 391: /* inner border */ 392: new BorderUIResource.LineBorderUIResource( 393: (line != null) ? line : Color.lightGray)); 394: } 395: 396: 397: /** 398: * Returns a shared MarginBorder. 399: */ 400: static Border getMarginBorder() // intentionally not public 401: { 402: /* Swing is not designed to be thread-safe, so there is no 403: * need to synchronize the access to the global variable. 404: */ 405: if (sharedMarginBorder == null) 406: sharedMarginBorder = new MarginBorder(); 407: 408: return sharedMarginBorder; 409: } 410: 411: 412: /** 413: * A border whose appearance depends on the state of 414: * the enclosed button. 415: * 416: * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" 417: * height="170" alt="[A screen shot of this border]" /> 418: * 419: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 420: * 421: * @author Sascha Brawer (brawer@dandelis.ch) 422: */ 423: public static class ButtonBorder 424: extends AbstractBorder 425: implements Serializable, UIResource 426: { 427: /** 428: * Determined using the <code>serialver</code> tool 429: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 430: */ 431: static final long serialVersionUID = -157053874580739687L; 432: 433: 434: /** 435: * The color for drawing the shaded parts of the border. 436: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 437: */ 438: protected Color shadow; 439: 440: 441: /** 442: * The color for drawing the dark shaded parts of the border. 443: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 444: */ 445: protected Color darkShadow; 446: 447: 448: /** 449: * The color for drawing the highlighted parts of the border. 450: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 451: */ 452: protected Color highlight; 453: 454: 455: /** 456: * The color for drawing the bright highlighted parts of the border. 457: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 458: */ 459: protected Color lightHighlight; 460: 461: 462: /** 463: * Constructs a new border for drawing a button in the Basic 464: * look and feel. 465: * 466: * @param shadow the shadow color. 467: * @param darkShadow a darker variant of the shadow color. 468: * @param highlight the highlight color. 469: * @param lightHighlight a brighter variant of the highlight color. 470: */ 471: public ButtonBorder(Color shadow, Color darkShadow, 472: Color highlight, Color lightHighlight) 473: { 474: /* These colors usually come from the UIDefaults of the current 475: * look and feel. Use fallback values if the colors are not 476: * supplied. The API specification is silent about what 477: * behavior is expected for null colors, so users should not 478: * rely on this fallback (which is why it is not documented in 479: * the above Javadoc). 480: */ 481: this.shadow = (shadow != null) ? shadow : Color.gray; 482: this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; 483: this.highlight = (highlight != null) ? highlight : Color.lightGray; 484: this.lightHighlight = (lightHighlight != null) 485: ? lightHighlight 486: : Color.white; 487: } 488: 489: 490: /** 491: * Paints the ButtonBorder around a given component. 492: * 493: * @param c the component whose border is to be painted. 494: * @param g the graphics for painting. 495: * @param x the horizontal position for painting the border. 496: * @param y the vertical position for painting the border. 497: * @param width the width of the available area for painting the border. 498: * @param height the height of the available area for painting the border. 499: * 500: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 501: */ 502: public void paintBorder(Component c, Graphics g, 503: int x, int y, int width, int height) 504: { 505: ButtonModel bmodel = null; 506: 507: if (c instanceof AbstractButton) 508: bmodel = ((AbstractButton) c).getModel(); 509: 510: BasicGraphicsUtils.drawBezel( 511: g, x, y, width, height, 512: /* pressed */ (bmodel != null) 513: && /* mouse button pressed */ bmodel.isPressed() 514: && /* mouse inside */ bmodel.isArmed(), 515: /* default */ (c instanceof JButton) 516: && ((JButton) c).isDefaultButton(), 517: shadow, darkShadow, highlight, lightHighlight); 518: } 519: 520: 521: /** 522: * Measures the width of this border. 523: * 524: * <p>Although the thickness of the actually painted border 525: * depends on the state of the enclosed component, this 526: * measurement always returns the same amount of pixels. Indeed, 527: * it would be rather confusing if a button was appearing to 528: * change its size depending on whether it is pressed or not. 529: * 530: * @param c the component whose border is to be measured. 531: * 532: * @return an Insets object whose <code>left</code>, 533: * <code>right</code>, <code>top</code> and 534: * <code>bottom</code> fields indicate the width of the 535: * border at the respective edge. 536: * 537: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 538: */ 539: public Insets getBorderInsets(Component c) 540: { 541: /* There is no obvious reason for overriding this method, but we 542: * try to have exactly the same API as the Sun reference 543: * implementation. 544: */ 545: return getBorderInsets(c, null); 546: } 547: 548: 549: /** 550: * Measures the width of this border, storing the results into a 551: * pre-existing Insets object. 552: * 553: * <p>Although the thickness of the actually painted border 554: * depends on the state of the enclosed component, this 555: * measurement always returns the same amount of pixels. Indeed, 556: * it would be rather confusing if a button was appearing to 557: * change its size depending on whether it is pressed or not. 558: * 559: * @param insets an Insets object for holding the result values. 560: * After invoking this method, the <code>left</code>, 561: * <code>right</code>, <code>top</code> and 562: * <code>bottom</code> fields indicate the width of the 563: * border at the respective edge. 564: * 565: * @return the same object that was passed for <code>insets</code>. 566: * 567: * @see #getBorderInsets(Component) 568: */ 569: public Insets getBorderInsets(Component c, Insets insets) 570: { 571: /* The exact amount has been determined using a test program 572: * that was run on the Sun reference implementation. With 573: * Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, the result is 574: * [3, 3, 3, 3]. With Sun JDK 1.4.1_01 on Linux/x86, the 575: * result is [2, 3, 3, 3]. We use the values from the 1.4.1_01 576: * release. 577: */ 578: if (insets == null) 579: return new Insets(2, 3, 3, 3); 580: 581: insets.top = 2; 582: insets.bottom = insets.left = insets.right = 3; 583: return insets; 584: } 585: } 586: 587: 588: /** 589: * A border that makes its enclosed component appear as lowered 590: * into the surface. Typically used for text fields. 591: * 592: * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" 593: * height="200" alt="[A screen shot of this border]" /> 594: * 595: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect 596: * 597: * @author Sascha Brawer (brawer@dandelis.ch) 598: */ 599: public static class FieldBorder 600: extends AbstractBorder 601: implements UIResource 602: { 603: /** 604: * Determined using the <code>serialver</code> tool 605: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 606: */ 607: static final long serialVersionUID = 949220756998454908L; 608: 609: 610: /** 611: * The color for drawing the outer half of the top and left 612: * edges. 613: */ 614: protected Color shadow; 615: 616: 617: /** 618: * The color for drawing the inner half of the top and left 619: * edges. 620: */ 621: protected Color darkShadow; 622: 623: 624: /** 625: * The color for drawing the inner half of the bottom and right 626: * edges. 627: */ 628: protected Color highlight; 629: 630: 631: /** 632: * The color for drawing the outer half of the bottom and right 633: * edges. 634: */ 635: protected Color lightHighlight; 636: 637: 638: /** 639: * Constructs a new border for drawing a text field in the Basic 640: * look and feel. 641: * 642: * @param shadow the color for drawing the outer half 643: * of the top and left edges. 644: * 645: * @param darkShadow the color for drawing the inner half 646: * of the top and left edges. 647: * 648: * @param highlight the color for drawing the inner half 649: * of the bottom and right edges. 650: * 651: * @param lightHighlight the color for drawing the outer half 652: * of the bottom and right edges. 653: */ 654: public FieldBorder(Color shadow, Color darkShadow, 655: Color highlight, Color lightHighlight) 656: { 657: /* These colors usually come from the UIDefaults of the current 658: * look and feel. Use fallback values if the colors are not 659: * supplied. The API specification is silent about what 660: * behavior is expected for null colors, so users should not 661: * rely on this fallback (which is why it is not documented in 662: * the above Javadoc). 663: */ 664: this.shadow = (shadow != null) ? shadow : Color.gray; 665: this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; 666: this.highlight = (highlight != null) ? highlight : Color.lightGray; 667: this.lightHighlight = (lightHighlight != null) 668: ? lightHighlight : Color.white; 669: } 670: 671: 672: /** 673: * Paints the FieldBorder around a given component. 674: * 675: * @param c the component whose border is to be painted. 676: * @param g the graphics for painting. 677: * @param x the horizontal position for painting the border. 678: * @param y the vertical position for painting the border. 679: * @param width the width of the available area for painting the border. 680: * @param height the height of the available area for painting the border. 681: * 682: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect 683: */ 684: public void paintBorder(Component c, Graphics g, 685: int x, int y, int width, int height) 686: { 687: BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, 688: shadow, darkShadow, 689: highlight, lightHighlight); 690: } 691: 692: 693: /** 694: * Measures the width of this border. 695: * 696: * @param c the component whose border is to be measured. 697: * If <code>c</code> is an instance of {@link 698: * javax.swing.text.JTextComponent}, its margin is 699: * added to the border size. 700: * 701: * @return an Insets object whose <code>left</code>, 702: * <code>right</code>, <code>top</code> and 703: * <code>bottom</code> fields indicate the width of the 704: * border at the respective edge. 705: * 706: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 707: */ 708: public Insets getBorderInsets(Component c) 709: { 710: return getBorderInsets(c, null); 711: } 712: 713: 714: /** 715: * Measures the width of this border, storing the results into a 716: * pre-existing Insets object. 717: * 718: * @param c the component whose border is to be measured. 719: * If <code>c</code> is an instance of {@link 720: * javax.swing.text.JTextComponent}, its margin is 721: * added to the border size. 722: * 723: * @param insets an Insets object for holding the result values. 724: * After invoking this method, the <code>left</code>, 725: * <code>right</code>, <code>top</code> and 726: * <code>bottom</code> fields indicate the width of the 727: * border at the respective edge. 728: * 729: * @return the same object that was passed for <code>insets</code>. 730: * 731: * @see #getBorderInsets(Component) 732: */ 733: public Insets getBorderInsets(Component c, Insets insets) 734: { 735: if (insets == null) 736: insets = new Insets(2, 2, 2, 2); 737: else 738: insets.top = insets.left = insets.bottom = insets.right = 2; 739: 740: if (c instanceof JTextComponent) 741: { 742: Insets margin = ((JTextComponent) c).getMargin(); 743: insets.top += margin.top; 744: insets.left += margin.left; 745: insets.bottom += margin.bottom; 746: insets.right += margin.right; 747: } 748: 749: return insets; 750: } 751: } 752: 753: 754: /** 755: * An invisible, but spacing border whose margin is determined 756: * by calling the <code>getMargin()</code> method of the enclosed 757: * component. If the enclosed component has no such method, 758: * this border will not occupy any space. 759: * 760: * <p><img src="doc-files/BasicBorders.MarginBorder-1.png" width="325" 761: * height="200" alt="[An illustration that shows how MarginBorder 762: * determines its borders]" /> 763: * 764: * @author Sascha Brawer (brawer@dandelis.ch) 765: */ 766: public static class MarginBorder 767: extends AbstractBorder 768: implements Serializable, UIResource 769: { 770: /** 771: * Determined using the <code>serialver</code> tool 772: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 773: */ 774: static final long serialVersionUID = -3035848353448896090L; 775: 776: 777: /** 778: * Constructs a new MarginBorder. 779: */ 780: public MarginBorder() 781: { 782: // Nothing to do here. 783: } 784: 785: /** 786: * Measures the width of this border. 787: * 788: * @param c the component whose border is to be measured. 789: * 790: * @return an Insets object whose <code>left</code>, <code>right</code>, 791: * <code>top</code> and <code>bottom</code> fields indicate the 792: * width of the border at the respective edge. 793: * 794: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 795: */ 796: public Insets getBorderInsets(Component c) 797: { 798: return getBorderInsets(c, new Insets(0, 0, 0, 0)); 799: } 800: 801: 802: /** 803: * Determines the insets of this border by calling the 804: * <code>getMargin()</code> method of the enclosed component. The 805: * resulting margin will be stored into the the <code>left</code>, 806: * <code>right</code>, <code>top</code> and <code>bottom</code> 807: * fields of the passed <code>insets</code> parameter. 808: * 809: * <p>Unfortunately, <code>getMargin()</code> is not a method of 810: * {@link javax.swing.JComponent} or some other common superclass 811: * of things with margins. While reflection could be used to 812: * determine the existence of this method, this would be slow on 813: * many virtual machines. Therefore, the current implementation 814: * knows about {@link javax.swing.AbstractButton#getMargin()}, 815: * {@link javax.swing.JPopupMenu#getMargin()}, {@link 816: * javax.swing.JToolBar#getMargin()}, and {@link 817: * javax.swing.text.JTextComponent}. If <code>c</code> is an 818: * instance of a known class, the respective 819: * <code>getMargin()</code> method is called to determine the 820: * correct margin. Otherwise, a zero-width margin is returned. 821: * 822: * @param c the component whose border is to be measured. 823: * 824: * @return the same object that was passed for <code>insets</code>, 825: * but with changed fields. 826: */ 827: public Insets getBorderInsets(Component c, Insets insets) 828: { 829: Insets margin = null; 830: 831: /* This is terrible object-oriented design. See the above Javadoc 832: * for an excuse. 833: */ 834: if (c instanceof AbstractButton) 835: margin = ((AbstractButton) c).getMargin(); 836: else if (c instanceof JPopupMenu) 837: margin = ((JPopupMenu) c).getMargin(); 838: else if (c instanceof JToolBar) 839: margin = ((JToolBar) c).getMargin(); 840: else if (c instanceof JTextComponent) 841: margin = ((JTextComponent) c).getMargin(); 842: 843: if (margin == null) 844: insets.top = insets.left = insets.bottom = insets.right = 0; 845: else 846: { 847: insets.top = margin.top; 848: insets.left = margin.left; 849: insets.bottom = margin.bottom; 850: insets.right = margin.right; 851: } 852: 853: return insets; 854: } 855: } 856: 857: 858: /** 859: * A border for drawing a separator line below JMenuBar. 860: * 861: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 862: * height="140" alt="[A screen shot of a JMenuBar with this border]" /> 863: * 864: * @author Sascha Brawer (brawer@dandelis.ch) 865: */ 866: public static class MenuBarBorder 867: extends AbstractBorder 868: implements UIResource 869: { 870: /** 871: * Determined using the <code>serialver</code> tool 872: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 873: */ 874: static final long serialVersionUID = -6909056571935227506L; 875: 876: 877: /** 878: * The shadow color, which is used for the upper line of the 879: * two-pixel thick bottom edge. 880: */ 881: private Color shadow; 882: 883: 884: /** 885: * The highlight color, which is used for the lower line of the 886: * two-pixel thick bottom edge. 887: */ 888: private Color highlight; 889: 890: 891: /** 892: * Constructs a new MenuBarBorder for drawing a JMenuBar in 893: * the Basic look and feel. 894: * 895: * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" 896: * height="140" alt="[A screen shot of a JMenuBar with this 897: * border]" /> 898: * 899: * @param shadow the shadow color, which is used for the upper 900: * line of the two-pixel thick bottom edge. 901: * 902: * @param highlight the shadow color, which is used for the lower 903: * line of the two-pixel thick bottom edge. 904: */ 905: public MenuBarBorder(Color shadow, Color highlight) 906: { 907: /* These colors usually come from the UIDefaults of the current 908: * look and feel. Use fallback values if the colors are not 909: * supplied. The API specification is silent about what 910: * behavior is expected for null colors, so users should not 911: * rely on this fallback (which is why it is not documented in 912: * the above Javadoc). 913: */ 914: this.shadow = (shadow != null) ? shadow : Color.gray; 915: this.highlight = (highlight != null) ? highlight : Color.white; 916: } 917: 918: 919: /** 920: * Paints the MenuBarBorder around a given component. 921: * 922: * @param c the component whose border is to be painted, usually 923: * an instance of {@link javax.swing.JMenuBar}. 924: * 925: * @param g the graphics for painting. 926: * @param x the horizontal position for painting the border. 927: * @param y the vertical position for painting the border. 928: * @param width the width of the available area for painting the border. 929: * @param height the height of the available area for painting the border. 930: */ 931: public void paintBor