too many usages dialog shows for regular find usages + more user friendly buttons

This commit is contained in:
Alexey Kudravtsev
2010-10-11 14:08:44 +04:00
parent dd3b1924db
commit 3182eb4a60
12 changed files with 136 additions and 99 deletions
@@ -45,7 +45,7 @@ public abstract class JavaFindUsagesDialog<T extends JavaFindUsagesOptions> exte
}
private static boolean isTextSearch(PsiElement element, boolean isSingleFile, FindUsagesHandler handler) {
return FindUsagesUtil.isSearchForTextOccurencesAvailable(element, isSingleFile, handler);
return FindUsagesUtil.isSearchForTextOccurrencesAvailable(element, isSingleFile, handler);
}
public void calcFindUsagesOptions(T options) {
@@ -43,7 +43,7 @@ public class CommonFindUsagesDialog extends AbstractFindUsagesDialog {
}
private static boolean isTextSearch(PsiElement element, boolean isSingleFile, FindUsagesHandler handler) {
return FindUsagesUtil.isSearchForTextOccurencesAvailable(element, isSingleFile, handler);
return FindUsagesUtil.isSearchForTextOccurrencesAvailable(element, isSingleFile, handler);
}
@Override
@@ -23,9 +23,7 @@ public class FindUsagesUtil {
private FindUsagesUtil() {
}
public static boolean isSearchForTextOccurencesAvailable(PsiElement element, boolean isSingleFile, FindUsagesHandler handler) {
if (isSingleFile) return false;
return handler != null && handler.isSearchForTextOccurencesAvailable(element, isSingleFile);
public static boolean isSearchForTextOccurrencesAvailable(PsiElement element, boolean isSingleFile, FindUsagesHandler handler) {
return !isSingleFile && handler != null && handler.isSearchForTextOccurencesAvailable(element, isSingleFile);
}
}
@@ -41,9 +41,7 @@ import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.FileIndexImplUtil;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Pair;
@@ -63,7 +61,6 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.UsageSearchContext;
import com.intellij.ui.GuiUtils;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.*;
import com.intellij.util.CommonProcessors;
@@ -75,6 +72,7 @@ import com.intellij.util.indexing.FileBasedIndex;
import gnu.trove.THashSet;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntIterator;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -84,7 +82,6 @@ import java.util.*;
import java.util.regex.Pattern;
public class FindInProjectUtil {
private static final int USAGES_LIMIT = 1000;
private static final int USAGES_PER_READ_ACTION = 100;
private static final int FILES_SIZE_LIMIT = 70 * 1024 * 1024; // megabytes.
private static final int SINGLE_FILE_SIZE_LIMIT = 5 * 1024 * 1024; // megabytes.
@@ -191,8 +188,8 @@ public class FindInProjectUtil {
return null;
}
String pattern;
final String[] strings = filter.split(",");
if (strings.length == 1) {
final List<String> strings = StringUtil.split(filter, ",");
if (strings.size() == 1) {
pattern = PatternUtil.convertToRegex(filter.trim());
}
else {
@@ -219,7 +216,7 @@ public class FindInProjectUtil {
int i = 0;
long totalFilesSize = 0;
int count = 0;
final boolean[] warningShown = new boolean[] {false};
final boolean[] warningShown = {false};
final UsageViewManager usageViewManager = UsageViewManager.getInstance(project);
for (final PsiFile psiFile : psiFiles) {
@@ -253,53 +250,55 @@ public class FindInProjectUtil {
progress.setText2(FindBundle.message("find.searching.for.string.in.file.occurrences.progress", count));
}
int countInFile = processUsagesInFile(psiFile, findModel, consumer, count, warningShown);
int countInFile = processUsagesInFile(psiFile, findModel, consumer);
count += countInFile;
if (countInFile > 0) {
totalFilesSize += fileLength;
if (totalFilesSize > FILES_SIZE_LIMIT && !warningShown[0]) {
showTooManyUsagesWaring(project, FindBundle.message("find.excessive.total.size.prompt", presentableSize(totalFilesSize),
ApplicationNamesInfo.getInstance().getProductName()));
warningShown[0] = true;
String message = FindBundle.message("find.excessive.total.size.prompt", presentableSize(totalFilesSize),
ApplicationNamesInfo.getInstance().getProductName());
UsageLimitUtil.showAndCancelIfAborted(project, message);
}
}
}
if (!largeFiles.isEmpty()) {
final StringBuilder message = new StringBuilder();
message.append("<html><body>");
@Language("HTML")
String message = "<html><body>";
if (largeFiles.size() == 1) {
final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile();
message.
append("File '").
append(getPresentablePath(vFile)).
append("'&nbsp;(").
append(presentableSize(getFileLength(vFile))).
append(") is ");
message
+= "File '"
+ getPresentablePath(vFile)
+ "'&nbsp;("
+ presentableSize(getFileLength(vFile))
+ ") is ";
}
else {
message.append("Files<br> ");
message += "Files<br> ";
int counter = 0;
for (PsiFile file : largeFiles) {
final VirtualFile vFile = file.getVirtualFile();
message.
append(getPresentablePath(vFile)).
append("&nbsp;(").
append(presentableSize(getFileLength(vFile))).
append(")<br> ");
message +=
getPresentablePath(vFile)
+ "&nbsp;("
+ presentableSize(getFileLength(vFile))
+ ")<br> ";
if (counter++ > 10) break;
}
message.append("are ");
message += "are ";
}
message.append("too large and cannot be scanned</body></html>");
message += "too large and cannot be scanned</body></html>";
final String finalMessage = message;
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, MessageType.WARNING, message.toString());
ToolWindowManager.getInstance(project).notifyByBalloon(ToolWindowId.FIND, MessageType.WARNING, finalMessage);
}
});
}
@@ -315,15 +314,13 @@ public class FindInProjectUtil {
private static int processUsagesInFile(final PsiFile psiFile,
final FindModel findModel,
final Processor<UsageInfo> consumer,
int alreadyCounted,
boolean[] warningShown) {
final Processor<UsageInfo> consumer) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile == null) return 0;
if (FileTypeManager.getInstance().getFileTypeByFile(virtualFile).isBinary()) return 0; // do not decompile .class files
final Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
if (document == null) return 0;
final int[] offset = new int[] {0};
final int[] offset = {0};
int count = 0;
int found;
do {
@@ -336,12 +333,6 @@ public class FindInProjectUtil {
}
});
count += found;
final int total = count + alreadyCounted;
if (found > 0 && total > USAGES_LIMIT && !warningShown[0]) {
showTooManyUsagesWaring(psiFile.getProject(), FindBundle.message("find.excessive.usage.count.prompt", total));
warningShown[0] = true;
}
}
while (found != 0);
return count;
@@ -372,42 +363,6 @@ public class FindInProjectUtil {
return length[0];
}
private static void showTooManyUsagesWaring(final Project project, final String message) {
int retCode = invokeAndWait(new Computable<Integer>() {
public Integer compute() {
return Messages.showYesNoDialog(project, message, FindBundle.message("find.excessive.usages.title"), Messages.getWarningIcon());
}
});
if (retCode != DialogWrapper.OK_EXIT_CODE) {
throw new ProcessCanceledException();
}
}
private static int invokeAndWait(final Computable<Integer> f) {
final int[] answer = new int[1];
try {
GuiUtils.invokeAndWait(new Runnable() {
public void run() {
answer[0] = f.compute();
}
});
}
catch (Exception e) {
answer[0] = 0;
}
return answer[0];
}
private static int showMessage(final Project project, final String message, final String title, final String[] buttons) {
return invokeAndWait(new Computable<Integer>() {
public Integer compute() {
return Messages.showDialog(project, message, title, buttons, 0, Messages.getWarningIcon());
}
});
}
private static Collection<PsiFile> getFilesToSearchIn(final FindModel findModel, final Project project, final PsiDirectory psiDirectory) {
return ApplicationManager.getApplication().runReadAction(new Computable<Collection<PsiFile>>() {
public Collection<PsiFile> compute() {
@@ -689,14 +644,6 @@ public class FindInProjectUtil {
return presentation;
}
public static boolean hasReadOnlyUsages(final Collection<Usage> usages) {
for (Usage usage : usages) {
if (usage.isReadOnly()) return true;
}
return false;
}
public static FindUsagesProcessPresentation setupProcessPresentation(final Project project,
final boolean showPanelIfOnlyOneUsage,
final UsageViewPresentation presentation) {
@@ -66,6 +66,14 @@ public class ReplaceInProjectManager {
myProject = project;
}
public static boolean hasReadOnlyUsages(final Collection<Usage> usages) {
for (Usage usage : usages) {
if (usage.isReadOnly()) return true;
}
return false;
}
static class ReplaceContext {
private final UsageView usageView;
private final FindModel findModel;
@@ -168,7 +176,7 @@ public class ReplaceInProjectManager {
private void replaceWithPrompt(final ReplaceContext replaceContext) {
final List<Usage> _usages = replaceContext.getUsageView().getSortedUsages();
if (FindInProjectUtil.hasReadOnlyUsages(_usages)) {
if (hasReadOnlyUsages(_usages)) {
WindowManager.getInstance().getStatusBar(myProject)
.setInfo(FindBundle.message("find.replace.occurrences.found.in.read.only.files.status"));
return;
@@ -363,7 +371,7 @@ public class ReplaceInProjectManager {
ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(VfsUtil.toVirtualFileArray(readOnlyFiles));
}
if (FindInProjectUtil.hasReadOnlyUsages(selectedUsages)) {
if (hasReadOnlyUsages(selectedUsages)) {
int result = Messages.showOkCancelDialog(replaceContext.getUsageView().getComponent(),
FindBundle.message("find.replace.occurrences.in.read.only.files.prompt"),
FindBundle.message("find.replace.occurrences.in.read.only.files.title"),
@@ -152,7 +152,7 @@ public class TextOccurrencesUtil {
public static boolean isSearchTextOccurencesEnabled(@NotNull PsiElement element) {
final FindUsagesManager findUsagesManager = ((FindManagerImpl)FindManager.getInstance(element.getProject())).getFindUsagesManager();
final FindUsagesHandler handler = findUsagesManager.getFindUsagesHandler(element, true);
return FindUsagesUtil.isSearchForTextOccurencesAvailable(element, false, handler);
return FindUsagesUtil.isSearchForTextOccurrencesAvailable(element, false, handler);
}
public interface UsageInfoFactory {
@@ -36,9 +36,6 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
/**
*
*/
public class UsageViewUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.usageView.UsageViewUtil");
@@ -96,10 +96,8 @@ find.origin.entire.scope.radio=E&ntire scope
find.searching.for.string.in.file.progress=Searching for ''{0}'' in {1}...
find.searching.for.string.in.file.occurrences.progress={0,choice,0#No|1#{0}} {0,choice,0#occurrences|1#occurrence|2#occurrences} found so far
find.excessive.total.size.prompt=Usages in files of total size {0} found. {1} may become unresponsive or even fail with OutOfMemoryError if you continue. Continue?
find.excessive.usage.count.prompt={0} usages found so far. Are you sure you wish to continue?
find.progress.search.completed=Search completed
find.file.size.megabytes={0} megabytes
find.excessive.usages.title=Too Many Usages
find.scope.project.title=Project
find.scope.module.title=Module {0}
find.scope.directory.title=Directory {0}
@@ -62,3 +62,7 @@ show.usages.only.usage=It''s the only usage in {0}
all.usages.are.in.this.line=All {0} usages in {1} are in this line
no.usages.found.in=No usages found in {0}
sort.alphabetically.action.text=Sort Members Alphabetically
button.text.continue=Continue
button.text.abort=Abort
find.excessive.usages.title=Too Many Usages
find.excessive.usage.count.prompt={0} usages found so far. Are you sure you wish to continue?
@@ -350,7 +350,7 @@ public class UsageInfo2UsageAdapter implements UsageInModule, UsageInLibrary, Us
@NotNull
public TextChunk[] getText() {
if (isValid()) {
// the check below makes sence only for valid PsiElement
// the check below makes sense only for valid PsiElement
final long currentModificationStamp = getCurrentModificationStamp();
if (currentModificationStamp != myModificationStamp) {
initChunks();
@@ -0,0 +1,69 @@
/*
* Copyright 2000-2010 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;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.ui.GuiUtils;
import com.intellij.usageView.UsageViewBundle;
import org.jetbrains.annotations.NotNull;
/**
* User: cdr
*/
public class UsageLimitUtil {
public static final int USAGES_LIMIT = 1000;
public static void showAndCancelIfAborted(final Project project, final String message) {
int retCode = showTooManyUsagesWarning(project, message);
if (retCode != DialogWrapper.OK_EXIT_CODE) {
throw new ProcessCanceledException();
}
}
public static int showTooManyUsagesWarning(@NotNull Project project, @NotNull String message) {
String[] buttons = {UsageViewBundle.message("button.text.continue"), UsageViewBundle.message("button.text.abort")};
return showMessage(project, message, UsageViewBundle.message("find.excessive.usages.title"), buttons);
}
private static int invokeAndWait(final Computable<Integer> f) {
final int[] answer = new int[1];
try {
GuiUtils.runOrInvokeAndWait(new Runnable() {
public void run() {
answer[0] = f.compute();
}
});
}
catch (Exception e) {
answer[0] = 0;
}
return answer[0];
}
private static int showMessage(final Project project, final String message, final String title, final String[] buttons) {
return invokeAndWait(new Computable<Integer>() {
public Integer compute() {
return Messages.showDialog(project, message, title, buttons, 0, Messages.getWarningIcon());
}
});
}
}
@@ -44,6 +44,7 @@ import com.intellij.usages.*;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Processor;
import com.intellij.util.ui.RangeBlinker;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -52,6 +53,7 @@ import javax.swing.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -280,23 +282,37 @@ public class UsageViewManagerImpl extends UsageViewManager {
private void searchUsages() {
UsageSearcher usageSearcher = mySearcherFactory.create();
final AtomicBoolean warningShown = new AtomicBoolean();
usageSearcher.generate(new Processor<Usage>() {
public boolean process(final Usage usage) {
checkSearchCanceled();
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (searchHasBeenCancelled() || indicator != null && indicator.isCanceled()) return false;
boolean incrementCounter = !isSelfUsage(usage, mySearchFor);
if (incrementCounter) {
int usageCount = myUsageCountWithoutDefinition.incrementAndGet();
final int usageCount = myUsageCountWithoutDefinition.incrementAndGet();
if (usageCount == 1 && !myProcessPresentation.isShowPanelIfOnlyOneUsage()) {
myFirstUsage.compareAndSet(null, usage);
}
if (usageCount > UsageLimitUtil.USAGES_LIMIT && !warningShown.get() && warningShown.compareAndSet(false, true)) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (searchHasBeenCancelled() || indicator != null && indicator.isCanceled()) return;
String message = UsageViewBundle.message("find.excessive.usage.count.prompt", myUsageCountWithoutDefinition.get());
int ret = UsageLimitUtil.showTooManyUsagesWarning(myProject, message);
if (ret != 0) {
setCurrentSearchCancelled(true);
}
}
});
}
UsageViewImpl usageView = getUsageView();
if (usageView != null) {
usageView.appendUsageLater(usage);
}
}
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
return indicator == null || !indicator.isCanceled();
}
});