Frames | No Frames |
1: /* MatteBorder.java -- 2: Copyright (C) 2003, 2004, 2006 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: import javax.swing.Icon; 47: 48: /** 49: * A border that is filled with either a solid color or with repeated 50: * icon tiles. 51: * 52: * <p><img src="doc-files/MatteBorder-1.png" width="500" height="150" 53: * alt="[Two MatteBorders]" /> 54: * 55: * @author Sascha Brawer (brawer@dandelis.ch) 56: */ 57: public class MatteBorder extends EmptyBorder 58: { 59: /** 60: * Determined using the <code>serialver</code> tool 61: * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. 62: */ 63: static final long serialVersionUID = 4422248989617298224L; 64: 65: 66: /** 67: * The color that is used for filling the border, or 68: * <code>null</code> if the border is filled with repetitions of a 69: * tile icon. 70: * 71: * @see #tileIcon 72: */ 73: protected Color color; 74: 75: 76: /** 77: * The icon is used for filling the border with a tile, or 78: * <code>null</code> if the border is filled with a solid 79: * color. 80: * 81: * @see #color 82: */ 83: protected Icon tileIcon; 84: 85: 86: /** 87: * Constructs a MatteBorder given the width on each side 88: * and a fill color. 89: * 90: * <p><img src="doc-files/MatteBorder-2.png" width="500" height="150" 91: * alt="[A picture of a MatteBorder made by this constructor]" /> 92: * 93: * @param top the width of the border at its top edge. 94: * @param left the width of the border at its left edge. 95: * @param bottom the width of the border at its bottom edge. 96: * @param right the width of the border at its right edge. 97: * @param matteColor the color for filling the border. 98: */ 99: public MatteBorder(int top, int left, int bottom, int right, 100: Color matteColor) 101: { 102: super(top, left, bottom, right); 103: 104: if (matteColor == null) 105: throw new IllegalArgumentException(); 106: 107: this.color = matteColor; 108: } 109: 110: 111: /** 112: * Constructs a MatteBorder given its insets and fill color. 113: * 114: * <p><img src="doc-files/MatteBorder-3.png" width="500" height="150" 115: * alt="[A picture of a MatteBorder made by this constructor]" /> 116: * 117: * @param borderInsets an Insets object whose <code>top</code>, 118: * <code>left</code>, <code>bottom</code> and <code>right</code> 119: * fields indicate the with of the border at the respective 120: * edge. 121: * 122: * @param matteColor the color for filling the border. 123: */ 124: public MatteBorder(Insets borderInsets, Color matteColor) 125: { 126: this(borderInsets.top, borderInsets.left, 127: borderInsets.bottom, borderInsets.right, 128: matteColor); 129: } 130: 131: 132: /** 133: * Constructs a MatteBorder given the width on each side 134: * and an icon for tiling the border area. 135: * 136: * <p><img src="doc-files/MatteBorder-4.png" width="500" height="150" 137: * alt="[A picture of a MatteBorder made by this constructor]" /> 138: * 139: * @param top the width of the border at its top edge. 140: * @param left the width of the border at its left edge. 141: * @param bottom the width of the border at its bottom edge. 142: * @param right the width of the border at its right edge. 143: * @param tileIcon an icon for tiling the border area. 144: */ 145: public MatteBorder(int top, int left, int bottom, int right, 146: Icon tileIcon) 147: { 148: super(top, left, bottom, right); 149: 150: this.tileIcon = tileIcon; 151: } 152: 153: 154: /** 155: * Constructs a MatteBorder given its insets and an icon 156: * for tiling the border area. 157: * 158: * <p><img src="doc-files/MatteBorder-5.png" width="500" height="150" 159: * alt="[A picture of a MatteBorder made by this constructor]" /> 160: * 161: * @param borderInsets an Insets object whose <code>top</code>, 162: * <code>left</code>, <code>bottom</code> and <code>right</code> 163: * fields indicate the with of the border at the respective 164: * edge. 165: * 166: * @param tileIcon an icon for tiling the border area. 167: */ 168: public MatteBorder(Insets borderInsets, Icon tileIcon) 169: { 170: this(borderInsets.top, borderInsets.left, 171: borderInsets.bottom, borderInsets.right, 172: tileIcon); 173: } 174: 175: 176: /** 177: * Constructs a MatteBorder given an icon for tiling the 178: * border area. The icon width is used for the border insets 179: * at the left and right edge, the icon height for the top and 180: * bottom edge. 181: * 182: * <p><img src="doc-files/MatteBorder-6.png" width="379" height="150" 183: * alt="[A picture of a MatteBorder made by this constructor]" /> 184: * 185: * @param tileIcon an icon for tiling the border area. 186: */ 187: public MatteBorder(Icon tileIcon) 188: { 189: this(-1, -1, -1, -1, tileIcon); 190: } 191: 192: 193: /** 194: * Paints the border for a given component. 195: * 196: * @param c the component whose border is to be painted. 197: * @param g the graphics for painting. 198: * @param x the horizontal position for painting the border. 199: * @param y the vertical position for painting the border. 200: * @param width the width of the available area for painting the border. 201: * @param height the height of the available area for painting the border. 202: */ 203: public void paintBorder(Component c, Graphics g, 204: int x, int y, int width, int height) 205: { 206: Insets i = getBorderInsets(); 207: paintEdge(c, g, x, y, width, i.top, 0, 0); // top edge 208: paintEdge(c, g, x, y + height - i.bottom, // bottom edge 209: width, i.bottom, 210: 0, height - i.bottom); 211: paintEdge(c, g, x, y + i.top, // left edge 212: i.left, height - i.top, 213: 0, i.top); 214: paintEdge(c, g, x + width - i.right, y + i.top, // right edge 215: i.right, height - i.bottom, 216: width - i.right, i.top); 217: } 218: 219: 220: /** 221: * Measures the width of this border. 222: * 223: * @param c the component whose border is to be measured. 224: * 225: * @return an Insets object whose <code>left</code>, <code>right</code>, 226: * <code>top</code> and <code>bottom</code> fields indicate the 227: * width of the border at the respective edge. 228: * 229: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 230: */ 231: public Insets getBorderInsets(Component c) 232: { 233: /* There is no obvious reason for overriding this method, but we 234: * try to have exactly the same API as the Sun reference 235: * implementation. 236: */ 237: return this.getBorderInsets(c, null); 238: } 239: 240: 241: /** 242: * Measures the width of this border, storing the results into a 243: * pre-existing Insets object. 244: * 245: * @param insets an Insets object for holding the result values. 246: * After invoking this method, the <code>left</code>, 247: * <code>right</code>, <code>top</code> and 248: * <code>bottom</code> fields indicate the width of the 249: * border at the respective edge. 250: * 251: * @return the same object that was passed for <code>insets</code>. 252: * 253: * @see #getBorderInsets() 254: */ 255: public Insets getBorderInsets(Component c, Insets insets) 256: { 257: if (insets == null) 258: insets = new Insets(0, 0, 0, 0); 259: 260: if ((tileIcon != null) 261: && (top < 0) && (left < 0) 262: && (right < 0) && (bottom < 0)) 263: { 264: insets.left = insets.right = tileIcon.getIconWidth(); 265: insets.top = insets.bottom = tileIcon.getIconHeight(); 266: return insets; 267: } 268: 269: /* Copy top, left, bottom and right into the respective 270: * field of insets. 271: */ 272: return super.getBorderInsets(c, insets); 273: } 274: 275: 276: /** 277: * Measures the width of this border. 278: * 279: * @return an Insets object whose <code>left</code>, <code>right</code>, 280: * <code>top</code> and <code>bottom</code> fields indicate the 281: * width of the border at the respective edge. 282: * 283: * @see #getBorderInsets(java.awt.Component, java.awt.Insets) 284: */ 285: public Insets getBorderInsets() 286: { 287: /* The inherited implementation of EmptyBorder.isBorderOpaque() 288: * would do the same. It is not clear why this is overriden in the 289: * Sun implementation, at least not from just reading the JavaDoc. 290: */ 291: return this.getBorderInsets(null, null); 292: } 293: 294: 295: /** 296: * Returns the color that is used for filling the border, or 297: * <code>null</code> if the border is filled with repetitions of a 298: * tile icon. 299: * 300: * @return The color (possibly <code>null</code>). 301: */ 302: public Color getMatteColor() 303: { 304: return color; 305: } 306: 307: 308: /** 309: * Returns the icon is used for tiling the border, or 310: * <code>null</code> if the border is filled with a color instead of 311: * an icon. 312: * 313: * @return The icon (possibly <code>null</code>). 314: */ 315: public Icon getTileIcon() 316: { 317: return tileIcon; 318: } 319: 320: 321: /** 322: * Determines whether this border fills every pixel in its area 323: * when painting. 324: * 325: * @return <code>true</code> if the border is filled with an 326: * opaque color; <code>false</code> if it is filled with 327: * a semi-transparent color or with an icon. 328: */ 329: public boolean isBorderOpaque() 330: { 331: return (color != null) && (color.getAlpha() == 255); 332: } 333: 334: 335: /** 336: * Paints a rectangular area of the border. This private helper 337: * method is called once for each of the border edges 338: * by {@link #paintBorder}. 339: * 340: * @param c the component whose border is being painted. 341: * @param g the graphics for painting. 342: * @param x the horizontal position of the rectangular area. 343: * @param y the vertical position of the rectangular area. 344: * @param width the width of the rectangular area. 345: * @param height the height of the rectangular area. 346: * @param dx the x displacement for repeating the tile. 347: * @param dy the y displacement for repeating the tile. 348: */ 349: private void paintEdge(Component c, Graphics g, 350: int x, int y, int width, int height, 351: int dx, int dy) 352: { 353: Color oldColor; 354: int iconWidth, iconHeight; 355: Graphics clipped; 356: 357: if ((width <= 0) || (height <= 0)) 358: return; 359: 360: /* Paint a colored rectangle if desired. */ 361: if (color != null) 362: { 363: oldColor = g.getColor(); 364: try 365: { 366: g.setColor(color); 367: g.fillRect(x, y, width, height); 368: } 369: finally 370: { 371: g.setColor(oldColor); 372: } 373: return; 374: } 375: 376: // If this border has no icon end painting here. 377: if (tileIcon == null) 378: return; 379: 380: /* Determine the width and height of the icon. Some icons return 381: * -1 if it is an image whose dimensions have not yet been 382: * retrieved. There is not much we can do about this, but we 383: * should at least avoid entering the paint loop below 384: * with negative increments. 385: */ 386: iconWidth = tileIcon.getIconWidth(); 387: iconHeight = tileIcon.getIconHeight(); 388: if ((iconWidth <= 0) || (iconHeight <= 0)) 389: return; 390: 391: dx = dx % iconWidth; 392: dy = dy % iconHeight; 393: 394: clipped = g.create(); 395: try 396: { 397: clipped.setClip(x, y, width, height); 398: for (int ty = y - dy; ty < y + height; ty += iconHeight) 399: for (int tx = x - dx; tx < x + width; tx += iconWidth) 400: tileIcon.paintIcon(c, clipped, tx, ty); 401: } 402: finally 403: { 404: clipped.dispose(); 405: } 406: } 407: }