private void rebuildPopup( @NotNull final UsageViewImpl usageView, @NotNull final List<Usage> usages, @NotNull List<UsageNode> nodes, @NotNull final JTable table, @NotNull final JBPopup popup, @NotNull final UsageViewPresentation presentation, @NotNull final RelativePoint popupPosition, boolean findUsagesInProgress) { ApplicationManager.getApplication().assertIsDispatchThread(); boolean shouldShowMoreSeparator = usages.contains(MORE_USAGES_SEPARATOR); if (shouldShowMoreSeparator) { nodes.add(MORE_USAGES_SEPARATOR_NODE); } String title = presentation.getTabText(); String fullTitle = getFullTitle( usages, title, shouldShowMoreSeparator, nodes.size() - (shouldShowMoreSeparator ? 1 : 0), findUsagesInProgress); ((AbstractPopup) popup).setCaption(fullTitle); List<UsageNode> data = collectData(usages, nodes, usageView, presentation); MyModel tableModel = setTableModel(table, usageView, data); List<UsageNode> existingData = tableModel.getItems(); int row = table.getSelectedRow(); int newSelection = updateModel(tableModel, existingData, data, row == -1 ? 0 : row); if (newSelection < 0 || newSelection >= tableModel.getRowCount()) { TableScrollingUtil.ensureSelectionExists(table); newSelection = table.getSelectedRow(); } else { table.getSelectionModel().setSelectionInterval(newSelection, newSelection); } TableScrollingUtil.ensureIndexIsVisible(table, newSelection, 0); setSizeAndDimensions(table, popup, popupPosition, data); }
private void setSizeAndDimensions( @NotNull JTable table, @NotNull JBPopup popup, @NotNull RelativePoint popupPosition, @NotNull List<UsageNode> data) { JComponent content = popup.getContent(); Window window = SwingUtilities.windowForComponent(content); Dimension d = window.getSize(); int width = calcMaxWidth(table); width = (int) Math.max(d.getWidth(), width); Dimension headerSize = ((AbstractPopup) popup).getHeaderPreferredSize(); width = Math.max((int) headerSize.getWidth(), width); width = Math.max(myWidth, width); if (myWidth == -1) myWidth = width; int newWidth = Math.max(width, d.width + width - myWidth); myWidth = newWidth; int rowsToShow = Math.min(30, data.size()); Dimension dimension = new Dimension(newWidth, table.getRowHeight() * rowsToShow); Rectangle rectangle = fitToScreen(dimension, popupPosition, table); dimension = rectangle.getSize(); Point location = window.getLocation(); if (!location.equals(rectangle.getLocation())) { window.setLocation(rectangle.getLocation()); } if (!data.isEmpty()) { TableScrollingUtil.ensureSelectionExists(table); } table.setSize(dimension); // table.setPreferredSize(dimension); // table.setMaximumSize(dimension); // table.setPreferredScrollableViewportSize(dimension); Dimension footerSize = ((AbstractPopup) popup).getFooterPreferredSize(); int newHeight = (int) (dimension.height + headerSize.getHeight() + footerSize.getHeight()) + 4 /* invisible borders, margins etc*/; Dimension newDim = new Dimension(dimension.width, newHeight); window.setSize(newDim); window.setMinimumSize(newDim); window.setMaximumSize(newDim); window.validate(); window.repaint(); table.revalidate(); table.repaint(); }
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(); } }); }