2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.psi.search;
18 import com.intellij.ide.IdeBundle;
19 import com.intellij.ide.favoritesTreeView.FavoritesManager;
20 import com.intellij.ide.hierarchy.HierarchyBrowserBase;
21 import com.intellij.ide.projectView.impl.AbstractUrl;
22 import com.intellij.openapi.actionSystem.CommonDataKeys;
23 import com.intellij.openapi.actionSystem.DataContext;
24 import com.intellij.openapi.actionSystem.LangDataKeys;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.editor.SelectionModel;
27 import com.intellij.openapi.fileEditor.FileEditorManager;
28 import com.intellij.openapi.module.*;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.util.Condition;
31 import com.intellij.openapi.util.Pair;
32 import com.intellij.openapi.util.TextRange;
33 import com.intellij.openapi.vfs.VirtualFile;
34 import com.intellij.openapi.wm.ToolWindow;
35 import com.intellij.openapi.wm.ToolWindowId;
36 import com.intellij.openapi.wm.ToolWindowManager;
37 import com.intellij.psi.PsiDocumentManager;
38 import com.intellij.psi.PsiElement;
39 import com.intellij.psi.PsiFile;
40 import com.intellij.psi.PsiWhiteSpace;
41 import com.intellij.psi.util.PsiTreeUtil;
42 import com.intellij.psi.util.PsiUtilCore;
43 import com.intellij.ui.content.Content;
44 import com.intellij.ui.content.ContentManager;
45 import com.intellij.usages.Usage;
46 import com.intellij.usages.UsageView;
47 import com.intellij.usages.UsageViewManager;
48 import com.intellij.usages.rules.PsiElementUsage;
49 import com.intellij.util.PlatformUtils;
50 import com.intellij.util.TreeItem;
51 import com.intellij.util.containers.ContainerUtil;
52 import org.jetbrains.annotations.NotNull;
53 import org.jetbrains.annotations.Nullable;
54 import org.jetbrains.jps.model.java.JavaSourceRootType;
59 public class PredefinedSearchScopeProviderImpl extends PredefinedSearchScopeProvider {
62 public List<SearchScope> getPredefinedScopes(@NotNull final Project project,
63 @Nullable final DataContext dataContext,
64 boolean suggestSearchInLibs,
65 boolean prevSearchFiles,
66 boolean currentSelection,
68 Collection<SearchScope> result = ContainerUtil.newLinkedHashSet();
69 result.add(GlobalSearchScope.projectScope(project));
70 if (suggestSearchInLibs) {
71 result.add(GlobalSearchScope.allScope(project));
74 if (ModuleUtil.isSupportedRootType(project, JavaSourceRootType.TEST_SOURCE)) {
75 result.add(GlobalSearchScopesCore.projectProductionScope(project));
76 result.add(GlobalSearchScopesCore.projectTestScope(project));
79 result.add(GlobalSearchScopes.openFilesScope(project));
81 if (dataContext != null) {
82 PsiElement dataContextElement = CommonDataKeys.PSI_FILE.getData(dataContext);
83 if (dataContextElement == null) {
84 dataContextElement = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
87 if (dataContextElement == null) {
88 final Editor selectedTextEditor = FileEditorManager.getInstance(project).getSelectedTextEditor();
89 if (selectedTextEditor != null) {
90 dataContextElement = PsiDocumentManager.getInstance(project).getPsiFile(selectedTextEditor.getDocument());
94 if (dataContextElement != null) {
95 if (!PlatformUtils.isCidr()) { // TODO: have an API to disable module scopes.
96 Module module = ModuleUtilCore.findModuleForPsiElement(dataContextElement);
98 module = LangDataKeys.MODULE.getData(dataContext);
100 if (module != null && !(ModuleType.get(module) instanceof InternalModuleType)) {
101 result.add(module.getModuleScope());
104 if (dataContextElement.getContainingFile() != null) {
105 result.add(new LocalSearchScope(dataContextElement, IdeBundle.message("scope.current.file")));
110 if (currentSelection) {
111 FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
112 final Editor selectedTextEditor = fileEditorManager.getSelectedTextEditor();
113 if (selectedTextEditor != null) {
114 final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(selectedTextEditor.getDocument());
115 if (psiFile != null) {
116 SelectionModel selectionModel = selectedTextEditor.getSelectionModel();
117 if (selectionModel.hasSelection()) {
118 int start = selectionModel.getSelectionStart();
119 final PsiElement startElement = psiFile.findElementAt(start);
120 if (startElement != null) {
121 int end = selectionModel.getSelectionEnd();
122 final PsiElement endElement = psiFile.findElementAt(end);
123 if (endElement != null) {
124 final PsiElement parent = PsiTreeUtil.findCommonParent(startElement, endElement);
125 if (parent != null) {
126 final List<PsiElement> elements = new ArrayList<PsiElement>();
127 final PsiElement[] children = parent.getChildren();
128 TextRange selection = new TextRange(start, end);
129 for (PsiElement child : children) {
130 if (!(child instanceof PsiWhiteSpace) &&
131 child.getContainingFile() != null &&
132 selection.contains(child.getTextOffset())) {
136 if (!elements.isEmpty()) {
137 SearchScope local = new LocalSearchScope(PsiUtilCore.toPsiElementArray(elements), IdeBundle.message("scope.selection"));
149 if (prevSearchFiles) {
150 addHierarchyScope(project, result);
152 UsageView selectedUsageView = UsageViewManager.getInstance(project).getSelectedUsageView();
153 if (selectedUsageView != null && !selectedUsageView.isSearchInProgress()) {
154 final Set<Usage> usages = selectedUsageView.getUsages();
155 final List<PsiElement> results = new ArrayList<PsiElement>(usages.size());
157 if (prevSearchFiles) {
158 final Set<VirtualFile> files = collectFiles(usages, true);
159 if (!files.isEmpty()) {
160 GlobalSearchScope prev = new GlobalSearchScope(project) {
161 private Set<VirtualFile> myFiles = null;
165 public String getDisplayName() {
166 return IdeBundle.message("scope.files.in.previous.search.result");
170 public synchronized boolean contains(@NotNull VirtualFile file) {
171 if (myFiles == null) {
172 myFiles = collectFiles(usages, false);
174 return myFiles.contains(file);
178 public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
183 public boolean isSearchInModuleContent(@NotNull Module aModule) {
188 public boolean isSearchInLibraries() {
196 for (Usage usage : usages) {
197 if (usage instanceof PsiElementUsage) {
198 final PsiElement element = ((PsiElementUsage)usage).getElement();
199 if (element != null && element.isValid() && element.getContainingFile() != null) {
200 results.add(element);
205 if (!results.isEmpty()) {
206 result.add(new LocalSearchScope(PsiUtilCore.toPsiElementArray(results), IdeBundle.message("scope.previous.search.results")));
212 final FavoritesManager favoritesManager = FavoritesManager.getInstance(project);
213 if (favoritesManager != null) {
214 for (final String favorite : favoritesManager.getAvailableFavoritesListNames()) {
215 final Collection<TreeItem<Pair<AbstractUrl, String>>> rootUrls = favoritesManager.getFavoritesListRootUrls(favorite);
216 if (rootUrls.isEmpty()) continue; // ignore unused root
217 result.add(new GlobalSearchScope(project) {
220 public String getDisplayName() {
221 return "Favorite \'" + favorite + "\'";
225 public boolean contains(@NotNull final VirtualFile file) {
226 return favoritesManager.contains(favorite, file);
230 public int compare(@NotNull final VirtualFile file1, @NotNull final VirtualFile file2) {
235 public boolean isSearchInModuleContent(@NotNull final Module aModule) {
240 public boolean isSearchInLibraries() {
247 ContainerUtil.addIfNotNull(result, getSelectedFilesScope(project, dataContext));
249 return ContainerUtil.newArrayList(result);
252 private static void addHierarchyScope(@NotNull Project project, Collection<SearchScope> result) {
253 final ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.HIERARCHY);
254 if (toolWindow == null) {
257 final ContentManager contentManager = toolWindow.getContentManager();
258 final Content content = contentManager.getSelectedContent();
259 if (content == null) {
262 final String name = content.getDisplayName();
263 final JComponent component = content.getComponent();
264 if (!(component instanceof HierarchyBrowserBase)) {
267 final HierarchyBrowserBase hierarchyBrowserBase = (HierarchyBrowserBase)component;
268 final PsiElement[] elements = hierarchyBrowserBase.getAvailableElements();
269 if (elements.length > 0) {
270 result.add(new LocalSearchScope(elements, "Hierarchy '" + name + "' (visible nodes only)"));
275 private static SearchScope getSelectedFilesScope(final Project project, @Nullable DataContext dataContext) {
276 final VirtualFile[] filesOrDirs = dataContext == null ? null : CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
277 if (filesOrDirs != null) {
278 final List<VirtualFile> selectedFiles = ContainerUtil.filter(filesOrDirs, new Condition<VirtualFile>() {
280 public boolean value(VirtualFile file) {
281 return !file.isDirectory();
284 if (!selectedFiles.isEmpty()) {
285 return GlobalSearchScope.filesScope(project, selectedFiles, "Selected Files");
291 protected static Set<VirtualFile> collectFiles(Set<Usage> usages, boolean findFirst) {
292 final Set<VirtualFile> files = new HashSet<VirtualFile>();
293 for (Usage usage : usages) {
294 if (usage instanceof PsiElementUsage) {
295 PsiElement psiElement = ((PsiElementUsage)usage).getElement();
296 if (psiElement != null && psiElement.isValid()) {
297 PsiFile psiFile = psiElement.getContainingFile();
298 if (psiFile != null) {
299 VirtualFile file = psiFile.getVirtualFile();
302 if (findFirst) return files;