| /* |
| * Copyright 2000-2013 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.ui; |
| |
| import com.intellij.util.ui.EmptyIcon; |
| import com.intellij.util.ui.UIUtil; |
| import com.intellij.util.ui.tree.WideSelectionTreeUI; |
| import org.jetbrains.annotations.Nls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import javax.swing.*; |
| import javax.swing.tree.TreeCellRenderer; |
| import java.awt.*; |
| |
| /** |
| * @author Vladimir Kondratyev |
| */ |
| public abstract class ColoredTreeCellRenderer extends SimpleColoredComponent implements TreeCellRenderer{ |
| private static final Icon LOADING_NODE_ICON = new EmptyIcon(8, 16); |
| |
| /** |
| * Defines whether the tree is selected or not |
| */ |
| protected boolean mySelected; |
| /** |
| * Defines whether the tree has focus or not |
| */ |
| private boolean myFocused; |
| private boolean myFocusedCalculated; |
| |
| protected JTree myTree; |
| |
| private boolean myOpaque = true; |
| @Override |
| public final Component getTreeCellRendererComponent(JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus){ |
| myTree = tree; |
| |
| clear(); |
| |
| mySelected = selected; |
| myFocusedCalculated = false; |
| |
| // We paint background if and only if tree path is selected and tree has focus. |
| // If path is selected and tree is not focused then we just paint focused border. |
| if (UIUtil.isFullRowSelectionLAF()) { |
| setBackground(selected ? UIUtil.getTreeSelectionBackground() : null); |
| } |
| else if (tree.getUI() instanceof WideSelectionTreeUI && ((WideSelectionTreeUI)tree.getUI()).isWideSelection()) { |
| setPaintFocusBorder(false); |
| if (selected) { |
| setBackground(hasFocus ? UIUtil.getTreeSelectionBackground() : UIUtil.getTreeUnfocusedSelectionBackground()); |
| } |
| } |
| else if (selected) { |
| setPaintFocusBorder(true); |
| if (isFocused()) { |
| setBackground(UIUtil.getTreeSelectionBackground()); |
| } |
| else { |
| setBackground(null); |
| } |
| } |
| else { |
| setBackground(null); |
| } |
| |
| if (value instanceof LoadingNode) { |
| setForeground(JBColor.GRAY); |
| setIcon(LOADING_NODE_ICON); |
| } |
| else { |
| setForeground(tree.getForeground()); |
| setIcon(null); |
| } |
| |
| if (UIUtil.isUnderGTKLookAndFeel()){ |
| super.setOpaque(false); // avoid nasty background |
| super.setIconOpaque(false); |
| } |
| else if (UIUtil.isUnderNimbusLookAndFeel() && selected && hasFocus) { |
| super.setOpaque(false); // avoid erasing Nimbus focus frame |
| super.setIconOpaque(false); |
| } |
| else if (tree.getUI() instanceof WideSelectionTreeUI && ((WideSelectionTreeUI)tree.getUI()).isWideSelection()) { |
| super.setOpaque(false); // avoid erasing Nimbus focus frame |
| super.setIconOpaque(false); |
| } |
| else { |
| super.setOpaque(myOpaque || selected && hasFocus || selected && isFocused()); // draw selection background even for non-opaque tree |
| } |
| |
| if (tree.getUI() instanceof WideSelectionTreeUI && UIUtil.isUnderAquaBasedLookAndFeel()) { |
| setMyBorder(null); |
| setIpad(new Insets(0, 2, 0, 2)); |
| } |
| |
| customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus); |
| |
| return this; |
| } |
| |
| public JTree getTree() { |
| return myTree; |
| } |
| |
| protected final boolean isFocused() { |
| if (!myFocusedCalculated) { |
| myFocused = calcFocusedState(); |
| myFocusedCalculated = true; |
| } |
| return myFocused; |
| } |
| |
| protected boolean calcFocusedState() { |
| return myTree.hasFocus(); |
| } |
| |
| @Override |
| public void setOpaque(boolean isOpaque) { |
| myOpaque = isOpaque; |
| super.setOpaque(isOpaque); |
| } |
| |
| @Override |
| public Font getFont() { |
| Font font = super.getFont(); |
| |
| // Cell renderers could have no parent and no explicit set font. |
| // Take tree font in this case. |
| if (font != null) return font; |
| JTree tree = getTree(); |
| return tree != null ? tree.getFont() : null; |
| } |
| |
| /** |
| * When the item is selected then we use default tree's selection foreground. |
| * It guaranties readability of selected text in any LAF. |
| */ |
| @Override |
| public void append(@NotNull @Nls String fragment, @NotNull SimpleTextAttributes attributes, boolean isMainText) { |
| if (mySelected && isFocused()) { |
| super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), UIUtil.getTreeSelectionForeground()), isMainText); |
| } |
| else if (mySelected && UIUtil.isUnderAquaBasedLookAndFeel()) { |
| super.append(fragment, new SimpleTextAttributes(attributes.getStyle(), UIUtil.getTreeForeground()), isMainText); |
| } |
| else { |
| super.append(fragment, attributes, isMainText); |
| } |
| } |
| |
| /** |
| * This method is invoked only for customization of component. |
| * All component attributes are cleared when this method is being invoked. |
| */ |
| public abstract void customizeCellRenderer(@NotNull JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus); |
| } |