1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing.border;
  26 
  27 import java.awt.Graphics;
  28 import java.awt.Insets;
  29 import java.awt.Color;
  30 import java.awt.Component;
  31 import java.awt.Graphics2D;
  32 import java.awt.Shape;
  33 import java.awt.geom.Path2D;
  34 import java.awt.geom.Rectangle2D;
  35 import java.awt.geom.RoundRectangle2D;
  36 import java.beans.ConstructorProperties;
  37 
  38 /**
  39  * A class which implements a line border of arbitrary thickness
  40  * and of a single color.
  41  * <p>
  42  * <strong>Warning:</strong>
  43  * Serialized objects of this class will not be compatible with
  44  * future Swing releases. The current serialization support is
  45  * appropriate for short term storage or RMI between applications running
  46  * the same version of Swing.  As of 1.4, support for long term storage
  47  * of all JavaBeans
  48  * has been added to the <code>java.beans</code> package.
  49  * Please see {@link java.beans.XMLEncoder}.
  50  *
  51  * @author David Kloba
  52  */
  53 @SuppressWarnings("serial") // Same-version serialization only
  54 public class LineBorder extends AbstractBorder
  55 {
  56     private static Border blackLine;
  57     private static Border grayLine;
  58 
  59     /**
  60      * Thickness of the border.
  61      */
  62     protected int thickness;
  63     /**
  64      * Color of the border.
  65      */
  66     protected Color lineColor;
  67     /**
  68      * Whether or not the border has rounded corners.
  69      */
  70     protected boolean roundedCorners;
  71 
  72     /**
  73      * Convenience method for getting the Color.black LineBorder of thickness 1.
  74      *
  75      * @return a {@code LineBorder} with {@code Color.black} and thickness of 1
  76      */
  77     public static Border createBlackLineBorder() {
  78         if (blackLine == null) {
  79             blackLine = new LineBorder(Color.black, 1);
  80         }
  81         return blackLine;
  82     }
  83 
  84     /**
  85      * Convenience method for getting the Color.gray LineBorder of thickness 1.
  86      *
  87      * @return a {@code LineBorder} with {@code Color.gray} and thickness of 1
  88      */
  89     public static Border createGrayLineBorder() {
  90         if (grayLine == null) {
  91             grayLine = new LineBorder(Color.gray, 1);
  92         }
  93         return grayLine;
  94     }
  95 
  96     /**
  97      * Creates a line border with the specified color and a
  98      * thickness = 1.
  99      *
 100      * @param color the color for the border
 101      */
 102     public LineBorder(Color color) {
 103         this(color, 1, false);
 104     }
 105 
 106     /**
 107      * Creates a line border with the specified color and thickness.
 108      *
 109      * @param color the color of the border
 110      * @param thickness the thickness of the border
 111      */
 112     public LineBorder(Color color, int thickness)  {
 113         this(color, thickness, false);
 114     }
 115 
 116     /**
 117      * Creates a line border with the specified color, thickness,
 118      * and corner shape.
 119      *
 120      * @param color the color of the border
 121      * @param thickness the thickness of the border
 122      * @param roundedCorners whether or not border corners should be round
 123      * @since 1.3
 124      */
 125     @ConstructorProperties({"lineColor", "thickness", "roundedCorners"})
 126     public LineBorder(Color color, int thickness, boolean roundedCorners)  {
 127         lineColor = color;
 128         this.thickness = thickness;
 129         this.roundedCorners = roundedCorners;
 130     }
 131 
 132     /**
 133      * Paints the border for the specified component with the
 134      * specified position and size.
 135      *
 136      * @param c the component for which this border is being painted
 137      * @param g the paint graphics
 138      * @param x the x position of the painted border
 139      * @param y the y position of the painted border
 140      * @param width the width of the painted border
 141      * @param height the height of the painted border
 142      */
 143     public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
 144         if ((this.thickness > 0) && (g instanceof Graphics2D)) {
 145             Graphics2D g2d = (Graphics2D) g;
 146 
 147             Color oldColor = g2d.getColor();
 148             g2d.setColor(this.lineColor);
 149 
 150             Shape outer;
 151             Shape inner;
 152 
 153             int offs = this.thickness;
 154             int size = offs + offs;
 155             if (this.roundedCorners) {
 156                 float arc = .2f * offs;
 157                 outer = new RoundRectangle2D.Float(x, y, width, height, offs, offs);
 158                 inner = new RoundRectangle2D.Float(x + offs, y + offs, width - size, height - size, arc, arc);
 159             }
 160             else {
 161                 outer = new Rectangle2D.Float(x, y, width, height);
 162                 inner = new Rectangle2D.Float(x + offs, y + offs, width - size, height - size);
 163             }
 164             Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
 165             path.append(outer, false);
 166             path.append(inner, false);
 167             g2d.fill(path);
 168             g2d.setColor(oldColor);
 169         }
 170     }
 171 
 172     /**
 173      * Reinitialize the insets parameter with this Border's current Insets.
 174      *
 175      * @param c the component for which this border insets value applies
 176      * @param insets the object to be reinitialized
 177      */
 178     public Insets getBorderInsets(Component c, Insets insets) {
 179         insets.set(thickness, thickness, thickness, thickness);
 180         return insets;
 181     }
 182 
 183     /**
 184      * Returns the color of the border.
 185      *
 186      * @return a {@code Color} object representing the color of this object
 187      */
 188     public Color getLineColor()     {
 189         return lineColor;
 190     }
 191 
 192     /**
 193      * Returns the thickness of the border.
 194      *
 195      * @return the thickness of this border
 196      */
 197     public int getThickness()       {
 198         return thickness;
 199     }
 200 
 201     /**
 202      * Returns whether this border will be drawn with rounded corners.
 203      *
 204      * @return {@code true} if this border should have rounded corners
 205      * @since 1.3
 206      */
 207     public boolean getRoundedCorners() {
 208         return roundedCorners;
 209     }
 210 
 211     /**
 212      * Returns whether or not the border is opaque.
 213      *
 214      * @return {@code true} if the border is opaque, {@code false} otherwise
 215      */
 216     public boolean isBorderOpaque() {
 217         return !roundedCorners;
 218     }
 219 
 220 }