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 }