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 }