001    /*
002     * $Id: JRendererLabel.java 3235 2009-02-01 15:01:07Z rah003 $
003     *
004     * Copyright 2006 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.Color;
024    import java.awt.Component;
025    import java.awt.Graphics;
026    import java.awt.Graphics2D;
027    import java.awt.Rectangle;
028    
029    import javax.swing.JLabel;
030    
031    import org.jdesktop.swingx.painter.Painter;
032    
033    /**
034     * A <code>JLabel</code> optimized for usage in renderers and
035     * with a minimal background painter support. <p>
036     * 
037     * <i>Note</i>: the painter support will be switched to painter_work as 
038     * soon it enters main. 
039     * 
040     * The reasoning for the performance-overrides is copied from core: <p>
041     * 
042     * The standard <code>JLabel</code> component was not
043     * designed to be used this way and we want to avoid 
044     * triggering a <code>revalidate</code> each time the
045     * cell is drawn. This would greatly decrease performance because the
046     * <code>revalidate</code> message would be
047     * passed up the hierarchy of the container to determine whether any other
048     * components would be affected.  
049     * As the renderer is only parented for the lifetime of a painting operation
050     * we similarly want to avoid the overhead associated with walking the
051     * hierarchy for painting operations.
052     * So this class
053     * overrides the <code>validate</code>, <code>invalidate</code>,
054     * <code>revalidate</code>, <code>repaint</code>, and
055     * <code>firePropertyChange</code> methods to be 
056     * no-ops and override the <code>isOpaque</code> method solely to improve
057     * performance.  If you write your own renderer component,
058     * please keep this performance consideration in mind.
059     * <p>
060     * 
061     * @author Jeanette Winzenburg
062     */
063    public class JRendererLabel extends JLabel implements PainterAware {
064    
065        protected Painter painter;
066        private boolean strict;
067    
068        /**
069         * 
070         */
071        public JRendererLabel() {
072            super();
073          setOpaque(true);
074        }
075    
076        /**
077         * Overridden for performance reasons.<p>
078         * PENDING: Think about Painters and opaqueness?
079         * 
080         */
081        @Override
082        public boolean isOpaque() { 
083            Color back = getBackground();
084            Component p = getParent(); 
085            if (p != null) { 
086                p = p.getParent(); 
087            }
088            // p should now be the JTable. 
089            boolean colorMatch = (back != null) && (p != null) && 
090                back.equals(p.getBackground()) && 
091                            p.isOpaque();
092            return !colorMatch && super.isOpaque(); 
093        }
094    
095        /**
096         * {@inheritDoc}
097         */
098        public void setPainter(Painter painter) {
099            Painter old = getPainter();
100            this.painter = painter;
101            firePropertyChange("painter", old, getPainter());
102        }
103    
104        /**
105         * {@inheritDoc}
106         */
107        public Painter getPainter() {
108            return painter;
109        }
110        /**
111         * {@inheritDoc} <p>
112         * 
113         * Overridden to inject Painter's painting. <p>
114         * TODO: cleanup logic - see JRendererCheckBox.
115         * 
116         */
117        @Override
118        protected void paintComponent(Graphics g) {
119            if (painter != null) {
120                // we have a custom (background) painter
121                // try to inject if possible
122                // there's no guarantee - some LFs have their own background 
123                // handling  elsewhere
124                if (isOpaque()) {
125                    // replace the paintComponent completely 
126                    paintComponentWithPainter((Graphics2D) g);
127                } else {
128                    // transparent apply the background painter before calling super
129                    paintPainter(g);
130                    super.paintComponent(g);
131                }
132            } else {
133                // nothing to worry about - delegate to super
134                super.paintComponent(g);
135            }
136        }
137    
138        /**
139         * 
140         * Hack around AbstractPainter.paint bug which disposes the Graphics.
141         * So here we give it a scratch to paint on. <p>
142         * TODO - remove again, the issue is fixed?
143         * 
144         * @param g the graphics to paint on
145         */
146        private void paintPainter(Graphics g) {
147            // fail fast: we assume that g must not be null
148            // which throws an NPE here instead deeper down the bowels
149            // this differs from corresponding core implementation!
150            Graphics2D scratch = (Graphics2D) g.create();
151            try {
152                painter.paint(scratch, this, getWidth(), getHeight());
153            }
154            finally {
155                scratch.dispose();
156            }
157        }
158        
159    //    public void setStrictWidth(boolean strict) {
160    //        this.strict = strict;
161    //    }
162    //
163    //    @Override
164    //    public Dimension getMaximumSize() {
165    //        if (strict) {
166    //            return super.getMaximumSize();
167    //        }
168    //        Dimension max = super.getMaximumSize();
169    //        max.width = Integer.MAX_VALUE - 1;
170    //        return max;
171    //    }
172    
173        /**
174         * PRE: painter != null, isOpaque()
175         * @param g
176         */
177        protected void paintComponentWithPainter(Graphics2D g) {
178            // 1. be sure to fill the background
179            // 2. paint the painter
180            // by-pass ui.update and hook into ui.paint directly
181            if (ui != null) {
182                // fail fast: we assume that g must not be null
183                // which throws an NPE here instead deeper down the bowels
184                // this differs from corresponding core implementation!
185                Graphics2D scratchGraphics = (Graphics2D) g.create();
186                    try {
187                        scratchGraphics.setColor(getBackground());
188                        scratchGraphics.fillRect(0, 0, getWidth(), getHeight());
189                        paintPainter(g);
190                        ui.paint(scratchGraphics, this);
191                    }
192                    finally {
193                        scratchGraphics.dispose();
194                    }
195            }        
196        }
197    
198        
199        /**
200         * {@inheritDoc} <p>
201         * 
202         * Overridden to not automatically de/register itself from/to the ToolTipManager.
203         * As rendering component it is not considered to be active in any way, so the
204         * manager must not listen. 
205         */
206        @Override
207        public void setToolTipText(String text) {
208            putClientProperty(TOOL_TIP_TEXT_KEY, text);
209        }
210    
211        /**
212         * Overridden for performance reasons.
213         * See the <a href="#override">Implementation Note</a> 
214         * for more information.
215         *
216         * @since 1.5
217         */
218        @Override
219        public void invalidate() {}
220    
221        /**
222         * Overridden for performance reasons.
223         * See the <a href="#override">Implementation Note</a> 
224         * for more information.
225         */
226        @Override
227        public void validate() {}
228    
229        /**
230         * Overridden for performance reasons.
231         * See the <a href="#override">Implementation Note</a> 
232         * for more information.
233         */
234        @Override
235        public void revalidate() {}
236    
237        /**
238         * Overridden for performance reasons.
239         * See the <a href="#override">Implementation Note</a> 
240         * for more information.
241         */
242        @Override
243        public void repaint(long tm, int x, int y, int width, int height) {}
244    
245        /**
246         * Overridden for performance reasons.
247         * See the <a href="#override">Implementation Note</a> 
248         * for more information.
249         */
250        @Override
251        public void repaint(Rectangle r) { }
252    
253        /**
254         * Overridden for performance reasons.
255         * See the <a href="#override">Implementation Note</a> 
256         * for more information.
257         *
258         * @since 1.5
259         */
260        @Override
261        public void repaint() {
262        }
263    
264        /**
265         * Overridden for performance reasons.
266         * See the <a href="#override">Implementation Note</a> 
267         * for more information.
268         */
269        @Override
270        protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {  
271            // Strings get interned...
272            if ("text".equals(propertyName)) {
273                super.firePropertyChange(propertyName, oldValue, newValue);
274            }
275        }
276    
277        /**
278         * Overridden for performance reasons.
279         * See the <a href="#override">Implementation Note</a> 
280         * for more information.
281         */
282        @Override
283        public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { }
284    
285    
286    }