@NotNull private static Couple<Collection<TextRange>> getUsages( @NotNull PsiElement target, PsiElement psiElement, boolean withDeclarations, boolean detectAccess) { List<TextRange> readRanges = new ArrayList<TextRange>(); List<TextRange> writeRanges = new ArrayList<TextRange>(); final ReadWriteAccessDetector detector = detectAccess ? ReadWriteAccessDetector.findDetector(target) : null; final FindUsagesManager findUsagesManager = ((FindManagerImpl) FindManager.getInstance(target.getProject())).getFindUsagesManager(); final FindUsagesHandler findUsagesHandler = findUsagesManager.getFindUsagesHandler(target, true); final LocalSearchScope scope = new LocalSearchScope(psiElement); Collection<PsiReference> refs = findUsagesHandler != null ? findUsagesHandler.findReferencesToHighlight(target, scope) : ReferencesSearch.search(target, scope).findAll(); for (PsiReference psiReference : refs) { if (psiReference == null) { LOG.error( "Null reference returned, findUsagesHandler=" + findUsagesHandler + "; target=" + target + " of " + target.getClass()); continue; } List<TextRange> destination; if (detector == null || detector.getReferenceAccess(target, psiReference) == ReadWriteAccessDetector.Access.Read) { destination = readRanges; } else { destination = writeRanges; } HighlightUsagesHandler.collectRangesToHighlight(psiReference, destination); } if (withDeclarations) { final TextRange declRange = HighlightUsagesHandler.getNameIdentifierRange(psiElement.getContainingFile(), target); if (declRange != null) { if (detector != null && detector.isDeclarationWriteAccess(target)) { writeRanges.add(declRange); } else { readRanges.add(declRange); } } } return Couple.<Collection<TextRange>>of(readRanges, writeRanges); }
@NotNull private static FindUsagesOptions getDefaultOptions(@NotNull FindUsagesHandler handler) { FindUsagesOptions options = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); // by default, scope in FindUsagesOptions is copied from the FindSettings, but we need a default // one options.searchScope = FindUsagesManager.getMaximalScope(handler); return options; }
private void showDialogAndFindUsages( @NotNull FindUsagesHandler handler, @NotNull RelativePoint popupPosition, Editor editor, int maxUsages) { AbstractFindUsagesDialog dialog = handler.getFindUsagesDialog(false, false, false); dialog.show(); if (dialog.isOK()) { dialog.calcFindUsagesOptions(); showElementUsages(handler, editor, popupPosition, maxUsages, getDefaultOptions(handler)); } }
@Nullable private static String getSecondInvocationTitle( @NotNull FindUsagesOptions options, @NotNull FindUsagesHandler handler) { if (getShowUsagesShortcut() != null) { GlobalSearchScope maximalScope = FindUsagesManager.getMaximalScope(handler); if (!notNullizeScope(options, handler.getProject()).equals(maximalScope)) { return "Press " + KeymapUtil.getShortcutText(getShowUsagesShortcut()) + " again to search in " + maximalScope.getDisplayName(); } } return null; }
private void navigateAndHint( @NotNull Usage usage, @Nullable final String hint, @NotNull final FindUsagesHandler handler, @NotNull final RelativePoint popupPosition, final int maxUsages, @NotNull final FindUsagesOptions options) { usage.navigate(true); if (hint == null) return; final Editor newEditor = getEditorFor(usage); if (newEditor == null) return; final Project project = handler.getProject(); // opening editor is performing in invokeLater IdeFocusManager.getInstance(project) .doWhenFocusSettlesDown( new Runnable() { @Override public void run() { newEditor .getScrollingModel() .runActionOnScrollingFinished( new Runnable() { @Override public void run() { // after new editor created, some editor resizing events are still // bubbling. To prevent hiding hint, invokeLater this IdeFocusManager.getInstance(project) .doWhenFocusSettlesDown( new Runnable() { @Override public void run() { if (newEditor.getComponent().isShowing()) { showHint( hint, newEditor, popupPosition, handler, maxUsages, options); } } }); } }); } }); }
private void showElementUsages( @NotNull final FindUsagesHandler handler, final Editor editor, @NotNull final RelativePoint popupPosition, final int maxUsages, @NotNull final FindUsagesOptions options) { ApplicationManager.getApplication().assertIsDispatchThread(); final UsageViewSettings usageViewSettings = UsageViewSettings.getInstance(); final UsageViewSettings savedGlobalSettings = new UsageViewSettings(); savedGlobalSettings.loadState(usageViewSettings); usageViewSettings.loadState(myUsageViewSettings); final Project project = handler.getProject(); UsageViewManager manager = UsageViewManager.getInstance(project); FindUsagesManager findUsagesManager = ((FindManagerImpl) FindManager.getInstance(project)).getFindUsagesManager(); final UsageViewPresentation presentation = findUsagesManager.createPresentation(handler, options); presentation.setDetachedMode(true); final UsageViewImpl usageView = (UsageViewImpl) manager.createUsageView(UsageTarget.EMPTY_ARRAY, Usage.EMPTY_ARRAY, presentation, null); Disposer.register( usageView, new Disposable() { @Override public void dispose() { myUsageViewSettings.loadState(usageViewSettings); usageViewSettings.loadState(savedGlobalSettings); } }); final List<Usage> usages = new ArrayList<Usage>(); final Set<UsageNode> visibleNodes = new LinkedHashSet<UsageNode>(); UsageInfoToUsageConverter.TargetElementsDescriptor descriptor = new UsageInfoToUsageConverter.TargetElementsDescriptor( handler.getPrimaryElements(), handler.getSecondaryElements()); final MyTable table = new MyTable(); final AsyncProcessIcon processIcon = new AsyncProcessIcon("xxx"); boolean hadMoreSeparator = visibleNodes.remove(MORE_USAGES_SEPARATOR_NODE); if (hadMoreSeparator) { usages.add(MORE_USAGES_SEPARATOR); visibleNodes.add(MORE_USAGES_SEPARATOR_NODE); } addUsageNodes(usageView.getRoot(), usageView, new ArrayList<UsageNode>()); TableScrollingUtil.installActions(table); final List<UsageNode> data = collectData(usages, visibleNodes, usageView, presentation); setTableModel(table, usageView, data); SpeedSearchBase<JTable> speedSearch = new MySpeedSearch(table); speedSearch.setComparator(new SpeedSearchComparator(false)); final JBPopup popup = createUsagePopup( usages, descriptor, visibleNodes, handler, editor, popupPosition, maxUsages, usageView, options, table, presentation, processIcon, hadMoreSeparator); Disposer.register(popup, usageView); // show popup only if find usages takes more than 300ms, otherwise it would flicker needlessly Alarm alarm = new Alarm(usageView); alarm.addRequest( new Runnable() { @Override public void run() { showPopupIfNeedTo(popup, popupPosition); } }, 300); final PingEDT pingEDT = new PingEDT( "Rebuild popup in EDT", new Condition<Object>() { @Override public boolean value(Object o) { return popup.isDisposed(); } }, 100, new Runnable() { @Override public void run() { if (popup.isDisposed()) return; final List<UsageNode> nodes = new ArrayList<UsageNode>(); List<Usage> copy; synchronized (usages) { // open up popup as soon as several usages 've been found if (!popup.isVisible() && (usages.size() <= 1 || !showPopupIfNeedTo(popup, popupPosition))) { return; } addUsageNodes(usageView.getRoot(), usageView, nodes); copy = new ArrayList<Usage>(usages); } rebuildPopup( usageView, copy, nodes, table, popup, presentation, popupPosition, !processIcon.isDisposed()); } }); final MessageBusConnection messageBusConnection = project.getMessageBus().connect(usageView); messageBusConnection.subscribe( UsageFilteringRuleProvider.RULES_CHANGED, new Runnable() { @Override public void run() { pingEDT.ping(); } }); Processor<Usage> collect = new Processor<Usage>() { private final UsageTarget[] myUsageTarget = { new PsiElement2UsageTargetAdapter(handler.getPsiElement()) }; @Override public boolean process(@NotNull Usage usage) { synchronized (usages) { if (!filter.shouldShow(usage)) return true; if (visibleNodes.size() >= maxUsages) return false; if (UsageViewManager.isSelfUsage(usage, myUsageTarget)) { return true; } Usage usageToAdd = transform(usage); if (usageToAdd == null) return true; UsageNode node = usageView.doAppendUsage(usageToAdd); usages.add(usageToAdd); if (node != null) { visibleNodes.add(node); boolean continueSearch = true; if (visibleNodes.size() == maxUsages) { visibleNodes.add(MORE_USAGES_SEPARATOR_NODE); usages.add(MORE_USAGES_SEPARATOR); continueSearch = false; } pingEDT.ping(); return continueSearch; } return true; } } }; final ProgressIndicator indicator = FindUsagesManager.startProcessUsages( handler, handler.getPrimaryElements(), handler.getSecondaryElements(), collect, options, new Runnable() { @Override public void run() { ApplicationManager.getApplication() .invokeLater( new Runnable() { @Override public void run() { Disposer.dispose(processIcon); Container parent = processIcon.getParent(); parent.remove(processIcon); parent.repaint(); pingEDT.ping(); // repaint title synchronized (usages) { if (visibleNodes.isEmpty()) { if (usages.isEmpty()) { String text = UsageViewBundle.message( "no.usages.found.in", searchScopePresentableName(options, project)); showHint( text, editor, popupPosition, handler, maxUsages, options); popup.cancel(); } else { // all usages filtered out } } else if (visibleNodes.size() == 1) { if (usages.size() == 1) { // the only usage Usage usage = visibleNodes.iterator().next().getUsage(); usage.navigate(true); // String message = // UsageViewBundle.message("show.usages.only.usage", // searchScopePresentableName(options, project)); // navigateAndHint(usage, message, handler, popupPosition, // maxUsages, options); popup.cancel(); } else { assert usages.size() > 1 : usages; // usage view can filter usages down to one Usage visibleUsage = visibleNodes.iterator().next().getUsage(); if (areAllUsagesInOneLine(visibleUsage, usages)) { String hint = UsageViewBundle.message( "all.usages.are.in.this.line", usages.size(), searchScopePresentableName(options, project)); navigateAndHint( visibleUsage, hint, handler, popupPosition, maxUsages, options); popup.cancel(); } } } else { String title = presentation.getTabText(); boolean shouldShowMoreSeparator = visibleNodes.contains(MORE_USAGES_SEPARATOR_NODE); String fullTitle = getFullTitle( usages, title, shouldShowMoreSeparator, visibleNodes.size() - (shouldShowMoreSeparator ? 1 : 0), false); ((AbstractPopup) popup).setCaption(fullTitle); } } } }, project.getDisposed()); } }); Disposer.register( popup, new Disposable() { @Override public void dispose() { indicator.cancel(); } }); }
public static List<ParameterInfoImpl> performChange( final Project project, final Editor editor, final PsiFile file, final PsiMethod method, final int minUsagesNumber, final ParameterInfoImpl[] newParametersInfo, final boolean changeAllUsages, final boolean allowDelegation) { if (!FileModificationService.getInstance().prepareFileForWrite(method.getContainingFile())) return null; final FindUsagesManager findUsagesManager = ((FindManagerImpl) FindManager.getInstance(project)).getFindUsagesManager(); final FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(method, false); if (handler == null) return null; // on failure or cancel (e.g. cancel of super methods dialog) final JavaMethodFindUsagesOptions options = new JavaMethodFindUsagesOptions(project); options.isImplementingMethods = true; options.isOverridingMethods = true; options.isUsages = true; options.isSearchForTextOccurrences = false; final int[] usagesFound = new int[1]; Runnable runnable = () -> { Processor<UsageInfo> processor = t -> ++usagesFound[0] < minUsagesNumber; handler.processElementUsages(method, processor, options); }; String progressTitle = QuickFixBundle.message("searching.for.usages.progress.title"); if (!ProgressManager.getInstance() .runProcessWithProgressSynchronously(runnable, progressTitle, true, project)) return null; if (ApplicationManager.getApplication().isUnitTestMode() || usagesFound[0] < minUsagesNumber) { ChangeSignatureProcessor processor = new ChangeSignatureProcessor( project, method, false, null, method.getName(), method.getReturnType(), newParametersInfo) { @Override @NotNull protected UsageInfo[] findUsages() { return changeAllUsages ? super.findUsages() : UsageInfo.EMPTY_ARRAY; } @Override protected void performRefactoring(@NotNull UsageInfo[] usages) { CommandProcessor.getInstance().setCurrentCommandName(getCommandName()); super.performRefactoring(usages); } }; processor.run(); ApplicationManager.getApplication().runWriteAction(() -> UndoUtil.markPsiFileForUndo(file)); return Arrays.asList(newParametersInfo); } else { final List<ParameterInfoImpl> parameterInfos = newParametersInfo != null ? new ArrayList<ParameterInfoImpl>(Arrays.asList(newParametersInfo)) : new ArrayList<ParameterInfoImpl>(); final PsiReferenceExpression refExpr = JavaTargetElementEvaluator.findReferenceExpression(editor); JavaChangeSignatureDialog dialog = JavaChangeSignatureDialog.createAndPreselectNew( project, method, parameterInfos, allowDelegation, refExpr); dialog.setParameterInfos(parameterInfos); dialog.show(); return dialog.isOK() ? dialog.getParameters() : null; } }