diff --git a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesDialog.java b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesDialog.java index c56ee406e735..c5ac84a6aad2 100644 --- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesDialog.java +++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesDialog.java @@ -45,7 +45,7 @@ public abstract class JavaFindUsagesDialog 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) { diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java b/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java index f0346d309ea0..34e1a12f6357 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/CommonFindUsagesDialog.java @@ -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 diff --git a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesUtil.java b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesUtil.java index afcc90bca06e..c7ce574ebda3 100644 --- a/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesUtil.java +++ b/platform/lang-impl/src/com/intellij/find/findUsages/FindUsagesUtil.java @@ -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); } } diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java index 16084a15b30d..0f8b51a745ce 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectUtil.java @@ -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 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(""); + @Language("HTML") + String message = ""; if (largeFiles.size() == 1) { final VirtualFile vFile = largeFiles.iterator().next().getVirtualFile(); - message. - append("File '"). - append(getPresentablePath(vFile)). - append("' ("). - append(presentableSize(getFileLength(vFile))). - append(") is "); + message + += "File '" + + getPresentablePath(vFile) + + "' (" + + presentableSize(getFileLength(vFile)) + + ") is "; } else { - message.append("Files
"); + message += "Files
"; int counter = 0; for (PsiFile file : largeFiles) { final VirtualFile vFile = file.getVirtualFile(); - message. - append(getPresentablePath(vFile)). - append(" ("). - append(presentableSize(getFileLength(vFile))). - append(")
"); + message += + getPresentablePath(vFile) + + " (" + + presentableSize(getFileLength(vFile)) + + ")
"; if (counter++ > 10) break; } - message.append("are "); + message += "are "; } - message.append("too large and cannot be scanned"); + message += "too large and cannot be scanned"; + 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 consumer, - int alreadyCounted, - boolean[] warningShown) { + final Processor 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() { - 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 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() { - public Integer compute() { - return Messages.showDialog(project, message, title, buttons, 0, Messages.getWarningIcon()); - } - }); - } - private static Collection getFilesToSearchIn(final FindModel findModel, final Project project, final PsiDirectory psiDirectory) { return ApplicationManager.getApplication().runReadAction(new Computable>() { public Collection compute() { @@ -689,14 +644,6 @@ public class FindInProjectUtil { return presentation; } - public static boolean hasReadOnlyUsages(final Collection 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) { diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index c7c64b34fba0..d031a7dc5964 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -66,6 +66,14 @@ public class ReplaceInProjectManager { myProject = project; } + public static boolean hasReadOnlyUsages(final Collection 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 _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"), diff --git a/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java b/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java index bc64e664a445..4afb2655df47 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java +++ b/platform/lang-impl/src/com/intellij/refactoring/util/TextOccurrencesUtil.java @@ -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 { diff --git a/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java b/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java index 8a98d4456056..cc74f8e8e146 100644 --- a/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java +++ b/platform/lang-impl/src/com/intellij/usageView/UsageViewUtil.java @@ -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"); diff --git a/platform/platform-resources-en/src/messages/FindBundle.properties b/platform/platform-resources-en/src/messages/FindBundle.properties index 2d3666179c5c..fffcd9f39049 100644 --- a/platform/platform-resources-en/src/messages/FindBundle.properties +++ b/platform/platform-resources-en/src/messages/FindBundle.properties @@ -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} diff --git a/platform/platform-resources-en/src/messages/UsageView.properties b/platform/platform-resources-en/src/messages/UsageView.properties index 026d288cc792..1538d1cf5ed3 100644 --- a/platform/platform-resources-en/src/messages/UsageView.properties +++ b/platform/platform-resources-en/src/messages/UsageView.properties @@ -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? diff --git a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java index 97873b7fde99..1f7d0b299204 100644 --- a/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java +++ b/platform/usageView/src/com/intellij/usages/UsageInfo2UsageAdapter.java @@ -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(); diff --git a/platform/usageView/src/com/intellij/usages/UsageLimitUtil.java b/platform/usageView/src/com/intellij/usages/UsageLimitUtil.java new file mode 100644 index 000000000000..13838c555a28 --- /dev/null +++ b/platform/usageView/src/com/intellij/usages/UsageLimitUtil.java @@ -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 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() { + public Integer compute() { + return Messages.showDialog(project, message, title, buttons, 0, Messages.getWarningIcon()); + } + }); + } +} diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java index b5f810b50bf6..a4946e92155e 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewManagerImpl.java @@ -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() { 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(); } });