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 + ", " + 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("timeID").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 }