IDEA-120751

This commit is contained in:
Alexey Kudravtsev
2014-07-01 13:07:28 +04:00
parent f29a59397b
commit 37711bc420
9 changed files with 761 additions and 504 deletions
@@ -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
@@ -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 + "&nbsp;"));
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;
}
@@ -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("<b>" + value + "</b>"), 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);
@@ -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<PsiElement> 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<PsiElement> allElements = ContainerUtil.concat(primaryElements, secondaryElements);
final UsageTarget[] targets = convertToUsageTargets(allElements, findUsagesOptions);
final PsiElement2UsageTargetAdapter[] targets = convertToUsageTargets(allElements, findUsagesOptions);
myAnotherManager.searchAndShowUsages(targets, new Factory<UsageSearcher>() {
@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) {
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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<Usage> myFirstUsage = new AtomicReference<Usage>();
@NotNull
private final Project myProject;
private final AtomicReference<UsageViewImpl> myUsageViewRef;
private final UsageViewPresentation myPresentation;
private final UsageTarget[] mySearchFor;
private final Factory<UsageSearcher> 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<UsageViewImpl> usageViewRef,
@NotNull UsageViewPresentation presentation,
@NotNull UsageTarget[] searchFor,
@NotNull Factory<UsageSearcher> 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 = "&nbsp;(" + KeymapUtil.getShortcutText(shortcut) + ")";
}
return "<a href='" + FIND_OPTIONS_HREF_TARGET + "'>Find Options...</a>" + shortcutText;
}
@NotNull
private static String createSearchInProjectHtml() {
return "<a href='" + SEARCH_IN_PROJECT_HREF_TARGET + "'>Search in Project</a>";
}
private static void notifyByFindBalloon(final HyperlinkListener listener,
@NotNull final MessageType info,
@NotNull FindUsagesProcessPresentation processPresentation,
@NotNull final Project project,
@NotNull final List<String> lines) {
com.intellij.usageView.UsageViewManager.getInstance(project); // in case tool window not registered
final Collection<PsiFile> largeFiles = processPresentation.getLargeFiles();
List<String> resultLines = new ArrayList<String>(lines);
HyperlinkListener resultListener = listener;
if (!largeFiles.isEmpty()) {
String shortMessage = "(<a href='" + LARGE_FILES_HREF_TARGET + "'>"
+ UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + "</a>)";
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<String> strings = new ArrayList<String>(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<String> strings) {
return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "<br>"));
}
@NotNull
private static String detailedLargeFilesMessage(@NotNull Collection<PsiFile> largeFiles) {
String message = "";
if (largeFiles.size() == 1) {
final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile();
message += "File " + presentableFileInfo(vFile) + " is ";
}
else {
message += "Files<br> ";
int counter = 0;
for (PsiFile file : largeFiles) {
final VirtualFile vFile = file.getVirtualFile();
message += presentableFileInfo(vFile) + "<br> ";
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)
+ "&nbsp;("
+ UsageViewManagerImpl.presentableSize(UsageViewManagerImpl.getFileLength(vFile))
+ ")";
}
@NotNull
private static String getPresentablePath(@NotNull final VirtualFile virtualFile) {
return "'" + ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@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<Segment> segments = new ArrayList<Segment>();
CommonProcessors.CollectProcessor<Segment> processor = new CommonProcessors.CollectProcessor<Segment>(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<Usage>() {
@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<Action> notFoundActions = myProcessPresentation.getNotFoundActions();
final String message = UsageViewBundle.message("dialog.no.usages.found.in",
StringUtil.decapitalize(myPresentation.getUsagesString()),
myPresentation.getScopeText());
if (notFoundActions.isEmpty()) {
List<String> lines = new ArrayList<String>();
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<String> titles = new ArrayList<String>(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<String> lines = new ArrayList<String>();
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<String> 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());
}
}
}
@@ -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<UsageView> 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<UsageSearcher> searcherFactory,
@NotNull final UsageViewPresentation presentation,
@NotNull final FindUsagesProcessPresentation processPresentation,
@Nullable final UsageViewStateListener listener,
@NotNull final SearchScope searchScope) {
final AtomicReference<UsageViewImpl> usageViewRef = new AtomicReference<UsageViewImpl>();
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 <T> void put(DataKey<T> key, T data) {
scope[0] = (SearchScope)data;
}
});
return scope[0];
}
return GlobalSearchScope.projectScope(myProject);
}
@Override
public void searchAndShowUsages(@NotNull UsageTarget[] searchFor,
@NotNull Factory<UsageSearcher> 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<Usage> myFirstUsage = new AtomicReference<Usage>();
@NotNull
private final Project myProject;
private final AtomicReference<UsageViewImpl> myUsageViewRef;
private final UsageViewPresentation myPresentation;
private final UsageTarget[] mySearchFor;
private final Factory<UsageSearcher> mySearcherFactory;
private final FindUsagesProcessPresentation myProcessPresentation;
private final UsageViewStateListener myListener;
private SearchForUsagesRunnable(@NotNull Project project,
@NotNull AtomicReference<UsageViewImpl> usageViewRef,
@NotNull UsageViewPresentation presentation,
@NotNull UsageTarget[] searchFor,
@NotNull Factory<UsageSearcher> 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<Usage>() {
@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<Action> 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<String> titles = new ArrayList<String>(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<String> lines = new ArrayList<String>(Arrays.asList(sLines));
final Collection<PsiFile> largeFiles = processPresentation.getLargeFiles();
List<String> resultLines = new ArrayList<String>(lines);
HyperlinkListener resultListener = listener;
if (!largeFiles.isEmpty()) {
String shortMessage = "(<a href='" + LARGE_FILES_HREF_TARGET + "'>"
+ UsageViewBundle.message("large.files.were.ignored", largeFiles.size()) + "</a>)";
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<String> strings = new ArrayList<String>(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<String> strings) {
return XmlStringUtil.wrapInHtml(StringUtil.join(strings, "<br>"));
}
@NotNull
private static String detailedLargeFilesMessage(@NotNull Collection<PsiFile> largeFiles) {
String message = "";
if (largeFiles.size() == 1) {
final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile();
message += "File " + presentableFileInfo(vFile) + " is ";
}
else {
message += "Files<br> ";
int counter = 0;
for (PsiFile file : largeFiles) {
final VirtualFile vFile = file.getVirtualFile();
message += presentableFileInfo(vFile) + "<br> ";
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)
+ "&nbsp;("
+ 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<String>() {
@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 = "&nbsp;(" + KeymapUtil.getShortcutText(shortcut) + ")";
}
return "<a href='" + FIND_OPTIONS_HREF_TARGET + "'>Find Options...</a>" + 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<Segment> segments = new ArrayList<Segment>();
CommonProcessors.CollectProcessor<Segment> processor = new CommonProcessors.CollectProcessor<Segment>(segments);
usageInfo.processRangeMarkers(processor);
rangeBlinker.resetMarkers(segments);
rangeBlinker.startBlinking();
}
}