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