private static void addUsageNodes( @NotNull GroupNode root, @NotNull final UsageViewImpl usageView, @NotNull List<UsageNode> outNodes) { for (UsageNode node : root.getUsageNodes()) { Usage usage = node.getUsage(); if (usageView.isVisible(usage)) { node.setParent(root); outNodes.add(node); } } for (GroupNode groupNode : root.getSubGroups()) { groupNode.setParent(root); addUsageNodes(groupNode, usageView, outNodes); } }
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 final Usage usage) { synchronized (usages) { if (visibleNodes.size() >= maxUsages) return false; if (UsageViewManager.isSelfUsage(usage, myUsageTarget)) return true; UsageNode node = ApplicationManager.getApplication() .runReadAction( new Computable<UsageNode>() { @Override public UsageNode compute() { return usageView.doAppendUsage(usage); } }); usages.add(usage); 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, descriptor, 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(); 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(); } }); }