001 /* 002 * $Id: WrappingIconPanel.java 3235 2009-02-01 15:01:07Z rah003 $ 003 * 004 * Copyright 2007 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 package org.jdesktop.swingx.renderer; 022 023 import java.awt.BorderLayout; 024 import java.awt.Color; 025 import java.awt.ComponentOrientation; 026 import java.awt.Font; 027 import java.awt.Rectangle; 028 029 import javax.swing.BorderFactory; 030 import javax.swing.Icon; 031 import javax.swing.JComponent; 032 import javax.swing.JLabel; 033 import javax.swing.border.Border; 034 035 import org.jdesktop.swingx.JXPanel; 036 import org.jdesktop.swingx.painter.Painter; 037 038 /** 039 * Compound component for usage in tree renderer. <p> 040 * 041 * Supports setting an icon for the node and a delegate component 042 * which is used to show the text/content of the node. The delegate 043 * component can be shared across renderers. <p> 044 * 045 * This implements the PainterAware by delegating to the delegate component if that 046 * is of type PainterAware. Does nothing if not. 047 */ 048 public class WrappingIconPanel extends JXPanel implements PainterAware { 049 protected JComponent delegate; 050 JLabel iconLabel; 051 String labelPosition = BorderLayout.CENTER; //2; 052 int iconLabelGap; 053 private Border ltorBorder; 054 private Border rtolBorder; 055 private boolean dropHackEnabled; 056 057 058 /** 059 * Instantiates and configures a WrappingIconPanel with the dropHack 060 * enabled. 061 * 062 */ 063 public WrappingIconPanel() { 064 this(true); 065 } 066 /** 067 * Instantiates and configures a WrappingIconPanel with the dropHack 068 * property set as indicated by the boolean. 069 * 070 * @param dropHackEnabled a boolean indicating whether the drop hack should 071 * be enabled. 072 * 073 * @see #isVisible() 074 */ 075 public WrappingIconPanel(boolean dropHackEnabled) { 076 setOpaque(false); 077 iconLabel = new JRendererLabel(); 078 iconLabelGap = iconLabel.getIconTextGap(); 079 iconLabel.setOpaque(false); 080 updateIconBorder(); 081 setBorder(null); 082 setLayout(new BorderLayout()); 083 add(iconLabel, BorderLayout.LINE_START); 084 setDropHackEnabled(dropHackEnabled); 085 } 086 087 /** 088 * {@inheritDoc} <p> 089 * 090 * Overridden to update the icon position. 091 */ 092 @Override 093 public void setComponentOrientation(ComponentOrientation o) { 094 super.setComponentOrientation(o); 095 updateIconBorder(); 096 } 097 098 /** 099 * Updates the icon position according to ComponentOrientation. 100 */ 101 private void updateIconBorder() { 102 if (ltorBorder == null) { 103 ltorBorder = BorderFactory.createEmptyBorder(0, 0, 0, iconLabelGap); 104 rtolBorder = BorderFactory.createEmptyBorder(0, iconLabelGap, 0, 0); 105 } 106 if (getComponentOrientation().isLeftToRight()) { 107 iconLabel.setBorder(ltorBorder); 108 } else { 109 iconLabel.setBorder(rtolBorder); 110 } 111 } 112 113 /** 114 * Sets the icon. 115 * 116 * @param icon the icon to use. 117 */ 118 public void setIcon(Icon icon) { 119 iconLabel.setIcon(icon); 120 iconLabel.setText(null); 121 validate(); 122 } 123 124 /** 125 * Returns the icon used in this panel, may be null. 126 * 127 * @return the icon used in this panel, may be null. 128 */ 129 public Icon getIcon() { 130 return iconLabel.getIcon(); 131 } 132 133 134 /** 135 * Sets the delegate component. 136 * 137 * @param comp the component to add as delegate. 138 */ 139 public void setComponent(JComponent comp) { 140 JComponent old = getComponent(); 141 if (delegate != null) { 142 remove(delegate); 143 } 144 delegate = comp; 145 add(delegate, labelPosition); 146 validate(); 147 firePropertyChange("component", old, getComponent()); 148 } 149 150 /** 151 * Returns the delegate component. 152 * 153 * @return the delegate component. 154 */ 155 public JComponent getComponent() { 156 return delegate; 157 } 158 159 /** 160 * {@inheritDoc} <p> 161 * 162 * Overridden to set the background of the delegate and icon label as well. 163 */ 164 @Override 165 public void setBackground(Color bg) { 166 super.setBackground(bg); 167 if (iconLabel != null) { 168 iconLabel.setBackground(bg); 169 } 170 if (delegate != null) { 171 delegate.setBackground(bg); 172 } 173 } 174 175 /** 176 * {@inheritDoc} <p> 177 * 178 * Overridden to set the foreground of the delegate and icon label as well. 179 */ 180 @Override 181 public void setForeground(Color bg) { 182 super.setForeground(bg); 183 if (iconLabel != null) { 184 iconLabel.setForeground(bg); 185 } 186 if (delegate != null) { 187 delegate.setForeground(bg); 188 } 189 } 190 191 192 193 194 /** 195 * {@inheritDoc} <p> 196 * 197 * Overridden to set the Font of the delegate as well. 198 */ 199 @Override 200 public void setFont(Font font) { 201 if (delegate != null) { 202 delegate.setFont(font); 203 } 204 super.setFont(font); 205 } 206 207 208 /** 209 * {@inheritDoc} 210 * <p> 211 * 212 * Overridden to hack around #766-swingx: cursor flickering in DnD when 213 * dragging over tree column. This is a core bug (#6700748) related to 214 * painting the rendering component on a CellRendererPane. A trick around is 215 * to let this return false. 216 * <p> 217 * 218 * Some LayoutManagers don't layout an invisible component, so need to make 219 * the hack-enabled configurable. This implementation will return false 220 * if isDropHackEnabled, super.isVisible otherwise. 221 */ 222 @Override 223 public boolean isVisible() { 224 return dropHackEnabled ? false : super.isVisible(); 225 } 226 227 228 /** 229 * {@inheritDoc} 230 * <p> 231 * 232 * Returns the delegate's Painter if it is of type PainterAware or null 233 * otherwise. 234 * 235 * @return the delegate's Painter or null. 236 */ 237 public Painter getPainter() { 238 if (delegate instanceof PainterAware) { 239 return ((PainterAware) delegate).getPainter(); 240 } 241 return null; 242 } 243 244 245 /** 246 * Sets the delegate's Painter if it is of type PainterAware. Does nothing otherwise. 247 * 248 * @param painter the Painter to apply to the delegate. 249 */ 250 public void setPainter(Painter painter) { 251 if (delegate instanceof PainterAware) { 252 ((PainterAware) delegate).setPainter(painter); 253 } 254 255 } 256 257 /** 258 * 259 * Returns the bounds of the delegate component or null if the delegate is null. 260 * 261 * PENDING JW: where do we use it? Maybe it was for testing only? 262 * 263 * @return the bounds of the delegate, or null if the delegate is null. 264 */ 265 public Rectangle getDelegateBounds() { 266 if (delegate == null) return null; 267 return delegate.getBounds(); 268 } 269 270 271 /** 272 * Sets the dropHackEnabled property. <p> 273 * 274 * The default value is true. 275 * 276 * @param dropHackEnabled 277 * 278 * @see #isVisible() 279 */ 280 public void setDropHackEnabled(boolean dropHackEnabled) { 281 this.dropHackEnabled = dropHackEnabled; 282 } 283 284 285 286 }