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