wide selection in trees under aqua laf + deferred icon tree cache invalidation fix...
[idea/community.git] / platform / platform-api / src / com / intellij / ui / ColoredTreeCellRenderer.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.ui;
17
18 import com.intellij.util.ui.EmptyIcon;
19 import com.intellij.util.ui.UIUtil;
20 import org.jetbrains.annotations.Nls;
21 import org.jetbrains.annotations.NotNull;
22
23 import javax.swing.*;
24 import javax.swing.tree.TreeCellRenderer;
25 import java.awt.*;
26
27 /**
28  * @author Vladimir Kondratyev
29  */
30 public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent implements TreeCellRenderer{
31   private static final Icon LOADING_NODE_ICON = new EmptyIcon(8, 16);
32
33   /**
34    * Defines whether the tree is selected or not
35    */
36   protected boolean mySelected;
37   /**
38    * Defines whether the tree has focus or not
39    */
40   protected boolean myFocused;
41
42   protected JTree myTree;
43   private boolean myOpaque = true;
44
45   public final Component getTreeCellRendererComponent(
46     JTree tree,
47     Object value,
48     boolean selected,
49     boolean expanded,
50     boolean leaf,
51     int row,
52     boolean hasFocus
53   ){
54     myTree = tree;
55
56     clear();
57
58     mySelected = selected;
59     myFocused = tree.hasFocus();
60
61     // We paint background if and only if tree path is selected and tree has focus.
62     // If path is selected and tree is not focused then we just paint focused border.
63     if (UIUtil.isFullRowSelectionLAF()) {
64         setBackground(selected ? UIUtil.getTreeSelectionBackground() : null);
65     }
66     else if (UIUtil.isUnderAquaLookAndFeel() && tree.getUI() instanceof UIUtil.MacTreeUI) {
67       setPaintFocusBorder(false);
68       setBackground(null);
69     }
70     else {
71       if (selected) {
72         setPaintFocusBorder(true);
73         if (myFocused) {
74           setBackground(UIUtil.getTreeSelectionBackground());
75         }
76         else {
77           setBackground(null);
78         }
79       }
80       else {
81         setBackground(null);
82       }
83     }
84
85     if (value instanceof LoadingNode) {
86       setForeground(Color.gray);
87       setIcon(LOADING_NODE_ICON);
88     }
89     else {
90       setForeground(tree.getForeground());
91       setIcon(null);
92     }
93
94     if (UIUtil.isUnderNimbusLookAndFeel() && selected && hasFocus) {
95       super.setOpaque(false);  // avoid erasing Nimbus focus frame
96       super.setIconOpaque(false);
97     }
98     else if (UIUtil.isUnderAquaLookAndFeel() && tree.getUI() instanceof UIUtil.MacTreeUI) {
99       super.setOpaque(false);  // avoid erasing Nimbus focus frame
100       super.setIconOpaque(false);
101     }
102     else {
103       super.setOpaque(myOpaque || selected && hasFocus || selected && tree.hasFocus()); // draw selection background even for non-opaque tree
104     }
105     customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus);
106
107     if (getFont() == null) {
108       setFont(tree.getFont());
109     }
110
111     return this;
112   }
113
114   public void setOpaque(boolean isOpaque) {
115     myOpaque = isOpaque;
116     super.setOpaque(isOpaque);
117   }
118
119   /**
120    * When the item is selected then we use default tree's selection foreground.
121    * It guaranties readability of selected text in any LAF.
122    */
123   public void append(@NotNull @Nls String fragment, @NotNull SimpleTextAttributes attributes, boolean isMainText) {
124     if (mySelected && (myFocused || UIUtil.isUnderNimbusLookAndFeel())) {
125       super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), UIUtil.getTreeSelectionForeground()), isMainText);
126     }
127     else {
128       super.append(fragment, attributes, isMainText);
129     }
130   }
131
132   /**
133    * This method is invoked only for customization of component.
134    * All component attributes are cleared when this method is being invoked.
135    */
136   public abstract void customizeCellRenderer(
137     JTree tree,
138     Object value,
139     boolean selected,
140     boolean expanded,
141     boolean leaf,
142     int row,
143     boolean hasFocus
144   );
145 }