001/* 002 * $Id: CellContext.java 3778 2010-09-07 10:10:49Z 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.awt.Color; 024import java.awt.Font; 025import java.io.Serializable; 026 027import javax.swing.Icon; 028import javax.swing.JComponent; 029import javax.swing.UIManager; 030import javax.swing.border.Border; 031import javax.swing.border.EmptyBorder; 032 033/** 034 * Encapsulates a snapshop of cell content and default display context 035 * for usage by a <code>ComponentProvider</code>. 036 * <p> 037 * 038 * One part is the super-set of properties that's traditionally passed into the 039 * core renderers' (Table-, List-, Tree-) getXXCellRendererComponent. Raw 040 * properties which define the context are 041 * 042 * <ul> 043 * <li> selected 044 * <li> focused 045 * <li> expanded 046 * <li> leaf 047 * </ul> 048 * 049 * Similarl to a ComponentAdapter, the properties are a super-set of those for 050 * a concrete component type. It's up to sub-classes (once the generics will be removed, until 051 * then the DefaultXXRenderers - PENDING JW: undecided - even after the generics removal, the 052 * param list in the subclasses are the same) fill any reasonable 053 * defaults for those not applicable to the specific component context. 054 * 055 * With those raw properties given, a CellContext looks up and returns dependent visual 056 * properties as appropriate for the concrete component. Typically, they are taken 057 * from the component if supported, or requested from the UIManager. 058 * Dependent properties are 059 * 060 * <ul> 061 * <li> foreground and background color 062 * <li> border 063 * <li> icon (relevant for trees only) 064 * <li> editable 065 * </ul> 066 * 067 * For a backdoor, the cell location (in horizontal and vertical view coordinates) 068 * and the originating component is accessible as well. Note that they are not necessarily 069 * valid for the "life" component. It's not recommended to actually use them. If needed, 070 * that's probably a sign the api is lacking :-) 071 * <p> 072 * 073 * 074 * <ul> 075 * 076 * <li>PENDING: still incomplete? how about Font? 077 * <li>PENDING: protected methods? Probably need to open up - derived 078 * properties should be accessible in client code. 079 * </ul> 080 * 081 * @author Jeanette Winzenburg 082 */ 083public class CellContext implements Serializable { 084 085 /** the default border for unfocused cells. */ 086 protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); 087 088 /** ?? the default border for unfocused cells. ?? */ 089 private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 090 1); 091 092 /** 093 * Returns the shared border for unfocused cells. 094 * <p> 095 * PENDING: ?? copied from default renderers - why is it done like this? 096 * 097 * @return the border for unfocused cells. 098 */ 099 private static Border getNoFocusBorder() { 100 if (System.getSecurityManager() != null) { 101 return SAFE_NO_FOCUS_BORDER; 102 } else { 103 return noFocusBorder; 104 } 105 } 106 107 /** PENDING JW: maybe make this a WeakReference? Would be a more robust fix for Issue #1040-swingx. */ 108 protected transient JComponent component; 109 110 /** PENDING JW: maybe make this a WeakReference? Would be a more robust fix for Issue #1040-swingx. */ 111 protected transient Object value; 112 113 protected transient int row; 114 115 protected transient int column; 116 117 protected transient boolean selected; 118 119 protected transient boolean focused; 120 121 protected transient boolean expanded; 122 123 protected transient boolean leaf; 124 125 protected transient boolean dropOn; 126 127 // --------------------------- install context 128 129 130 /** 131 * Sets the state of the cell's context. Convenience method for subclasses. 132 * 133 * @param value the content value of the cell 134 * @param row the cell's row index in view coordinates 135 * @param column the cell's column index in view coordinates 136 * @param selected the cell's selected state 137 * @param focused the cell's focused state 138 * @param expanded the cell's expanded state 139 * @param leaf the cell's leaf state 140 */ 141 protected void installState(Object value, int row, int column, 142 boolean selected, boolean focused, boolean expanded, boolean leaf) { 143 this.value = value; 144 this.row = row; 145 this.column = column; 146 this.selected = selected; 147 this.focused = focused; 148 this.expanded = expanded; 149 this.leaf = leaf; 150 } 151 152 /** 153 * Replaces the value of this cell context with the given parameter and returns 154 * the replaced value. 155 * 156 * @param value the new value of the cell context 157 * @return the replaced value of the cell context 158 */ 159 public Object replaceValue(Object value) { 160 Object old = getValue(); 161 this.value = value; 162 return old; 163 } 164 165 // -------------------- accessors of installed state 166 167 /** 168 * Returns the component the cell resides on, may be null. Subclasses are 169 * expected to override and return the component type they are handling. 170 * 171 * @return the component the cell resides on, may be null. 172 */ 173 public JComponent getComponent() { 174 return component; 175 } 176 177 /** 178 * Returns the value of the cell as set in the install. 179 * 180 * @return the content value of the cell. 181 */ 182 public Object getValue() { 183 return value; 184 } 185 186 /** 187 * Returns the cell's row index in view coordinates as set in the install. 188 * 189 * @return the cell's row index. 190 */ 191 public int getRow() { 192 return row; 193 } 194 195 /** 196 * Returns the cell's column index in view coordinates as set in the 197 * install. 198 * 199 * @return the cell's column index. 200 */ 201 public int getColumn() { 202 return column; 203 } 204 205 /** 206 * Returns the selected state as set in the install. 207 * 208 * @return the cell's selected state. 209 */ 210 public boolean isSelected() { 211 return selected; 212 } 213 214 /** 215 * Returns the focused state as set in the install. 216 * 217 * @return the cell's focused state. 218 */ 219 public boolean isFocused() { 220 return focused; 221 } 222 223 /** 224 * Returns the expanded state as set in the install. 225 * 226 * @return the cell's expanded state. 227 */ 228 public boolean isExpanded() { 229 return expanded; 230 } 231 232 /** 233 * Returns the leaf state as set in the install. 234 * 235 * @return the cell's leaf state. 236 */ 237 public boolean isLeaf() { 238 return leaf; 239 } 240 241 // -------------------- accessors for derived state 242 /** 243 * Returns the cell's editability. Subclasses should override to return a 244 * reasonable cell-related state. 245 * <p> 246 * 247 * Here: false. 248 * 249 * @return the cell's editable property. 250 */ 251 public boolean isEditable() { 252 return false; 253 } 254 255 /** 256 * Returns the icon. Subclasses should override to return a reasonable 257 * cell-related state. 258 * <p> 259 * 260 * Here: <code>null</code>. 261 * 262 * @return the cell's icon. 263 */ 264 public Icon getIcon() { 265 return null; 266 } 267 268 /** 269 * Returns a boolean indicating if the cell is a drop location with any of the dropOn 270 * modes. It's up to subclasses to implement. 271 * <p> 272 * 273 * Here: false. 274 * 275 * @return true if the current cell is a drop location with any of the dropOn modes, 276 * false otherwise 277 */ 278 protected boolean isDropOn() { 279 return dropOn; 280 } 281 282 /** 283 * Returns the foreground color of the renderered component or null if the 284 * component is null 285 * <p> 286 * 287 * PENDING: fallback to UI properties if comp == null? 288 * 289 * @return the foreground color of the rendered component. 290 */ 291 protected Color getForeground() { 292 if (isDropOn()) { 293 return getSelectionForeground(); 294 } 295 return getComponent() != null ? getComponent().getForeground() : null; 296 } 297 298 /** 299 * Returns the background color of the renderered component or null if the 300 * component is null 301 * <p> 302 * 303 * PENDING: fallback to UI properties if comp == null? 304 * 305 * @return the background color of the rendered component. 306 */ 307 protected Color getBackground() { 308 if (isDropOn()) { 309 return getSelectionBackground(); 310 } 311 return getComponent() != null ? getComponent().getBackground() : null; 312 } 313 314 /** 315 * Returns the default selection background color of the renderered 316 * component. Typically, the color is LF specific. It's up to subclasses to 317 * look it up. Here: returns null. 318 * <p> 319 * 320 * PENDING: return UI properties here? 321 * 322 * @return the selection background color of the rendered component. 323 */ 324 protected Color getSelectionBackground() { 325 return null; 326 } 327 328 /** 329 * Returns the default selection foreground color of the renderered 330 * component. Typically, the color is LF specific. It's up to subclasses to 331 * look it up. Here: returns null. 332 * <p> 333 * 334 * PENDING: return UI properties here? 335 * 336 * @return the selection foreground color of the rendered component. 337 */ 338 protected Color getSelectionForeground() { 339 return null; 340 } 341 342 /** 343 * Returns the default focus border of the renderered component. Typically, 344 * the border is LF specific. 345 * 346 * @return the focus border of the rendered component. 347 */ 348 protected Border getFocusBorder() { 349 Border border = null; 350 if (isSelected()) { 351 border = UIManager 352 .getBorder(getUIKey("focusSelectedCellHighlightBorder")); 353 } 354 if (border == null) { 355 border = UIManager.getBorder(getUIKey("focusCellHighlightBorder")); 356 } 357 return border; 358 } 359 360 /** 361 * Returns the default border of the renderered component depending on cell 362 * state. Typically, the border is LF specific. 363 * <p> 364 * 365 * Here: returns the focus border if the cell is focused, the context 366 * defined no focus border otherwise. 367 * 368 * @return the default border of the rendered component. 369 */ 370 protected Border getBorder() { 371 if (isFocused()) { 372 return getFocusBorder(); 373 } 374 Border border = UIManager.getBorder(getUIKey("cellNoFocusBorder")); 375 return border != null ? border : getNoFocusBorder(); 376 } 377 378 /** 379 * Returns the default focused foreground color of the renderered component. 380 * Typically, the color is LF specific. 381 * 382 * @return the focused foreground color of the rendered component. 383 */ 384 protected Color getFocusForeground() { 385 return UIManager.getColor(getUIKey("focusCellForeground")); 386 } 387 388 /** 389 * Returns the default focused background color of the renderered component. 390 * Typically, the color is LF specific. 391 * 392 * @return the focused background color of the rendered component. 393 */ 394 protected Color getFocusBackground() { 395 return UIManager.getColor(getUIKey("focusCellBackground")); 396 } 397 398 protected Color getDropCellForeground() { 399 return UIManager.getColor(getUIKey("dropCellForeground")); 400 } 401 402 protected Color getDropCellBackground() { 403 return UIManager.getColor(getUIKey("dropCellBackground")); 404 } 405 // ----------------------- convenience 406 407 /** 408 * Convenience method to build a component type specific lookup key for the 409 * UIManager. 410 * 411 * @param key the general part of the key 412 * @return a composed key build of a component type prefix and the input. 413 */ 414 protected String getUIKey(String key) { 415 return getUIPrefix() + key; 416 } 417 418 /** 419 * Returns the component type specific prefix of keys for lookup in the 420 * UIManager. Subclasses must override, here: returns the empty String. 421 * 422 * @return the component type specific prefix. 423 */ 424 protected String getUIPrefix() { 425 return ""; 426 } 427 428 /** 429 * Returns the Font of the target component or null if no component installed. 430 * @return 431 */ 432 protected Font getFont() { 433 return getComponent() != null ? getComponent().getFont() : null; 434 } 435 436 public String getCellRendererName() { 437 return getUIPrefix() + "cellRenderer"; 438 } 439 440}