use editor font in editor popups - more components fixed
[idea/community.git] / platform / lang-impl / src / com / intellij / find / actions / ShowUsagesTableCellRenderer.java
1 /*
2  * Copyright 2000-2015 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
17 package com.intellij.find.actions;
18
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.vfs.VirtualFile;
21 import com.intellij.psi.PsiFile;
22 import com.intellij.psi.PsiManager;
23 import com.intellij.psi.search.SearchScope;
24 import com.intellij.ui.FileColorManager;
25 import com.intellij.ui.SimpleColoredComponent;
26 import com.intellij.ui.SimpleTextAttributes;
27 import com.intellij.usages.TextChunk;
28 import com.intellij.usages.Usage;
29 import com.intellij.usages.UsageGroup;
30 import com.intellij.usages.UsagePresentation;
31 import com.intellij.usages.impl.GroupNode;
32 import com.intellij.usages.impl.UsageNode;
33 import com.intellij.usages.impl.UsageViewImpl;
34 import com.intellij.usages.impl.UsageViewManagerImpl;
35 import com.intellij.usages.rules.UsageInFile;
36 import com.intellij.util.ui.EmptyIcon;
37 import com.intellij.util.ui.UIUtil;
38 import org.jetbrains.annotations.NotNull;
39
40 import javax.swing.*;
41 import javax.swing.table.TableCellRenderer;
42 import javax.swing.table.TableColumnModel;
43 import java.awt.*;
44 import java.util.concurrent.atomic.AtomicInteger;
45
46 /**
47 * @author cdr
48 */
49 class ShowUsagesTableCellRenderer implements TableCellRenderer {
50   private final UsageViewImpl myUsageView;
51   @NotNull private final AtomicInteger myOutOfScopeUsages;
52   @NotNull private final SearchScope mySearchScope;
53
54   ShowUsagesTableCellRenderer(@NotNull UsageViewImpl usageView, @NotNull AtomicInteger outOfScopeUsages, @NotNull SearchScope searchScope) {
55     myUsageView = usageView;
56     myOutOfScopeUsages = outOfScopeUsages;
57     mySearchScope = searchScope;
58   }
59
60   @Override
61   public Component getTableCellRendererComponent(JTable list, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
62     UsageNode usageNode = value instanceof UsageNode ? (UsageNode)value : null;
63
64     Usage usage = usageNode == null ? null : usageNode.getUsage();
65
66     JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0,0));
67
68     panel.setFont(list.getFont());
69
70     Color fileBgColor = getBackgroundColor(isSelected, usage);
71     final Color bg = UIUtil.getListSelectionBackground();
72     final Color fg = UIUtil.getListSelectionForeground();
73     Color panelBackground = isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor;
74     Color panelForeground = isSelected ? fg : list.getForeground();
75     panel.setBackground(panelBackground);
76     panel.setForeground(panelForeground);
77
78     SimpleColoredComponent textChunks = new SimpleColoredComponent();
79     textChunks.setIpad(new Insets(0, 0, 0, 0));
80     textChunks.setBorder(null);
81
82     if (usage == null || usageNode instanceof ShowUsagesAction.StringNode) {
83       textChunks.append(value != null ? value.toString() : "", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
84       return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row);
85     }
86     if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) {
87       textChunks.append("...<");
88       textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
89       textChunks.append(">...");
90       return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row);
91     }
92     else if (usage == ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) {
93       textChunks.append("...<");
94       textChunks.append(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
95       textChunks.append(">...");
96       return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row);
97     }
98
99     if (column == 0) {
100       GroupNode parent = (GroupNode)usageNode.getParent();
101       appendGroupText(parent, panel, fileBgColor);
102     }
103     else if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR && usage != ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) {
104       UsagePresentation presentation = usage.getPresentation();
105       TextChunk[] text = presentation.getText();
106
107       if (column == 1) {
108         final Icon icon = presentation.getIcon();
109         textChunks.setIcon(icon == null ? EmptyIcon.ICON_16 : icon);
110         if (text.length != 0) {
111           SimpleTextAttributes attributes = isSelected ?
112             new SimpleTextAttributes(bg, fg, fg, SimpleTextAttributes.STYLE_ITALIC) :
113             deriveAttributesWithColor(text[0].getSimpleAttributesIgnoreBackground(), fileBgColor);
114           textChunks.append(text[0].getText(), attributes);
115         }
116       }
117       else if (column == 2) {
118         for (int i = 1; i < text.length; i++) {
119           TextChunk textChunk = text[i];
120           final SimpleTextAttributes attrs = textChunk.getSimpleAttributesIgnoreBackground();
121           SimpleTextAttributes attributes = isSelected ?
122             new SimpleTextAttributes(bg, fg, fg, attrs.getStyle()) : deriveAttributesWithColor(attrs, fileBgColor);
123           textChunks.append(textChunk.getText(), attributes);
124         }
125       }
126       else {
127         assert false : column;
128       }
129     }
130     panel.add(textChunks);
131     return panel;
132   }
133
134   @NotNull
135   private static Component textComponentSpanningWholeRow(@NotNull SimpleColoredComponent chunks,
136                                                          Color panelBackground,
137                                                          Color panelForeground,
138                                                          final int column,
139                                                          @NotNull final JTable table, int row) {
140     final SimpleColoredComponent component = new SimpleColoredComponent() {
141       @Override
142       protected void doPaint(Graphics2D g) {
143         int offset = 0;
144         int i = 0;
145         final TableColumnModel columnModel = table.getColumnModel();
146         while (i < column) {
147           offset += columnModel.getColumn(i).getWidth();
148           i++;
149         }
150         g.translate(-offset, 0);
151
152         //if (column == columnModel.getColumnCount()-1) {
153         //}
154         setSize(getWidth()+offset, getHeight()); // should increase the column width so that selection background will be visible even after offset translation
155
156         super.doPaint(g);
157
158         g.translate(+offset, 0);
159       }
160
161       @NotNull
162       @Override
163       public Dimension getPreferredSize() {
164         //return super.getPreferredSize();
165         return column == table.getColumnModel().getColumnCount()-1 ? super.getPreferredSize() : new Dimension(0,0);
166         // it should span the whole row, so we can't return any specific value here,
167         // because otherwise it would be used in the "max width" calculation in com.intellij.find.actions.ShowUsagesAction.calcMaxWidth
168       }
169     };
170
171     component.setIpad(new Insets(0,0,0,0));
172     component.setBorder(null);
173     component.setBackground(panelBackground);
174     component.setForeground(panelForeground);
175
176     for (SimpleColoredComponent.ColoredIterator iterator = chunks.iterator(); iterator.hasNext(); ) {
177       iterator.next();
178       String fragment = iterator.getFragment();
179       SimpleTextAttributes attributes = iterator.getTextAttributes();
180       attributes = attributes.derive(attributes.getStyle(), panelForeground, panelBackground, attributes.getWaveColor());
181       component.append(fragment, attributes);
182     }
183
184     return component;
185   }
186
187   private static SimpleTextAttributes deriveAttributesWithColor(SimpleTextAttributes attributes, Color fileBgColor) {
188     if (fileBgColor != null) {
189       attributes = attributes.derive(-1,null, fileBgColor,null);
190     }
191     return attributes;
192   }
193
194   private Color getBackgroundColor(boolean isSelected, Usage usage) {
195     Color fileBgColor = null;
196     if (isSelected) {
197       fileBgColor = UIUtil.getListSelectionBackground();
198     }
199     else {
200       VirtualFile virtualFile = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() : null;
201       if (virtualFile != null) {
202         Project project = myUsageView.getProject();
203         PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
204         if (psiFile != null && psiFile.isValid()) {
205           final Color color = FileColorManager.getInstance(project).getRendererBackground(psiFile);
206           if (color != null) fileBgColor = color;
207         }
208       }
209     }
210     return fileBgColor;
211   }
212
213   private void appendGroupText(final GroupNode node, JPanel panel, Color fileBgColor) {
214     UsageGroup group = node == null ? null : node.getGroup();
215     if (group == null) return;
216     GroupNode parentGroup = (GroupNode)node.getParent();
217     appendGroupText(parentGroup, panel, fileBgColor);
218     if (node.canNavigateToSource()) {
219       SimpleColoredComponent renderer = new SimpleColoredComponent();
220
221       renderer.setIcon(group.getIcon(false));
222       SimpleTextAttributes attributes = deriveAttributesWithColor(SimpleTextAttributes.REGULAR_ATTRIBUTES, fileBgColor);
223       renderer.append(group.getText(myUsageView), attributes);
224       renderer.append(" ", attributes);
225       renderer.setIpad(new Insets(0,0,0,0));
226       renderer.setBorder(null);
227       panel.add(renderer);
228     }
229   }
230 }