001    /*
002     * $Id: ComponentProvider.java 3152 2008-12-23 18:12:39Z kschaefe $
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.io.Serializable;
024    
025    import javax.swing.Icon;
026    import javax.swing.JComponent;
027    import javax.swing.JLabel;
028    
029    /**
030     * Abstract base class of a provider for a cell rendering component. Configures
031     * the component's content and default visuals depending on the renderee's state
032     * as captured in a <code>CellContext</code>. It's basically re-usable across
033     * all types of renderees (JTable, JList, JTree).
034     * <p>
035     * 
036     * To ease content configuration, it supports a pluggable
037     * <code>StringValue</code> which purpose is to create and return a string
038     * representation of a given object. Implemenations of a ComponentProvider can
039     * use it to configure their rendering component as appropriate.<p>
040     * 
041     * F.i. to show a Contributor cell object as "Busywoman, Herta" implement a
042     * custom StringValue and use it in a text rendering provider. (Note that SwingX
043     * default implementations of Table/List/TreeCellRenderer have convenience
044     * constructors to take the converter and create a default LabelProvider which
045     * uses it).
046     * 
047     * <pre><code>
048     * StringValue stringValue = new StringValue() {
049     * 
050     *     public String getString(Object value) {
051     *         if (!(value instanceof Contributor))
052     *             return TO_STRING.getString(value);
053     *         Contributor contributor = (Contributor) value;
054     *         return contributor.lastName + &quot;, &quot; + contributor.firstName;
055     *     }
056     * 
057     * };
058     * table.setDefaultRenderer(Contributor.class, new DefaultTableRenderer(
059     *         stringValue));
060     * list.setCellRenderer(new DefaultListRenderer(stringValue));
061     * tree.setCellRenderer(new DefaultTreeRenderer(stringValue));
062     * 
063     * </code></pre>
064     * 
065     * To ease handling of formatted localizable content, there's a
066     * <code>FormatStringValue</code> which is pluggable with a
067     * <code>Format</code>. <p>
068     * 
069     * F.i. to show a Date's time in the default Locale's SHORT
070     * version and right align the cell
071     * 
072     * <pre><code>
073     *   StringValue stringValue = new FormatStringValue(
074     *       DateFormat.getTimeInstance(DateFormat.SHORT));
075     *   table.getColumnExt(&quot;timeID&quot;).setCellRenderer(
076     *       new DefaultTableRenderer(stringValue, JLabel.RIGHT);  
077     * </code></pre>
078     * 
079     * 
080     * <p>
081     * 
082     * Guarantees to completely configure the visual properties listed below. As a
083     * consequence, client code (f.i. in <code>Highlighter</code>s) can safely
084     * change them without long-lasting visual artefacts.
085     * 
086     * <ul>
087     * <li> foreground and background, depending on selected and focused state
088     * <li> border
089     * <li> font
090     * <li> Painter (if applicable)
091     * <li> enabled
092     * <li> componentOrientation
093     * <li> tooltipText
094     * <li> minimum-, maximum-, preferredSize
095     * <li> horizontal alignment (if applicable)
096     * </ul>
097     * 
098     * As this internally delegates default visual configuration to a
099     * <code>DefaultVisuals</code> (which handles the first eight items)
100     * subclasses have to guarantee the alignment only.
101     * <p>
102     * 
103     * 
104     * @see StringValue
105     * @see FormatStringValue
106     * @see IconValue
107     * @see BooleanValue
108     * @see CellContext
109     * @see DefaultTableRenderer
110     * @see DefaultListRenderer
111     * @see DefaultTreeRenderer
112     * @see DefaultVisuals
113     */
114    public abstract class ComponentProvider<T extends JComponent> 
115        implements Serializable {
116        /** component to render with. */
117        protected T rendererComponent;
118        /** configurator of default visuals. */
119        protected DefaultVisuals<T> defaultVisuals;
120        /** horizontal (text) alignment of component. 
121         * PENDING: useful only for labels, buttons? */
122        protected int alignment;
123        /** the converter to use for string representation. 
124         * PENDING: IconValue? */
125        protected StringValue formatter;
126        
127        /**
128         * Instantiates a component provider with LEADING
129         * horizontal alignment and default to-String converter. <p> 
130         *
131         */
132        public ComponentProvider() {
133            this(null, JLabel.LEADING);
134        }
135    
136        /**
137         * Instantiates a component provider with LEADING
138         * horizontal alignment and the given converter. <p> 
139         *
140         * @param converter the converter to use for mapping the cell value to a
141         *        String representation.
142         */
143        public ComponentProvider(StringValue converter) {
144            this(converter, JLabel.LEADING);
145        }
146    
147        /**
148         * Instantiates a LabelProvider with given to-String converter and given
149         * horizontal alignment. If the converter is null, the default TO_STRING is
150         * used.
151         * 
152         * @param converter the converter to use for mapping the cell value to a
153         *        String representation.
154         * @param alignment the horizontal alignment.
155         */
156        public ComponentProvider(StringValue converter, int alignment) {
157            setHorizontalAlignment(alignment);
158            setStringValue(converter);
159            rendererComponent = createRendererComponent();
160            defaultVisuals = createDefaultVisuals();
161        }
162    
163        /**
164         * Configures and returns an appropriate component to render a cell
165         * in the given context. If the context is null, returns the
166         * component in its current state.
167         * 
168         * @param context the cell context to configure from
169         * @return a component to render a cell in the given context.
170         */
171        public T getRendererComponent(CellContext context) {
172            if (context != null) {
173                configureVisuals(context);
174                configureContent(context);
175            }
176            return rendererComponent;
177        }
178        
179        /**
180         * Sets the horizontal alignment property to configure the component with.
181         * Allowed values are those accepted by corresponding JLabel setter. The
182         * default value is JLabel.LEADING. This controller guarantees to apply the
183         * alignment on each request for a configured rendering component, if 
184         * possible. Note that not all components have a horizontal alignment
185         * property.
186         * 
187         * @param alignment the horizontal alignment to use when configuring the
188         *   rendering component.
189         */
190        public void setHorizontalAlignment(int alignment) {
191           this.alignment = alignment; 
192        }
193        
194        /**
195         * Returns the horizontal alignment.
196         * 
197         * @return the horizontal alignment of the rendering component.
198         * 
199         * @see #setHorizontalAlignment(int)
200         * 
201         */
202        public int getHorizontalAlignment() {
203            return alignment;
204        }
205    
206        /**
207         * Sets the StringValue to use. If the given StringValue is null,
208         * defaults to <code>StringValue.TO_STRING</code>. <p>
209         * 
210         * @param formatter the format to use.
211         */
212        public void setStringValue(StringValue formatter) {
213            if (formatter == null) {
214                formatter = StringValues.TO_STRING;
215            }
216            this.formatter = formatter;
217        }
218    
219        /**
220         * Returns the StringValue to use for obtaining 
221         * the String representation. <p>
222         * 
223         * @return the StringValue used by this provider, guaranteed to
224         *   be not null.
225         */
226        public StringValue getStringValue() {
227            return formatter;
228        }
229    
230        /**
231         * Returns a string representation of the content.
232         * <p>
233         * 
234         * This method guarantees to return the same string representation as would
235         * appear in the renderer, given that the corresponding cellContext has the
236         * same value as the parameter passed-in here. That is (assuming that the
237         * rendering component has a getText())
238         * 
239         * <pre><code>
240         * if (equals(value, context.getValue()) {
241         *     assertEquals(provider.getString(value), 
242         *     provider.getRenderingComponent(context).getText());
243         * }
244         * </code></pre>
245         * 
246         * This implementation simply delegates to its StringValue. Subclasses might
247         * need to override to comply.
248         * <p>
249         * 
250         * This is a second attempt - the driving force is the need for a consistent
251         * string representation across all (new and old) themes: rendering,
252         * (pattern) filtering/highlighting, searching, auto-complete ...
253         * <p>
254         * 
255         * @param value the object to represent as string.
256         * @return a appropriate string representation of the cell's content.
257         */
258        public String getString(Object value) {
259            return formatter.getString(value);
260        }
261        
262        /**
263         * Returns a String representation of the content.<p>
264         * 
265         * This method messages the 
266         * <code>StringValue</code> to get the String rep. Meant as 
267         * a convenience for subclasses.
268         * 
269         * @param context the cell context, must not be null.
270         * @return a appropriate string representation of the cell's content.
271         */
272        protected String getValueAsString(CellContext context) {
273            Object value = context.getValue();
274            return formatter.getString(value);
275        }
276    
277        /**
278         * Returns a Icon representation of the content.<p>
279         * 
280         * This method messages the 
281         * <code>IconValue</code> to get the Icon rep. Meant as 
282         * a convenience for subclasses.
283         * 
284         * @param context the cell context, must not be null.
285         * @return a appropriate icon representation of the cell's content,
286         *   or null if non if available.
287         */
288        protected Icon getValueAsIcon(CellContext context) {
289            Object value = context.getValue();
290            if (formatter instanceof IconValue) {
291                return ((IconValue) formatter).getIcon(value);
292            }
293            return null;
294        }
295    
296        /**
297         * Configures the rendering component's default visuals frome
298         * the given cell context. Here: delegates to the renderer
299         * controller.
300         * 
301         * @param context the cell context to configure from, must not be null.
302         * @see DefaultVisuals
303         */
304        protected void configureVisuals(CellContext context) {
305            defaultVisuals.configureVisuals(rendererComponent, context);
306        }
307    
308        /**
309         * Configures the renderering component's content and state from the
310         * given cell context.
311         * 
312         * @param context the cell context to configure from, must not be null.
313         * 
314         * @see #configureState(CellContext)
315         * @see #format(CellContext)
316         */
317        protected void configureContent(CellContext context) {
318            configureState(context);
319            format(context);
320        }
321    
322        /**
323         * Formats the renderering component's content from the
324         * given cell context.
325         * 
326         * @param context the cell context to configure from, must not be null.
327         */
328        protected abstract void format(CellContext context);
329    
330        /**
331         * Configures the renderering component's state from the
332         * given cell context.
333         * @param context the cell context to configure from, must not be null.
334         */
335        protected abstract void configureState(CellContext context); 
336    
337        /**
338         * Factory method to create and return the component to use for rendering.<p>
339         * 
340         * @return the component to use for rendering.
341         */
342        protected abstract T createRendererComponent();
343    
344        /**
345         * Factory method to create and return the DefaultVisuals used by this
346         * to configure the default visuals. Here: creates the default controller
347         * parameterized to the same type as this.
348         * 
349         * @return the controller used to configure the default visuals of
350         *   the rendering component.
351         */
352        protected DefaultVisuals<T> createDefaultVisuals() {
353            return new DefaultVisuals<T>();
354        }
355    
356        /**
357         * Intermediate exposure during refactoring...
358         * 
359         * @return the default visual configurator used by this.
360         */
361        protected DefaultVisuals<T> getDefaultVisuals() {
362            return defaultVisuals;
363        }
364    
365    
366    }