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    }