diff options
Diffstat (limited to 'platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java')
-rw-r--r-- | platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java | 196 |
1 files changed, 114 insertions, 82 deletions
diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java index f84fed5a05d9..84776f4bf7ff 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesAction.java @@ -37,6 +37,7 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupChooserBuilder; @@ -50,7 +51,6 @@ import com.intellij.pom.Navigatable; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiElement; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.SearchScope; import com.intellij.ui.*; @@ -84,14 +84,17 @@ import java.awt.event.ActionListener; import java.util.*; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; public class ShowUsagesAction extends AnAction implements PopupAction { private final boolean showSettingsDialogBefore; private static final int USAGES_PAGE_SIZE = 100; - static final NullUsage MORE_USAGES_SEPARATOR = NullUsage.INSTANCE; + static final Usage MORE_USAGES_SEPARATOR = NullUsage.INSTANCE; private static final UsageNode MORE_USAGES_SEPARATOR_NODE = UsageViewImpl.NULL_NODE; + static final Usage USAGES_OUTSIDE_SCOPE_SEPARATOR = new UsageAdapter(); + private static final UsageNode USAGES_OUTSIDE_SCOPE_NODE = new UsageNode(USAGES_OUTSIDE_SCOPE_SEPARATOR, new UsageViewTreeModelBuilder(new UsageViewPresentation(), UsageTarget.EMPTY_ARRAY)); private static final Comparator<UsageNode> USAGE_NODE_COMPARATOR = new Comparator<UsageNode>() { @Override @@ -100,8 +103,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (c2 instanceof StringNode) return -1; Usage o1 = c1.getUsage(); Usage o2 = c2.getUsage(); - if (o1 == MORE_USAGES_SEPARATOR) return 1; - if (o2 == MORE_USAGES_SEPARATOR) return -1; + int weight1 = o1 == USAGES_OUTSIDE_SCOPE_SEPARATOR ? 2 : o1 == MORE_USAGES_SEPARATOR ? 1 : 0; + int weight2 = o2 == USAGES_OUTSIDE_SCOPE_SEPARATOR ? 2 : o2 == MORE_USAGES_SEPARATOR ? 1 : 0; + if (weight1 != weight2) return weight1 - weight2; VirtualFile v1 = UsageListCellRenderer.getVirtualFile(o1); VirtualFile v2 = UsageListCellRenderer.getVirtualFile(o2); @@ -193,26 +197,18 @@ public class ShowUsagesAction extends AnAction implements PopupAction { private void startFindUsages(@NotNull PsiElement element, @NotNull RelativePoint popupPosition, Editor editor, int maxUsages) { Project project = element.getProject(); FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(project)).getFindUsagesManager(); - FindUsagesHandler handler = findUsagesManager.getNewFindUsagesHandler(element, false); + FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false); if (handler == null) return; if (showSettingsDialogBefore) { showDialogAndFindUsages(handler, popupPosition, editor, maxUsages); return; } - showElementUsages(handler, editor, popupPosition, maxUsages, getDefaultOptions(handler)); + showElementUsages(editor, popupPosition, handler, maxUsages, handler.getFindUsagesOptions(DataManager.getInstance().getDataContext())); } - @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 = GlobalSearchScope.projectScope(handler.getProject()); - return options; - } - - private void showElementUsages(@NotNull final FindUsagesHandler handler, - final Editor editor, + private void showElementUsages(final Editor editor, @NotNull final RelativePoint popupPosition, + @NotNull final FindUsagesHandler handler, final int maxUsages, @NotNull final FindUsagesOptions options) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -236,30 +232,26 @@ public class ShowUsagesAction extends AnAction implements PopupAction { usageViewSettings.loadState(savedGlobalSettings); } }); + final AtomicInteger outOfScopeUsages = new AtomicInteger(); final List<Usage> usages = new ArrayList<Usage>(); final Set<UsageNode> visibleNodes = new LinkedHashSet<UsageNode>(); 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); + setTableModel(table, usageView, data, outOfScopeUsages, options.searchScope); SpeedSearchBase<JTable> speedSearch = new MySpeedSearch(table); speedSearch.setComparator(new SpeedSearchComparator(false)); final JBPopup popup = createUsagePopup(usages, visibleNodes, handler, editor, popupPosition, - maxUsages, usageView, options, table, presentation, processIcon, hadMoreSeparator); + maxUsages, usageView, options, table, presentation, processIcon); Disposer.register(popup, usageView); @@ -293,7 +285,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { copy = new ArrayList<Usage>(usages); } - rebuildPopup(usageView, copy, nodes, table, popup, presentation, popupPosition, !processIcon.isDisposed()); + rebuildPopup(usageView, copy, nodes, table, popup, presentation, popupPosition, !processIcon.isDisposed(), outOfScopeUsages, + options.searchScope); } }); @@ -305,11 +298,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } }); - + final UsageTarget[] myUsageTarget = {new PsiElement2UsageTargetAdapter(handler.getPsiElement())}; Processor<Usage> collect = new Processor<Usage>() { - private final UsageTarget[] myUsageTarget = {new PsiElement2UsageTargetAdapter(handler.getPsiElement())}; @Override public boolean process(@NotNull final Usage usage) { + if (!UsageViewManagerImpl.isInScope(usage, options.searchScope)) { + if (outOfScopeUsages.getAndIncrement() == 0) { + visibleNodes.add(USAGES_OUTSIDE_SCOPE_NODE); + usages.add(USAGES_OUTSIDE_SCOPE_SEPARATOR); + } + return true; + } synchronized (usages) { if (visibleNodes.size() >= maxUsages) return false; if(UsageViewManager.isSelfUsage(usage, myUsageTarget)) return true; @@ -352,8 +351,8 @@ public class ShowUsagesAction extends AnAction implements PopupAction { 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); + String text = UsageViewBundle.message("no.usages.found.in", searchScopePresentableName(options)); + hint(editor, text, handler, popupPosition, maxUsages, options, false); popup.cancel(); } else { @@ -364,8 +363,13 @@ public class ShowUsagesAction extends AnAction implements PopupAction { 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); + if (usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) { + hint(editor, UsageViewManagerImpl.outOfScopeMessage(outOfScopeUsages.get(), options.searchScope), handler, popupPosition, maxUsages, options, true); + } + else { + String message = UsageViewBundle.message("show.usages.only.usage", searchScopePresentableName(options)); + navigateAndHint(usage, message, handler, popupPosition, maxUsages, options); + } popup.cancel(); } else { @@ -373,7 +377,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { // 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)); + String hint = UsageViewBundle.message("all.usages.are.in.this.line", usages.size(), searchScopePresentableName(options)); navigateAndHint(visibleUsage, hint, handler, popupPosition, maxUsages, options); popup.cancel(); } @@ -451,21 +455,6 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } } - private void showHint(@NotNull String text, - @Nullable final Editor editor, - @NotNull final RelativePoint popupPosition, - @NotNull FindUsagesHandler handler, - int maxUsages, - @NotNull FindUsagesOptions options) { - JComponent label = createHintComponent(text, handler, popupPosition, editor, HIDE_HINTS_ACTION, maxUsages, options); - if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) { - HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY | - HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0); - } - else { - HintManager.getInstance().showInformationHint(editor, label); - } - } @NotNull private JComponent createHintComponent(@NotNull String text, @@ -474,8 +463,12 @@ public class ShowUsagesAction extends AnAction implements PopupAction { final Editor editor, @NotNull final Runnable cancelAction, final int maxUsages, - @NotNull final FindUsagesOptions options) { + @NotNull final FindUsagesOptions options, + boolean isWarning) { JComponent label = HintUtil.createInformationLabel(suggestSecondInvocation(options, handler, text + " ")); + if (isWarning) { + label.setBackground(MessageType.WARNING.getPopupBackground()); + } InplaceButton button = createSettingsButton(handler, popupPosition, editor, maxUsages, cancelAction); JPanel panel = new JPanel(new BorderLayout()) { @@ -540,19 +533,13 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (dialog.isOK()) { dialog.calcFindUsagesOptions(); FindUsagesOptions options = handler.getFindUsagesOptions(DataManager.getInstance().getDataContext()); - showElementUsages(handler, editor, popupPosition, maxUsages, options); + showElementUsages(editor, popupPosition, handler, maxUsages, options); } } - private static String searchScopePresentableName(@NotNull FindUsagesOptions options, @NotNull Project project) { - return notNullizeScope(options, project).getDisplayName(); - } - @NotNull - private static SearchScope notNullizeScope(@NotNull FindUsagesOptions options, @NotNull Project project) { - SearchScope scope = options.searchScope; - if (scope == null) return ProjectScope.getAllScope(project); - return scope; + private static String searchScopePresentableName(@NotNull FindUsagesOptions options) { + return options.searchScope.getDisplayName(); } @NotNull @@ -566,8 +553,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { @NotNull final FindUsagesOptions options, @NotNull final JTable table, @NotNull final UsageViewPresentation presentation, - @NotNull final AsyncProcessIcon processIcon, - boolean hadMoreSeparator) { + @NotNull final AsyncProcessIcon processIcon) { table.setRowHeight(PlatformIcons.CLASS_ICON.getIconHeight()+2); table.setShowGrid(false); table.setShowVerticalLines(false); @@ -579,14 +565,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { PopupChooserBuilder builder = new PopupChooserBuilder(table); final String title = presentation.getTabText(); if (title != null) { - String result = getFullTitle(usages, title, hadMoreSeparator, visibleNodes.size() - 1, true); + String result = getFullTitle(usages, title, false, visibleNodes.size() - 1, true); builder.setTitle(result); builder.setAdText(getSecondInvocationTitle(options, handler)); } builder.setMovable(true).setResizable(true); final AtomicReference<Object> selectedUsage = new AtomicReference<Object>(); - final AtomicBoolean moreUsages = new AtomicBoolean(); + final AtomicBoolean moreUsagesSelected = new AtomicBoolean(); + final AtomicBoolean outsideScopeUsagesSelected = new AtomicBoolean(); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { @@ -596,12 +583,17 @@ public class ShowUsagesAction extends AnAction implements PopupAction { Object value = table.getValueAt(i, 0); if (value instanceof UsageNode) { Usage usage = ((UsageNode)value).getUsage(); - if (usage == MORE_USAGES_SEPARATOR) { - moreUsages.set(true); + outsideScopeUsagesSelected.set(false); + moreUsagesSelected.set(false); + if (usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) { + outsideScopeUsagesSelected.set(true); + selectedUsage.set(null); + } + else if (usage == MORE_USAGES_SEPARATOR) { + moreUsagesSelected.set(true); selectedUsage.set(null); } else { - moreUsages.set(false); selectedUsage.set(usage instanceof UsageInfo2UsageAdapter ? ((UsageInfo2UsageAdapter)usage).getUsageInfo().copy() : usage); } break; @@ -613,10 +605,15 @@ public class ShowUsagesAction extends AnAction implements PopupAction { builder.setItemChoosenCallback(new Runnable() { @Override public void run() { - if (moreUsages.get()) { + if (moreUsagesSelected.get()) { appendMoreUsages(editor, popupPosition, handler, maxUsages, options); return; } + if (outsideScopeUsagesSelected.get()) { + options.searchScope = GlobalSearchScope.projectScope(handler.getProject()); + showElementUsages(editor, popupPosition, handler, maxUsages, options); + return; + } Object usage = selectedUsage.get(); if (usage instanceof UsageInfo) { UsageViewUtil.navigateTo((UsageInfo)usage, true); @@ -684,7 +681,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { JComponent content = popup[0].getContent(); myWidth = (int)(toolBar.getPreferredSize().getWidth() - + new JLabel(getFullTitle(usages, title, hadMoreSeparator, visibleNodes.size() - 1, true)).getPreferredSize().getWidth() + + new JLabel(getFullTitle(usages, title, false, visibleNodes.size() - 1, true)).getPreferredSize().getWidth() + settingsButton.getPreferredSize().getWidth()); myWidth = -1; for (AnAction action : toolbar.getChildren(null)) { @@ -770,7 +767,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { 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)) { + if (!options.searchScope.equals(maximalScope)) { return "Press " + KeymapUtil.getShortcutText(getShowUsagesShortcut()) + " again to search in " + maximalScope.getDisplayName(); } } @@ -784,7 +781,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { int maxUsages) { FindUsagesOptions cloned = options.clone(); cloned.searchScope = FindUsagesManager.getMaximalScope(handler); - showElementUsages(handler, editor, popupPosition, maxUsages, cloned); + showElementUsages(editor, popupPosition, handler, maxUsages, cloned); } @Nullable @@ -827,7 +824,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { @NotNull private static MyModel setTableModel(@NotNull JTable table, @NotNull UsageViewImpl usageView, - @NotNull final List<UsageNode> data) { + @NotNull final List<UsageNode> data, + @NotNull AtomicInteger outOfScopeUsages, + @NotNull SearchScope searchScope) { ApplicationManager.getApplication().assertIsDispatchThread(); final int columnCount = calcColumnCount(data); MyModel model = table.getModel() instanceof MyModel ? (MyModel)table.getModel() : null; @@ -835,7 +834,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { model = new MyModel(data, columnCount); table.setModel(model); - ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(usageView); + ShowUsagesTableCellRenderer renderer = new ShowUsagesTableCellRenderer(usageView, outOfScopeUsages, searchScope); for (int i=0;i<table.getColumnModel().getColumnCount();i++) { TableColumn column = table.getColumnModel().getColumn(i); column.setCellRenderer(renderer); @@ -908,21 +907,27 @@ public class ShowUsagesAction extends AnAction implements PopupAction { @NotNull final JBPopup popup, @NotNull final UsageViewPresentation presentation, @NotNull final RelativePoint popupPosition, - boolean findUsagesInProgress) { + boolean findUsagesInProgress, + @NotNull AtomicInteger outOfScopeUsages, + @NotNull SearchScope searchScope) { ApplicationManager.getApplication().assertIsDispatchThread(); boolean shouldShowMoreSeparator = usages.contains(MORE_USAGES_SEPARATOR); if (shouldShowMoreSeparator) { nodes.add(MORE_USAGES_SEPARATOR_NODE); } + boolean hasOutsideScopeUsages = usages.contains(USAGES_OUTSIDE_SCOPE_SEPARATOR); + if (hasOutsideScopeUsages && !shouldShowMoreSeparator) { + nodes.add(USAGES_OUTSIDE_SCOPE_NODE); + } String title = presentation.getTabText(); - String fullTitle = getFullTitle(usages, title, shouldShowMoreSeparator, nodes.size() - (shouldShowMoreSeparator ? 1 : 0), findUsagesInProgress); + String fullTitle = getFullTitle(usages, title, shouldShowMoreSeparator || hasOutsideScopeUsages, nodes.size() - (shouldShowMoreSeparator || hasOutsideScopeUsages ? 1 : 0), findUsagesInProgress); ((AbstractPopup)popup).setCaption(fullTitle); List<UsageNode> data = collectData(usages, nodes, usageView, presentation); - MyModel tableModel = setTableModel(table, usageView, data); + MyModel tableModel = setTableModel(table, usageView, data, outOfScopeUsages, searchScope); List<UsageNode> existingData = tableModel.getItems(); int row = table.getSelectedRow(); @@ -1021,8 +1026,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { private void appendMoreUsages(Editor editor, @NotNull RelativePoint popupPosition, @NotNull FindUsagesHandler handler, - int maxUsages, final FindUsagesOptions options) { - showElementUsages(handler, editor, popupPosition, maxUsages+USAGES_PAGE_SIZE, options); + int maxUsages, + @NotNull FindUsagesOptions options) { + showElementUsages(editor, popupPosition, handler, maxUsages+USAGES_PAGE_SIZE, options); } private static void addUsageNodes(@NotNull GroupNode root, @NotNull final UsageViewImpl usageView, @NotNull List<UsageNode> outNodes) { @@ -1054,25 +1060,51 @@ public class ShowUsagesAction extends AnAction implements PopupAction { if (hint == null) return; final Editor newEditor = getEditorFor(usage); if (newEditor == null) return; + hint(newEditor, hint, handler, popupPosition, maxUsages, options, false); + } + + private void showHint(@Nullable final Editor editor, + @NotNull String hint, + @NotNull FindUsagesHandler handler, + @NotNull final RelativePoint popupPosition, + int maxUsages, + @NotNull FindUsagesOptions options, + boolean isWarning) { + JComponent label = createHintComponent(hint, handler, popupPosition, editor, HIDE_HINTS_ACTION, maxUsages, options, isWarning); + if (editor == null || editor.isDisposed() || !editor.getComponent().isShowing()) { + HintManager.getInstance().showHint(label, popupPosition, HintManager.HIDE_BY_ANY_KEY | + HintManager.HIDE_BY_TEXT_CHANGE | HintManager.HIDE_BY_SCROLLING, 0); + } + else { + HintManager.getInstance().showInformationHint(editor, label); + } + } + + private void hint(@Nullable final Editor editor, + @NotNull final String hint, + @NotNull final FindUsagesHandler handler, + @NotNull final RelativePoint popupPosition, + final int maxUsages, + @NotNull final FindUsagesOptions options, + final boolean isWarning) { 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() { + Runnable runnable = 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); - } + showHint(editor, hint, handler, popupPosition, maxUsages, options, isWarning); } }); } - }); + }; + if (editor == null) runnable.run(); else editor.getScrollingModel().runActionOnScrollingFinished(runnable); } }); } @@ -1119,9 +1151,9 @@ public class ShowUsagesAction extends AnAction implements PopupAction { } static class StringNode extends UsageNode { - private final Object myString; + @NotNull private final Object myString; - public StringNode(Object string) { + public StringNode(@NotNull Object string) { super(NullUsage.INSTANCE, new UsageViewTreeModelBuilder(new UsageViewPresentation(), UsageTarget.EMPTY_ARRAY)); myString = string; } @@ -1159,7 +1191,7 @@ public class ShowUsagesAction extends AnAction implements PopupAction { UsageNode node = (UsageNode)element; if (node instanceof StringNode) return ""; Usage usage = node.getUsage(); - if (usage == MORE_USAGES_SEPARATOR) return ""; + if (usage == MORE_USAGES_SEPARATOR || usage == USAGES_OUTSIDE_SCOPE_SEPARATOR) return ""; GroupNode group = (GroupNode)node.getParent(); return usage.getPresentation().getPlainText() + group; } |