2
* Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Substance Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.substance.api.renderers;
32
import java.awt.Color;
33
import java.awt.Component;
34
import java.awt.Dimension;
36
import java.awt.Graphics;
37
import java.awt.Insets;
38
import java.awt.Rectangle;
41
import javax.swing.Icon;
42
import javax.swing.JLabel;
43
import javax.swing.JTree;
44
import javax.swing.SwingConstants;
45
import javax.swing.UIManager;
46
import javax.swing.plaf.BorderUIResource;
47
import javax.swing.plaf.ColorUIResource;
48
import javax.swing.plaf.FontUIResource;
49
import javax.swing.plaf.TreeUI;
50
import javax.swing.tree.TreeCellRenderer;
52
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
53
import org.pushingpixels.substance.api.ComponentState;
54
import org.pushingpixels.substance.api.SubstanceColorScheme;
55
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
56
import org.pushingpixels.substance.internal.animation.StateTransitionTracker;
57
import org.pushingpixels.substance.internal.animation.StateTransitionTracker.StateContributionInfo;
58
import org.pushingpixels.substance.internal.ui.SubstanceTreeUI;
59
import org.pushingpixels.substance.internal.ui.SubstanceTreeUI.TreePathId;
60
import org.pushingpixels.substance.internal.utils.SubstanceColorSchemeUtilities;
61
import org.pushingpixels.substance.internal.utils.SubstanceImageCreator;
62
import org.pushingpixels.substance.internal.utils.SubstanceStripingUtils;
65
* Default renderer for tree cells.
67
* @author Kirill Grouchnikov
70
public class SubstanceDefaultTreeCellRenderer extends JLabel implements
72
/** Last tree the renderer was painted in. */
75
/** Is the value currently selected. */
76
protected boolean selected;
78
/** True if has focus. */
79
protected boolean hasFocus;
82
* Returns a new instance of SubstanceDefaultTreeCellRenderer. Alignment is
83
* set to left aligned. Icons and text color are determined from the
86
public SubstanceDefaultTreeCellRenderer() {
87
this.setHorizontalAlignment(SwingConstants.LEFT);
88
this.putClientProperty(SubstanceLookAndFeel.COLORIZATION_FACTOR, 1.0);
92
* Returns the default icon that is used to represent non-leaf nodes that
95
* @return The default icon for non-leaf expanded nodes.
97
public Icon getDefaultOpenIcon() {
98
return UIManager.getIcon("Tree.openIcon");
102
* Returns the default icon that is used to represent non-leaf nodes that
105
* @return The default icon for non-leaf non-expanded nodes.
107
public Icon getDefaultClosedIcon() {
108
return UIManager.getIcon("Tree.closedIcon");
112
* Returns the default icon that is used to represent leaf nodes.
114
* @return The default icon for leaf nodes.
116
public Icon getDefaultLeafIcon() {
117
return UIManager.getIcon("Tree.leafIcon");
121
* Subclassed to map <code>FontUIResource</code>s to null. If
122
* <code>font</code> is null, or a <code>FontUIResource</code>, this has the
123
* effect of letting the font of the JTree show through. On the other hand,
124
* if <code>font</code> is non-null, and not a <code>FontUIResource</code>,
125
* the font becomes <code>font</code>.
128
public void setFont(Font font) {
129
if (font instanceof FontUIResource)
135
* Gets the font of this component.
137
* @return this component's font; if a font has not been set for this
138
* component, the font of its parent is returned
141
public Font getFont() {
142
Font font = super.getFont();
144
if ((font == null) && (this.tree != null)) {
145
// Strive to return a non-null value, otherwise the html support
146
// will typically pick up the wrong font in certain situations.
147
font = this.tree.getFont();
153
* Configures the renderer based on the passed in components. The value is
154
* set from messaging the tree with <code>convertValueToText</code>, which
155
* ultimately invokes <code>toString</code> on <code>value</code>. The
156
* foreground color is set based on the selection and the icon is set based
157
* on on leaf and expanded.
160
public Component getTreeCellRendererComponent(JTree tree, Object value,
161
boolean sel, boolean expanded, boolean leaf, int row,
163
String stringValue = tree.convertValueToText(value, sel, expanded,
164
leaf, row, hasFocus);
167
this.hasFocus = hasFocus;
168
this.setText(stringValue);
170
TreeUI treeUI = tree.getUI();
171
if (treeUI instanceof SubstanceTreeUI) {
172
SubstanceTreeUI ui = (SubstanceTreeUI) treeUI;
173
TreePathId pathId = new TreePathId(tree.getPathForRow(row));
175
StateTransitionTracker.ModelStateInfo modelStateInfo = ui
176
.getModelStateInfo(pathId);
177
ComponentState currState = ui.getPathState(pathId);
179
// special case for drop location
180
JTree.DropLocation dropLocation = tree.getDropLocation();
181
boolean isDropLocation = (dropLocation != null
182
&& dropLocation.getChildIndex() == -1 && tree
183
.getRowForPath(dropLocation.getPath()) == row);
185
if (!isDropLocation && (modelStateInfo != null)) {
186
Map<ComponentState, StateContributionInfo> activeStates = modelStateInfo
187
.getStateContributionMap();
188
SubstanceColorScheme colorScheme = getColorSchemeForState(tree,
190
if (currState.isDisabled() || (activeStates == null)
191
|| (activeStates.size() == 1)) {
192
super.setForeground(new ColorUIResource(colorScheme
193
.getForegroundColor()));
199
for (Map.Entry<ComponentState, StateTransitionTracker.StateContributionInfo> activeEntry : modelStateInfo
200
.getStateContributionMap().entrySet()) {
201
ComponentState activeState = activeEntry.getKey();
202
SubstanceColorScheme scheme = getColorSchemeForState(
203
tree, ui, activeState);
204
Color schemeFg = scheme.getForegroundColor();
205
float contribution = activeEntry.getValue()
207
aggrRed += schemeFg.getRed() * contribution;
208
aggrGreen += schemeFg.getGreen() * contribution;
209
aggrBlue += schemeFg.getBlue() * contribution;
211
super.setForeground(new ColorUIResource(new Color(
212
(int) aggrRed, (int) aggrGreen, (int) aggrBlue)));
215
SubstanceColorScheme scheme = getColorSchemeForState(tree, ui,
217
if (isDropLocation) {
218
scheme = SubstanceColorSchemeUtilities.getColorScheme(tree,
219
ColorSchemeAssociationKind.TEXT_HIGHLIGHT,
222
super.setForeground(new ColorUIResource(scheme
223
.getForegroundColor()));
227
this.setForeground(UIManager
228
.getColor("Tree.selectionForeground"));
230
this.setForeground(UIManager.getColor("Tree.textForeground"));
233
if (SubstanceLookAndFeel.isCurrentLookAndFeel())
234
SubstanceStripingUtils.applyStripedBackground(tree, row, this);
236
// There needs to be a way to specify disabled icons.
237
if (!tree.isEnabled()) {
238
this.setEnabled(false);
240
this.setDisabledIcon(SubstanceImageCreator
241
.toGreyscale(SubstanceImageCreator.makeTransparent(
242
tree, this.getDefaultLeafIcon(), 0.5)));
243
} else if (expanded) {
244
this.setDisabledIcon(SubstanceImageCreator
245
.toGreyscale(SubstanceImageCreator.makeTransparent(
246
tree, this.getDefaultOpenIcon(), 0.5)));
247
// setIcon(SubstanceImageCreator.toGreyscale(
248
// SubstanceImageCreator
249
// .makeTransparent(getDefaultOpenIcon(), 0.5)));
251
this.setDisabledIcon(SubstanceImageCreator
252
.toGreyscale(SubstanceImageCreator.makeTransparent(
253
tree, this.getDefaultClosedIcon(), 0.5)));
254
// setIcon(SubstanceImageCreator.toGreyscale(
255
// SubstanceImageCreator
256
// .makeTransparent(getDefaultClosedIcon(), 0.5)));
259
this.setEnabled(true);
261
this.setIcon(this.getDefaultLeafIcon());
262
} else if (expanded) {
263
this.setIcon(this.getDefaultOpenIcon());
265
this.setIcon(this.getDefaultClosedIcon());
268
this.setComponentOrientation(tree.getComponentOrientation());
270
this.setOpaque(false);
274
if (treeUI instanceof SubstanceTreeUI) {
275
SubstanceTreeUI ui = (SubstanceTreeUI) treeUI;
276
Insets regInsets = ui.getCellRendererInsets();
278
.setBorder(new BorderUIResource.EmptyBorderUIResource(
285
private SubstanceColorScheme getColorSchemeForState(JTree tree,
286
SubstanceTreeUI ui, ComponentState activeState) {
287
SubstanceColorScheme scheme = (activeState == ComponentState.ENABLED) ? ui
288
.getDefaultColorScheme()
289
: SubstanceColorSchemeUtilities.getColorScheme(tree,
290
ColorSchemeAssociationKind.HIGHLIGHT, activeState);
291
if (scheme == null) {
292
scheme = SubstanceColorSchemeUtilities.getColorScheme(tree,
293
ColorSchemeAssociationKind.HIGHLIGHT, activeState);
299
* Overrides <code>JComponent.getPreferredSize</code> to return slightly
300
* wider preferred size value.
303
public Dimension getPreferredSize() {
304
Dimension retDimension = super.getPreferredSize();
306
if (retDimension != null)
307
retDimension = new Dimension(retDimension.width + 3,
308
retDimension.height);
313
* Overridden for performance reasons. See the <a
314
* href="#override">Implementation Note</a> for more information.
317
public void validate() {
321
* Overridden for performance reasons. See the <a
322
* href="#override">Implementation Note</a> for more information.
327
public void invalidate() {
331
* Overridden for performance reasons. See the <a
332
* href="#override">Implementation Note</a> for more information.
335
public void revalidate() {
339
* Overridden for performance reasons. See the <a
340
* href="#override">Implementation Note</a> for more information.
343
public void repaint(long tm, int x, int y, int width, int height) {
347
* Overridden for performance reasons. See the <a
348
* href="#override">Implementation Note</a> for more information.
351
public void repaint(Rectangle r) {
355
* Overridden for performance reasons. See the <a
356
* href="#override">Implementation Note</a> for more information.
361
public void repaint() {
365
* Overridden for performance reasons. See the <a
366
* href="#override">Implementation Note</a> for more information.
369
protected void firePropertyChange(String propertyName, Object oldValue,
371
if ("text".equals(propertyName))
372
super.firePropertyChange(propertyName, oldValue, newValue);
376
* Overridden for performance reasons. See the <a
377
* href="#override">Implementation Note</a> for more information.
380
public void firePropertyChange(String propertyName, byte oldValue,
385
* Overridden for performance reasons. See the <a
386
* href="#override">Implementation Note</a> for more information.
389
public void firePropertyChange(String propertyName, char oldValue,
394
* Overridden for performance reasons. See the <a
395
* href="#override">Implementation Note</a> for more information.
398
public void firePropertyChange(String propertyName, short oldValue,
403
* Overridden for performance reasons. See the <a
404
* href="#override">Implementation Note</a> for more information.
407
public void firePropertyChange(String propertyName, int oldValue,
412
* Overridden for performance reasons. See the <a
413
* href="#override">Implementation Note</a> for more information.
416
public void firePropertyChange(String propertyName, long oldValue,
421
* Overridden for performance reasons. See the <a
422
* href="#override">Implementation Note</a> for more information.
425
public void firePropertyChange(String propertyName, float oldValue,
430
* Overridden for performance reasons. See the <a
431
* href="#override">Implementation Note</a> for more information.
434
public void firePropertyChange(String propertyName, double oldValue,
439
* Overridden for performance reasons. See the <a
440
* href="#override">Implementation Note</a> for more information.
443
public void firePropertyChange(String propertyName, boolean oldValue,
450
* @see javax.swing.JComponent#paint(java.awt.Graphics)
453
public final void paint(Graphics g) {
460
* @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
463
protected final void paintComponent(Graphics g) {
464
super.paintComponent(g);