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