1 package com
.intellij
.find
.findUsages
;
3 import com
.intellij
.codeInsight
.hint
.HintUtil
;
4 import com
.intellij
.codeInsight
.hint
.HintManagerImpl
;
5 import com
.intellij
.codeInsight
.hint
.HintManager
;
6 import com
.intellij
.find
.FindBundle
;
7 import com
.intellij
.lang
.findUsages
.LanguageFindUsages
;
8 import com
.intellij
.navigation
.NavigationItem
;
9 import com
.intellij
.openapi
.actionSystem
.ActionManager
;
10 import com
.intellij
.openapi
.actionSystem
.AnAction
;
11 import com
.intellij
.openapi
.actionSystem
.IdeActions
;
12 import com
.intellij
.openapi
.application
.ApplicationManager
;
13 import com
.intellij
.openapi
.diagnostic
.Logger
;
14 import com
.intellij
.openapi
.editor
.Document
;
15 import com
.intellij
.openapi
.editor
.Editor
;
16 import com
.intellij
.openapi
.extensions
.Extensions
;
17 import com
.intellij
.openapi
.fileEditor
.FileEditor
;
18 import com
.intellij
.openapi
.fileEditor
.FileEditorLocation
;
19 import com
.intellij
.openapi
.fileEditor
.TextEditor
;
20 import com
.intellij
.openapi
.keymap
.KeymapUtil
;
21 import com
.intellij
.openapi
.progress
.ProgressIndicator
;
22 import com
.intellij
.openapi
.progress
.ProgressManager
;
23 import com
.intellij
.openapi
.progress
.Task
;
24 import com
.intellij
.openapi
.project
.Project
;
25 import com
.intellij
.openapi
.ui
.Messages
;
26 import com
.intellij
.openapi
.util
.*;
27 import com
.intellij
.openapi
.util
.text
.StringUtil
;
28 import com
.intellij
.openapi
.wm
.StatusBar
;
29 import com
.intellij
.openapi
.wm
.WindowManager
;
30 import com
.intellij
.psi
.*;
31 import com
.intellij
.psi
.search
.LocalSearchScope
;
32 import com
.intellij
.psi
.search
.SearchScope
;
33 import com
.intellij
.ui
.LightweightHint
;
34 import com
.intellij
.ui
.content
.Content
;
35 import com
.intellij
.usageView
.UsageInfo
;
36 import com
.intellij
.usageView
.UsageViewManager
;
37 import com
.intellij
.usageView
.UsageViewUtil
;
38 import com
.intellij
.usages
.*;
39 import com
.intellij
.usages
.impl
.UsageViewManagerImpl
;
40 import com
.intellij
.util
.Processor
;
41 import org
.jdom
.Element
;
42 import org
.jetbrains
.annotations
.NonNls
;
43 import org
.jetbrains
.annotations
.NotNull
;
44 import org
.jetbrains
.annotations
.Nullable
;
47 import java
.util
.ArrayList
;
48 import java
.util
.Arrays
;
49 import java
.util
.Collections
;
50 import java
.util
.List
;
51 import java
.util
.concurrent
.CopyOnWriteArrayList
;
53 public class FindUsagesManager
implements JDOMExternalizable
{
54 private static final Logger LOG
= Logger
.getInstance("#com.intellij.find.findParameterUsages.FindUsagesManager");
56 private enum FileSearchScope
{
63 private static final Key
<String
> KEY_START_USAGE_AGAIN
= Key
.create("KEY_START_USAGE_AGAIN");
64 @NonNls private static final String VALUE_START_USAGE_AGAIN
= "START_AGAIN";
65 private final Project myProject
;
66 private final com
.intellij
.usages
.UsageViewManager myAnotherManager
;
67 private boolean myToOpenInNewTab
= false;
68 private final List
<FindUsagesHandlerFactory
> myHandlers
= new ArrayList
<FindUsagesHandlerFactory
>();
70 public static class SearchData
{
71 public SmartPsiElementPointer
[] myElements
= null;
72 public FindUsagesOptions myOptions
= null;
74 public boolean equals(final Object o
) {
75 if (this == o
) return true;
76 if (o
== null || getClass() != o
.getClass()) return false;
78 final SearchData that
= (SearchData
)o
;
80 if (!Arrays
.equals(myElements
, that
.myElements
)) return false;
81 if (myOptions
!= null ?
!myOptions
.equals(that
.myOptions
) : that
.myOptions
!= null) return false;
86 public int hashCode() {
87 return myElements
!= null ? Arrays
.hashCode(myElements
) : 0;
91 private SearchData myLastSearchInFileData
= new SearchData();
92 private final CopyOnWriteArrayList
<SearchData
> myFindUsagesHistory
= new CopyOnWriteArrayList
<SearchData
>();
94 public FindUsagesManager(final Project project
, com
.intellij
.usages
.UsageViewManager anotherManager
) {
96 myAnotherManager
= anotherManager
;
99 public void registerFindUsagesHandler(FindUsagesHandlerFactory handler
) {
100 myHandlers
.add(0, handler
);
103 public boolean canFindUsages(@NotNull final PsiElement element
) {
104 for (FindUsagesHandlerFactory factory
: myHandlers
) {
105 if (factory
.canFindUsages(element
)) {
109 for (FindUsagesHandlerFactory factory
: Extensions
.getExtensions(FindUsagesHandlerFactory
.EP_NAME
, myProject
)) {
110 if (factory
.canFindUsages(element
)) {
117 public void clearFindingNextUsageInFile() {
118 myLastSearchInFileData
.myOptions
= null;
119 myLastSearchInFileData
.myElements
= null;
122 public boolean findNextUsageInFile(FileEditor editor
) {
123 return findUsageInFile(editor
, FileSearchScope
.AFTER_CARET
);
126 public boolean findPreviousUsageInFile(FileEditor editor
) {
127 return findUsageInFile(editor
, FileSearchScope
.BEFORE_CARET
);
130 public void readExternal(Element element
) throws InvalidDataException
{
131 myToOpenInNewTab
= JDOMExternalizer
.readBoolean(element
, "OPEN_NEW_TAB");
134 public void writeExternal(Element element
) throws WriteExternalException
{
135 JDOMExternalizer
.write(element
, "OPEN_NEW_TAB", myToOpenInNewTab
);
138 private boolean findUsageInFile(@NotNull FileEditor editor
, FileSearchScope direction
) {
139 PsiElement
[] elements
= restorePsiElements(myLastSearchInFileData
, true);
140 if (elements
== null) return false;
141 if (elements
.length
== 0) return true;//all elements have invalidated
143 UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
= new UsageInfoToUsageConverter
.TargetElementsDescriptor(elements
);
146 TextEditor textEditor
= (TextEditor
)editor
;
147 Document document
= textEditor
.getEditor().getDocument();
148 PsiFile psiFile
= PsiDocumentManager
.getInstance(myProject
).getPsiFile(document
);
149 if (psiFile
== null) return false;
151 findUsagesInEditor(descriptor
, getFindUsagesHandler(elements
[0], false), psiFile
, direction
, myLastSearchInFileData
.myOptions
, textEditor
);
155 // returns null if cannot find, empty Pair if all elements have been changed
157 private PsiElement
[] restorePsiElements(SearchData searchData
, final boolean showErrorMessage
) {
158 if (searchData
== null) return null;
159 SmartPsiElementPointer
[] lastSearchElements
= searchData
.myElements
;
160 if (lastSearchElements
== null) return null;
161 List
<PsiElement
> elements
= new ArrayList
<PsiElement
>();
162 for (SmartPsiElementPointer pointer
: lastSearchElements
) {
163 PsiElement element
= pointer
.getElement();
164 if (element
!= null) elements
.add(element
);
166 if (elements
.isEmpty() && showErrorMessage
) {
167 Messages
.showMessageDialog(myProject
, FindBundle
.message("find.searched.elements.have.been.changed.error"),
168 FindBundle
.message("cannot.search.for.usages.title"), Messages
.getInformationIcon());
170 //clearFindingNextUsageInFile();
171 return PsiElement
.EMPTY_ARRAY
;
174 return elements
.toArray(new PsiElement
[elements
.size()]);
177 private void initLastSearchElement(final FindUsagesOptions findUsagesOptions
,
178 UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
) {
179 myLastSearchInFileData
= createSearchData(descriptor
.getAllElements(), findUsagesOptions
);
182 private SearchData
createSearchData(final List
<?
extends PsiElement
> psiElements
, final FindUsagesOptions findUsagesOptions
) {
183 SearchData data
= new SearchData();
185 data
.myElements
= new SmartPsiElementPointer
[psiElements
.size()];
187 for (PsiElement psiElement
: psiElements
) {
188 data
.myElements
[idx
++] = SmartPointerManager
.getInstance(myProject
).createSmartPsiElementPointer(psiElement
);
190 data
.myOptions
= findUsagesOptions
;
195 public FindUsagesHandler
getFindUsagesHandler(PsiElement element
, final boolean forHighlightUsages
) {
196 for (FindUsagesHandlerFactory factory
: myHandlers
) {
197 if (factory
.canFindUsages(element
)) {
198 final FindUsagesHandler handler
= factory
.createFindUsagesHandler(element
, forHighlightUsages
);
199 if (handler
!= null) {
204 for (FindUsagesHandlerFactory factory
: Extensions
.getExtensions(FindUsagesHandlerFactory
.EP_NAME
, myProject
)) {
205 if (factory
.canFindUsages(element
)) {
206 final FindUsagesHandler handler
= factory
.createFindUsagesHandler(element
, forHighlightUsages
);
207 if (handler
!= null) {
215 public void findUsages(@NotNull PsiElement psiElement
, final PsiFile scopeFile
, final FileEditor editor
) {
216 final FindUsagesHandler handler
= getFindUsagesHandler(psiElement
, false);
217 if (handler
== null) return;
219 boolean singleFile
= scopeFile
!= null;
220 final AbstractFindUsagesDialog dialog
= handler
.getFindUsagesDialog(singleFile
, shouldOpenInNewTab(), mustOpenInNewTab());
223 if (!dialog
.isOK()) return;
226 setOpenInNewTab(dialog
.isShowInSeparateWindow());
228 FindUsagesOptions findUsagesOptions
= dialog
.calcFindUsagesOptions();
230 clearFindingNextUsageInFile();
231 LOG
.assertTrue(handler
.getPsiElement().isValid());
232 final UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
=
233 new UsageInfoToUsageConverter
.TargetElementsDescriptor(handler
.getPrimaryElements(), handler
.getSecondaryElements());
235 findUsagesOptions
= (FindUsagesOptions
)findUsagesOptions
.clone();
236 findUsagesOptions
.isDerivedClasses
= false;
237 findUsagesOptions
.isDerivedInterfaces
= false;
238 findUsagesOptions
.isImplementingClasses
= false;
239 editor
.putUserData(KEY_START_USAGE_AGAIN
, null);
240 findUsagesInEditor(descriptor
, handler
, scopeFile
, FileSearchScope
.FROM_START
, findUsagesOptions
, editor
);
243 findUsages(descriptor
, handler
, dialog
.isSkipResultsWhenOneUsage(), dialog
.isShowInSeparateWindow(), findUsagesOptions
);
248 public static SearchScope
getCurrentSearchScope(FindUsagesHandler handler
) {
249 if (handler
== null) return null;
250 FindUsagesOptions findUsagesOptions
= handler
.getFindUsagesOptions();
251 return findUsagesOptions
.searchScope
;
254 // return null on failure or cancel
256 public UsageViewPresentation
processUsages(@NotNull PsiElement element
, @NotNull final Processor
<Usage
> processor
, FindUsagesHandler handler
) {
257 if (handler
== null) return null;
259 FindUsagesOptions findUsagesOptions
= handler
.getFindUsagesOptions();
261 LOG
.assertTrue(handler
.getPsiElement().isValid());
262 final UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
=
263 new UsageInfoToUsageConverter
.TargetElementsDescriptor(handler
.getPrimaryElements(), handler
.getSecondaryElements());
265 UsageViewPresentation presentation
= createPresentation(element
, findUsagesOptions
, myToOpenInNewTab
);
266 final UsageSearcher usageSearcher
= createUsageSearcher(descriptor
, handler
, findUsagesOptions
, null);
267 final boolean[] canceled
= {false};
268 final int[] usageCount
= {0};
269 Task task
= new Task
.Modal(myProject
, UsageViewManagerImpl
.getProgressTitle(presentation
), true) {
270 public void run(@NotNull final ProgressIndicator indicator
) {
271 usageSearcher
.generate(new Processor
<Usage
>() {
272 public boolean process(final Usage usage
) {
274 return processor
.process(usage
);
280 public NotificationInfo
getNotificationInfo() {
281 return new NotificationInfo("Find Usages", "Find Usages Finished", usageCount
[0] + " Usage(s) Found");
284 public void onCancel() {
288 ProgressManager
.getInstance().run(task
);
289 if (canceled
[0]) return null;
293 private void setOpenInNewTab(final boolean toOpenInNewTab
) {
294 if (!mustOpenInNewTab()) {
295 myToOpenInNewTab
= toOpenInNewTab
;
299 private boolean shouldOpenInNewTab() {
300 return mustOpenInNewTab() || myToOpenInNewTab
;
303 private boolean mustOpenInNewTab() {
304 Content selectedContent
= UsageViewManager
.getInstance(myProject
).getSelectedContent(true);
305 return selectedContent
!= null && selectedContent
.isPinned();
309 private static UsageSearcher
createUsageSearcher(final UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
,
310 final FindUsagesHandler handler
,
311 final FindUsagesOptions options
,
312 final PsiFile scopeFile
) {
314 return new UsageSearcher() {
315 public void generate(@NotNull final Processor
<Usage
> processor
) {
316 if (scopeFile
!= null) {
317 options
.searchScope
= new LocalSearchScope(scopeFile
);
319 final Processor
<UsageInfo
> usageInfoProcessorToUsageProcessorAdapter
= new Processor
<UsageInfo
>() {
320 public boolean process(UsageInfo usageInfo
) {
321 return processor
.process(UsageInfoToUsageConverter
.convert(descriptor
, usageInfo
));
324 List
<?
extends PsiElement
> elements
=
325 ApplicationManager
.getApplication().runReadAction(new Computable
<List
<?
extends PsiElement
>>() {
326 public List
<?
extends PsiElement
> compute() {
327 return descriptor
.getAllElements();
330 for (final PsiElement element
: elements
) {
331 ApplicationManager
.getApplication().runReadAction(new Runnable() {
333 LOG
.assertTrue(element
.isValid());
336 handler
.processElementUsages(element
, usageInfoProcessorToUsageProcessorAdapter
, options
);
342 private static PsiElement2UsageTargetAdapter
[] convertToUsageTargets(final List
<?
extends PsiElement
> elementsToSearch
) {
343 final ArrayList
<PsiElement2UsageTargetAdapter
> targets
= new ArrayList
<PsiElement2UsageTargetAdapter
>(elementsToSearch
.size());
344 for (PsiElement element
: elementsToSearch
) {
345 convertToUsageTarget(targets
, element
);
347 return targets
.toArray(new PsiElement2UsageTargetAdapter
[targets
.size()]);
350 private void findUsages(final UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
,
351 final FindUsagesHandler handler
,
352 final boolean toSkipUsagePanelWhenOneUsage
,
353 final boolean toOpenInNewTab
,
354 final FindUsagesOptions findUsagesOptions
) {
356 List
<?
extends PsiElement
> elements
= descriptor
.getAllElements();
357 final UsageTarget
[] targets
= convertToUsageTargets(elements
);
358 myAnotherManager
.searchAndShowUsages(targets
, new Factory
<UsageSearcher
>() {
359 public UsageSearcher
create() {
360 return createUsageSearcher(descriptor
, handler
, findUsagesOptions
, null);
362 }, !toSkipUsagePanelWhenOneUsage
, true, createPresentation(elements
.get(0), findUsagesOptions
, toOpenInNewTab
), null);
363 addToHistory(elements
, findUsagesOptions
);
366 private static UsageViewPresentation
createPresentation(PsiElement psiElement
,
367 final FindUsagesOptions findUsagesOptions
,
368 boolean toOpenInNewTab
) {
369 UsageViewPresentation presentation
= new UsageViewPresentation();
370 String scopeString
= findUsagesOptions
.searchScope
!= null ? findUsagesOptions
.searchScope
.getDisplayName() : null;
371 presentation
.setScopeText(scopeString
);
372 String usagesString
= generateUsagesString(findUsagesOptions
);
373 presentation
.setUsagesString(usagesString
);
375 if (scopeString
!= null) {
376 title
= FindBundle
.message("find.usages.of.element.in.scope.panel.title", usagesString
, UsageViewUtil
.getLongName(psiElement
), scopeString
);
379 title
= FindBundle
.message("find.usages.of.element.panel.title", usagesString
, UsageViewUtil
.getLongName(psiElement
));
381 presentation
.setTabText(title
);
382 presentation
.setTabName(FindBundle
.message("find.usages.of.element.tab.name", usagesString
, UsageViewUtil
.getShortName(psiElement
)));
383 presentation
.setTargetsNodeText(StringUtil
.capitalize(UsageViewUtil
.getType(psiElement
)));
384 presentation
.setOpenInNewTab(toOpenInNewTab
);
388 private void findUsagesInEditor(final UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
,
389 final FindUsagesHandler handler
,
390 final PsiFile scopeFile
,
391 final FileSearchScope direction
,
392 final FindUsagesOptions findUsagesOptions
,
393 @NotNull FileEditor fileEditor
) {
394 initLastSearchElement(findUsagesOptions
, descriptor
);
398 final FileEditorLocation currentLocation
= fileEditor
.getCurrentLocation();
400 final UsageSearcher usageSearcher
= createUsageSearcher(descriptor
, handler
, findUsagesOptions
, scopeFile
);
401 final boolean[] usagesWereFound
= {false};
403 Usage fUsage
= findSiblingUsage(myProject
, usageSearcher
, direction
, currentLocation
, usagesWereFound
, fileEditor
);
405 if (fUsage
!= null) {
406 fUsage
.navigate(true);
407 fUsage
.selectInEditor();
409 else if (!usagesWereFound
[0]) {
410 String message
= getNoUsagesFoundMessage(descriptor
.getPrimaryElements()[0]);
411 showHintOrStatusBarMessage(message
, fileEditor
);
414 fileEditor
.putUserData(KEY_START_USAGE_AGAIN
, VALUE_START_USAGE_AGAIN
);
415 showHintOrStatusBarMessage(getSearchAgainMessage(descriptor
.getPrimaryElements()[0], direction
), fileEditor
);
419 private static String
getNoUsagesFoundMessage(PsiElement psiElement
) {
420 String elementType
= UsageViewUtil
.getType(psiElement
);
421 String elementName
= UsageViewUtil
.getShortName(psiElement
);
422 return FindBundle
.message("find.usages.of.element_type.element_name.not.found.message", elementType
, elementName
);
425 private void clearStatusBar() {
426 StatusBar statusBar
= WindowManager
.getInstance().getStatusBar(myProject
);
427 statusBar
.setInfo("");
430 private static String
getSearchAgainMessage(PsiElement element
, final FileSearchScope direction
) {
431 String message
= getNoUsagesFoundMessage(element
);
432 if (direction
== FileSearchScope
.AFTER_CARET
) {
433 AnAction action
= ActionManager
.getInstance().getAction(IdeActions
.ACTION_FIND_NEXT
);
434 String shortcutsText
= KeymapUtil
.getFirstKeyboardShortcutText(action
);
435 if (shortcutsText
.length() > 0) {
436 message
= FindBundle
.message("find.search.again.from.top.hotkey.message", message
, shortcutsText
);
439 message
= FindBundle
.message("find.search.again.from.top.action.message", message
);
443 String shortcutsText
=
444 KeymapUtil
.getFirstKeyboardShortcutText(ActionManager
.getInstance().getAction(IdeActions
.ACTION_FIND_PREVIOUS
));
445 if (shortcutsText
.length() > 0) {
446 message
= FindBundle
.message("find.search.again.from.bottom.hotkey.message", message
, shortcutsText
);
449 message
= FindBundle
.message("find.search.again.from.bottom.action.message", message
);
455 private void showHintOrStatusBarMessage(String message
, FileEditor fileEditor
) {
456 if (fileEditor
instanceof TextEditor
) {
457 TextEditor textEditor
= (TextEditor
)fileEditor
;
458 showEditorHint(message
, textEditor
.getEditor());
461 StatusBar statusBar
= WindowManager
.getInstance().getStatusBar(myProject
);
462 statusBar
.setInfo(message
);
466 private static Usage
findSiblingUsage(@NotNull final Project project
,
467 @NotNull final UsageSearcher usageSearcher
,
469 final FileEditorLocation currentLocation
,
470 @NotNull final boolean[] usagesWereFound
,
471 @NotNull FileEditor fileEditor
) {
472 if (fileEditor
.getUserData(KEY_START_USAGE_AGAIN
) != null) {
473 dir
= dir
== FileSearchScope
.AFTER_CARET ? FileSearchScope
.FROM_START
: FileSearchScope
.FROM_END
;
476 final FileSearchScope direction
= dir
;
478 final com
.intellij
.usages
.UsageViewManager usageViewManager
= com
.intellij
.usages
.UsageViewManager
.getInstance(project
);
479 usageViewManager
.setCurrentSearchCancelled(false);
480 final Usage
[] foundUsage
= {null};
481 usageSearcher
.generate(new Processor
<Usage
>() {
482 public boolean process(Usage usage
) {
483 if (usageViewManager
.searchHasBeenCancelled()) return false;
485 usagesWereFound
[0] = true;
487 if (direction
== FileSearchScope
.FROM_START
) {
488 foundUsage
[0] = usage
;
491 else if (direction
== FileSearchScope
.FROM_END
) {
492 foundUsage
[0] = usage
;
494 else if (direction
== FileSearchScope
.AFTER_CARET
) {
495 if (Comparing
.compare(usage
.getLocation(), currentLocation
) > 0) {
496 foundUsage
[0] = usage
;
500 else if (direction
== FileSearchScope
.BEFORE_CARET
) {
501 if (Comparing
.compare(usage
.getLocation(), currentLocation
) < 0) {
502 if (foundUsage
[0] != null) {
503 if (foundUsage
[0].getLocation().compareTo(usage
.getLocation()) < 0) {
504 foundUsage
[0] = usage
;
508 foundUsage
[0] = usage
;
520 fileEditor
.putUserData(KEY_START_USAGE_AGAIN
, null);
522 return foundUsage
[0];
525 private static void convertToUsageTarget(final List
<PsiElement2UsageTargetAdapter
> targets
, PsiElement elementToSearch
) {
526 if (elementToSearch
instanceof NavigationItem
) {
527 targets
.add(new PsiElement2UsageTargetAdapter(elementToSearch
));
530 throw new IllegalArgumentException("Wrong usage target:" + elementToSearch
);
534 private static String
generateUsagesString(final FindUsagesOptions selectedOptions
) {
535 String suffix
= " " + FindBundle
.message("find.usages.panel.title.separator") + " ";
536 ArrayList
<String
> strings
= new ArrayList
<String
>();
537 if (selectedOptions
.isUsages
538 || selectedOptions
.isClassesUsages
||
539 selectedOptions
.isMethodsUsages
||
540 selectedOptions
.isFieldsUsages
) {
541 strings
.add(FindBundle
.message("find.usages.panel.title.usages"));
543 if (selectedOptions
.isIncludeOverloadUsages
) {
544 strings
.add(FindBundle
.message("find.usages.panel.title.overloaded.methods.usages"));
546 if (selectedOptions
.isDerivedClasses
) {
547 strings
.add(FindBundle
.message("find.usages.panel.title.derived.classes"));
549 if (selectedOptions
.isDerivedInterfaces
) {
550 strings
.add(FindBundle
.message("find.usages.panel.title.derived.interfaces"));
552 if (selectedOptions
.isImplementingClasses
) {
553 strings
.add(FindBundle
.message("find.usages.panel.title.implementing.classes"));
555 if (selectedOptions
.isImplementingMethods
) {
556 strings
.add(FindBundle
.message("find.usages.panel.title.implementing.methods"));
558 if (selectedOptions
.isOverridingMethods
) {
559 strings
.add(FindBundle
.message("find.usages.panel.title.overriding.methods"));
561 if (strings
.isEmpty()) {
562 strings
.add(FindBundle
.message("find.usages.panel.title.usages"));
564 String usagesString
= "";
565 for (int i
= 0; i
< strings
.size(); i
++) {
566 String s
= strings
.get(i
);
567 usagesString
+= i
== strings
.size() - 1 ? s
: s
+ suffix
;
572 private static void showEditorHint(String message
, final Editor editor
) {
573 JComponent component
= HintUtil
.createInformationLabel(message
);
574 final LightweightHint hint
= new LightweightHint(component
);
575 HintManagerImpl
.getInstanceImpl().showEditorHint(hint
, editor
, HintManager
.UNDER
,
576 HintManager
.HIDE_BY_ANY_KEY
| HintManager
.HIDE_BY_TEXT_CHANGE
| HintManager
.HIDE_BY_SCROLLING
, 0, false);
579 public static String
getHelpID(PsiElement element
) {
580 return LanguageFindUsages
.INSTANCE
.forLanguage(element
.getLanguage()).getHelpId(element
);
583 private void addToHistory(final List
<?
extends PsiElement
> elements
, final FindUsagesOptions findUsagesOptions
) {
584 SearchData data
= createSearchData(elements
, findUsagesOptions
);
585 myFindUsagesHistory
.remove(data
);
586 myFindUsagesHistory
.add(data
);
588 // todo configure history depth limit
589 if (myFindUsagesHistory
.size() > 15) {
590 myFindUsagesHistory
.remove(0);
594 public void rerunAndRecallFromHistory(SearchData searchData
) {
595 myFindUsagesHistory
.remove(searchData
);
596 PsiElement
[] elements
= restorePsiElements(searchData
, true);
597 if (elements
== null || elements
.length
== 0) return;
598 UsageInfoToUsageConverter
.TargetElementsDescriptor descriptor
= new UsageInfoToUsageConverter
.TargetElementsDescriptor(elements
);
599 findUsages(descriptor
, getFindUsagesHandler(elements
[0], false), false, false, searchData
.myOptions
);
602 // most recent entry is at the end of the list
603 public List
<SearchData
> getFindUsageHistory() {
604 removeInvalidElementsFromHistory();
605 return Collections
.unmodifiableList(myFindUsagesHistory
);
608 private void removeInvalidElementsFromHistory() {
609 for (SearchData data
: myFindUsagesHistory
) {
610 PsiElement
[] elements
= restorePsiElements(data
, false);
611 if (elements
== null || elements
.length
== 0) myFindUsagesHistory
.remove(data
);