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
  54:   extends AbstractBorder
  55: {
  56:   /**
  57:    * Determined using the <code>serialver</code> tool
  58:    * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
  59:    */
  60:   static final long serialVersionUID = -787563427772288970L;
  61: 
  62: 
  63:   /**
  64:    * A shared instance of a black, one pixel thick, plain LineBorder.
  65:    * The singleton object is lazily created by {@link
  66:    * #createBlackLineBorder()} upon its first invocation.
  67:    */
  68:   private static LineBorder blackLineBorder;
  69: 
  70: 
  71:   /**
  72:    * A shared instance of a gray, one pixel thick, plain LineBorder.
  73:    * The singleton object is lazily created by {@link
  74:    * #createBlackGrayBorder()} upon its first invocation.
  75:    */
  76:   private static LineBorder grayLineBorder;
  77: 
  78: 
  79:   /**
  80:    * The width of the line in pixels.
  81:    */
  82:   protected int thickness;
  83: 
  84: 
  85:   /**
  86:    * The color of the line.
  87:    */
  88:   protected Color lineColor;
  89: 
  90: 
  91:   /**
  92:    * Indicates whether the line is drawn with rounded corners
  93:    * (<code>true</code>) or not ((<code>false</code>).
  94:    */
  95:   protected boolean roundedCorners;
  96: 
  97: 
  98:   /**
  99:    * Constructs a LineBorder given its color.  The border will be one
 100:    * pixel thick and have plain corners.
 101:    *
 102:    * @param color the color for drawing the border.
 103:    *
 104:    * @see #LineBorder(java.awt.Color, int, boolean)
 105:    */
 106:   public LineBorder(Color color)
 107:   {
 108:     this(color, /* thickness */ 1, /* roundedCorners */ false);
 109:   }
 110: 
 111: 
 112:   /**
 113:    * Constructs a LineBorder given its color and thickness.  The
 114:    * border will have plain corners.
 115:    *
 116:    * @param color the color for drawing the border.
 117:    * @param thickness the width of the line in pixels.
 118:    *
 119:    * @see #LineBorder(java.awt.Color, int, boolean)
 120:    */
 121:   public LineBorder(Color color, int thickness)
 122:   {
 123:     this (color, thickness, /* roundedCorners */ false);
 124:   }
 125:   
 126:   
 127:   /**
 128:    * Constructs a LineBorder given its color, thickness, and whether
 129:    * it has rounded corners.
 130:    * 
 131:    * <p><img src="doc-files/LineBorder-1.png" width="500" height="200"
 132:    * alt="[An illustration of two LineBorders]" />
 133:    *
 134:    * <p>Note that the enlarged view in the right-hand picture shows
 135:    * that the implementation draws one more pixel than specified,
 136:    * provided that <code>roundedCorders</code> is <code>true</code>
 137:    * and anti-aliasing is turned on while painting. While this might
 138:    * be considered a bug, the Sun reference implementation (at least
 139:    * JDK 1.3.1 on Apple MacOS X 10.1.5) can be observed to fill
 140:    * exactly the same pixels as shown above. The GNU Classpath
 141:    * LineBorder replicates the observed behavior of the Sun
 142:    * implementation.
 143:    *
 144:    * @param color the color for drawing the border.
 145:    * @param thickness the width of the line in pixels.
 146:    * @param roundedCorners <code>true</code> for rounded corners,
 147:    *        <code>false</code> for plain corners.
 148:    *
 149:    * @since 1.3
 150:    */
 151:   // For the bug mentioned in the JavaDoc, please see also the comment
 152:   // in the paintBorder method below.
 153:   //
 154:   public LineBorder(Color color, int thickness, boolean roundedCorners)
 155:   {
 156:     if ((color == null) || (thickness < 0))
 157:       throw new IllegalArgumentException();
 158: 
 159:     this.lineColor = color;
 160:     this.thickness = thickness;
 161:     this.roundedCorners = roundedCorners;
 162:   }
 163:   
 164:   
 165:   /**
 166:    * Returns a black, one pixel thick, plain LineBorder. The method
 167:    * may always return the same (singleton) LineBorder instance.
 168:    */
 169:   public static Border createBlackLineBorder()
 170:   {
 171:     /* Swing is not designed to be thread-safe, so there is no
 172:      * need to synchronize the access to the global variable.
 173:      */
 174:     if (blackLineBorder == null)
 175:       blackLineBorder = new LineBorder(Color.black);
 176:     
 177:     return blackLineBorder;
 178:   }
 179:   
 180:   
 181:   /**
 182:    * Returns a gray, one pixel thick, plain LineBorder. The method
 183:    * may always return the same (singleton) LineBorder instance.
 184:    */
 185:   public static Border createGrayLineBorder()
 186:   {
 187:     /* Swing is not designed to be thread-safe, so there is no
 188:      * need to synchronize the access to the global variable.
 189:      */
 190:     if (grayLineBorder == null)
 191:       grayLineBorder = new LineBorder(Color.gray);
 192:     
 193:     return grayLineBorder;
 194:   }
 195:   
 196:   
 197:   /**
 198:    * Paints the line border around a given Component.
 199:    *
 200:    * @param c the component whose border is to be painted.
 201:    * @param g the graphics for painting.
 202:    * @param x the horizontal position for painting the border.
 203:    * @param y the vertical position for painting the border.
 204:    * @param width the width of the available area for painting the border.
 205:    * @param height the height of the available area for painting the border.
 206:    */
 207:   public void paintBorder(Component c, Graphics  g,
 208:                           int x, int y, int width, int height)
 209:   {
 210:     Color oldColor = g.getColor();
 211: 
 212:     try
 213:     {
 214:       g.setColor(lineColor);
 215: 
 216:       /* If width and height were not adjusted, the border would
 217:        * appear one pixel too large in both directions.
 218:        */
 219:       width -= 1;
 220:       height -= 1;
 221: 
 222:       /* Blurred, too large appearance
 223:        * -----------------------------
 224:        * While Java 2D has introduced line strokes of arbitrary width,
 225:        * it seems desirable to keep this code independent of Java 2D.
 226:        * Therefore, multiple nested rectangles (or rounded rectangles)
 227:        * are drawn in order to simulate a line whose thickness is
 228:        * greater than one pixel.
 229:        *
 230:        * This hack causes a blurred appearance when anti-aliasing is
 231:        * on. Interestingly enough, though, the Sun JDK 1.3.1 (at least
 232:        * on MacOS X 10.1.5) shows exactly the same appearance under
 233:        * this condition. It thus seems likely that Sun does the same
 234:        * hack for simulating thick lines.  For this reason, the
 235:        * blurred appearance seems acceptable -- especially since GNU
 236:        * Classpath tries to be compatible with the Sun reference
 237:        * implementation.
 238:        */
 239:       for (int i = 0; i < thickness; i++)
 240:       {
 241:         if (roundedCorners)
 242:           g.drawRoundRect(x, y, width, height, thickness, thickness);
 243:         else
 244:           g.drawRect(x, y, width, height);
 245: 
 246:         x += 1;
 247:         y += 1;
 248:         width -= 2;
 249:         height -= 2;
 250:       }
 251:     }
 252:     finally
 253:     {
 254:       g.setColor(oldColor);
 255:     }
 256:   }
 257:   
 258:   
 259:   /**
 260:    * Measures the width of this border.
 261:    *
 262:    * @param c the component whose border is to be measured.
 263:    *
 264:    * @return an Insets object whose <code>left</code>, <code>right</code>,
 265:    *         <code>top</code> and <code>bottom</code> fields indicate the
 266:    *         width of the border at the respective edge, which is the
 267:    *         thickness of the line.
 268:    *
 269:    * @see #getBorderInsets(java.awt.Component, java.awt.Insets)
 270:    */
 271:   public Insets getBorderInsets(Component c)
 272:   {
 273:     return new Insets(thickness, thickness, thickness, thickness);
 274:   }
 275:   
 276:   
 277:   /**
 278:    * Measures the width of this border, storing the results into a
 279:    * pre-existing Insets object.
 280:    *
 281:    * @param insets an Insets object for holding the result values.
 282:    *        After invoking this method, the <code>left</code>,
 283:    *        <code>right</code>, <code>top</code> and
 284:    *        <code>bottom</code> fields indicate the width of the
 285:    *        border at the respective edge, which is the thickness
 286:    *        of the line.
 287:    *
 288:    * @return the same object that was passed for <code>insets</code>.
 289:    *
 290:    * @see #getBorderInsets(Component)
 291:    */
 292:   public Insets getBorderInsets(Component c, Insets insets)
 293:   {
 294:     insets.left = insets.right = insets.top = insets.bottom = thickness;
 295:     return insets;
 296:   }
 297:   
 298:   
 299:   /**
 300:    * Returns the color of the line.
 301:    */
 302:   public Color getLineColor()
 303:   {
 304:     return lineColor;
 305:   }
 306:   
 307:   
 308:   /**
 309:    * Returns the thickness of the line in pixels.
 310:    */
 311:   public int getThickness()
 312:   {
 313:     return thickness;
 314:   }
 315:   
 316:   
 317:   /**
 318:    * Returns whether this LineBorder os drawm with rounded
 319:    * or with plain corners.
 320:    *
 321:    * @return <code>true</code> if the corners are rounded,
 322:    *         <code>false</code> if the corners are plain.
 323:    */
 324:   public boolean getRoundedCorners()
 325:   {
 326:     return roundedCorners;
 327:   }
 328:   
 329:   
 330:   /**
 331:    * Determines whether this border fills every pixel in its area
 332:    * when painting.
 333:    *
 334:    * @return <code>true</code> if the corners are plain and the line
 335:    *         color is fully opaque; <code>false</code> if the corners
 336:    *         are rounded or the line color is partially transparent.
 337:    */
 338:   public boolean isBorderOpaque()
 339:   {
 340:     return (!roundedCorners) && (lineColor.getAlpha() == 255);
 341:   }
 342: }