001/* 002 * $Id: WrappingProvider.java 3927 2011-02-22 16:34:11Z kleopatra $ 003 * 004 * Copyright 2007 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 javax.swing.BorderFactory; 024import javax.swing.Icon; 025import javax.swing.tree.DefaultMutableTreeNode; 026 027import org.jdesktop.swingx.rollover.RolloverRenderer; 028import org.jdesktop.swingx.treetable.TreeTableNode; 029 030 031/** 032 * Wrapping ComponentProvider for usage in tree rendering. Handles the icon 033 * itself, delegates the node content to the wrappee. Value-based icon and 034 * content mapping can be configured by custom <code>IconValue</code>s and 035 * <b>StringValue</b>, respectively. 036 * <p> 037 * 038 * An example of how to configure a file tree by using the system icons and 039 * display names 040 * 041 * <pre><code> 042 * TreeCellRenderer r = new DefaultTreeRenderer( 043 * IconValues.FILE_ICON, StringValues.FILE_NAME); 044 * tree.setCellRenderer(r); 045 * treeTable.setTreeCellRenderer(r); 046 * </code></pre> 047 * 048 * PENDING: ui specific focus rect variation (draw rect around icon) missing 049 * <p> 050 */ 051public class WrappingProvider extends 052 ComponentProvider<WrappingIconPanel> implements RolloverRenderer { 053 054 protected ComponentProvider<?> wrappee; 055 private boolean unwrapUserObject; 056 057 /** 058 * Instantiates a WrappingProvider with default delegate provider. 059 * 060 */ 061 public WrappingProvider() { 062 this((ComponentProvider<?>) null); 063 } 064 065 /** 066 * Instantiates a WrappingProvider with default wrappee, configured 067 * to use the wrappeeStringValue. Uses the 068 * given IconValue to configure the icon. 069 * 070 * @param iconValue the IconValue to use for configuring the icon. 071 * @param wrappeeStringValue the StringValue to use in the wrappee. 072 */ 073 public WrappingProvider(IconValue iconValue, StringValue wrappeeStringValue) { 074 this(iconValue, wrappeeStringValue, true); 075 } 076 077 /** 078 * Instantiates a WrappingProvider with default wrappee. Uses the 079 * given IconValue to configure the icon. 080 * 081 * @param iconValue the IconValue to use for configuring the icon. 082 */ 083 public WrappingProvider(IconValue iconValue) { 084 this(iconValue, null); 085 } 086 087 /** 088 * Instantiates a WrappingProvider with default wrappee configured 089 * with the given StringValue. 090 * 091 * PENDING: we have a slight semantic glitch compared to super because 092 * the given StringValue is <b>not</b> for use in this provider but for use 093 * in the wrappee! 094 * 095 * @param wrappeeStringValue the StringValue to use in the wrappee. 096 */ 097 public WrappingProvider(StringValue wrappeeStringValue) { 098 this(null, wrappeeStringValue); 099 } 100 101 /** 102 * Instantiates a WrappingProvider with the given delegate 103 * provider for the node content. If null, a default 104 * LabelProvider will be used. 105 * 106 * @param delegate the provider to use as delegate 107 */ 108 public WrappingProvider(ComponentProvider<?> delegate) { 109 this(delegate, true); 110 } 111 112 /** 113 * Instantiates a WrappingProvider with the given delegate 114 * provider for the node content and unwrapUserObject property. 115 * If the delegate is null, a default LabelProvider will be used. 116 * 117 * @param delegate the provider to use as delegate 118 * @param unwrapUserObject a flag indicating whether this provider 119 * should auto-unwrap the userObject from the context value. 120 */ 121 public WrappingProvider(ComponentProvider<?> delegate, boolean unwrapUserObject) { 122 this(null, delegate, unwrapUserObject); 123 } 124 125 /** 126 * Instantiates a WrappingProvider with the given delegate 127 * provider for the node content and unwrapUserObject property. 128 * If the delegate is null, a default LabelProvider will be used. 129 * 130 * @param iv the icon converter to use for this provider 131 * @param delegate the provider to use as delegate 132 * @param unwrapUserObject a flag indicating whether this provider 133 * should auto-unwrap the userObject from the context value. 134 */ 135 public WrappingProvider(IconValue iv, ComponentProvider<?> delegate, boolean unwrapUserObject) { 136 super(iv != null ? (new MappedValue(null, iv)) : StringValues.EMPTY); 137 setWrappee(delegate); 138 setUnwrapUserObject(unwrapUserObject); 139 } 140 141 /** 142 * Instantiates a WrappingProvider with the given delegate 143 * provider for the node content and unwrapUserObject property. 144 * If the delegate is null, a default LabelProvider will be used. 145 * 146 * @param iv the icon converter to use for this provider 147 * @param delegateStringValue the StringValue to use in the wrappee. 148 * @param unwrapUserObject a flag indicating whether this provider 149 * should auto-unwrap the userObject from the context value. 150 */ 151 public WrappingProvider(IconValue iv, StringValue delegateStringValue, boolean unwrapUserObject) { 152 this(iv, (ComponentProvider<?>) null, unwrapUserObject); 153 getWrappee().setStringValue(delegateStringValue); 154 } 155 156 /** 157 * Sets the given provider as delegate for the node content. 158 * If the delegate is null, a default LabelProvider is set.<p> 159 * 160 * PENDING: rename to setDelegate? 161 * 162 * @param delegate the provider to use as delegate. 163 */ 164 public void setWrappee(ComponentProvider<?> delegate) { 165 if (delegate == null) { 166 delegate = new LabelProvider(); 167 } 168 this.wrappee = delegate; 169 } 170 171 /** 172 * Returns the delegate provider used to render the node content. 173 * 174 * @return the provider used for rendering the node content. 175 */ 176 public ComponentProvider<?> getWrappee() { 177 return wrappee; 178 } 179 180 /** 181 * Sets the unwrapUserObject property. If true, this provider 182 * replaces a context value of type XXNode with its user object before 183 * delegating to the wrappee. Otherwise the value is passed as-is always.<p> 184 * 185 * The default value is true. 186 * 187 * @param unwrap 188 * @see #getUnwrapUserObject() 189 */ 190 public void setUnwrapUserObject(boolean unwrap) { 191 this.unwrapUserObject = unwrap; 192 } 193 194 /** 195 * Returns a boolean indicating whether this provider tries to unwrap 196 * a userObject from a tree/table/node type value before delegating the 197 * context. 198 * 199 * @return a flag indicating the auto-unwrap property. 200 * 201 * @see #setUnwrapUserObject(boolean) 202 */ 203 public boolean getUnwrapUserObject() { 204 return unwrapUserObject; 205 } 206 207 /** 208 * {@inheritDoc} <p> 209 * 210 * Overridden to comply to contract: returns the string representation as 211 * provided by the wrappee (as this level has no string rep). Must do the 212 * same unwrapping magic as in configuring the rendering component if the 213 * unwrapUserObject property is true. <p> 214 * 215 * 216 * @param value the Object to get a String representation for. 217 * 218 * @see #setUnwrapUserObject(boolean) 219 * @see #getUnwrappedValue(Object) 220 */ 221 @Override 222 public String getString(Object value) { 223 value = getUnwrappedValue(value); 224 return wrappee.getString(value); 225 } 226 227 /** 228 * Sets a boolean indicating whether or not the main component's opacity 229 * should be applied to the Icon region.<p> 230 * 231 * The default value is false. This covers the main use case in a JTree. 232 * 233 * @param extendsComponentOpacity 234 */ 235 public void setExtendsComponentOpacity(boolean extendsComponentOpacity) { 236 rendererComponent.setExtendsComponentOpacity(extendsComponentOpacity); 237 238 } 239 /** 240 * @return the extendsComponentOpacity 241 */ 242 public boolean getExtendsComponentOpacity() { 243 return rendererComponent.getExtendsComponentOpacity(); 244 } 245 246 247 /** 248 * Returns the value as it should be passed to the delegate. If the unwrapUserObject 249 * property is true, tries return a userObject as appropriate for the value type. 250 * Returns the given value itself, ff the property is false or the type does 251 * not support the notion of userObject<p> 252 * 253 * Here: unwraps userObject of DefaultMutableTreeNode and TreeTableNode.<p> 254 * 255 * @param value the value to possibly unwrap 256 * @return the userObject if the value has an appropriate type and the 257 * unwrapUserObject property is true, otherwise returns the value unchanged. 258 * 259 * @see #setUnwrapUserObject(boolean) 260 * @see #getString(Object) 261 * @see #getRendererComponent(CellContext) 262 */ 263 protected Object getUnwrappedValue(Object value) { 264 if (!getUnwrapUserObject()) return value; 265 if (value instanceof DefaultMutableTreeNode) { 266 value = ((DefaultMutableTreeNode) value).getUserObject(); 267 } else if (value instanceof TreeTableNode) { 268 TreeTableNode node = (TreeTableNode) value; 269 value = node.getUserObject(); 270 } 271 return value; 272 } 273 274 /** 275 * {@inheritDoc} 276 */ 277 @Override 278 public WrappingIconPanel getRendererComponent(CellContext context) { 279 if (context != null) { 280 rendererComponent.setComponent(wrappee.rendererComponent); 281 Object oldValue = adjustContextValue(context); 282 // PENDING JW: sequence of config? 283 // A - first wrappee, then this allows to override configure/format methods 284 // of this class and overrule the wrappee 285 // B - first this, then wrappee allows overrule by overriding getRendererComp 286 // would take control from wrappee (f.i. Hyperlink foreground) 287 super.getRendererComponent(context); 288 wrappee.getRendererComponent(context); 289 restoreContextValue(context, oldValue); 290 return rendererComponent; 291 } 292 // PENDING JW: Findbugs barking [NP] Load of known null value 293 // probably can move the return rendererComponent from the if 294 // to here (the contract is to return the comp as-is if the 295 // context is null) - so we can do it here instead of delegating 296 // to super? 297 return super.getRendererComponent(context); 298 } 299 300 /** 301 * Restores the context value to the old value. 302 * 303 * @param context the CellContext to restore. 304 * @param oldValue the value to restore the context to. 305 */ 306 protected void restoreContextValue(CellContext context, Object oldValue) { 307 context.replaceValue(oldValue); 308 } 309 310 /** 311 * Replace the context's value with the userobject if the value is a type 312 * supporting the notion of userObject and this provider's unwrapUserObject 313 * property is true. Otherwise does nothing.<p> 314 * 315 * Subclasses may override but must guarantee to return the original 316 * value for restoring. 317 * 318 * @param context the context to adjust 319 * @return the old context value 320 * 321 * @see #setUnwrapUserObject(boolean) 322 * @see #getString(Object) 323 */ 324 protected Object adjustContextValue(CellContext context) { 325 Object oldValue = context.getValue(); 326 if (getUnwrapUserObject()) { 327 context.replaceValue(getUnwrappedValue(oldValue)); 328 } 329 return oldValue; 330 } 331 332 @Override 333 protected void configureState(CellContext context) { 334 rendererComponent.setBorder(BorderFactory.createEmptyBorder()); 335 } 336 337// /** 338// * @return 339// */ 340// private boolean isBorderAroundIcon() { 341// return Boolean.TRUE.equals(UIManager.get("Tree.drawsFocusBorderAroundIcon")); 342// } 343 344 @Override 345 protected WrappingIconPanel createRendererComponent() { 346 return new WrappingIconPanel(); 347 } 348 349 /** 350 * {@inheritDoc} <p> 351 * 352 * Here: implemented to set the icon. 353 */ 354 @Override 355 protected void format(CellContext context) { 356 rendererComponent.setIcon(getValueAsIcon(context)); 357 } 358 359 /** 360 * {@inheritDoc} <p> 361 * 362 * Overridden to fallback to the default icons supplied by the 363 * context if super returns null. 364 * 365 */ 366 @Override 367 protected Icon getValueAsIcon(CellContext context) { 368 Icon icon = super.getValueAsIcon(context); 369 if (icon == null) { 370 return context.getIcon(); 371 } 372 return IconValue.NULL_ICON == icon ? null : icon; 373 } 374 375 //----------------- implement RolloverController 376 377 378 /** 379 * {@inheritDoc} 380 */ 381 @Override 382 public void doClick() { 383 if (isEnabled()) { 384 ((RolloverRenderer) wrappee).doClick(); 385 } 386 } 387 388 /** 389 * {@inheritDoc} 390 */ 391 @Override 392 public boolean isEnabled() { 393 return (wrappee instanceof RolloverRenderer) && 394 ((RolloverRenderer) wrappee).isEnabled(); 395 } 396 397 398 399}