Source for javax.swing.border.LineBorder

   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 LineBorder. The method
 166:    * may always return the same (singleton) LineBorder instance.
 167:    */
 168:   public static Border createBlackLineBorder()
 169:   {
 170:     /* Swing is not designed to be thread-safe, so there is no
 171:      * need to synchronize the access to the global variable.
 172:      */
 173:     if (blackLineBorder == null)
 174:       blackLineBorder = new LineBorder(Color.black);
 175:     
 176:     return blackLineBorder;
 177:   }
 178:   
 179:   
 180:   /**
 181:    * Returns a gray, one pixel thick, plain LineBorder. The method
 182:    * may always return the same (singleton) LineBorder instance.
 183:    */
 184:   public static Border createGrayLineBorder()
 185:   {
 186:     /* Swing is not designed to be thread-safe, so there is no
 187:      * need to synchronize the access to the global variable.
 188:      */
 189:     if (grayLineBorder == null)
 190:       grayLineBorder = new LineBorder(Color.gray);
 191:     
 192:     return grayLineBorder;
 193:   }
 194:   
 195:   
 196:   /**
 197:    * Paints the line border around a given Component.
 198:    *
 199:    * @param c the component whose border is to be painted.
 200:    * @param g the graphics for painting.
 201:    * @param x the horizontal position for painting the border.
 202:    * @param y the vertical position for painting the border.
 203:    * @param width the width of the available area for painting the border.
 204:    * @param height the height of the available area for painting the border.
 205:    */
 206:   public void paintBorder(Component c, Graphics  g,
 207:                           int x, int y, int width, int height)
 208:   {
 209:     Color oldColor = g.getColor();
 210: 
 211:     try
 212:     {
 213:       g.setColor(lineColor);
 214: 
 215:       // If width and height were not adjusted, the border would
 216:       // appear one pixel too large in both directions.
 217:       width -= 1;
 218:       height -= 1;
 219: 
 220:       // Blurred, too large appearance
 221:       // -----------------------------
 222:       // While Java 2D has introduced line strokes of arbitrary width,
 223:       // it seems desirable to keep this code independent of Java 2D.
 224:       // Therefore, multiple nested rectangles (or rounded rectangles)
 225:       // are drawn in order to simulate a line whose thickness is
 226:       // greater than one pixel.
 227:       //
 228:       // This hack causes a blurred appearance when anti-aliasing is
 229:       // on. Interestingly enough, though, the Sun JDK 1.3.1 (at least
 230:       // on MacOS X 10.1.5) shows exactly the same appearance under
 231:       // this condition. It thus seems likely that Sun does the same
 232:       // hack for simulating thick lines.  For this reason, the
 233:       // blurred appearance seems acceptable -- especially since GNU
 234:       // Classpath tries to be compatible with the Sun reference
 235:       // implementation.
 236:       for (int i = 0; i < thickness; i++)
 237:       {
 238:         if (roundedCorners)
 239:           g.drawRoundRect(x, y, width, height, thickness, thickness);
 240:         else
 241:           g.drawRect(x, y, width, height);
 242: 
 243:         x += 1;
 244:         y += 1;
 245:         width -= 2;
 246:         height -= 2;
 247:       }
 248:     }
 249:     finally
 250:     {
 251:       g.setColor(oldColor);
 252:     }
 253:   }
 254:   
 255:   
 256:   /**
 257:    * Measures the width of this border.
 258:    *
 259:    * @param c the component whose border is to be measured.
 260:    *
 261:    * @return an Insets object whose <code>left</code>, <code>right</code>,
 262:    *         <code>top</code> and <code>bottom</code> fields indicate the
 263:    *         width of the border at the respective edge, which is the
 264:    *         thickness of the line.
 265:    *
 266:    * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
 267:    */
 268:   public Insets getBorderInsets(Component c)
 269:   {
 270:     return new Insets(thickness, thickness, thickness, thickness);
 271:   }
 272:   
 273:   
 274:   /**
 275:    * Measures the width of this border, storing the results into a
 276:    * pre-existing Insets object.
 277:    *
 278:    * @param insets an Insets object for holding the result values.
 279:    *        After invoking this method, the <code>left</code>,
 280:    *        <code>right</code>, <code>top</code> and
 281:    *        <code>bottom</code> fields indicate the width of the
 282:    *        border at the respective edge, which is the thickness
 283:    *        of the line.
 284:    *
 285:    * @return the same object that was passed for <code>insets</code>.
 286:    *
 287:    * @see #getBorderInsets(Component)
 288:    */
 289:   public Insets getBorderInsets(Component c, Insets insets)
 290:   {
 291:     insets.left = insets.right = insets.top = insets.bottom = thickness;
 292:     return insets;
 293:   }
 294:   
 295:   
 296:   /**
 297:    * Returns the color of the line.
 298:    */
 299:   public Color getLineColor()
 300:   {
 301:     return lineColor;
 302:   }
 303:   
 304:   
 305:   /**
 306:    * Returns the thickness of the line in pixels.
 307:    */
 308:   public int getThickness()
 309:   {
 310:     return thickness;
 311:   }
 312:   
 313:   
 314:   /**
 315:    * Returns whether this LineBorder os drawm with rounded
 316:    * or with plain corners.
 317:    *
 318:    * @return <code>true</code> if the corners are rounded,
 319:    *         <code>false</code> if the corners are plain.
 320:    */
 321:   public boolean getRoundedCorners()
 322:   {
 323:     return roundedCorners;
 324:   }
 325:   
 326:   
 327:   /**
 328:    * Determines whether this border fills every pixel in its area
 329:    * when painting.
 330:    *
 331:    * @return <code>true</code> if the corners are plain and the line
 332:    *         color is fully opaque; <code>false</code> if the corners
 333:    *         are rounded or the line color is partially transparent.
 334:    */
 335:   public boolean isBorderOpaque()
 336:   {
 337:     return (!roundedCorners) && (lineColor.getAlpha() == 255);
 338:   }
 339: }