blob: d0a0648285d60cce4600308bd77223528d329b1a [file] [log] [blame]
/*
* 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.ide.util;
import com.intellij.ide.ui.UISettings;
import com.intellij.navigation.ColoredItemPresentation;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.markup.EffectType;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.problems.WolfTheProblemSolver;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.ui.*;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.Function;
import com.intellij.util.IconUtil;
import com.intellij.util.text.Matcher;
import com.intellij.util.text.MatcherHolder;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Comparator;
public abstract class PsiElementListCellRenderer<T extends PsiElement> extends JPanel implements ListCellRenderer, MatcherHolder {
private Matcher myMatcher;
private boolean myFocusBorderEnabled = true;
protected PsiElementListCellRenderer() {
super(new BorderLayout());
}
@Override
public void setPatternMatcher(final Matcher matcher) {
myMatcher = matcher;
}
protected static Color getBackgroundColor(@Nullable Object value) {
if (value instanceof PsiElement) {
final PsiElement psiElement = (PsiElement)value;
final FileColorManager colorManager = FileColorManager.getInstance(psiElement.getProject());
if (colorManager.isEnabled()) {
VirtualFile file = null;
PsiFile psiFile = psiElement.getContainingFile();
if (psiFile != null) {
file = psiFile.getVirtualFile();
} else if (psiElement instanceof PsiDirectory) {
file = ((PsiDirectory)psiElement).getVirtualFile();
}
final Color fileBgColor = file != null ? colorManager.getRendererBackground(file) : null;
if (fileBgColor != null) {
return fileBgColor;
}
}
}
return UIUtil.getListBackground();
}
private class LeftRenderer extends ColoredListCellRenderer {
private final String myModuleName;
private final Matcher myMatcher;
public LeftRenderer(final String moduleName, Matcher matcher) {
myModuleName = moduleName;
myMatcher = matcher;
}
@Override
protected void customizeCellRenderer(JList list, Object value, int index, boolean selected, boolean hasFocus) {
Color bgColor = UIUtil.getListBackground();
Color color = list.getForeground();
setPaintFocusBorder(hasFocus && UIUtil.isToUseDottedCellBorder() && myFocusBorderEnabled);
if (value instanceof PsiElement) {
T element = (T)value;
String name = element.isValid() ? getElementText(element) : "INVALID";
PsiFile psiFile = element.isValid() ? element.getContainingFile() : null;
boolean isProblemFile = false;
if (psiFile != null) {
VirtualFile vFile = psiFile.getVirtualFile();
if (vFile != null) {
if (WolfTheProblemSolver.getInstance(psiFile.getProject()).isProblemFile(vFile)) {
isProblemFile = true;
}
FileStatus status = FileStatusManager.getInstance(psiFile.getProject()).getStatus(vFile);
color = status.getColor();
final FileColorManager colorManager = FileColorManager.getInstance(psiFile.getProject());
if (colorManager.isEnabled()) {
final Color fileBgColor = colorManager.getRendererBackground(psiFile);
bgColor = fileBgColor == null ? bgColor : fileBgColor;
}
}
}
TextAttributes attributes = getNavigationItemAttributes(value);
if (isProblemFile) {
attributes = TextAttributes.merge(new TextAttributes(color, null, JBColor.RED, EffectType.WAVE_UNDERSCORE, Font.PLAIN), attributes);
}
SimpleTextAttributes nameAttributes = attributes != null ? SimpleTextAttributes.fromTextAttributes(attributes) : null;
if (nameAttributes == null) nameAttributes = new SimpleTextAttributes(Font.PLAIN, color);
assert name != null : "Null name for PSI element " + element + " (by " + PsiElementListCellRenderer.this + ")";
SpeedSearchUtil.appendColoredFragmentForMatcher(name, this, nameAttributes, myMatcher, bgColor, selected);
if (!element.isValid()) {
append(" Invalid", SimpleTextAttributes.ERROR_ATTRIBUTES);
return;
}
setIcon(PsiElementListCellRenderer.this.getIcon(element));
String containerText = getContainerText(element, name + (myModuleName != null ? myModuleName + " " : ""));
if (containerText != null) {
append(" " + containerText, new SimpleTextAttributes(Font.PLAIN, JBColor.GRAY));
}
}
else if (!customizeNonPsiElementLeftRenderer(this, list, value, index, selected, hasFocus)) {
setIcon(IconUtil.getEmptyIcon(false));
append(value == null ? "" : value.toString(), new SimpleTextAttributes(Font.PLAIN, list.getForeground()));
}
setBackground(selected ? UIUtil.getListSelectionBackground() : bgColor);
}
}
@Nullable
protected static TextAttributes getNavigationItemAttributes(Object value) {
TextAttributes attributes = null;
if (value instanceof NavigationItem) {
TextAttributesKey attributesKey = null;
final ItemPresentation presentation = ((NavigationItem)value).getPresentation();
if (presentation instanceof ColoredItemPresentation) attributesKey = ((ColoredItemPresentation) presentation).getTextAttributesKey();
if (attributesKey != null) {
attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(attributesKey);
}
}
return attributes;
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
removeAll();
DefaultListCellRenderer rightRenderer = getRightCellRenderer(value);
ListCellRenderer leftRenderer = new LeftRenderer(null, myMatcher);
final Component leftCellRendererComponent = leftRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (rightRenderer != null) {
final Component rightCellRendererComponent = rightRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
rightCellRendererComponent
.setBackground(isSelected ? UIUtil.getListSelectionBackground() : leftCellRendererComponent.getBackground());
add(rightCellRendererComponent, BorderLayout.EAST);
final JPanel spacer = new JPanel();
spacer.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
spacer.setBackground(isSelected ? UIUtil.getListSelectionBackground() : leftCellRendererComponent.getBackground());
add(spacer, BorderLayout.CENTER);
}
add(leftCellRendererComponent, BorderLayout.WEST);
setBackground(isSelected ? UIUtil.getListSelectionBackground() : leftCellRendererComponent.getBackground());
return this;
}
protected void setFocusBorderEnabled(boolean enabled) {
myFocusBorderEnabled = enabled;
}
protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer,
JList list,
Object value,
int index,
boolean selected,
boolean hasFocus) {
return false;
}
@Nullable
protected DefaultListCellRenderer getRightCellRenderer(final Object value) {
if (UISettings.getInstance().SHOW_ICONS_IN_QUICK_NAVIGATION) {
final DefaultListCellRenderer renderer = ModuleRendererFactory.findInstance(value).getModuleRenderer();
if (renderer instanceof PlatformModuleRendererFactory.PlatformModuleRenderer) {
// it won't display any new information
return null;
}
return renderer;
}
return null;
}
public abstract String getElementText(T element);
@Nullable
protected abstract String getContainerText(T element, final String name);
@Iconable.IconFlags
protected abstract int getIconFlags();
protected Icon getIcon(PsiElement element) {
return element.getIcon(getIconFlags());
}
public Comparator<T> getComparator() {
return new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return getComparingObject(o1).compareTo(getComparingObject(o2));
}
};
}
@NotNull
public Comparable getComparingObject(T element) {
String elementText = getElementText(element);
String containerText = getContainerText(element, elementText);
return containerText != null ? elementText + " " + containerText : elementText;
}
public void installSpeedSearch(PopupChooserBuilder builder) {
installSpeedSearch(builder, false);
}
public void installSpeedSearch(PopupChooserBuilder builder, final boolean includeContainerText) {
builder.setFilteringEnabled(new Function<Object, String>() {
@Override
public String fun(Object o) {
if (o instanceof PsiElement) {
final String elementText = getElementText((T)o);
if (includeContainerText) {
return elementText + " " + getContainerText((T)o, elementText);
}
return elementText;
}
else {
return o.toString();
}
}
});
}
/**
* User {@link #installSpeedSearch(com.intellij.openapi.ui.popup.PopupChooserBuilder)} instead
*/
@Deprecated
public void installSpeedSearch(JList list) {
new ListSpeedSearch(list) {
@Override
protected String getElementText(Object o) {
if (o instanceof PsiElement) {
final String elementText = PsiElementListCellRenderer.this.getElementText((T)o);
return elementText + " " + getContainerText((T)o, elementText);
}
else {
return o.toString();
}
}
};
}
}