diff --git a/platform/lang-api/src/com/intellij/find/FindManager.java b/platform/lang-api/src/com/intellij/find/FindManager.java index 102872655dca..56339d116e14 100644 --- a/platform/lang-api/src/com/intellij/find/FindManager.java +++ b/platform/lang-api/src/com/intellij/find/FindManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.search.SearchScope; import com.intellij.util.messages.Topic; import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NotNull; @@ -217,6 +218,7 @@ public abstract class FindManager { * @param element the element to find the usages for. */ public abstract void findUsages(@NotNull PsiElement element); + public abstract void findUsagesInScope(@NotNull PsiElement element, @NotNull SearchScope searchScope); /** * Shows the Find Usages dialog (if {@code showDialog} is true} and performs the Find Usages operation for the 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 USAGE_NODE_COMPARATOR = new Comparator() { @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 usages = new ArrayList(); final Set visibleNodes = new LinkedHashSet(); 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()); TableScrollingUtil.installActions(table); final List data = collectData(usages, visibleNodes, usageView, presentation); - setTableModel(table, usageView, data); + setTableModel(table, usageView, data, outOfScopeUsages, options.searchScope); SpeedSearchBase 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(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 collect = new Processor() { - 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 selectedUsage = new AtomicReference(); - 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 data) { + @NotNull final List 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 data = collectData(usages, nodes, usageView, presentation); - MyModel tableModel = setTableModel(table, usageView, data); + MyModel tableModel = setTableModel(table, usageView, data, outOfScopeUsages, searchScope); List 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 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; } diff --git a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java index 7603bab35b7b..d9848fdec4b0 100644 --- a/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/find/actions/ShowUsagesTableCellRenderer.java @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; +import com.intellij.psi.search.SearchScope; import com.intellij.ui.FileColorManager; import com.intellij.ui.SimpleColoredComponent; import com.intellij.ui.SimpleTextAttributes; @@ -30,24 +31,30 @@ import com.intellij.usages.UsagePresentation; import com.intellij.usages.impl.GroupNode; import com.intellij.usages.impl.UsageNode; import com.intellij.usages.impl.UsageViewImpl; +import com.intellij.usages.impl.UsageViewManagerImpl; import com.intellij.usages.rules.UsageInFile; import com.intellij.util.ui.EmptyIcon; import com.intellij.util.ui.UIUtil; -import com.intellij.xml.util.XmlStringUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; import java.awt.*; +import java.util.concurrent.atomic.AtomicInteger; /** * @author cdr */ class ShowUsagesTableCellRenderer implements TableCellRenderer { private final UsageViewImpl myUsageView; + @NotNull private final AtomicInteger myOutOfScopeUsages; + @NotNull private final SearchScope mySearchScope; - ShowUsagesTableCellRenderer(@NotNull UsageViewImpl usageView) { + ShowUsagesTableCellRenderer(@NotNull UsageViewImpl usageView, @NotNull AtomicInteger outOfScopeUsages, @NotNull SearchScope searchScope) { myUsageView = usageView; + myOutOfScopeUsages = outOfScopeUsages; + mySearchScope = searchScope; } @Override @@ -60,32 +67,37 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer { Color fileBgColor = getBackgroundColor(isSelected, usage); final Color bg = UIUtil.getListSelectionBackground(); final Color fg = UIUtil.getListSelectionForeground(); - panel.setBackground(isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor); - panel.setForeground(isSelected ? fg : list.getForeground()); - - if (usage == null || usageNode instanceof ShowUsagesAction.StringNode) { - panel.setLayout(new BorderLayout()); - if (column == 0) { - panel.add(new JLabel(XmlStringUtil.wrapInHtml("" + value + ""), SwingConstants.CENTER)); - } - return panel; - } - + Color panelBackground = isSelected ? bg : fileBgColor == null ? list.getBackground() : fileBgColor; + Color panelForeground = isSelected ? fg : list.getForeground(); + panel.setBackground(panelBackground); + panel.setForeground(panelForeground); SimpleColoredComponent textChunks = new SimpleColoredComponent(); - textChunks.setIpad(new Insets(0,0,0,0)); + textChunks.setIpad(new Insets(0, 0, 0, 0)); textChunks.setBorder(null); + if (usage == null || usageNode instanceof ShowUsagesAction.StringNode) { + textChunks.append(value.toString(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) { + textChunks.append("...<"); + textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + textChunks.append(">..."); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + else if (usage == ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) { + textChunks.append("...<"); + textChunks.append(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); + textChunks.append(">..."); + return textComponentSpanningWholeRow(textChunks, panelBackground, panelForeground, column, list, row); + } + if (column == 0) { GroupNode parent = (GroupNode)usageNode.getParent(); appendGroupText(parent, panel, fileBgColor); - if (usage == ShowUsagesAction.MORE_USAGES_SEPARATOR) { - textChunks.append("...<"); - textChunks.append("more usages", SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES); - textChunks.append(">..."); - } } - else if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR) { + else if (usage != ShowUsagesAction.MORE_USAGES_SEPARATOR && usage != ShowUsagesAction.USAGES_OUTSIDE_SCOPE_SEPARATOR) { UsagePresentation presentation = usage.getPresentation(); TextChunk[] text = presentation.getText(); @@ -116,6 +128,59 @@ class ShowUsagesTableCellRenderer implements TableCellRenderer { return panel; } + @NotNull + private static Component textComponentSpanningWholeRow(@NotNull SimpleColoredComponent chunks, + Color panelBackground, + Color panelForeground, + final int column, + @NotNull final JTable table, int row) { + final SimpleColoredComponent component = new SimpleColoredComponent() { + @Override + protected void doPaint(Graphics2D g) { + int offset = 0; + int i = 0; + final TableColumnModel columnModel = table.getColumnModel(); + while (i < column) { + offset += columnModel.getColumn(i).getWidth(); + i++; + } + g.translate(-offset, 0); + + //if (column == columnModel.getColumnCount()-1) { + //} + setSize(getWidth()+offset, getHeight()); // should increase the column width so that selection background will be visible even after offset translation + + super.doPaint(g); + + g.translate(+offset, 0); + } + + @NotNull + @Override + public Dimension getPreferredSize() { + //return super.getPreferredSize(); + return column == table.getColumnModel().getColumnCount()-1 ? super.getPreferredSize() : new Dimension(0,0); + // it should span the whole row, so we can't return any specific value here, + // because otherwise it would be used in the "max width" calculation in com.intellij.find.actions.ShowUsagesAction.calcMaxWidth + } + }; + + component.setIpad(new Insets(0,0,0,0)); + component.setBorder(null); + component.setBackground(panelBackground); + component.setForeground(panelForeground); + + for (SimpleColoredComponent.ColoredIterator iterator = chunks.iterator(); iterator.hasNext(); ) { + iterator.next(); + String fragment = iterator.getFragment(); + SimpleTextAttributes attributes = iterator.getTextAttributes(); + attributes = attributes.derive(attributes.getStyle(), panelForeground, panelBackground, attributes.getWaveColor()); + component.append(fragment, attributes); + } + + return component; + } + private static SimpleTextAttributes deriveAttributesWithColor(SimpleTextAttributes attributes, Color fileBgColor) { if (fileBgColor != null) { attributes = attributes.derive(-1,null, fileBgColor,null); diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java index 6e6765594e22..d3978780e535 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesManager.java @@ -205,8 +205,8 @@ public class FindUsagesManager implements JDOMExternalizable { return null; } - public void findUsages(@NotNull PsiElement psiElement, final PsiFile scopeFile, final FileEditor editor, boolean showDialog) { - FindUsagesHandler handler = getNewFindUsagesHandler(psiElement, false); + public void findUsages(@NotNull PsiElement psiElement, final PsiFile scopeFile, final FileEditor editor, boolean showDialog, @Nullable("null means default (stored in options)") SearchScope searchScope) { + FindUsagesHandler handler = getFindUsagesHandler(psiElement, false); if (handler == null) return; boolean singleFile = scopeFile != null; @@ -222,8 +222,8 @@ public class FindUsagesManager implements JDOMExternalizable { setOpenInNewTab(dialog.isShowInSeparateWindow()); FindUsagesOptions findUsagesOptions = dialog.calcFindUsagesOptions(); - if (!showDialog) { - findUsagesOptions.searchScope = GlobalSearchScope.projectScope(myProject); + if (searchScope != null) { + findUsagesOptions.searchScope = searchScope; } clearFindingNextUsageInFile(); @@ -235,7 +235,7 @@ public class FindUsagesManager implements JDOMExternalizable { @NotNull FindUsagesOptions findUsagesOptions, PsiFile scopeFile, FileEditor editor) { - FindUsagesHandler handler = getNewFindUsagesHandler(psiElement, false); + FindUsagesHandler handler = getFindUsagesHandler(psiElement, false); if (handler == null) return; startFindUsages(findUsagesOptions, handler, scopeFile, editor); } @@ -262,7 +262,7 @@ public class FindUsagesManager implements JDOMExternalizable { } } - public void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { + public static void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { if (targets.length == 0) return; NavigationItem target = targets[0]; if (!(target instanceof ConfigurableUsageTarget)) return; @@ -368,9 +368,10 @@ public class FindUsagesManager implements JDOMExternalizable { final Iterable elements = ContainerUtil.concat(primaryElements, secondaryElements); optionsClone.fastTrack = new SearchRequestCollector(new SearchSession()); - //if (optionsClone.searchScope instanceof GlobalSearchScope) { - // optionsClone.searchScope = optionsClone.searchScope.union(GlobalSearchScope.projectScope(project)); - //} + if (optionsClone.searchScope instanceof GlobalSearchScope) { + // we will search in project scope always but warn if some usage is out of scope + optionsClone.searchScope = optionsClone.searchScope.union(GlobalSearchScope.projectScope(project)); + } try { for (final PsiElement element : elements) { ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -437,14 +438,14 @@ public class FindUsagesManager implements JDOMExternalizable { throw new AssertionError(handler + " " + findUsagesOptions); } Iterable allElements = ContainerUtil.concat(primaryElements, secondaryElements); - final UsageTarget[] targets = convertToUsageTargets(allElements, findUsagesOptions); + final PsiElement2UsageTargetAdapter[] targets = convertToUsageTargets(allElements, findUsagesOptions); myAnotherManager.searchAndShowUsages(targets, new Factory() { @Override public UsageSearcher create() { return createUsageSearcher(primaryElements, secondaryElements, handler, findUsagesOptions, null); } }, !toSkipUsagePanelWhenOneUsage, true, createPresentation(primaryElements[0], findUsagesOptions, shouldOpenInNewTab()), null); - myHistory.add((ConfigurableUsageTarget)targets[0]); + myHistory.add(targets[0]); } private static void dropResolveCacheRegularly(ProgressIndicator indicator, @NotNull final Project project) { diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java index a05332d283c4..5e4c59dfd572 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetAdapter.java @@ -40,7 +40,6 @@ import com.intellij.psi.meta.PsiMetaData; import com.intellij.psi.meta.PsiMetaOwner; import com.intellij.psi.meta.PsiPresentableMetaData; import com.intellij.psi.search.LocalSearchScope; -import com.intellij.psi.search.ProjectScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.ui.ComputableIcon; @@ -219,18 +218,16 @@ public class PsiElement2UsageTargetAdapter return psiElement == null ? UsageViewBundle.message("node.invalid") : FindBundle.message("recent.find.usages.action.popup", StringUtil.capitalize(UsageViewUtil.getType(psiElement)), DescriptiveNameUtil.getDescriptiveName(psiElement), - scopeString == null - ? ProjectScope.getAllScope(psiElement.getProject()).getDisplayName() - : scopeString + scopeString ); } @Override public void showSettings() { - FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(myPointer.getProject())).getFindUsagesManager(); PsiElement element = getElement(); if (element != null) { - findUsagesManager.findUsages(element, null, null, true); + FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(myPointer.getProject())).getFindUsagesManager(); + findUsagesManager.findUsages(element, null, null, true, null); } } diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java index a16050a08b07..a44208095e02 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/PsiElement2UsageTargetComposite.java @@ -43,7 +43,7 @@ public class PsiElement2UsageTargetComposite extends PsiElement2UsageTargetAdapt PsiElement element = getElement(); if (element == null) return; FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(element.getProject())).getFindUsagesManager(); - FindUsagesHandler handler = findUsagesManager.getNewFindUsagesHandler(element, false); + FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, false); boolean skipResultsWithOneUsage = FindSettings.getInstance().isSkipResultsWithOneUsage(); findUsagesManager.findUsages(myDescriptor.getPrimaryElements(), myDescriptor.getAdditionalElements(), handler, myOptions, skipResultsWithOneUsage); } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index 6400db8c43db..e327ec79c227 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -59,6 +59,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.search.LexerEditorHighlighterLexer; +import com.intellij.psi.search.SearchScope; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.ui.LightweightHint; @@ -859,14 +860,19 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo findUsages(element, false); } + @Override + public void findUsagesInScope(@NotNull PsiElement element, @NotNull SearchScope searchScope) { + myFindUsagesManager.findUsages(element, null, null, false, searchScope); + } + @Override public void findUsages(@NotNull PsiElement element, boolean showDialog) { - myFindUsagesManager.findUsages(element, null, null, showDialog); + myFindUsagesManager.findUsages(element, null, null, showDialog, null); } @Override public void showSettingsAndFindUsages(@NotNull NavigationItem[] targets) { - myFindUsagesManager.showSettingsAndFindUsages(targets); + FindUsagesManager.showSettingsAndFindUsages(targets); } @Override @@ -882,7 +888,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo Document document = editor.getDocument(); PsiFile psiFile = PsiDocumentManager.getInstance(myProject).getPsiFile(document); - myFindUsagesManager.findUsages(element, psiFile, fileEditor, false); + myFindUsagesManager.findUsages(element, psiFile, fileEditor, false, null); } } diff --git a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java new file mode 100644 index 000000000000..8b065b30d167 --- /dev/null +++ b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java @@ -0,0 +1,478 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.usages.impl; + +import com.intellij.find.FindManager; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.util.ProgressWrapper; +import com.intellij.openapi.progress.util.TooManyUsagesStatus; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.popup.Balloon; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Segment; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.ToolWindowId; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.SearchScope; +import com.intellij.ui.HyperlinkAdapter; +import com.intellij.usageView.UsageViewBundle; +import com.intellij.usages.*; +import com.intellij.util.Alarm; +import com.intellij.util.ArrayUtil; +import com.intellij.util.CommonProcessors; +import com.intellij.util.Processor; +import com.intellij.util.ui.RangeBlinker; +import com.intellij.xml.util.XmlStringUtil; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import java.awt.event.ActionEvent; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +class SearchForUsagesRunnable implements Runnable { + @NonNls private static final String FIND_OPTIONS_HREF_TARGET = "FindOptions"; + @NonNls private static final String SEARCH_IN_PROJECT_HREF_TARGET = "SearchInProject"; + @NonNls private static final String LARGE_FILES_HREF_TARGET = "LargeFiles"; + private final AtomicInteger myUsageCountWithoutDefinition = new AtomicInteger(0); + private final AtomicReference myFirstUsage = new AtomicReference(); + @NotNull + private final Project myProject; + private final AtomicReference myUsageViewRef; + private final UsageViewPresentation myPresentation; + private final UsageTarget[] mySearchFor; + private final Factory mySearcherFactory; + private final FindUsagesProcessPresentation myProcessPresentation; + @NotNull private final SearchScope mySearchScope; + private final UsageViewManager.UsageViewStateListener myListener; + private final UsageViewManagerImpl myUsageViewManager; + private final AtomicInteger myOutOfScopeUsages = new AtomicInteger(); + + SearchForUsagesRunnable(@NotNull UsageViewManagerImpl usageViewManager, + @NotNull Project project, + @NotNull AtomicReference usageViewRef, + @NotNull UsageViewPresentation presentation, + @NotNull UsageTarget[] searchFor, + @NotNull Factory searcherFactory, + @NotNull FindUsagesProcessPresentation processPresentation, + @NotNull SearchScope scope, + @Nullable UsageViewManager.UsageViewStateListener listener) { + myProject = project; + myUsageViewRef = usageViewRef; + myPresentation = presentation; + mySearchFor = searchFor; + mySearcherFactory = searcherFactory; + myProcessPresentation = processPresentation; + mySearchScope = scope; + myListener = listener; + myUsageViewManager = usageViewManager; + } + + @NotNull + private static String createOptionsHtml(@NonNls UsageTarget[] searchFor) { + KeyboardShortcut shortcut = UsageViewImpl.getShowUsagesWithSettingsShortcut(searchFor); + String shortcutText = ""; + if (shortcut != null) { + shortcutText = " (" + KeymapUtil.getShortcutText(shortcut) + ")"; + } + return "Find Options..." + shortcutText; + } + + @NotNull + private static String createSearchInProjectHtml() { + return "Search in Project"; + } + + private static void notifyByFindBalloon(final HyperlinkListener listener, + @NotNull final MessageType info, + @NotNull FindUsagesProcessPresentation processPresentation, + @NotNull final Project project, + @NotNull final List lines) { + com.intellij.usageView.UsageViewManager.getInstance(project); // in case tool window not registered + + final Collection largeFiles = processPresentation.getLargeFiles(); + List resultLines = new ArrayList(lines); + HyperlinkListener resultListener = listener; + if (!largeFiles.isEmpty()) { + String shortMessage = "(" + + UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + ")"; + + resultLines.add(shortMessage); + resultListener = new HyperlinkAdapter(){ + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(LARGE_FILES_HREF_TARGET)) { + String detailedMessage = detailedLargeFilesMessage(largeFiles); + List strings = new ArrayList(lines); + strings.add(detailedMessage); + ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener); + } + else if (listener != null) { + listener.hyperlinkUpdate(e); + } + } + }; + } + + ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(resultLines), AllIcons.Actions.Find, resultListener); + } + + @NotNull + private static String wrapInHtml(@NotNull List strings) { + return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "
")); + } + + @NotNull + private static String detailedLargeFilesMessage(@NotNull Collection largeFiles) { + String message = ""; + if (largeFiles.size() == 1) { + final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile(); + message += "File " + presentableFileInfo(vFile) + " is "; + } + else { + message += "Files
"; + + int counter = 0; + for (PsiFile file : largeFiles) { + final VirtualFile vFile = file.getVirtualFile(); + message += presentableFileInfo(vFile) + "
"; + if (counter++ > 10) break; + } + + message += "are "; + } + + message += "too large and cannot be scanned"; + return message; + } + + @NotNull + private static String presentableFileInfo(@NotNull VirtualFile vFile) { + return getPresentablePath(vFile) + + " (" + + UsageViewManagerImpl.presentableSize(UsageViewManagerImpl.getFileLength(vFile)) + + ")"; + } + + @NotNull + private static String getPresentablePath(@NotNull final VirtualFile virtualFile) { + return "'" + ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public String compute() { + return virtualFile.getPresentableUrl(); + } + }) + "'"; + } + + @NotNull + private HyperlinkListener createGotToOptionsListener(@NotNull final UsageTarget[] targets) { + return new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(FIND_OPTIONS_HREF_TARGET)) { + FindManager.getInstance(myProject).showSettingsAndFindUsages(targets); + } + } + }; + } + @NotNull + private HyperlinkListener createSearchInProjectListener() { + return new HyperlinkAdapter() { + @Override + protected void hyperlinkActivated(HyperlinkEvent e) { + if (e.getDescription().equals(SEARCH_IN_PROJECT_HREF_TARGET)) { + PsiElement psiElement = getPsiElement(mySearchFor); + if (psiElement != null) { + FindManager.getInstance(myProject).findUsagesInScope(psiElement, GlobalSearchScope.projectScope(myProject)); + } + } + } + }; + } + + private static PsiElement getPsiElement(UsageTarget[] searchFor) { + if (!(searchFor[0] instanceof PsiElementUsageTarget)) return null; + return ((PsiElementUsageTarget)searchFor[0]).getElement(); + } + + private static void flashUsageScriptaculously(@NotNull final Usage usage) { + if (!(usage instanceof UsageInfo2UsageAdapter)) { + return; + } + UsageInfo2UsageAdapter usageInfo = (UsageInfo2UsageAdapter)usage; + + Editor editor = usageInfo.openTextEditor(true); + if (editor == null) return; + TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES); + + RangeBlinker rangeBlinker = new RangeBlinker(editor, attributes, 6); + List segments = new ArrayList(); + CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(segments); + usageInfo.processRangeMarkers(processor); + rangeBlinker.resetMarkers(segments); + rangeBlinker.startBlinking(); + } + + private UsageViewImpl getUsageView(ProgressIndicator indicator) { + UsageViewImpl usageView = myUsageViewRef.get(); + if (usageView != null) return usageView; + int usageCount = myUsageCountWithoutDefinition.get(); + if (usageCount >= 2 || usageCount == 1 && myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + usageView = new UsageViewImpl(myProject, myPresentation, mySearchFor, mySearcherFactory); + usageView.associateProgress(indicator); + if (myUsageViewRef.compareAndSet(null, usageView)) { + openView(usageView); + final Usage firstUsage = myFirstUsage.get(); + if (firstUsage != null) { + final UsageViewImpl finalUsageView = usageView; + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + finalUsageView.appendUsage(firstUsage); + } + }); + } + } + else { + Disposer.dispose(usageView); + } + return myUsageViewRef.get(); + } + return null; + } + + private void openView(@NotNull final UsageViewImpl usageView) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (myProject.isDisposed()) return; + myUsageViewManager.addContent(usageView, myPresentation); + if (myListener != null) { + myListener.usageViewCreated(usageView); + } + myUsageViewManager.showToolWindow(false); + } + }); + } + + @Override + public void run() { + AtomicBoolean findUsagesStartedShown = new AtomicBoolean(); + searchUsages(findUsagesStartedShown); + endSearchForUsages(findUsagesStartedShown); + } + + private void searchUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { + ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); + TooManyUsagesStatus.createFor(indicator); + Alarm findUsagesStartedBalloon = new Alarm(); + findUsagesStartedBalloon.addRequest(new Runnable() { + @Override + public void run() { + notifyByFindBalloon(null, MessageType.WARNING, myProcessPresentation, myProject, + Collections.singletonList(UsageViewManagerImpl.getProgressTitle(myPresentation))); + findStartedBalloonShown.set(true); + } + }, 300, ModalityState.NON_MODAL); + UsageSearcher usageSearcher = mySearcherFactory.create(); + + usageSearcher.generate(new Processor() { + @Override + public boolean process(final Usage usage) { + ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); + if (indicator != null && indicator.isCanceled()) return false; + + if (!UsageViewManagerImpl.isInScope(usage, mySearchScope)) { + myOutOfScopeUsages.incrementAndGet(); + return true; + } + + boolean incrementCounter = !UsageViewManager.isSelfUsage(usage, mySearchFor); + + if (incrementCounter) { + final int usageCount = myUsageCountWithoutDefinition.incrementAndGet(); + if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + myFirstUsage.compareAndSet(null, usage); + } + + final UsageViewImpl usageView = getUsageView(indicator); + + TooManyUsagesStatus tooManyUsagesStatus; + if (usageCount > UsageLimitUtil.USAGES_LIMIT && (tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator)).switchTooManyUsagesStatus()) { + UsageViewManagerImpl.showTooManyUsagesWarning(myProject, tooManyUsagesStatus, indicator, myPresentation, usageCount, usageView); + } + + if (usageView != null) { + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + usageView.appendUsage(usage); + } + }); + } + } + return indicator == null || !indicator.isCanceled(); + } + }); + if (getUsageView(indicator) != null) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myUsageViewManager.showToolWindow(true); + } + }, myProject.getDisposed()); + } + Disposer.dispose(findUsagesStartedBalloon); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (findStartedBalloonShown.get()) { + Balloon balloon = ToolWindowManager.getInstance(myProject).getToolWindowBalloon(ToolWindowId.FIND); + if (balloon != null) { + balloon.hide(); + } + } + } + }, myProject.getDisposed()); + } + + private void endSearchForUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { + assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread(); + int usageCount = myUsageCountWithoutDefinition.get(); + if (usageCount == 0 && myProcessPresentation.isShowNotFoundMessage()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + final List notFoundActions = myProcessPresentation.getNotFoundActions(); + final String message = UsageViewBundle.message("dialog.no.usages.found.in", + StringUtil.decapitalize(myPresentation.getUsagesString()), + myPresentation.getScopeText()); + + if (notFoundActions.isEmpty()) { + List lines = new ArrayList(); + lines.add(StringUtil.escapeXml(message)); + if (myOutOfScopeUsages.get() != 0) { + lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope)); + } + if (myProcessPresentation.isShowFindOptionsPrompt()) { + lines.add(createOptionsHtml(mySearchFor)); + } + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(createGotToOptionsListener(mySearchFor), + type, myProcessPresentation, myProject, lines); + findStartedBalloonShown.set(false); + } + else { + List titles = new ArrayList(notFoundActions.size() + 1); + titles.add(UsageViewBundle.message("dialog.button.ok")); + for (Action action : notFoundActions) { + Object value = action.getValue(FindUsagesProcessPresentation.NAME_WITH_MNEMONIC_KEY); + if (value == null) value = action.getValue(Action.NAME); + + titles.add((String)value); + } + + int option = Messages.showDialog(myProject, message, UsageViewBundle.message("dialog.title.information"), + ArrayUtil.toStringArray(titles), 0, Messages.getInformationIcon()); + + if (option > 0) { + notFoundActions.get(option - 1).actionPerformed(new ActionEvent(this, 0, titles.get(option))); + } + } + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + else if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + Usage usage = myFirstUsage.get(); + if (usage.canNavigate()) { + usage.navigate(true); + flashUsageScriptaculously(usage); + } + List lines = new ArrayList(); + + lines.add("Only one usage found."); + if (myOutOfScopeUsages.get() != 0) { + lines.add(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope)); + } + lines.add(createOptionsHtml(mySearchFor)); + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(createGotToOptionsListener(mySearchFor), + type, myProcessPresentation, myProject, + lines); + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + else { + final UsageViewImpl usageView = myUsageViewRef.get(); + if (usageView != null) { + usageView.drainQueuedUsageNodes(); + usageView.setSearchInProgress(false); + } + + final List lines; + final HyperlinkListener hyperlinkListener; + if (myOutOfScopeUsages.get() == 0 || getPsiElement(mySearchFor)==null) { + lines = Collections.emptyList(); + hyperlinkListener = null; + } + else { + lines = Arrays.asList(UsageViewManagerImpl.outOfScopeMessage(myOutOfScopeUsages.get(), mySearchScope), createSearchInProjectHtml()); + hyperlinkListener = createSearchInProjectListener(); + } + + if (!myProcessPresentation.getLargeFiles().isEmpty() || myOutOfScopeUsages.get() != 0) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + MessageType type = myOutOfScopeUsages.get() == 0 ? MessageType.INFO : MessageType.WARNING; + notifyByFindBalloon(hyperlinkListener, type, myProcessPresentation, myProject, lines); + } + }, ModalityState.NON_MODAL, myProject.getDisposed()); + } + } + + if (myListener != null) { + myListener.findingUsagesFinished(myUsageViewRef.get()); + } + } +} diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java index 1667cc4a9858..6d7ce9c07a14 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java @@ -15,59 +15,37 @@ */ package com.intellij.usages.impl; -import com.intellij.find.FindManager; import com.intellij.find.SearchInBackgroundOption; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.KeyboardShortcut; +import com.intellij.openapi.actionSystem.DataKey; +import com.intellij.openapi.actionSystem.DataSink; +import com.intellij.openapi.actionSystem.TypeSafeDataProvider; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.CodeInsightColors; -import com.intellij.openapi.editor.colors.EditorColorsManager; -import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; -import com.intellij.openapi.progress.util.ProgressWrapper; import com.intellij.openapi.progress.util.TooManyUsagesStatus; import com.intellij.openapi.project.DumbModeAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Factory; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.psi.PsiFile; -import com.intellij.ui.HyperlinkAdapter; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.LocalSearchScope; +import com.intellij.psi.search.SearchScope; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.content.Content; import com.intellij.usageView.UsageViewBundle; import com.intellij.usages.*; -import com.intellij.util.Alarm; -import com.intellij.util.ArrayUtil; -import com.intellij.util.CommonProcessors; -import com.intellij.util.Processor; -import com.intellij.util.ui.RangeBlinker; +import com.intellij.usages.rules.PsiElementUsage; +import com.intellij.usages.rules.UsageInFile; import com.intellij.util.ui.UIUtil; -import com.intellij.xml.util.XmlStringUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import javax.swing.event.HyperlinkListener; -import java.awt.event.ActionEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** @@ -76,8 +54,6 @@ import java.util.concurrent.atomic.AtomicReference; public class UsageViewManagerImpl extends UsageViewManager { private final Project myProject; private static final Key USAGE_VIEW_KEY = Key.create("USAGE_VIEW"); - @NonNls private static final String LARGE_FILES_HREF_TARGET = "LargeFiles"; - @NonNls private static final String FIND_OPTIONS_HREF_TARGET = "FindOptions"; public UsageViewManagerImpl(@NotNull Project project) { myProject = project; @@ -113,7 +89,7 @@ public class UsageViewManagerImpl extends UsageViewManager { return showUsages(searchedFor, foundUsages, presentation, null); } - private void addContent(@NotNull UsageViewImpl usageView, @NotNull UsageViewPresentation presentation) { + void addContent(@NotNull UsageViewImpl usageView, @NotNull UsageViewPresentation presentation) { Content content = com.intellij.usageView.UsageViewManager.getInstance(myProject).addContent( presentation.getTabText(), presentation.getTabName(), @@ -146,14 +122,26 @@ public class UsageViewManagerImpl extends UsageViewManager { @NotNull final UsageViewPresentation presentation, @NotNull final FindUsagesProcessPresentation processPresentation, @Nullable final UsageViewStateListener listener) { + final SearchScope searchScope = getSearchScope(searchFor); + return doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener, searchScope); + } + + UsageView doSearchAndShow(@NotNull final UsageTarget[] searchFor, + @NotNull final Factory searcherFactory, + @NotNull final UsageViewPresentation presentation, + @NotNull final FindUsagesProcessPresentation processPresentation, + @Nullable final UsageViewStateListener listener, + @NotNull final SearchScope searchScope) { final AtomicReference usageViewRef = new AtomicReference(); + Task.Backgroundable task = new Task.Backgroundable(myProject, getProgressTitle(presentation), true, new SearchInBackgroundOption()) { @Override public void run(@NotNull final ProgressIndicator indicator) { - new SearchForUsagesRunnable(UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory, - processPresentation, listener).run(); + new SearchForUsagesRunnable(UsageViewManagerImpl.this, UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory, + processPresentation, searchScope, listener).run(); } + @NotNull @Override public DumbModeAction getDumbModeAction() { return DumbModeAction.CANCEL; @@ -170,6 +158,22 @@ public class UsageViewManagerImpl extends UsageViewManager { return usageViewRef.get(); } + @NotNull + private SearchScope getSearchScope(@NotNull UsageTarget[] searchFor) { + UsageTarget target = searchFor[0]; + if (target instanceof TypeSafeDataProvider) { + final SearchScope[] scope = new SearchScope[1]; + ((TypeSafeDataProvider)target).calcData(UsageView.USAGE_SCOPE, new DataSink() { + @Override + public void put(DataKey key, T data) { + scope[0] = (SearchScope)data; + } + }); + return scope[0]; + } + return GlobalSearchScope.projectScope(myProject); + } + @Override public void searchAndShowUsages(@NotNull UsageTarget[] searchFor, @NotNull Factory searcherFactory, @@ -197,7 +201,7 @@ public class UsageViewManagerImpl extends UsageViewManager { return StringUtil.escapeXml(result); } - private void showToolWindow(boolean activateWindow) { + void showToolWindow(boolean activateWindow) { ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND); toolWindow.show(null); if (activateWindow && !toolWindow.isActive()) { @@ -238,304 +242,6 @@ public class UsageViewManagerImpl extends UsageViewManager { }); } - private class SearchForUsagesRunnable implements Runnable { - private final AtomicInteger myUsageCountWithoutDefinition = new AtomicInteger(0); - private final AtomicReference myFirstUsage = new AtomicReference(); - @NotNull - private final Project myProject; - private final AtomicReference myUsageViewRef; - private final UsageViewPresentation myPresentation; - private final UsageTarget[] mySearchFor; - private final Factory mySearcherFactory; - private final FindUsagesProcessPresentation myProcessPresentation; - private final UsageViewStateListener myListener; - - private SearchForUsagesRunnable(@NotNull Project project, - @NotNull AtomicReference usageViewRef, - @NotNull UsageViewPresentation presentation, - @NotNull UsageTarget[] searchFor, - @NotNull Factory searcherFactory, - @NotNull FindUsagesProcessPresentation processPresentation, - @Nullable UsageViewStateListener listener) { - myProject = project; - myUsageViewRef = usageViewRef; - myPresentation = presentation; - mySearchFor = searchFor; - mySearcherFactory = searcherFactory; - myProcessPresentation = processPresentation; - myListener = listener; - } - - private UsageViewImpl getUsageView(ProgressIndicator indicator) { - UsageViewImpl usageView = myUsageViewRef.get(); - if (usageView != null) return usageView; - int usageCount = myUsageCountWithoutDefinition.get(); - if (usageCount >= 2 || usageCount == 1 && myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - usageView = new UsageViewImpl(myProject, myPresentation, mySearchFor, mySearcherFactory); - usageView.associateProgress(indicator); - if (myUsageViewRef.compareAndSet(null, usageView)) { - openView(usageView); - final Usage firstUsage = myFirstUsage.get(); - if (firstUsage != null) { - final UsageViewImpl finalUsageView = usageView; - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - finalUsageView.appendUsage(firstUsage); - } - }); - } - } - else { - Disposer.dispose(usageView); - } - return myUsageViewRef.get(); - } - return null; - } - - private void openView(@NotNull final UsageViewImpl usageView) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (myProject.isDisposed()) return; - addContent(usageView, myPresentation); - if (myListener != null) { - myListener.usageViewCreated(usageView); - } - showToolWindow(false); - } - }); - } - - @Override - public void run() { - AtomicBoolean findUsagesStartedShown = new AtomicBoolean(); - searchUsages(findUsagesStartedShown); - endSearchForUsages(findUsagesStartedShown); - } - - private void searchUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { - ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); - TooManyUsagesStatus.createFor(indicator); - Alarm findUsagesStartedBalloon = new Alarm(); - findUsagesStartedBalloon.addRequest(new Runnable() { - @Override - public void run() { - notifyByFindBalloon(null, MessageType.WARNING, myProcessPresentation, UsageViewManagerImpl.this.myProject, - getProgressTitle(myPresentation)); - findStartedBalloonShown.set(true); - } - }, 300, ModalityState.NON_MODAL); - UsageSearcher usageSearcher = mySearcherFactory.create(); - - usageSearcher.generate(new Processor() { - @Override - public boolean process(final Usage usage) { - ProgressIndicator indicator = ProgressWrapper.unwrap(ProgressManager.getInstance().getProgressIndicator()); - if (indicator != null && indicator.isCanceled()) return false; - TooManyUsagesStatus tooManyUsagesStatus = TooManyUsagesStatus.getFrom(indicator); - boolean incrementCounter = !isSelfUsage(usage, mySearchFor); - - if (incrementCounter) { - final int usageCount = myUsageCountWithoutDefinition.incrementAndGet(); - if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - myFirstUsage.compareAndSet(null, usage); - } - - final UsageViewImpl usageView = getUsageView(indicator); - - if (usageCount > UsageLimitUtil.USAGES_LIMIT && tooManyUsagesStatus.switchTooManyUsagesStatus()) { - showTooManyUsagesWarning(myProject, tooManyUsagesStatus, indicator, myPresentation, usageCount, usageView); - } - - if (usageView != null) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - usageView.appendUsage(usage); - } - }); - } - } - return indicator == null || !indicator.isCanceled(); - } - }); - if (getUsageView(indicator) != null) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - showToolWindow(true); - } - }, myProject.getDisposed()); - } - Disposer.dispose(findUsagesStartedBalloon); - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - if (findStartedBalloonShown.get()) { - Balloon balloon = ToolWindowManager.getInstance(myProject).getToolWindowBalloon(ToolWindowId.FIND); - if (balloon != null) { - balloon.hide(); - } - } - } - }, myProject.getDisposed()); - } - - private void endSearchForUsages(@NotNull final AtomicBoolean findStartedBalloonShown) { - assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread(); - int usageCount = myUsageCountWithoutDefinition.get(); - if (usageCount == 0 && myProcessPresentation.isShowNotFoundMessage()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - final List notFoundActions = myProcessPresentation.getNotFoundActions(); - final String message = UsageViewBundle.message("dialog.no.usages.found.in", - StringUtil.decapitalize(myPresentation.getUsagesString()), - myPresentation.getScopeText()); - - if (notFoundActions.isEmpty()) { - String[] lines = myProcessPresentation.isShowFindOptionsPrompt() ? new String[] {StringUtil.escapeXml(message), createOptionsHtml(mySearchFor)} : new String[]{StringUtil.escapeXml(message)}; - notifyByFindBalloon(createGotToOptionsListener(mySearchFor), - MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject, lines); - findStartedBalloonShown.set(false); - } - else { - List titles = new ArrayList(notFoundActions.size() + 1); - titles.add(UsageViewBundle.message("dialog.button.ok")); - for (Action action : notFoundActions) { - Object value = action.getValue(FindUsagesProcessPresentation.NAME_WITH_MNEMONIC_KEY); - if (value == null) value = action.getValue(Action.NAME); - - titles.add((String)value); - } - - int option = Messages.showDialog(myProject, message, UsageViewBundle.message("dialog.title.information"), - ArrayUtil.toStringArray(titles), 0, Messages.getInformationIcon()); - - if (option > 0) { - notFoundActions.get(option - 1).actionPerformed(new ActionEvent(this, 0, titles.get(option))); - } - } - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - else if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - Usage usage = myFirstUsage.get(); - if (usage.canNavigate()) { - usage.navigate(true); - flashUsageScriptaculously(usage); - } - notifyByFindBalloon(createGotToOptionsListener(mySearchFor), - MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject,"Only one usage found.", createOptionsHtml( - mySearchFor)); - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - else { - final UsageViewImpl usageView = myUsageViewRef.get(); - if (usageView != null) { - usageView.drainQueuedUsageNodes(); - usageView.setSearchInProgress(false); - } - if (!myProcessPresentation.getLargeFiles().isEmpty()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - notifyByFindBalloon(null, MessageType.INFO, myProcessPresentation, UsageViewManagerImpl.this.myProject); - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - } - - if (myListener != null) { - myListener.findingUsagesFinished(myUsageViewRef.get()); - } - } - } - - private static void notifyByFindBalloon(final HyperlinkListener listener, - @NotNull final MessageType info, - @NotNull FindUsagesProcessPresentation processPresentation, - @NotNull final Project project, - @NotNull String... sLines) { - com.intellij.usageView.UsageViewManager.getInstance(project); // in case tool window not registered - - final List lines = new ArrayList(Arrays.asList(sLines)); - final Collection largeFiles = processPresentation.getLargeFiles(); - List resultLines = new ArrayList(lines); - HyperlinkListener resultListener = listener; - if (!largeFiles.isEmpty()) { - String shortMessage = "(" - + UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + ")"; - - resultLines.add(shortMessage); - resultListener = new HyperlinkAdapter(){ - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - if (e.getDescription().equals(LARGE_FILES_HREF_TARGET)) { - String detailedMessage = detailedLargeFilesMessage(largeFiles); - List strings = new ArrayList(lines); - strings.add(detailedMessage); - ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(strings), AllIcons.Actions.Find, listener); - } - else if (listener != null) { - listener.hyperlinkUpdate(e); - } - } - }; - } - - ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, info, wrapInHtml(resultLines), AllIcons.Actions.Find, resultListener); - } - - @NotNull - private static String wrapInHtml(@NotNull List strings) { - return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "
")); - } - - @NotNull - private static String detailedLargeFilesMessage(@NotNull Collection largeFiles) { - String message = ""; - if (largeFiles.size() == 1) { - final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile(); - message += "File " + presentableFileInfo(vFile) + " is "; - } - else { - message += "Files
"; - - int counter = 0; - for (PsiFile file : largeFiles) { - final VirtualFile vFile = file.getVirtualFile(); - message += presentableFileInfo(vFile) + "
"; - if (counter++ > 10) break; - } - - message += "are "; - } - - message += "too large and cannot be scanned"; - return message; - } - - @NotNull - private static String presentableFileInfo(@NotNull VirtualFile vFile) { - return getPresentablePath(vFile) - + " (" - + presentableSize(getFileLength(vFile)) - + ")"; - } - - @NotNull - public static String presentableSize(long bytes) { - long megabytes = bytes / (1024 * 1024); - return UsageViewBundle.message("find.file.size.megabytes", Long.toString(megabytes)); - } - public static long getFileLength(@NotNull final VirtualFile virtualFile) { final long[] length = {-1L}; ApplicationManager.getApplication().runReadAction(new Runnable() { @@ -550,52 +256,22 @@ public class UsageViewManagerImpl extends UsageViewManager { } @NotNull - private static String getPresentablePath(@NotNull final VirtualFile virtualFile) { - return "'" + ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public String compute() { - return virtualFile.getPresentableUrl(); - } - }) + "'"; + public static String presentableSize(long bytes) { + long megabytes = bytes / (1024 * 1024); + return UsageViewBundle.message("find.file.size.megabytes", Long.toString(megabytes)); + } + + public static boolean isInScope(@NotNull Usage usage, @NotNull SearchScope searchScope) { + VirtualFile file = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() : usage instanceof PsiElementUsage ? PsiUtilCore + .getVirtualFile(((PsiElementUsage)usage).getElement()) : null; + return file != null && (searchScope instanceof LocalSearchScope + ? ((LocalSearchScope)searchScope).isInScope(file) : ((GlobalSearchScope)searchScope).contains(file)); } @NotNull - private HyperlinkListener createGotToOptionsListener(@NotNull final UsageTarget[] targets) { - return new HyperlinkAdapter() { - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - if (e.getDescription().equals(FIND_OPTIONS_HREF_TARGET)) { - FindManager.getInstance(myProject).showSettingsAndFindUsages(targets); - } - } - }; + public static String outOfScopeMessage(int nUsages, @NotNull SearchScope searchScope) { + return (nUsages == 1 ? "One usage is" : nUsages + " usages are") + + " out of scope '"+ searchScope.getDisplayName()+"'"; } - @NotNull - private static String createOptionsHtml(@NonNls UsageTarget[] searchFor) { - KeyboardShortcut shortcut = UsageViewImpl.getShowUsagesWithSettingsShortcut(searchFor); - String shortcutText = ""; - if (shortcut != null) { - shortcutText = " (" + KeymapUtil.getShortcutText(shortcut) + ")"; - } - return "Find Options..." + shortcutText; - } - - private static void flashUsageScriptaculously(@NotNull final Usage usage) { - if (!(usage instanceof UsageInfo2UsageAdapter)) { - return; - } - UsageInfo2UsageAdapter usageInfo = (UsageInfo2UsageAdapter)usage; - - Editor editor = usageInfo.openTextEditor(true); - if (editor == null) return; - TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.BLINKING_HIGHLIGHTS_ATTRIBUTES); - - RangeBlinker rangeBlinker = new RangeBlinker(editor, attributes, 6); - List segments = new ArrayList(); - CommonProcessors.CollectProcessor processor = new CommonProcessors.CollectProcessor(segments); - usageInfo.processRangeMarkers(processor); - rangeBlinker.resetMarkers(segments); - rangeBlinker.startBlinking(); - } }