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 {@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: }