blob: a33bc9e484375f1ebbf7348087fa0239e468df26 [file] [log] [blame]
/*
* 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.SearchInBackgroundOption;
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.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.util.TooManyUsagesStatus;
import com.intellij.openapi.project.DumbModeAction;
import com.intellij.openapi.project.Project;
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.PsiElement;
import com.intellij.psi.search.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.content.Content;
import com.intellij.usageView.UsageViewBundle;
import com.intellij.usages.*;
import com.intellij.usages.rules.PsiElementUsage;
import com.intellij.usages.rules.UsageInFile;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author max
*/
public class UsageViewManagerImpl extends UsageViewManager {
private final Project myProject;
private static final Key<UsageView> USAGE_VIEW_KEY = Key.create("USAGE_VIEW");
public UsageViewManagerImpl(@NotNull Project project) {
myProject = project;
}
@Override
@NotNull
public UsageView createUsageView(@NotNull UsageTarget[] targets,
@NotNull Usage[] usages,
@NotNull UsageViewPresentation presentation,
Factory<UsageSearcher> usageSearcherFactory) {
UsageViewImpl usageView = new UsageViewImpl(myProject, presentation, targets, usageSearcherFactory);
appendUsages(usages, usageView);
usageView.setSearchInProgress(false);
return usageView;
}
@Override
@NotNull
public UsageView showUsages(@NotNull UsageTarget[] searchedFor,
@NotNull Usage[] foundUsages,
@NotNull UsageViewPresentation presentation,
Factory<UsageSearcher> factory) {
UsageView usageView = createUsageView(searchedFor, foundUsages, presentation, factory);
addContent((UsageViewImpl)usageView, presentation);
showToolWindow(true);
return usageView;
}
@Override
@NotNull
public UsageView showUsages(@NotNull UsageTarget[] searchedFor, @NotNull Usage[] foundUsages, @NotNull UsageViewPresentation presentation) {
return showUsages(searchedFor, foundUsages, presentation, null);
}
void addContent(@NotNull UsageViewImpl usageView, @NotNull UsageViewPresentation presentation) {
Content content = com.intellij.usageView.UsageViewManager.getInstance(myProject).addContent(
presentation.getTabText(),
presentation.getTabName(),
presentation.getToolwindowTitle(),
true,
usageView.getComponent(),
presentation.isOpenInNewTab(),
true
);
usageView.setContent(content);
content.putUserData(USAGE_VIEW_KEY, usageView);
}
@Override
public UsageView searchAndShowUsages(@NotNull final UsageTarget[] searchFor,
@NotNull final Factory<UsageSearcher> searcherFactory,
final boolean showPanelIfOnlyOneUsage,
final boolean showNotFoundMessage,
@NotNull final UsageViewPresentation presentation,
@Nullable final UsageViewStateListener listener) {
final FindUsagesProcessPresentation processPresentation = new FindUsagesProcessPresentation(presentation);
processPresentation.setShowNotFoundMessage(showNotFoundMessage);
processPresentation.setShowPanelIfOnlyOneUsage(showPanelIfOnlyOneUsage);
return doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener);
}
private UsageView doSearchAndShow(@NotNull final UsageTarget[] searchFor,
@NotNull final Factory<UsageSearcher> searcherFactory,
@NotNull final UsageViewPresentation presentation,
@NotNull final FindUsagesProcessPresentation processPresentation,
@Nullable final UsageViewStateListener listener) {
final SearchScope searchScope = getMaxSearchScopeToWarnOfFallingOutOf(searchFor);
return doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener, searchScope);
}
private 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 searchScopeToWarnOfFallingOutOf) {
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, UsageViewManagerImpl.this.myProject, usageViewRef, presentation, searchFor, searcherFactory,
processPresentation, searchScopeToWarnOfFallingOutOf, listener).run();
}
@NotNull
@Override
public DumbModeAction getDumbModeAction() {
return DumbModeAction.CANCEL;
}
@Override
@Nullable
public NotificationInfo getNotificationInfo() {
String notification = usageViewRef.get() != null ? usageViewRef.get().getUsagesCount() + " Usage(s) Found" : "No Usages Found";
return new NotificationInfo("Find Usages", "Find Usages Finished", notification);
}
};
ProgressManager.getInstance().run(task);
return usageViewRef.get();
}
@NotNull
private SearchScope getMaxSearchScopeToWarnOfFallingOutOf(@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.allScope(myProject); // by default do not warn of falling out of scope
}
@Override
public void searchAndShowUsages(@NotNull UsageTarget[] searchFor,
@NotNull Factory<UsageSearcher> searcherFactory,
@NotNull FindUsagesProcessPresentation processPresentation,
@NotNull UsageViewPresentation presentation,
@Nullable UsageViewStateListener listener) {
doSearchAndShow(searchFor, searcherFactory, presentation, processPresentation, listener);
}
@Override
public UsageView getSelectedUsageView() {
final Content content = com.intellij.usageView.UsageViewManager.getInstance(myProject).getSelectedContent();
if (content != null) {
return content.getUserData(USAGE_VIEW_KEY);
}
return null;
}
@NotNull
public static String getProgressTitle(@NotNull UsageViewPresentation presentation) {
final String scopeText = presentation.getScopeText();
String usagesString = StringUtil.capitalize(presentation.getUsagesString());
return UsageViewBundle.message("progress.searching.for.in", usagesString, scopeText);
}
void showToolWindow(boolean activateWindow) {
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND);
toolWindow.show(null);
if (activateWindow && !toolWindow.isActive()) {
toolWindow.activate(null);
}
}
private static void appendUsages(@NotNull final Usage[] foundUsages, @NotNull final UsageViewImpl usageView) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
for (Usage foundUsage : foundUsages) {
usageView.appendUsage(foundUsage);
}
}
});
}
static void showTooManyUsagesWarning(@NotNull final Project project,
@NotNull final TooManyUsagesStatus tooManyUsagesStatus,
@NotNull final ProgressIndicator indicator,
@NotNull final UsageViewPresentation presentation,
final int usageCount,
final UsageViewImpl usageView) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (usageView != null && usageView.searchHasBeenCancelled() || indicator.isCanceled()) return;
String message = UsageViewBundle.message("find.excessive.usage.count.prompt", usageCount, StringUtil.pluralize(presentation.getUsagesWord()));
UsageLimitUtil.Result ret = UsageLimitUtil.showTooManyUsagesWarning(project, message, presentation);
if (ret == UsageLimitUtil.Result.ABORT && usageView != null) {
usageView.cancelCurrentSearch();
indicator.cancel();
}
tooManyUsagesStatus.userResponded();
}
});
}
public static long getFileLength(@NotNull final VirtualFile virtualFile) {
final long[] length = {-1L};
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (!virtualFile.isValid()) return;
if (virtualFile.getFileType().isBinary()) return;
length[0] = virtualFile.getLength();
}
});
return length[0];
}
@NotNull
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) {
PsiElement element = null;
VirtualFile file = usage instanceof UsageInFile ? ((UsageInFile)usage).getFile() :
usage instanceof PsiElementUsage ? PsiUtilCore.getVirtualFile(element = ((PsiElementUsage)usage).getElement()) : null;
if (file != null) {
return isFileInScope(file, searchScope);
}
else if(element != null) {
return searchScope instanceof EverythingGlobalScope ||
searchScope instanceof ProjectScopeImpl ||
searchScope instanceof ProjectAndLibrariesScope;
}
return false;
}
private static boolean isFileInScope(@NotNull VirtualFile file, @NotNull SearchScope searchScope) {
if (searchScope instanceof LocalSearchScope) {
return ((LocalSearchScope)searchScope).isInScope(file);
}
else {
return ((GlobalSearchScope)searchScope).contains(file);
}
}
@NotNull
public static String outOfScopeMessage(int nUsages, @NotNull SearchScope searchScope) {
return (nUsages == 1 ? "One usage is" : nUsages + " usages are") +
" out of scope '"+ searchScope.getDisplayName()+"'";
}
}