001 /* 002 * $Id: IconBorder.java 2528 2007-12-14 13:49:37Z stolis $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx.border; 023 024 import java.awt.Component; 025 import java.awt.ComponentOrientation; 026 import java.awt.Graphics; 027 import java.awt.Insets; 028 import java.awt.Rectangle; 029 import java.io.Serializable; 030 031 import javax.swing.Icon; 032 import javax.swing.SwingConstants; 033 import javax.swing.border.Border; 034 035 import org.jdesktop.swingx.icon.EmptyIcon; 036 037 /** 038 * {@code IconBorder} creates a border that places an {@code Icon} in the border 039 * on the horizontal axis. The border does not add any additional insets other 040 * than the inset required to produce the space for the icon. If additional 041 * insets are required, users should create a 042 * {@link javax.swing.border.CompoundBorder compund border}. 043 * <p> 044 * This border is useful when attempting to add {@code Icon}s to pre-existing 045 * components without requiring specialty painting. 046 * 047 * @author Amy Fowler 048 * @author Karl Schaefer 049 * 050 * @version 1.1 051 */ 052 public class IconBorder implements Border, Serializable { 053 054 /** 055 * An empty icon. 056 */ 057 public static final Icon EMPTY_ICON = new EmptyIcon(); 058 private int padding; 059 private Icon icon; 060 private int iconPosition; 061 private Rectangle iconBounds = new Rectangle(); 062 063 /** 064 * Creates an {@code IconBorder} with an empty icon in a trailing position 065 * with a padding of 4. 066 * 067 * @see #EMPTY_ICON 068 */ 069 public IconBorder() { 070 this(null); 071 } 072 073 /** 074 * Creates an {@code IconBorder} with the specified icon in a trailing 075 * position with a padding of 4. 076 * 077 * @param validIcon 078 * the icon to set. This may be {@code null} to represent an 079 * empty icon. 080 * @see #EMPTY_ICON 081 */ 082 public IconBorder(Icon validIcon) { 083 this(validIcon, SwingConstants.TRAILING); 084 } 085 086 /** 087 * Creates an {@code IconBorder} with the specified constraints and a 088 * padding of 4. 089 * 090 * @param validIcon 091 * the icon to set. This may be {@code null} to represent an 092 * empty icon. 093 * @param iconPosition 094 * the position to place the icon relative to the component 095 * contents. This must be one of the following 096 * {@code SwingConstants}: 097 * <ul> 098 * <li>{@code LEADING}</li> 099 * <li>{@code TRAILING}</li> 100 * <li>{@code EAST}</li> 101 * <li>{@code WEST}</li> 102 * </ul> 103 * @throws IllegalArgumentException 104 * if {@code iconPosition} is not a valid position. 105 * @see #EMPTY_ICON 106 */ 107 public IconBorder(Icon validIcon, int iconPosition) { 108 this(validIcon, iconPosition, 4); 109 } 110 111 /** 112 * Creates an {@code IconBorder} with the specified constraints. If 113 * {@code validIcon} is {@code null}, {@code EMPTY_ICON} is used instead. 114 * If {@code padding} is negative, then the border does not use padding. 115 * 116 * @param validIcon 117 * the icon to set. This may be {@code null} to represent an 118 * empty icon. 119 * @param iconPosition 120 * the position to place the icon relative to the component 121 * contents. This must be one of the following 122 * {@code SwingConstants}: 123 * <ul> 124 * <li>{@code LEADING}</li> 125 * <li>{@code TRAILING}</li> 126 * <li>{@code EAST}</li> 127 * <li>{@code WEST}</li> 128 * </ul> 129 * @param padding 130 * the padding to surround the icon with. All non-positive values 131 * set the padding to 0. 132 * @throws IllegalArgumentException 133 * if {@code iconPosition} is not a valid position. 134 * @see #EMPTY_ICON 135 */ 136 public IconBorder(Icon validIcon, int iconPosition, int padding) { 137 setIcon(validIcon); 138 setPadding(padding); 139 setIconPosition(iconPosition); 140 } 141 142 private boolean isValidPosition(int position) { 143 boolean result = false; 144 145 switch (position) { 146 case SwingConstants.LEADING: 147 case SwingConstants.TRAILING: 148 case SwingConstants.EAST: 149 case SwingConstants.WEST: 150 result = true; 151 break; 152 default: 153 result = false; 154 } 155 156 return result; 157 } 158 159 /** 160 * {@inheritDoc} 161 */ 162 public Insets getBorderInsets(Component c) { 163 int horizontalInset = icon.getIconWidth() + (2 * padding); 164 int iconPosition = bidiDecodeLeadingTrailing(c.getComponentOrientation(), this.iconPosition); 165 if (iconPosition == SwingConstants.EAST) { 166 return new Insets(0, 0, 0, horizontalInset); 167 } 168 return new Insets(0, horizontalInset, 0, 0); 169 } 170 171 /** 172 * Sets the icon for this border. 173 * 174 * @param validIcon 175 * the icon to set. This may be {@code null} to represent an 176 * empty icon. 177 * @see #EMPTY_ICON 178 */ 179 public void setIcon(Icon validIcon) { 180 this.icon = validIcon == null ? EMPTY_ICON : validIcon; 181 } 182 183 /** 184 * This border is not opaque. 185 * 186 * @return always returns {@code false} 187 */ 188 public boolean isBorderOpaque() { 189 return false; 190 } 191 192 /** 193 * {@inheritDoc} 194 */ 195 public void paintBorder(Component c, Graphics g, int x, int y, int width, 196 int height) { 197 int iconPosition = bidiDecodeLeadingTrailing(c.getComponentOrientation(), this.iconPosition); 198 if (iconPosition == SwingConstants.NORTH_EAST) { 199 iconBounds.y = y + padding; 200 iconBounds.x = x + width - padding - icon.getIconWidth(); 201 } else if (iconPosition == SwingConstants.EAST) { // EAST 202 iconBounds.y = y 203 + ((height - icon.getIconHeight()) / 2); 204 iconBounds.x = x + width - padding - icon.getIconWidth(); 205 } else if (iconPosition == SwingConstants.WEST) { 206 iconBounds.y = y 207 + ((height - icon.getIconHeight()) / 2); 208 iconBounds.x = x + padding; 209 } 210 iconBounds.width = icon.getIconWidth(); 211 iconBounds.height = icon.getIconHeight(); 212 icon.paintIcon(c, g, iconBounds.x, iconBounds.y); 213 } 214 215 /** 216 * Returns EAST or WEST depending on the ComponentOrientation and 217 * the given postion LEADING/TRAILING this method has no effect for other 218 * position values 219 */ 220 private int bidiDecodeLeadingTrailing(ComponentOrientation c, int position) { 221 if(position == SwingConstants.TRAILING) { 222 if(!c.isLeftToRight()) { 223 return SwingConstants.WEST; 224 } 225 return SwingConstants.EAST; 226 } 227 if(position == SwingConstants.LEADING) { 228 if(c.isLeftToRight()) { 229 return SwingConstants.WEST; 230 } 231 return SwingConstants.EAST; 232 } 233 return position; 234 } 235 236 /** 237 * Gets the padding surrounding the icon. 238 * 239 * @return the padding for the icon. This value is guaranteed to be 240 * nonnegative. 241 */ 242 public int getPadding() { 243 return padding; 244 } 245 246 /** 247 * Sets the padding around the icon. 248 * 249 * @param padding 250 * the padding to set. If {@code padding < 0}, then 251 * {@code padding} will be set to {@code 0}. 252 */ 253 public void setPadding(int padding) { 254 this.padding = padding < 0 ? 0 : padding; 255 } 256 257 /** 258 * Returns the position to place the icon (relative to the component contents). 259 * 260 * @return one of the following {@code SwingConstants}: 261 * <ul> 262 * <li>{@code LEADING}</li> 263 * <li>{@code TRAILING}</li> 264 * <li>{@code EAST}</li> 265 * <li>{@code WEST}</li> 266 * </ul> 267 */ 268 public int getIconPosition() { 269 return iconPosition; 270 } 271 272 /** 273 * Sets the position to place the icon (relative to the component contents). 274 * 275 * @param iconPosition must be one of the following {@code SwingConstants}: 276 * <ul> 277 * <li>{@code LEADING}</li> 278 * <li>{@code TRAILING}</li> 279 * <li>{@code EAST}</li> 280 * <li>{@code WEST}</li> 281 * </ul> 282 * @throws IllegalArgumentException 283 * if {@code iconPosition} is not a valid position. 284 */ 285 public void setIconPosition(int iconPosition) { 286 if (!isValidPosition(iconPosition)) { 287 throw new IllegalArgumentException("Invalid icon position"); 288 } 289 this.iconPosition = iconPosition; 290 } 291 292 }