1 package com
.intellij
.find
.actions
;
3 import com
.intellij
.codeInsight
.hint
.HintManager
;
4 import com
.intellij
.codeInsight
.hint
.HintUtil
;
5 import com
.intellij
.featureStatistics
.FeatureUsageTracker
;
6 import com
.intellij
.find
.FindBundle
;
7 import com
.intellij
.find
.FindManager
;
8 import com
.intellij
.find
.findUsages
.FindUsagesHandler
;
9 import com
.intellij
.find
.findUsages
.FindUsagesManager
;
10 import com
.intellij
.find
.findUsages
.PsiElement2UsageTargetAdapter
;
11 import com
.intellij
.find
.impl
.FindManagerImpl
;
12 import com
.intellij
.openapi
.actionSystem
.AnAction
;
13 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
14 import com
.intellij
.openapi
.actionSystem
.PlatformDataKeys
;
15 import com
.intellij
.openapi
.editor
.Editor
;
16 import com
.intellij
.openapi
.fileEditor
.FileEditor
;
17 import com
.intellij
.openapi
.fileEditor
.FileEditorLocation
;
18 import com
.intellij
.openapi
.fileEditor
.TextEditor
;
19 import com
.intellij
.openapi
.project
.Project
;
20 import com
.intellij
.openapi
.ui
.popup
.JBPopup
;
21 import com
.intellij
.openapi
.ui
.popup
.JBPopupFactory
;
22 import com
.intellij
.openapi
.ui
.popup
.PopupChooserBuilder
;
23 import com
.intellij
.openapi
.util
.Disposer
;
24 import com
.intellij
.openapi
.vfs
.VirtualFile
;
25 import com
.intellij
.psi
.PsiDocumentManager
;
26 import com
.intellij
.psi
.PsiElement
;
27 import com
.intellij
.psi
.search
.ProjectScope
;
28 import com
.intellij
.psi
.search
.PsiElementProcessor
;
29 import com
.intellij
.psi
.search
.SearchScope
;
30 import com
.intellij
.ui
.ColoredListCellRenderer
;
31 import com
.intellij
.ui
.ListSpeedSearch
;
32 import com
.intellij
.ui
.SimpleTextAttributes
;
33 import com
.intellij
.ui
.SpeedSearchBase
;
34 import com
.intellij
.ui
.awt
.RelativePoint
;
35 import com
.intellij
.usages
.*;
36 import com
.intellij
.usages
.impl
.GroupNode
;
37 import com
.intellij
.usages
.impl
.UsageNode
;
38 import com
.intellij
.usages
.impl
.UsageViewImpl
;
39 import com
.intellij
.util
.CommonProcessors
;
40 import gnu
.trove
.THashSet
;
41 import org
.jetbrains
.annotations
.NotNull
;
45 import java
.util
.ArrayList
;
46 import java
.util
.List
;
48 import java
.util
.Vector
;
50 public class ShowUsagesAction
extends AnAction
{
51 public ShowUsagesAction() {
52 setInjectedContext(true);
55 public void actionPerformed(AnActionEvent e
) {
56 final Project project
= e
.getData(PlatformDataKeys
.PROJECT
);
57 if (project
== null) return;
58 final RelativePoint popupPosition
= JBPopupFactory
.getInstance().guessBestPopupLocation(e
.getDataContext());
59 PsiDocumentManager
.getInstance(project
).commitAllDocuments();
60 FeatureUsageTracker
.getInstance().triggerFeatureUsed("navigation.goto.usages");
62 UsageTarget
[] usageTargets
= e
.getData(UsageView
.USAGE_TARGETS_KEY
);
63 final Editor editor
= e
.getData(PlatformDataKeys
.EDITOR
);
64 if (usageTargets
== null) {
65 FindUsagesAction
.chooseAmbiguousTargetAndPerform(project
, editor
, new PsiElementProcessor
<PsiElement
>() {
66 public boolean execute(final PsiElement element
) {
67 showElementUsages(project
, element
, editor
, popupPosition
);
73 PsiElement element
= ((PsiElement2UsageTargetAdapter
)usageTargets
[0]).getElement();
74 showElementUsages(project
, element
, editor
, popupPosition
);
78 private static void showElementUsages(@NotNull Project project
, final PsiElement element
, Editor editor
, final RelativePoint popupPosition
) {
79 ArrayList
<Usage
> usages
= new ArrayList
<Usage
>();
80 CommonProcessors
.CollectProcessor
<Usage
> collect
= new CommonProcessors
.CollectProcessor
<Usage
>(usages
);
81 FindUsagesManager findUsagesManager
= ((FindManagerImpl
)FindManager
.getInstance(project
)).getFindUsagesManager();
82 FindUsagesHandler handler
= findUsagesManager
.getFindUsagesHandler(element
, false);
83 UsageViewPresentation presentation
= findUsagesManager
.processUsages(element
, collect
, handler
);
84 if (presentation
== null) return;
85 if (usages
.isEmpty()) {
86 String text
= FindBundle
.message("no.usages.found.in", searchScopePresentableName(element
, handler
));
88 HintManager
.getInstance().showInformationHint(editor
, text
);
91 JLabel label
= HintUtil
.createInformationLabel(text
);
92 HintManager
.getInstance().showHint(label
, popupPosition
, HintManager
.HIDE_BY_ANY_KEY
| HintManager
.HIDE_BY_TEXT_CHANGE
| HintManager
.HIDE_BY_SCROLLING
, 0);
96 final String title
= presentation
.getTabText();
97 JBPopup popup
= getUsagePopup(usages
, title
, project
, element
, handler
);
99 popup
.show(popupPosition
);
104 private static String
searchScopePresentableName(PsiElement element
, final FindUsagesHandler handler
) {
105 SearchScope searchScope
= FindUsagesManager
.getCurrentSearchScope(handler
);
106 if (searchScope
== null) searchScope
= ProjectScope
.getAllScope(element
.getProject());
107 return searchScope
.getDisplayName();
110 private static JBPopup
getUsagePopup(List
<Usage
> usages
, final String title
, final Project project
, PsiElement element
,
111 final FindUsagesHandler handler
) {
112 Usage
[] arr
= usages
.toArray(new Usage
[usages
.size()]);
113 UsageViewPresentation presentation
= new UsageViewPresentation();
114 presentation
.setDetachedMode(true);
115 final UsageViewImpl usageView
= (UsageViewImpl
)UsageViewManager
.getInstance(project
).createUsageView(new UsageTarget
[0], arr
, presentation
, null);
117 GroupNode root
= usageView
.getRoot();
118 List
<UsageNode
> nodes
= new ArrayList
<UsageNode
>();
119 Set
<Usage
> filteredUsages
= new THashSet
<Usage
>();
121 addUsageNodes(root
, nodes
, usageView
, filteredUsages
);
122 if (nodes
.size() == 1) {
123 // usage view can filter usages down to one
124 Usage usage
= nodes
.get(0).getUsage();
125 if (filteredUsages
.size() == 1) {
126 navigateAndHint(usage
, FindBundle
.message("show.usages.only.usage", searchScopePresentableName(element
, handler
)));
129 navigateAndHint(usage
, FindBundle
.message("all.usages.are.in.this.line", filteredUsages
.size(), searchScopePresentableName(element
, handler
)));
131 Disposer
.dispose(usageView
);
135 final JList list
= new JList(new Vector
<UsageNode
>(nodes
));
136 list
.setCellRenderer(new ListCellRenderer(){
137 public Component
getListCellRendererComponent(JList list
, Object value
, int index
, boolean isSelected
, boolean cellHasFocus
) {
138 JPanel panel
= new JPanel(new GridBagLayout());
139 UsageNode usageNode
= (UsageNode
)value
;
140 int seq
= appendGroupText((GroupNode
)usageNode
.getParent(), panel
,list
, value
, index
, isSelected
);
142 ColoredListCellRenderer usageRenderer
= new ColoredListCellRenderer() {
143 protected void customizeCellRenderer(JList list
, Object value
, int index
, boolean selected
, boolean hasFocus
) {
144 UsageNode usageNode
= (UsageNode
)value
;
145 Usage usage
= usageNode
.getUsage();
146 UsagePresentation presentation
= usage
.getPresentation();
147 setIcon(presentation
.getIcon());
149 TextChunk
[] text
= presentation
.getText();
150 for (TextChunk textChunk
: text
) {
151 append(textChunk
.getText(), SimpleTextAttributes
.fromTextAttributes(textChunk
.getAttributes()));
155 usageRenderer
.setIpad(new Insets(0,0,0,0));
156 usageRenderer
.setBorder(null);
157 usageRenderer
.getListCellRendererComponent(list
, value
, index
, isSelected
, false);
158 panel
.add(usageRenderer
, new GridBagConstraints(seq
, 0, GridBagConstraints
.REMAINDER
, 0, 1, 0,
159 GridBagConstraints
.NORTHWEST
, GridBagConstraints
.HORIZONTAL
, new Insets(0,0,0,0), 0, 1));
160 panel
.setBackground(list
.getBackground());
163 private int appendGroupText(final GroupNode node
, JPanel panel
, JList list
, Object value
, int index
, boolean isSelected
) {
164 if (node
!= null && node
.getGroup() != null) {
165 int seq
= appendGroupText((GroupNode
)node
.getParent(), panel
, list
, value
, index
, isSelected
);
166 if (node
.canNavigateToSource()) {
167 ColoredListCellRenderer renderer
= new ColoredListCellRenderer() {
168 protected void customizeCellRenderer(JList list
, Object value
, int index
, boolean selected
, boolean hasFocus
) {
169 UsageGroup group
= node
.getGroup();
170 setIcon(group
.getIcon(false));
171 append(group
.getText(usageView
), SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
172 append(" ", SimpleTextAttributes
.REGULAR_ATTRIBUTES
);
175 renderer
.setIpad(new Insets(0,0,0,0));
176 renderer
.setBorder(null);
177 renderer
.getListCellRendererComponent(list
, value
, index
, isSelected
, false);
178 panel
.add(renderer
, new GridBagConstraints(seq
, 0, 1, 0, 0, 0,
179 GridBagConstraints
.NORTHWEST
, GridBagConstraints
.NONE
, new Insets(0,0,0,0), 0, 1));
187 final Runnable runnable
= new Runnable() {
189 Object element
= list
.getSelectedValue();
190 if (element
== null) return;
191 UsageNode node
= (UsageNode
)element
;
192 Usage usage
= node
.getUsage();
193 navigateAndHint(usage
, null);
197 ListSpeedSearch speedSearch
= new ListSpeedSearch(list
) {
198 protected String
getElementText(final Object element
) {
199 StringBuilder text
= new StringBuilder();
200 UsageNode node
= (UsageNode
)element
;
201 Usage usage
= node
.getUsage();
202 VirtualFile virtualFile
= UsageListCellRenderer
.getVirtualFile(usage
);
203 if (virtualFile
!= null) {
204 text
.append(virtualFile
.getName());
206 TextChunk
[] chunks
= usage
.getPresentation().getText();
207 for (TextChunk chunk
: chunks
) {
208 text
.append(chunk
.getText());
210 return text
.toString();
213 speedSearch
.setComparator(new SpeedSearchBase
.SpeedSearchComparator() {
214 public void translatePattern(final StringBuilder buf
, final String pattern
) {
215 final int len
= pattern
.length();
216 for (int i
= 0; i
< len
; ++i
) {
217 translateCharacter(buf
, pattern
.charAt(i
));
222 PopupChooserBuilder builder
= new PopupChooserBuilder(list
);
224 builder
.setTitle(title
+ " " +FindBundle
.message("some.usages.found", usages
.size()));
227 final JBPopup popup
= builder
.setItemChoosenCallback(runnable
).createPopup();
228 Disposer
.register(popup
, usageView
);
232 private static void addUsageNodes(GroupNode root
, List
<UsageNode
> outNodes
, final UsageViewImpl usageView
, final Set
<Usage
> filteredUsages
) {
233 for (UsageNode node
: root
.getUsageNodes()) {
234 Usage usage
= node
.getUsage();
235 if (usageView
.isVisible(usage
)) {
236 node
.setParent(root
);
238 filteredUsages
.add(usage
);
241 for (GroupNode groupNode
: root
.getSubGroups()) {
242 groupNode
.setParent(root
);
243 addUsageNodes(groupNode
, outNodes
, usageView
, filteredUsages
);
247 public void update(AnActionEvent e
){
248 FindUsagesInFileAction
.updateFindUsagesAction(e
);
251 private static void navigateAndHint(Usage usage
, final String hint
) {
252 usage
.navigate(true);
253 if (hint
== null) return;
254 FileEditorLocation location
= usage
.getLocation();
255 FileEditor newFileEditor
= location
== null ?
null : location
.getEditor();
256 final Editor newEditor
= newFileEditor
instanceof TextEditor ?
((TextEditor
)newFileEditor
).getEditor() : null;
257 if (newEditor
!= null) {
258 //opening editor is performing in invokeLater
259 SwingUtilities
.invokeLater(new Runnable() {
261 newEditor
.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
263 // after new editor created, some editor resizing events are still bubbling. To prevent hiding hint, invokeLater this
264 SwingUtilities
.invokeLater(new Runnable() {
266 HintManager
.getInstance().showInformationHint(newEditor
, hint
);