001/*
002 * $Id: DefaultVisuals.java 3778 2010-09-07 10:10:49Z 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.io.Serializable;
025
026import javax.swing.JComponent;
027
028/**
029 * Encapsulates the default visual configuration of renderering components,
030 * respecting the state of the passed-in <code>CellContext</code>. It's
031 * basically re-usable across all types of renderees (JTable, JList, JTree).
032 * <p>
033 * 
034 * Guarantees to completely configure the default visual properties (listed
035 * below) of a given component. As a consequence, client code (f.i. in
036 * <code>Highlighter</code>s) can safely change them without long-lasting
037 * visual artefacts.
038 * 
039 * <ul>
040 * <li> foreground and background, depending on selected and focused state
041 * <li> border
042 * <li> font
043 * <li> Painter (if applicable)
044 * <li> enabled
045 * <li> componentOrientation
046 * <li> toolTipText
047 * <li> minimum-, maximum-, preferredSize
048 * <li> name
049 * </ul>
050 * 
051 * Client code will rarely need to be aware of this class. It's the single
052 * place to change on introduction of new properties considered as belonging
053 * to the "default visuals" of rendering components. <p>
054 * 
055 * PENDING: allow mutators for overruling the <code>CellContext</code>s
056 * defaults? Would prefer not to, as in the context of SwingX visual config on
057 * the renderer level is discouraged (the way to go are <code>Highlighter</code>s.<p>
058 * 
059 * PENDING: not yet quite decided whether the toolTipText property belongs
060 * into the visual default config. Doing so gives client code the choice to
061 * set it either in a Highlighter or a custom ComponentProvider.
062 * 
063 * @author Jeanette Winzenburg
064 * 
065 * @see CellContext
066 */
067public class DefaultVisuals<T extends JComponent> implements Serializable {
068
069
070    private Color unselectedForeground;
071
072    private Color unselectedBackground;
073
074    /**
075     * Sets the renderer's unselected-foreground color to the specified color.
076     * If <code>not null</code> this color will overrule the default color of
077     * the CellContext.
078     * 
079     * @param c set the foreground color to this value
080     */
081    public void setForeground(Color c) {
082        unselectedForeground = c;
083    }
084
085    /**
086     * Sets the renderer's unselected-background color to the specified color.
087     * If <code>not null</code> this color will overrule the default color of
088     * the CellContext.
089     * 
090     * @param c set the background color to this value
091     */
092    public void setBackground(Color c) {
093        unselectedBackground = c;
094    }
095
096    
097    //---------------- subclass configuration    
098    /**
099     * Configures all default visual state of the rendering component from the 
100     * given cell context.
101     * 
102     * @param renderingComponent the component to configure, must not be null
103     * @param context the cell context to configure from, must not be null
104     * @throws NullPointerException if either renderingComponent or cellContext 
105     *   is null
106     */
107    public void configureVisuals(T renderingComponent, CellContext context) {
108        configureState(renderingComponent, context);
109        configureColors(renderingComponent, context);
110        configureBorder(renderingComponent, context);
111        configurePainter(renderingComponent, context);
112    }
113
114    /**
115     * Configures the default Painter if applicable. Here: set's to null.
116     * 
117     * @param renderingComponent the component to configure, must not be null
118     * @param context the cell context to configure from, must not be null
119     */
120    protected void configurePainter(T renderingComponent, CellContext context) {
121        if (renderingComponent instanceof PainterAware) {
122            ((PainterAware) renderingComponent).setPainter(null);
123        }
124        
125    }
126
127    /**
128     * Configure "divers" visual state of the rendering component from the given
129     * cell context.
130     * <p>
131     * 
132     * Here: synch <code>Font</code>, <code>ComponentOrientation</code> and
133     * <code>enabled</code> to context's component. Resets toolTipText to null.
134     * Calls configureSizes to reset xxSize if appropriate. Resets the component's
135     * name property.
136     * <p>
137     * 
138     * PENDING: not fully defined - "divers" means everything that's not 
139     * <code>Color</code>s
140     * nor <code>Border</code> nor <code>Painter</code>.
141     *      
142     * @param renderingComponent the component to configure, must not be null
143     * @param context the cell context to configure from, must not be null
144     */
145    protected void configureState(T renderingComponent, CellContext context) {
146        renderingComponent.setName(context.getCellRendererName());
147        renderingComponent.setToolTipText(null);
148        configureSizes(renderingComponent, context);
149        // PENDING JW: as of Issue #1269 this was changed to query the
150        // CellContext for the font - should move out off the else?
151        // context takes care of null component
152        renderingComponent.setFont(context.getFont());
153        if (context.getComponent() == null) {
154            // what to do?
155            // we guarantee to cleanup completely - what are the defaults?
156            // leave the decistion to the context?
157        } else {
158            renderingComponent.setEnabled(context.getComponent().isEnabled());
159            renderingComponent.applyComponentOrientation(context.getComponent()
160                    .getComponentOrientation());
161        }
162    }
163
164    /**
165     * Configures min-, max, preferredSize properties of the renderingComponent.
166     * 
167     * Here: set all to null.
168     * 
169     * @param renderingComponent the component to configure, must not be null
170     * @param context the cell context to configure from, must not be null
171     */
172    protected void configureSizes(T renderingComponent, CellContext context) {
173        renderingComponent.setPreferredSize(null);
174        renderingComponent.setMinimumSize(null);
175        renderingComponent.setMaximumSize(null);
176    }
177
178    /**
179     * Configures colors of rendering component from the given cell context.
180     * 
181     * @param renderingComponent the component to configure, must not be null
182     * @param context the cell context to configure from, must not be null
183     */
184    protected void configureColors(T renderingComponent, CellContext context) {
185        if (context.isSelected()) {
186            renderingComponent.setForeground(context.getSelectionForeground());
187            renderingComponent.setBackground(context.getSelectionBackground());
188        } else {
189            renderingComponent.setForeground(getForeground(context));
190            renderingComponent.setBackground(getBackground(context));
191        }
192        if (context.isFocused()) {
193            configureFocusColors(renderingComponent, context);
194        }
195    }
196    /**
197     * Configures focus-related colors form given cell context.<p>
198     * 
199     * PENDING: move to context as well? - it's the only comp
200     * with focus specifics? Problem is the parameter type...
201     * 
202     * @param renderingComponent the component to configure, must not be null
203     * @param context the cell context to configure from, must not be null
204     */
205    protected void configureFocusColors(T renderingComponent, CellContext context) {
206        if (!context.isSelected() && context.isEditable()) {
207            Color col = context.getFocusForeground();
208            if (col != null) {
209                renderingComponent.setForeground(col);
210            }
211            col = context.getFocusBackground();
212            if (col != null) {
213                renderingComponent.setBackground(col);
214            }
215        }
216    }
217
218
219    /**
220     * Configures the rendering component's border from the given cell context.<p>
221     * 
222     * @param renderingComponent the component to configure, must not be null
223     * @param context the cell context to configure from, must not be null
224     */
225    protected void configureBorder(T renderingComponent, CellContext context) {
226        renderingComponent.setBorder(context.getBorder());
227    }
228
229    /**
230     * Returns the unselected foreground to use for the rendering 
231     * component. <p>
232     * 
233     * Here: returns this renderer's unselected foreground is not null,
234     * returns the foreground from the given context. In other words:
235     * the renderer's foreground takes precedence if set.
236     * 
237     * @param context the cell context.
238     * @return the unselected foreground.
239     */
240    protected Color getForeground(CellContext context) {
241        if (unselectedForeground != null)
242            return unselectedForeground;
243        return context.getForeground();
244    }
245
246    /**
247     * Returns the unselected background to use for the rendering 
248     * component. <p>
249     * 
250     * Here: returns this renderer's unselected background is not null,
251     * returns the background from the given context. In other words:
252     * the renderer's background takes precedence if set.
253     * 
254     * @param context the cell context.
255     * @return the unselected background.
256     */
257    protected Color getBackground(CellContext context) {
258        if (unselectedBackground != null)
259            return unselectedBackground;
260        return context.getBackground();
261    }
262
263    
264
265}