private void showNode(@NotNull final UsageNode node) { if (!myPresentation.isDetachedMode()) { UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { if (isDisposed) return; TreePath usagePath = new TreePath(node.getPath()); myTree.expandPath(usagePath.getParentPath()); TreeUtil.selectPath(myTree, usagePath); } }); } }
public void setSearchInProgress(boolean searchInProgress) { mySearchInProgress = searchInProgress; if (!myPresentation.isDetachedMode()) { UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { if (isDisposed) return; final UsageNode firstUsageNode = myModel.getFirstUsageNode(); if (firstUsageNode != null) { showNode(firstUsageNode); } } }); } }
@Override public void removeUsage(@NotNull Usage usage) { final UsageNode node = myUsageNodes.remove(usage); if (node != NULL_NODE && node != null && !myPresentation.isDetachedMode()) { UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { if (isDisposed) return; TreeModel treeModel = myTree.getModel(); ((DefaultTreeModel) treeModel).removeNodeFromParent(node); ((GroupNode) myTree.getModel().getRoot()).removeUsage(node); } }); } }
private void showUsages(final UsageInfo[] usages) { UsageViewPresentation presentation = new UsageViewPresentation(); presentation.setTabText("Safe Delete Conflicts"); presentation.setTargetsNodeText( RefactoringBundle.message("attempting.to.delete.targets.node.text")); presentation.setShowReadOnlyStatusAsRed(true); presentation.setShowCancelButton(true); presentation.setCodeUsagesString(RefactoringBundle.message("references.found.in.code")); presentation.setUsagesInGeneratedCodeString( RefactoringBundle.message("references.found.in.generated.code")); presentation.setNonCodeUsagesString( RefactoringBundle.message("occurrences.found.in.comments.strings.and.non.java.files")); presentation.setUsagesString(RefactoringBundle.message("usageView.usagesText")); UsageViewManager manager = UsageViewManager.getInstance(myProject); final UsageView usageView = showUsages(usages, presentation, manager); usageView.addPerformOperationAction( new RerunSafeDelete(myProject, myElements, usageView), RefactoringBundle.message("retry.command"), null, RefactoringBundle.message("rerun.safe.delete")); usageView.addPerformOperationAction( () -> { UsageInfo[] preprocessedUsages = usages; for (SafeDeleteProcessorDelegate delegate : Extensions.getExtensions(SafeDeleteProcessorDelegate.EP_NAME)) { preprocessedUsages = delegate.preprocessUsages(myProject, preprocessedUsages); if (preprocessedUsages == null) return; } final UsageInfo[] filteredUsages = UsageViewUtil.removeDuplicatedUsages(preprocessedUsages); execute(filteredUsages); }, "Delete Anyway", RefactoringBundle.message("usageView.need.reRun"), RefactoringBundle.message("usageView.doAction")); }
private void reset() { ApplicationManager.getApplication().assertIsDispatchThread(); myUsageNodes.clear(); myIsFirstVisibleUsageFound = false; myModel.reset(); if (!myPresentation.isDetachedMode()) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { if (isDisposed) return; TreeUtil.expand(myTree, 2); } }); } }
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); }
public void searchAndShowUsages( @NotNull UsageViewManager manager, @NotNull Factory<UsageSearcher> usageSearcherFactory, @NotNull final FindModel findModelCopy, @NotNull UsageViewPresentation presentation, @NotNull FindUsagesProcessPresentation processPresentation, final FindManager findManager) { presentation.setMergeDupLinesAvailable(false); final ReplaceContext[] context = new ReplaceContext[1]; manager.searchAndShowUsages( new UsageTarget[] { new FindInProjectUtil.StringUsageTarget(myProject, findModelCopy.getStringToFind()) }, usageSearcherFactory, processPresentation, presentation, new UsageViewManager.UsageViewStateListener() { @Override public void usageViewCreated(@NotNull UsageView usageView) { context[0] = new ReplaceContext(usageView, findModelCopy); addReplaceActions(context[0]); } @Override public void findingUsagesFinished(final UsageView usageView) { if (context[0] != null && findManager.getFindInProjectModel().isPromptOnReplace()) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { replaceWithPrompt(context[0]); context[0].invalidateExcludedSetCache(); } }); } } }); }
@NotNull private static UsageViewPresentation createPresentation( @NotNull UsageViewDescriptor descriptor, @NotNull Usage[] usages) { UsageViewPresentation presentation = new UsageViewPresentation(); presentation.setTabText(RefactoringBundle.message("usageView.tabText")); presentation.setTargetsNodeText(descriptor.getProcessedElementsHeader()); presentation.setShowReadOnlyStatusAsRed(true); presentation.setShowCancelButton(true); presentation.setUsagesString(RefactoringBundle.message("usageView.usagesText")); int codeUsageCount = 0; int nonCodeUsageCount = 0; int dynamicUsagesCount = 0; Set<PsiFile> codeFiles = new HashSet<>(); Set<PsiFile> nonCodeFiles = new HashSet<>(); Set<PsiFile> dynamicUsagesCodeFiles = new HashSet<>(); for (Usage usage : usages) { if (usage instanceof PsiElementUsage) { final PsiElementUsage elementUsage = (PsiElementUsage) usage; final PsiElement element = elementUsage.getElement(); if (element == null) continue; final PsiFile containingFile = element.getContainingFile(); if (elementUsage.isNonCodeUsage()) { nonCodeUsageCount++; nonCodeFiles.add(containingFile); } else { codeUsageCount++; codeFiles.add(containingFile); } if (usage instanceof UsageInfo2UsageAdapter) { final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo(); if (usageInfo instanceof MoveRenameUsageInfo && usageInfo.isDynamicUsage()) { dynamicUsagesCount++; dynamicUsagesCodeFiles.add(containingFile); } } } } codeFiles.remove(null); nonCodeFiles.remove(null); dynamicUsagesCodeFiles.remove(null); String codeReferencesText = descriptor.getCodeReferencesText(codeUsageCount, codeFiles.size()); presentation.setCodeUsagesString(codeReferencesText); final String commentReferencesText = descriptor.getCommentReferencesText(nonCodeUsageCount, nonCodeFiles.size()); if (commentReferencesText != null) { presentation.setNonCodeUsagesString(commentReferencesText); } presentation.setDynamicUsagesString( "Dynamic " + StringUtil.decapitalize( descriptor.getCodeReferencesText( dynamicUsagesCount, dynamicUsagesCodeFiles.size()))); String generatedCodeString; if (codeReferencesText.contains("in code")) { generatedCodeString = StringUtil.replace(codeReferencesText, "in code", "in generated code"); } else { generatedCodeString = codeReferencesText + " in generated code"; } presentation.setUsagesInGeneratedCodeString(generatedCodeString); return presentation; }
@NotNull private JBPopup createUsagePopup( @NotNull final List<Usage> usages, @NotNull final UsageInfoToUsageConverter.TargetElementsDescriptor descriptor, @NotNull Set<UsageNode> visibleNodes, @NotNull final FindUsagesHandler handler, final Editor editor, @NotNull final RelativePoint popupPosition, final int maxUsages, @NotNull final UsageViewImpl usageView, @NotNull final FindUsagesOptions options, @NotNull final JTable table, @NotNull final UsageViewPresentation presentation, @NotNull final AsyncProcessIcon processIcon, boolean hadMoreSeparator) { table.setRowHeight(PlatformIcons.CLASS_ICON.getIconHeight() + 2); table.setShowGrid(false); table.setShowVerticalLines(false); table.setShowHorizontalLines(false); table.setTableHeader(null); table.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); table.setIntercellSpacing(new Dimension(0, 0)); PopupChooserBuilder builder = new PopupChooserBuilder(table); final String title = presentation.getTabText(); if (title != null) { String result = getFullTitle(usages, title, hadMoreSeparator, visibleNodes.size() - 1, true); builder.setTitle(result); builder.setAdText(getSecondInvocationTitle(options, handler)); } builder.setMovable(true).setResizable(true); builder.setItemChoosenCallback( new Runnable() { @Override public void run() { int[] selected = table.getSelectedRows(); for (int i : selected) { Object value = table.getValueAt(i, 0); if (value instanceof UsageNode) { Usage usage = ((UsageNode) value).getUsage(); if (usage == MORE_USAGES_SEPARATOR) { appendMoreUsages(editor, popupPosition, handler, maxUsages); return; } navigateAndHint(usage, null, handler, popupPosition, maxUsages, options); } } } }); final JBPopup[] popup = new JBPopup[1]; KeyboardShortcut shortcut = UsageViewImpl.getShowUsagesWithSettingsShortcut(); if (shortcut != null) { new DumbAwareAction() { @Override public void actionPerformed(AnActionEvent e) { popup[0].cancel(); showDialogAndFindUsages(handler, popupPosition, editor, maxUsages); } }.registerCustomShortcutSet(new CustomShortcutSet(shortcut.getFirstKeyStroke()), table); } shortcut = getShowUsagesShortcut(); if (shortcut != null) { new DumbAwareAction() { @Override public void actionPerformed(AnActionEvent e) { popup[0].cancel(); searchEverywhere(options, handler, editor, popupPosition, maxUsages); } }.registerCustomShortcutSet(new CustomShortcutSet(shortcut.getFirstKeyStroke()), table); } InplaceButton settingsButton = createSettingsButton( handler, popupPosition, editor, maxUsages, new Runnable() { @Override public void run() { popup[0].cancel(); } }); ActiveComponent spinningProgress = new ActiveComponent() { @Override public void setActive(boolean active) {} @Override public JComponent getComponent() { return processIcon; } }; builder.setCommandButton(new CompositeActiveComponent(spinningProgress, settingsButton)); DefaultActionGroup toolbar = new DefaultActionGroup(); usageView.addFilteringActions(toolbar); toolbar.add(UsageGroupingRuleProviderImpl.createGroupByFileStructureAction(usageView)); toolbar.add( new AnAction( "Open Find Usages Toolwindow", "Show all usages in a separate toolwindow", AllIcons.Toolwindows.ToolWindowFind) { { AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_FIND_USAGES); setShortcutSet(action.getShortcutSet()); } @Override public void actionPerformed(AnActionEvent e) { hideHints(); popup[0].cancel(); FindUsagesManager findUsagesManager = ((FindManagerImpl) FindManager.getInstance(usageView.getProject())) .getFindUsagesManager(); findUsagesManager.findUsages( handler.getPrimaryElements(), handler.getSecondaryElements(), handler, options, FindSettings.getInstance().isSkipResultsWithOneUsage()); } }); ActionToolbar actionToolbar = ActionManager.getInstance() .createActionToolbar(ActionPlaces.USAGE_VIEW_TOOLBAR, toolbar, true); actionToolbar.setReservePlaceAutoPopupIcon(false); final JComponent toolBar = actionToolbar.getComponent(); toolBar.setOpaque(false); builder.setSettingButton(toolBar); popup[0] = builder.createPopup(); JComponent content = popup[0].getContent(); myWidth = (int) (toolBar.getPreferredSize().getWidth() + new JLabel( getFullTitle( usages, title, hadMoreSeparator, visibleNodes.size() - 1, true)) .getPreferredSize() .getWidth() + settingsButton.getPreferredSize().getWidth()); myWidth = -1; for (AnAction action : toolbar.getChildren(null)) { action.unregisterCustomShortcutSet(usageView.getComponent()); action.registerCustomShortcutSet(action.getShortcutSet(), content); } return popup[0]; }
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(); } }); }
@Override public void addButtonToLowerPane(@NotNull Runnable runnable, @NotNull String text) { int index = myButtonPanel.getComponentCount(); if (index > 0 && myPresentation.isShowCancelButton()) index--; myButtonPanel.addButtonRunnable(index, runnable, text); }
public UsageViewImpl( @NotNull final Project project, @NotNull UsageViewPresentation presentation, @NotNull UsageTarget[] targets, Factory<UsageSearcher> usageSearcherFactory) { myPresentation = presentation; myTargets = targets; myUsageSearcherFactory = usageSearcherFactory; myProject = project; myTree = new Tree() { { ToolTipManager.sharedInstance().registerComponent(this); } @Override public String getToolTipText(MouseEvent e) { TreePath path = getPathForLocation(e.getX(), e.getY()); if (path != null) { if (getCellRenderer() instanceof UsageViewTreeCellRenderer) { return UsageViewTreeCellRenderer.getTooltipText(path.getLastPathComponent()); } } return null; } @Override public boolean isPathEditable(final TreePath path) { return path.getLastPathComponent() instanceof UsageViewTreeModelBuilder.TargetsRootNode; } }; myRootPanel = new MyPanel(myTree); Disposer.register(this, myRootPanel); myModelTracker = new UsageModelTracker(project); Disposer.register(this, myModelTracker); myModel = new UsageViewTreeModelBuilder(myPresentation, targets); myRoot = (GroupNode) myModel.getRoot(); myBuilder = new UsageNodeTreeBuilder( myTargets, getActiveGroupingRules(project), getActiveFilteringRules(project), myRoot); final MessageBusConnection messageBusConnection = myProject.getMessageBus().connect(this); messageBusConnection.subscribe( UsageFilteringRuleProvider.RULES_CHANGED, new Runnable() { @Override public void run() { rulesChanged(); } }); if (!myPresentation.isDetachedMode()) { UIUtil.invokeLaterIfNeeded( new Runnable() { @Override public void run() { // lock here to avoid concurrent execution of this init and dispose in other thread synchronized (lock) { if (isDisposed) return; myTree.setModel(myModel); myRootPanel.setLayout(new BorderLayout()); final SimpleToolWindowPanel twPanel = new SimpleToolWindowPanel(false, true); myRootPanel.add(twPanel, BorderLayout.CENTER); JPanel toolbarPanel = new JPanel(new BorderLayout()); toolbarPanel.add(createActionsToolbar(), BorderLayout.WEST); toolbarPanel.add(createFiltersToolbar(), BorderLayout.CENTER); twPanel.setToolbar(toolbarPanel); myCentralPanel = new JPanel(); myCentralPanel.setLayout(new BorderLayout()); setupCentralPanel(); initTree(); twPanel.setContent(myCentralPanel); myTree.setCellRenderer(new UsageViewTreeCellRenderer(UsageViewImpl.this)); collapseAll(); myModelTracker.addListener(UsageViewImpl.this); if (myPresentation.isShowCancelButton()) { addButtonToLowerPane( new Runnable() { @Override public void run() { close(); } }, UsageViewBundle.message("usage.view.cancel.button")); } myTree .getSelectionModel() .addTreeSelectionListener( new TreeSelectionListener() { @Override public void valueChanged(final TreeSelectionEvent e) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { if (isDisposed) return; List<UsageInfo> infos = getSelectedUsageInfos(); if (infos != null && myUsagePreviewPanel != null) { myUsagePreviewPanel.updateLayout(infos); } } }); } }); } } }); } myTransferToEDTQueue = new TransferToEDTQueue<Usage>( "Insert usages", new Processor<Usage>() { @Override public boolean process(Usage usage) { appendUsage(usage); return true; } }, new Condition<Object>() { @Override public boolean value(Object o) { return isDisposed || project.isDisposed() || com.intellij.usages.UsageViewManager.getInstance(project) .searchHasBeenCancelled(); } }, 200); }