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