001/*
002 * $Id: JRendererCheckBox.java 3512 2009-09-22 07:54:02Z 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.Graphics;
024import java.awt.Graphics2D;
025import java.awt.Rectangle;
026
027import javax.swing.JCheckBox;
028import javax.swing.UIManager;
029
030import org.jdesktop.swingx.painter.Painter;
031
032/**
033 * A <code>JCheckBox</code> optimized for usage in renderers and
034 * with a minimal background painter support. <p>
035 * 
036 * <i>Note</i>: the painter support will be switched to painter_work as 
037 * soon it enters main. 
038 * 
039 * @author Jeanette Winzenburg
040 */
041public class JRendererCheckBox extends JCheckBox implements PainterAware {
042    protected Painter painter;
043
044    /**
045     * {@inheritDoc}
046     */
047    public Painter getPainter() {
048        return painter;
049    }
050
051
052    /**
053     * {@inheritDoc}
054     */
055    public void setPainter(Painter painter) {
056        Painter old = getPainter();
057        this.painter = painter;
058        if (painter != null) {
059            // ui maps to !opaque
060            // Note: this is incomplete - need to keep track of the 
061            // "real" contentfilled property
062            // JW: revisit - really needed after fix for #897?
063            setContentAreaFilled(false);
064        } // PENDING JW: asymetric! no else?
065//        else {
066//            setContentAreaFilled(true);
067//        }
068        firePropertyChange("painter", old, getPainter());
069    }
070
071    /**
072     * {@inheritDoc} <p>
073     * 
074     * Overridden to return true if there is no painter.<p>
075     * 
076     */
077    @Override
078    public boolean isOpaque() {
079        // JW: fix for #897, not sure of any side-effects
080        // contentAreaFilled and opaque might be inconsistent
081        return painter == null;
082    }
083
084    /**
085     * Overridden for performance reasons.<p>
086     * PENDING: Think about Painters and opaqueness?
087     * 
088     */
089//    @Override
090//    public boolean isOpaque() { 
091//        Color back = getBackground();
092//        Component p = getParent(); 
093//        if (p != null) { 
094//            p = p.getParent(); 
095//        }
096//        // p should now be the JTable. 
097//        boolean colorMatch = (back != null) && (p != null) && 
098//            back.equals(p.getBackground()) && 
099//                        p.isOpaque();
100//        return !colorMatch && super.isOpaque(); 
101//    }
102
103    /**
104     * {@inheritDoc} <p>
105     * 
106     * Overridden to not automatically de/register itself from/to the ToolTipManager.
107     * As rendering component it is not considered to be active in any way, so the
108     * manager must not listen. 
109     */
110    @Override
111    public void setToolTipText(String text) {
112        putClientProperty(TOOL_TIP_TEXT_KEY, text);
113    }
114
115    
116    @Override
117    protected void paintComponent(Graphics g) {
118        // JW: hack around for #1178-swingx (core issue) 
119        // grab painting if Nimbus detected
120        if ((painter != null) || isNimbus()) {
121            // we have a custom (background) painter
122            // try to inject if possible
123            // there's no guarantee - some LFs have their own background 
124            // handling  elsewhere
125            paintComponentWithPainter((Graphics2D) g);
126        } else {
127            // no painter - delegate to super
128            super.paintComponent(g);
129        }
130    }
131
132    /**
133     * Hack around Nimbus not respecting background colors if UIResource.
134     * So by-pass ... 
135     * 
136     * @return
137     */
138    private boolean isNimbus() {
139        return UIManager.getLookAndFeel().getName().contains("Nimbus");
140    }
141
142
143    /**
144     * 
145     * Hack around AbstractPainter.paint bug which disposes the Graphics.
146     * So here we give it a scratch to paint on. <p>
147     * TODO - remove again, the issue is fixed?
148     * 
149     * @param g the graphics to paint on
150     */
151    private void paintPainter(Graphics g) {
152        if (painter == null) return;
153        // fail fast: we assume that g must not be null
154        // which throws an NPE here instead deeper down the bowels
155        // this differs from corresponding core implementation!
156        Graphics2D scratch = (Graphics2D) g.create();
157        try {
158            painter.paint(scratch, this, getWidth(), getHeight());
159        }
160        finally {
161            scratch.dispose();
162        }
163    }
164
165    /**
166     * 
167     * @param g
168     */
169    protected void paintComponentWithPainter(Graphics2D g) {
170        // 1. be sure to fill the background
171        // 2. paint the painter
172        // by-pass ui.update and hook into ui.paint directly
173        if (ui != null) {
174            // fail fast: we assume that g must not be null
175            // which throws an NPE here instead deeper down the bowels
176            // this differs from corresponding core implementation!
177            Graphics scratchGraphics = g.create();
178            try {
179                scratchGraphics.setColor(getBackground());
180                scratchGraphics.fillRect(0, 0, getWidth(), getHeight());
181                paintPainter(g);
182                ui.paint(scratchGraphics, this);
183            } finally {
184                scratchGraphics.dispose();
185            }
186        }
187
188    }
189    
190    /**
191     * Overridden for performance reasons.
192     * See the <a href="#override">Implementation Note</a> 
193     * for more information.
194     *
195     * @since 1.5
196     */
197    @Override
198    public void invalidate() {}
199
200    /**
201     * Overridden for performance reasons.
202     * See the <a href="#override">Implementation Note</a> 
203     * for more information.
204     */
205    @Override
206    public void validate() {}
207
208    /**
209     * Overridden for performance reasons.
210     * See the <a href="#override">Implementation Note</a> 
211     * for more information.
212     */
213    @Override
214    public void revalidate() {}
215
216    /**
217     * Overridden for performance reasons.
218     * See the <a href="#override">Implementation Note</a> 
219     * for more information.
220     */
221    @Override
222    public void repaint(long tm, int x, int y, int width, int height) {}
223
224    /**
225     * Overridden for performance reasons.
226     * See the <a href="#override">Implementation Note</a> 
227     * for more information.
228     */
229    @Override
230    public void repaint(Rectangle r) { }
231
232    /**
233     * Overridden for performance reasons.
234     * See the <a href="#override">Implementation Note</a> 
235     * for more information.
236     *
237     * @since 1.5
238     */
239    @Override
240    public void repaint() {
241    }
242
243    /**
244     * Overridden for performance reasons.
245     * See the <a href="#override">Implementation Note</a> 
246     * for more information.
247     */
248    @Override
249    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {  
250        // Strings get interned...
251        if ("text".equals(propertyName)) {
252            super.firePropertyChange(propertyName, oldValue, newValue);
253        }
254    }
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 firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { }
263
264
265
266}