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 paintBorder(Component c, Graphics g, 932: int x, int y, int width, int height) 933: { 934: Color oldColor; 935: 936: /* To understand this code, it might be helpful to look at the 937: * image "BasicBorders.MenuBarBorder-1.png" that is included 938: * with the JavaDoc. It is located in the "doc-files" 939: * subdirectory. 940: */ 941: oldColor = g.getColor(); 942: y = y + height - 2; 943: try 944: { 945: g.setColor(shadow); 946: g.drawLine(x, y, x + width - 2, y); 947: g.drawLine(x, y + 1, x, y + 1); 948: g.drawLine(x + width - 2, y + 1, x + width - 2, y + 1); 949: 950: g.setColor(highlight); 951: g.drawLine(x + 1, y + 1, x + width - 3, y + 1); 952: g.drawLine(x + width - 1, y, x + width - 1, y + 1); 953: } 954: finally 955: { 956: g.setColor(oldColor); 957: } 958: } 959: 960: 961: /** 962: * Measures the width of this border. 963: * 964: * @param c the component whose border is to be measured. 965: * 966: * @return an Insets object whose <code>left</code>, 967: * <code>right</code>, <code>top</code> and 968: * <code>bottom</code> fields indicate the width of the 969: * border at the respective edge. 970: * 971: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 972: */ 973: public Insets getBorderInsets(Component c) 974: { 975: /* There is no obvious reason for overriding this method, but we 976: * try to have exactly the same API as the Sun reference 977: * implementation. 978: */ 979: return getBorderInsets(c, null); 980: } 981: 982: 983: /** 984: * Measures the width of this border, storing the results into a 985: * pre-existing Insets object. 986: * 987: * @param insets an Insets object for holding the result values. 988: * After invoking this method, the <code>left</code>, 989: * <code>right</code>, <code>top</code> and 990: * <code>bottom</code> fields indicate the width of the 991: * border at the respective edge. 992: * 993: * @return the same object that was passed for <code>insets</code>. 994: * 995: * @see #getBorderInsets(Component) 996: */ 997: public Insets getBorderInsets(Component c, Insets insets) 998: { 999: /* The exact amount has been determined using a test program 1000: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1001: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [0,0,2,0], 1002: * which was expected from looking at the screen shot. 1003: */ 1004: if (insets == null) 1005: return new Insets(0, 0, 2, 0); 1006: 1007: insets.left = insets.right = insets.top = 0; 1008: insets.bottom = 2; 1009: return insets; 1010: } 1011: } 1012: 1013: 1014: /** 1015: * A border for drawing radio buttons in the Basic look and feel. 1016: * 1017: * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" 1018: * height="135" alt="[A screen shot of this border]" /> 1019: * 1020: * <p>Note about the screen shot: Normally, the 1021: * <code>borderPainted</code> property is <code>false</code> for 1022: * JRadioButtons. For this screen shot, it has been set to 1023: * <code>true</code> so the borders get drawn. Also, a 1024: * concretization of the Basic look and would typically provide 1025: * icons for the various states of radio buttons. 1026: * 1027: * <p>Note that the focus rectangle is invisible If the radio button 1028: * is currently selected. While it might be debatable whether this 1029: * makes a lot of sense, this behavior can be observed in the Sun 1030: * reference implementation (in JDK 1.3.1 and 1.4.1). The Classpath 1031: * implementation tries to exactly replicate the JDK appearance. 1032: * 1033: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1034: * 1035: * @author Sascha Brawer (brawer@dandelis.ch) 1036: */ 1037: public static class RadioButtonBorder 1038: extends ButtonBorder 1039: { 1040: /** 1041: * Determined using the <code>serialver</code> tool 1042: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 1043: */ 1044: static final long serialVersionUID = 1596945751743747369L; 1045: 1046: 1047: /** 1048: * Constructs a new border for drawing a JRadioButton in 1049: * the Basic look and feel. 1050: * 1051: * @param shadow the shadow color. 1052: * @param darkShadow a darker variant of the shadow color. 1053: * @param highlight the highlight color. 1054: * @param lightHighlight a brighter variant of the highlight color. 1055: */ 1056: public RadioButtonBorder(Color shadow, Color darkShadow, 1057: Color highlight, Color lightHighlight) 1058: { 1059: /* The superclass ButtonBorder substitutes null arguments 1060: * with fallback colors. 1061: */ 1062: super(shadow, darkShadow, highlight, lightHighlight); 1063: } 1064: 1065: 1066: /** 1067: * Paints the RadioButtonBorder around a given component. 1068: * 1069: * <p>The Sun implementation always seems to draw exactly 1070: * the same border, irrespective of the state of the button. 1071: * This is rather surprising, but GNU Classpath emulates the 1072: * observable behavior. 1073: * 1074: * @param c the component whose border is to be painted. 1075: * @param g the graphics for painting. 1076: * @param x the horizontal position for painting the border. 1077: * @param y the vertical position for painting the border. 1078: * @param width the width of the available area for painting the border. 1079: * @param height the height of the available area for painting the border. 1080: * 1081: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1082: */ 1083: public void paintBorder(Component c, Graphics g, 1084: int x, int y, int width, int height) 1085: { 1086: AbstractButton button = null; 1087: ButtonModel bmodel = null; 1088: boolean lowered = false; 1089: boolean focused = false; 1090: 1091: if (c instanceof AbstractButton) 1092: { 1093: button = (AbstractButton) c; 1094: bmodel = button.getModel(); 1095: } 1096: 1097: if (bmodel != null) 1098: { 1099: lowered = button.isSelected() 1100: || (/* mouse inside */ bmodel.isArmed() && bmodel.isPressed()); 1101: focused = button.hasFocus() && button.isFocusPainted(); 1102: } 1103: 1104: if (lowered) 1105: BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height, 1106: shadow, darkShadow, 1107: highlight, lightHighlight); 1108: else 1109: BasicGraphicsUtils.drawBezel(g, x, y, width, height, 1110: /* isPressed */ false, 1111: /* isPefault */ focused, 1112: shadow, darkShadow, 1113: highlight, lightHighlight); 1114: } 1115: 1116: 1117: /** 1118: * Measures the width of this border. 1119: * 1120: * @param c the component whose border is to be measured. 1121: * 1122: * @return an Insets object whose <code>left</code>, 1123: * <code>right</code>, <code>top</code> and 1124: * <code>bottom</code> fields indicate the width of the 1125: * border at the respective edge. 1126: * 1127: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 1128: */ 1129: public Insets getBorderInsets(Component c) 1130: { 1131: /* There is no obvious reason for overriding this method, but we 1132: * try to have exactly the same API as the Sun reference 1133: * implementation. 1134: */ 1135: return getBorderInsets(c, null); 1136: } 1137: 1138: 1139: /** 1140: * Measures the width of this border, storing the results into a 1141: * pre-existing Insets object. 1142: * 1143: * @param insets an Insets object for holding the result values. 1144: * After invoking this method, the <code>left</code>, 1145: * <code>right</code>, <code>top</code> and 1146: * <code>bottom</code> fields indicate the width of the 1147: * border at the respective edge. 1148: * 1149: * @return the same object that was passed for <code>insets</code>. 1150: * 1151: * @see #getBorderInsets(Component) 1152: */ 1153: public Insets getBorderInsets(Component c, Insets insets) 1154: { 1155: /* The exact amount has been determined using a test program 1156: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1157: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. 1158: */ 1159: if (insets == null) 1160: return new Insets(2, 2, 2, 2); 1161: 1162: insets.left = insets.right = insets.top = insets.bottom = 2; 1163: return insets; 1164: } 1165: } 1166: 1167: 1168: /** 1169: * A one-pixel thick border for rollover buttons, for example in 1170: * tool bars. 1171: * 1172: * @since 1.4 1173: * @author Sascha Brawer (brawer@dandelis.ch) 1174: */ 1175: public static class RolloverButtonBorder 1176: extends ButtonBorder 1177: { 1178: /** 1179: * Determined using the <code>serialver</code> tool 1180: * of Sun JDK 1.4.1_01 on GNU/Linux 2.4.20 for x86. 1181: */ 1182: static final long serialVersionUID = 1976364864896996846L; 1183: 1184: 1185: /** 1186: * Constructs a new border for drawing a roll-over button 1187: * in the Basic look and feel. 1188: * 1189: * @param shadow the shadow color. 1190: * @param darkShadow a darker variant of the shadow color. 1191: * @param highlight the highlight color. 1192: * @param lightHighlight a brighter variant of the highlight color. 1193: */ 1194: public RolloverButtonBorder(Color shadow, Color darkShadow, 1195: Color highlight, Color lightHighlight) 1196: { 1197: super(shadow, darkShadow, highlight, lightHighlight); 1198: } 1199: 1200: 1201: /** 1202: * Paints the border around a rollover button. If <code>c</code> 1203: * is not an {@link javax.swing.AbstractButton} whose model 1204: * returns <code>true</code> for {@link 1205: * javax.swing.ButtonModel#isRollover}, nothing gets painted at 1206: * all. 1207: * 1208: * @param c the button whose border is to be painted. 1209: * @param g the graphics for painting. 1210: * @param x the horizontal position for painting the border. 1211: * @param y the vertical position for painting the border. 1212: * @param width the width of the available area for painting the border. 1213: * @param height the height of the available area for painting the border. 1214: */ 1215: public void paintBorder(Component c, Graphics g, 1216: int x, int y, int width, int height) 1217: { 1218: ButtonModel bmodel = null; 1219: boolean drawPressed; 1220: Color oldColor = g.getColor(); 1221: int x2, y2; 1222: 1223: if (c instanceof AbstractButton) 1224: bmodel = ((AbstractButton) c).getModel(); 1225: 1226: /* Draw nothing if c is not a rollover button. */ 1227: if ((bmodel == null) || !bmodel.isRollover()) 1228: return; 1229: 1230: /* Draw nothing if the mouse is pressed, but outside the button. */ 1231: if (bmodel.isPressed() && !bmodel.isArmed()) 1232: return; 1233: 1234: drawPressed = bmodel.isSelected() || bmodel.isPressed(); 1235: x2 = x + width - 1; 1236: y2 = y + height - 1; 1237: 1238: try 1239: { 1240: g.setColor(drawPressed ? shadow : lightHighlight); 1241: g.drawLine(x, y, x2 - 1, y); // top edge 1242: g.drawLine(x, y + 1, x, y2 - 1); // left edge 1243: 1244: g.setColor(drawPressed ? lightHighlight : shadow); 1245: g.drawLine(x, y2, x2, y2); // bottom edge 1246: g.drawLine(x2, y, x2, y2 - 1); // right edge 1247: } 1248: finally 1249: { 1250: g.setColor(oldColor); 1251: } 1252: } 1253: } 1254: 1255: 1256: /** 1257: * A border for JSplitPanes in the Basic look and feel. The divider 1258: * in the middle of the JSplitPane has its own border class, of which 1259: * an instance can be obtained with {@link #getSplitPaneDividerBorder()}. 1260: * 1261: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 1262: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 1263: * 1264: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 1265: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 1266: * 1267: * <p>In contrast to the other borders of the Basic look and feel, 1268: * this class is not serializable. While this might be unintended, 1269: * GNU Classpath follows the specification in order to be fully 1270: * compatible with the Sun reference implementation. 1271: * 1272: * <p>In the Sun JDK, the bottom edge of the divider also gets 1273: * painted if the orientation of the enclosed JSplitPane is 1274: * <code>JSplitPane.VERTICAL_SPLIT</code> (at least in versions 1275: * 1.3.1 and 1.4.1). GNU Classpath does not replicate this bug. A 1276: * report has been filed with Sun (bug ID 4885629). 1277: * 1278: * <p>Note that the bottom left pixel of the border has a different 1279: * color depending on the orientation of the enclosed JSplitPane. 1280: * Although this is visually inconsistent, Classpath replicates the 1281: * appearance of the Sun reference implementation. A bug report has 1282: * been filed with Sun (review ID 188774). 1283: * 1284: * @see #getSplitPaneBorder() 1285: * @see #getSplitPaneDividerBorder() 1286: * 1287: * @author Sascha Brawer (brawer@dandelis.ch) 1288: */ 1289: public static class SplitPaneBorder implements Border, UIResource 1290: { 1291: /** 1292: * Indicates that the top edge shall be not be painted 1293: * by {@link #paintRect}. 1294: */ 1295: private static final int SUPPRESS_TOP = 1; 1296: 1297: 1298: /** 1299: * Indicates that the left edge shall be not be painted 1300: * by {@link #paintRect}. 1301: */ 1302: private static final int SUPPRESS_LEFT = 2; 1303: 1304: 1305: /** 1306: * Indicates that the bottom edge shall be not be painted 1307: * by {@link #paintRect}. 1308: */ 1309: private static final int SUPPRESS_BOTTOM = 4; 1310: 1311: 1312: /** 1313: * Indicates that the right edge shall be not be painted 1314: * by {@link #paintRect}. 1315: */ 1316: private static final int SUPPRESS_RIGHT = 8; 1317: 1318: 1319: /** 1320: * The color for drawing the bottom and right edges of the border. 1321: */ 1322: protected Color highlight; 1323: 1324: 1325: /** 1326: * The color for drawing the top and left edges of the border. 1327: */ 1328: protected Color shadow; 1329: 1330: 1331: /** 1332: * Constructs a new border for drawing a JSplitPane in the Basic 1333: * look and feel. The divider in the middle of the JSplitPane has 1334: * its own border class, <code>SplitPaneDividerBorder</code>. 1335: * 1336: * @param shadow the shadow color. 1337: * @param highlight the highlight color. 1338: */ 1339: public SplitPaneBorder(Color highlight, Color shadow) 1340: { 1341: /* These colors usually come from the UIDefaults of the current 1342: * look and feel. Use fallback values if the colors are not 1343: * supplied. The API specification is silent about what 1344: * behavior is expected for null colors, so users should not 1345: * rely on this fallback (which is why it is not documented in 1346: * the above Javadoc). 1347: */ 1348: this.shadow = (shadow != null) ? shadow : Color.black; 1349: this.highlight = (highlight != null) ? highlight : Color.white; 1350: } 1351: 1352: 1353: /** 1354: * Paints the border around a <code>JSplitPane</code>. 1355: * 1356: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" 1357: * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> 1358: * 1359: * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" 1360: * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> 1361: * 1362: * @param c the <code>JSplitPane</code> whose border is to be painted. 1363: * @param g the graphics for painting. 1364: * @param x the horizontal position for painting the border. 1365: * @param y the vertical position for painting the border. 1366: * @param width the width of the available area for painting the border. 1367: * @param height the height of the available area for painting the border. 1368: */ 1369: public void paintBorder(Component c, Graphics g, 1370: int x, int y, int width, int height) 1371: { 1372: JSplitPane splitPane; 1373: Component content; 1374: 1375: if (!(c instanceof JSplitPane)) 1376: return; 1377: 1378: splitPane = (JSplitPane) c; 1379: switch (splitPane.getOrientation()) 1380: { 1381: case JSplitPane.HORIZONTAL_SPLIT: 1382: if ((content = splitPane.getLeftComponent()) != null) 1383: paintRect(g, SUPPRESS_RIGHT, true, x, y, content.getBounds()); 1384: if ((content = splitPane.getRightComponent()) != null) 1385: paintRect(g, SUPPRESS_LEFT, true, x, y, content.getBounds()); 1386: break; 1387: 1388: case JSplitPane.VERTICAL_SPLIT: 1389: if ((content = splitPane.getTopComponent()) != null) 1390: paintRect(g, SUPPRESS_BOTTOM, false, x, y, content.getBounds()); 1391: if ((content = splitPane.getBottomComponent()) != null) 1392: paintRect(g, SUPPRESS_TOP, false, x, y, content.getBounds()); 1393: break; 1394: } 1395: } 1396: 1397: 1398: /** 1399: * Paints a border around a child of a <code>JSplitPane</code>, 1400: * omitting some of the edges. 1401: * 1402: * @param g the graphics for painting. 1403: * 1404: * @param suppress a bit mask indicating the set of suppressed 1405: * edges, for example <code>SUPPRESS_TOP | SUPPRESS_RIGHT</code>. 1406: * 1407: * @param x the x coordinate of the SplitPaneBorder. 1408: * 1409: * @param y the y coordinate of the SplitPaneBorder. 1410: * 1411: * @param shadeBottomLeftPixel <code>true</code> to paint the 1412: * bottom left pixel in the shadow color, 1413: * <code>false</code> for the highlight color. The Basic 1414: * look and feel uses the highlight color for the bottom 1415: * left pixel of the border of a JSplitPane whose 1416: * orientation is VERTICAL_SPLIT, and the shadow color 1417: * otherwise. While this might be a strange distinction, 1418: * Classpath tries to look identical to the reference 1419: * implementation. A bug report has been filed with Sun; 1420: * its review ID is 188774. We currently replicate the 1421: * Sun behavior. 1422: * 1423: * @param rect the bounds of the child of JSplitPane whose 1424: * border is to be painted. 1425: */ 1426: private void paintRect(Graphics g, int suppress, 1427: boolean shadeBottomLeftPixel, 1428: int x, int y, 1429: Rectangle rect) 1430: { 1431: if (rect == null) 1432: return; 1433: 1434: /* On each edge, the border exceeds the enclosed child by one 1435: * pixel. See the image "BasicBorders.SplitPaneBorder-1.png" in 1436: * the directory "doc-files". 1437: */ 1438: x += rect.x - 1; 1439: y += rect.y - 1; 1440: int right = x + rect.width + 1; 1441: int bottom = y + rect.height + 1; 1442: 1443: Color oldColor = g.getColor(); 1444: try 1445: { 1446: g.setColor(shadow); 1447: if ((suppress & SUPPRESS_TOP) == 0) 1448: g.drawLine(x, y, right, y); 1449: if ((suppress & SUPPRESS_LEFT) == 0) 1450: g.drawLine(x, y, x, bottom); 1451: else 1452: g.drawLine(x, bottom, x, bottom); // one pixel 1453: 1454: g.setColor(highlight); 1455: if ((suppress & SUPPRESS_BOTTOM) == 0) 1456: g.drawLine(x + (shadeBottomLeftPixel ? 1 : 0), bottom, right, bottom); 1457: else if (!shadeBottomLeftPixel) 1458: g.drawLine(x, bottom, x, bottom); // one pixel 1459: 1460: if ((suppress & SUPPRESS_RIGHT) == 0) 1461: g.drawLine(right, y, right, bottom); 1462: } 1463: finally 1464: { 1465: g.setColor(oldColor); 1466: } 1467: } 1468: 1469: 1470: /** 1471: * Measures the width of this border. 1472: * 1473: * @param c the component whose border is to be measured, usually 1474: * an instance of {@link javax.swing.JSplitPane}. 1475: * 1476: * @return an Insets object whose <code>left</code>, 1477: * <code>right</code>, <code>top</code> and 1478: * <code>bottom</code> fields indicate the width of the 1479: * border at the respective edge. 1480: */ 1481: public Insets getBorderInsets(Component c) 1482: { 1483: return new Insets(1, 1, 1, 1); 1484: } 1485: 1486: 1487: /** 1488: * Determines whether this border fills every pixel in its area 1489: * when painting. 1490: * 1491: * @return <code>false</code> because this border does not 1492: * paint over the pixels where the divider joins 1493: * the border. 1494: */ 1495: public boolean isBorderOpaque() 1496: { 1497: /* Strangely, the Sun implementation (tested with JDK 1.3.1 and 1498: * 1.4.1_01) seems to always return true. It could be a bug, 1499: * but without knowing the details of their implementation, it is 1500: * hard to decide. 1501: */ 1502: return false; 1503: } 1504: } 1505: 1506: 1507: /** 1508: * A border for the divider inside a JSplitPane. 1509: * 1510: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 1511: * width="520" height="200" alt="[A screen shot of this border]" /> 1512: * 1513: * @author Sascha Brawer (brawer@dandelis.ch) 1514: */ 1515: private static class SplitPaneDividerBorder 1516: implements Border, UIResource, Serializable 1517: { 1518: /** 1519: * Constructs a new border for drawing the divider of a JSplitPane 1520: * in the Basic look and feel. The outer parts of the JSplitPane have 1521: * their own border class, <code>SplitPaneBorder</code>. 1522: */ 1523: public SplitPaneDividerBorder() 1524: { 1525: // Nothing to do here. 1526: } 1527: 1528: /** 1529: * Paints the border around the divider of a <code>JSplitPane</code>. 1530: * 1531: * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" 1532: * width="520" height="200" alt="[A picture that shows which pixels 1533: * get painted in what color]" /> 1534: * 1535: * @param c the <code>JSplitPane</code> whose divider’s border 1536: * is to be painted. 1537: * @param g the graphics for painting. 1538: * @param x the horizontal position for painting the border. 1539: * @param y the vertical position for painting the border. 1540: * @param width the width of the available area for painting the border. 1541: * @param height the height of the available area for painting the border. 1542: */ 1543: public void paintBorder(Component c, Graphics g, 1544: int x, int y, int width, int height) 1545: { 1546: Color highlight = UIManager.getColor("SplitPane.highlight"); 1547: Color shadow = UIManager.getColor("SplitPane.shadow"); 1548: Color oldColor, dcol; 1549: int x2, y2; 1550: JSplitPane sp; 1551: 1552: sp = getSplitPane(c); 1553: if (sp == null) 1554: return; 1555: 1556: x2 = x + width - 1; 1557: y2 = y + height - 1; 1558: oldColor = g.getColor(); 1559: dcol = c.getBackground(); 1560: try 1561: { 1562: switch (sp.getOrientation()) 1563: { 1564: case JSplitPane.HORIZONTAL_SPLIT: 1565: g.setColor(dcol); 1566: g.drawLine(x + 1, y, x2 - 1, y); 1567: g.drawLine(x + 1, y2, x2 - 1, y2); 1568: g.setColor(sp.getLeftComponent() != null ? highlight : dcol); 1569: g.drawLine(x, y, x, y2); 1570: g.setColor(sp.getRightComponent() != null ? shadow : dcol); 1571: g.drawLine(x2, y, x2, y2); 1572: break; 1573: 1574: case JSplitPane.VERTICAL_SPLIT: 1575: g.setColor(dcol); 1576: g.drawLine(x, y + 1, x, y2 - 1); 1577: g.drawLine(x2, y + 1, x2, y2 - 1); 1578: g.setColor(sp.getTopComponent() != null ? highlight : dcol); 1579: g.drawLine(x, y, x2, y); 1580: g.setColor(sp.getBottomComponent() != null ? shadow : dcol); 1581: g.drawLine(x, y2, x2, y2); 1582: break; 1583: } 1584: } 1585: finally 1586: { 1587: g.setColor(oldColor); 1588: } 1589: } 1590: 1591: 1592: /** 1593: * Measures the width of this border. 1594: * 1595: * @param c the component whose border is to be measured, usually 1596: * an instance of {@link javax.swing.JSplitPane}. 1597: * 1598: * @return an Insets object whose <code>left</code>, 1599: * <code>right</code>, <code>top</code> and 1600: * <code>bottom</code> fields indicate the width of the 1601: * border at the respective edge. 1602: */ 1603: public Insets getBorderInsets(Component c) 1604: { 1605: return new Insets(1, 1, 1, 1); 1606: } 1607: 1608: /** 1609: * Determines whether this border fills every pixel in its area 1610: * when painting. 1611: * 1612: * @return <code>true</code> 1613: */ 1614: public boolean isBorderOpaque() 1615: { 1616: return true; 1617: } 1618: 1619: 1620: /** 1621: * Determines the JSplitPane whose divider is being painted. 1622: * 1623: * @param c an instance of BasicSplitPaneDivider. 1624: * 1625: * @return a <code>JSplitPane</code>, or <code>null</code> if 1626: * <code>c</code> is not an instance of {@link 1627: * javax.swing.plaf.basic.BasicSplitPaneDivider}. 1628: */ 1629: private JSplitPane getSplitPane(Component c) 1630: { 1631: if (c instanceof BasicSplitPaneDivider) 1632: return (((BasicSplitPaneDivider) c).getBasicSplitPaneUI()) 1633: .getSplitPane(); 1634: else 1635: return null; 1636: } 1637: } 1638: 1639: 1640: /** 1641: * A border for toggle buttons in the Basic look and feel. 1642: * 1643: * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" 1644: * width="270" height="135" alt="[A screen shot of this border]" /> 1645: * 1646: * <p>The Sun implementation always seems to draw exactly 1647: * the same border, irrespective of the state of the button. 1648: * This is rather surprising, but GNU Classpath emulates the 1649: * observable behavior. 1650: * 1651: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1652: * 1653: * @author Sascha Brawer (brawer@dandelis.ch) 1654: */ 1655: public static class ToggleButtonBorder 1656: extends ButtonBorder 1657: { 1658: /** 1659: * Determined using the <code>serialver</code> tool 1660: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 1661: */ 1662: static final long serialVersionUID = -3528666548001058394L; 1663: 1664: 1665: /** 1666: * Constructs a new border for drawing a JToggleButton in 1667: * the Basic look and feel. 1668: * 1669: * @param shadow the shadow color. 1670: * @param darkShadow a darker variant of the shadow color. 1671: * @param highlight the highlight color. 1672: * @param lightHighlight a brighter variant of the highlight color. 1673: */ 1674: public ToggleButtonBorder(Color shadow, Color darkShadow, 1675: Color highlight, Color lightHighlight) 1676: { 1677: /* The superclass ButtonBorder substitutes null arguments 1678: * with fallback colors. 1679: */ 1680: super(shadow, darkShadow, highlight, lightHighlight); 1681: } 1682: 1683: 1684: /** 1685: * Paints the ToggleButtonBorder around a given component. 1686: * 1687: * <p>The Sun implementation always seems to draw exactly 1688: * the same border, irrespective of the state of the button. 1689: * This is rather surprising, but GNU Classpath emulates the 1690: * observable behavior. 1691: * 1692: * @param c the component whose border is to be painted. 1693: * @param g the graphics for painting. 1694: * @param x the horizontal position for painting the border. 1695: * @param y the vertical position for painting the border. 1696: * @param width the width of the available area for painting the border. 1697: * @param height the height of the available area for painting the border. 1698: * 1699: * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel 1700: */ 1701: public void paintBorder(Component c, Graphics g, 1702: int x, int y, int width, int height) 1703: { 1704: /* The author of this code tried various variants for setting 1705: * the state of the enclosed JToggleButton, but it seems that 1706: * the drawn border is always identical. Weird, because this 1707: * means that the user does not see whether the JToggleButton 1708: * is selected or not. 1709: */ 1710: BasicGraphicsUtils.drawBezel(g, x, y, width, height, 1711: /* pressed */ false, 1712: /* default */ false, 1713: shadow, darkShadow, 1714: highlight, lightHighlight); 1715: } 1716: 1717: 1718: /** 1719: * Measures the width of this border. 1720: * 1721: * @param c the component whose border is to be measured. 1722: * 1723: * @return an Insets object whose <code>left</code>, 1724: * <code>right</code>, <code>top</code> and 1725: * <code>bottom</code> fields indicate the width of the 1726: * border at the respective edge. 1727: * 1728: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 1729: */ 1730: public Insets getBorderInsets(Component c) 1731: { 1732: /* There is no obvious reason for overriding this method, but we 1733: * try to have exactly the same API as the Sun reference 1734: * implementation. 1735: */ 1736: return getBorderInsets(c, null); 1737: } 1738: 1739: 1740: /** 1741: * Measures the width of this border, storing the results into a 1742: * pre-existing Insets object. 1743: * 1744: * @param insets an Insets object for holding the result values. 1745: * After invoking this method, the <code>left</code>, 1746: * <code>right</code>, <code>top</code> and 1747: * <code>bottom</code> fields indicate the width of the 1748: * border at the respective edge. 1749: * 1750: * @return the same object that was passed for <code>insets</code>. 1751: * 1752: * @see #getBorderInsets(Component) 1753: */ 1754: public Insets getBorderInsets(Component c, Insets insets) 1755: { 1756: /* The exact amount has been determined using a test program 1757: * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the 1758: * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. 1759: */ 1760: if (insets == null) 1761: return new Insets(2, 2, 2, 2); 1762: 1763: insets.left = insets.right = insets.top = insets.bottom = 2; 1764: return insets; 1765: } 1766: } 1767: 1768: }