Frames | No Frames |
1: /* LineBorder.java -- 2: Copyright (C) 2003 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.border; 40: 41: import java.awt.Color; 42: import java.awt.Component; 43: import java.awt.Graphics; 44: import java.awt.Insets; 45: 46: 47: /** 48: * A border that consists of a line whose thickness and color can be 49: * specified. There also is a variant with rounded corners. 50: * 51: * @author Sascha Brawer (brawer@dandelis.ch) 52: */ 53: public class LineBorder extends AbstractBorder 54: { 55: /** 56: * Determined using the <code>serialver</code> tool 57: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 58: */ 59: static final long serialVersionUID = -787563427772288970L; 60: 61: 62: /** 63: * A shared instance of a black, one pixel thick, plain LineBorder. 64: * The singleton object is lazily created by {@link 65: * #createBlackLineBorder()} upon its first invocation. 66: */ 67: private static LineBorder blackLineBorder; 68: 69: 70: /** 71: * A shared instance of a gray, one pixel thick, plain LineBorder. 72: * The singleton object is lazily created by {@link 73: * #createGrayLineBorder()} upon its first invocation. 74: */ 75: private static LineBorder grayLineBorder; 76: 77: 78: /** 79: * The width of the line in pixels. 80: */ 81: protected int thickness; 82: 83: 84: /** 85: * The color of the line. 86: */ 87: protected Color lineColor; 88: 89: 90: /** 91: * Indicates whether the line is drawn with rounded corners 92: * (<code>true</code>) or not ((<code>false</code>). 93: */ 94: protected boolean roundedCorners; 95: 96: 97: /** 98: * Constructs a LineBorder given its color. The border will be one 99: * pixel thick and have plain corners. 100: * 101: * @param color the color for drawing the border. 102: * 103: * @see #LineBorder(java.awt.Color, int, boolean) 104: */ 105: public LineBorder(Color color) 106: { 107: this(color, /* thickness */ 1, /* roundedCorners */ false); 108: } 109: 110: 111: /** 112: * Constructs a LineBorder given its color and thickness. The 113: * border will have plain corners. 114: * 115: * @param color the color for drawing the border. 116: * @param thickness the width of the line in pixels. 117: * 118: * @see #LineBorder(java.awt.Color, int, boolean) 119: */ 120: public LineBorder(Color color, int thickness) 121: { 122: this (color, thickness, /* roundedCorners */ false); 123: } 124: 125: 126: /** 127: * Constructs a LineBorder given its color, thickness, and whether 128: * it has rounded corners. 129: * 130: * <p><img src="doc-files/LineBorder-1.png" width="500" height="200" 131: * alt="[An illustration of two LineBorders]" /> 132: * 133: * <p>Note that the enlarged view in the right-hand picture shows 134: * that the implementation draws one more pixel than specified, 135: * provided that <code>roundedCorders</code> is <code>true</code> 136: * and anti-aliasing is turned on while painting. While this might 137: * be considered a bug, the Sun reference implementation (at least 138: * JDK 1.3.1 on Apple MacOS X 10.1.5) can be observed to fill 139: * exactly the same pixels as shown above. The GNU Classpath 140: * LineBorder replicates the observed behavior of the Sun 141: * implementation. 142: * 143: * @param color the color for drawing the border. 144: * @param thickness the width of the line in pixels. 145: * @param roundedCorners <code>true</code> for rounded corners, 146: * <code>false</code> for plain corners. 147: * 148: * @since 1.3 149: */ 150: // For the bug mentioned in the JavaDoc, please see also the comment 151: // in the paintBorder method below. 152: // 153: public LineBorder(Color color, int thickness, boolean roundedCorners) 154: { 155: if ((color == null) || (thickness < 0)) 156: throw new IllegalArgumentException(); 157: 158: this.lineColor = color; 159: this.thickness = thickness; 160: this.roundedCorners = roundedCorners; 161: } 162: 163: 164: /** 165: * Returns a black, one pixel thick, plain {@link LineBorder}. The method 166: * may always return the same (singleton) {@link LineBorder} instance. 167: * 168: * @return The border. 169: */ 170: public static Border createBlackLineBorder() 171: { 172: /* Swing is not designed to be thread-safe, so there is no 173: * need to synchronize the access to the global variable. 174: */ 175: if (blackLineBorder == null) 176: blackLineBorder = new LineBorder(Color.black); 177: 178: return blackLineBorder; 179: } 180: 181: 182: /** 183: * Returns a gray, one pixel thick, plain {@link LineBorder}. The method 184: * may always return the same (singleton) {@link LineBorder} instance. 185: * 186: * @return The border. 187: */ 188: public static Border createGrayLineBorder() 189: { 190: /* Swing is not designed to be thread-safe, so there is no 191: * need to synchronize the access to the global variable. 192: */ 193: if (grayLineBorder == null) 194: grayLineBorder = new LineBorder(Color.gray); 195: 196: return grayLineBorder; 197: } 198: 199: 200: /** 201: * Paints the line border around a given Component. 202: * 203: * @param c the component whose border is to be painted. 204: * @param g the graphics for painting. 205: * @param x the horizontal position for painting the border. 206: * @param y the vertical position for painting the border. 207: * @param width the width of the available area for painting the border. 208: * @param height the height of the available area for painting the border. 209: */ 210: public void paintBorder(Component c, Graphics g, 211: int x, int y, int width, int height) 212: { 213: Color oldColor = g.getColor(); 214: 215: try 216: { 217: g.setColor(lineColor); 218: 219: // If width and height were not adjusted, the border would 220: // appear one pixel too large in both directions. 221: width -= 1; 222: height -= 1; 223: 224: // Blurred, too large appearance 225: // ----------------------------- 226: // While Java 2D has introduced line strokes of arbitrary width, 227: // it seems desirable to keep this code independent of Java 2D. 228: // Therefore, multiple nested rectangles (or rounded rectangles) 229: // are drawn in order to simulate a line whose thickness is 230: // greater than one pixel. 231: // 232: // This hack causes a blurred appearance when anti-aliasing is 233: // on. Interestingly enough, though, the Sun JDK 1.3.1 (at least 234: // on MacOS X 10.1.5) shows exactly the same appearance under 235: // this condition. It thus seems likely that Sun does the same 236: // hack for simulating thick lines. For this reason, the 237: // blurred appearance seems acceptable -- especially since GNU 238: // Classpath tries to be compatible with the Sun reference 239: // implementation. 240: for (int i = 0; i < thickness; i++) 241: { 242: if (roundedCorners) 243: g.drawRoundRect(x, y, width, height, thickness, thickness); 244: else 245: g.drawRect(x, y, width, height); 246: 247: x += 1; 248: y += 1; 249: width -= 2; 250: height -= 2; 251: } 252: } 253: finally 254: { 255: g.setColor(oldColor); 256: } 257: } 258: 259: 260: /** 261: * Measures the width of this border. 262: * 263: * @param c the component whose border is to be measured. 264: * 265: * @return an Insets object whose <code>left</code>, <code>right</code>, 266: * <code>top</code> and <code>bottom</code> fields indicate the 267: * width of the border at the respective edge, which is the 268: * thickness of the line. 269: * 270: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 271: */ 272: public Insets getBorderInsets(Component c) 273: { 274: return new Insets(thickness, thickness, thickness, thickness); 275: } 276: 277: 278: /** 279: * Measures the width of this border, storing the results into a 280: * pre-existing Insets object. 281: * 282: * @param insets an Insets object for holding the result values. 283: * After invoking this method, the <code>left</code>, 284: * <code>right</code>, <code>top</code> and 285: * <code>bottom</code> fields indicate the width of the 286: * border at the respective edge, which is the thickness 287: * of the line. 288: * 289: * @return the same object that was passed for <code>insets</code>. 290: * 291: * @see #getBorderInsets(Component) 292: */ 293: public Insets getBorderInsets(Component c, Insets insets) 294: { 295: insets.left = insets.right = insets.top = insets.bottom = thickness; 296: return insets; 297: } 298: 299: 300: /** 301: * Returns the color of the line. 302: * 303: * @return The line color (never <code>null</code>). 304: */ 305: public Color getLineColor() 306: { 307: return lineColor; 308: } 309: 310: 311: /** 312: * Returns the thickness of the line in pixels. 313: * 314: * @return The line thickness (in pixels). 315: */ 316: public int getThickness() 317: { 318: return thickness; 319: } 320: 321: 322: /** 323: * Returns whether this LineBorder os drawm with rounded 324: * or with plain corners. 325: * 326: * @return <code>true</code> if the corners are rounded, 327: * <code>false</code> if the corners are plain. 328: */ 329: public boolean getRoundedCorners() 330: { 331: return roundedCorners; 332: } 333: 334: 335: /** 336: * Determines whether this border fills every pixel in its area 337: * when painting. 338: * 339: * @return <code>true</code> if the corners are plain and the line 340: * color is fully opaque; <code>false</code> if the corners 341: * are rounded or the line color is partially transparent. 342: */ 343: public boolean isBorderOpaque() 344: { 345: return (!roundedCorners) && (lineColor.getAlpha() == 255); 346: } 347: }