2 * Copyright 2000-2009 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.ide.util.scopeChooser;
18 import com.intellij.ide.DataManager;
19 import com.intellij.ide.IdeBundle;
20 import com.intellij.ide.favoritesTreeView.FavoritesManager;
21 import com.intellij.ide.projectView.impl.AbstractUrl;
22 import com.intellij.ide.ui.ListCellRendererWrapper;
23 import com.intellij.openapi.Disposable;
24 import com.intellij.openapi.actionSystem.DataContext;
25 import com.intellij.openapi.actionSystem.LangDataKeys;
26 import com.intellij.openapi.actionSystem.PlatformDataKeys;
27 import com.intellij.openapi.editor.Editor;
28 import com.intellij.openapi.extensions.Extensions;
29 import com.intellij.openapi.fileEditor.FileEditorManager;
30 import com.intellij.openapi.module.Module;
31 import com.intellij.openapi.module.ModuleUtil;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.util.Pair;
34 import com.intellij.openapi.vfs.VirtualFile;
35 import com.intellij.packageDependencies.ChangeListsScopesProvider;
36 import com.intellij.packageDependencies.DependencyValidationManager;
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.search.*;
42 import com.intellij.psi.search.scope.packageSet.NamedScope;
43 import com.intellij.psi.search.scope.packageSet.NamedScopeManager;
44 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
45 import com.intellij.psi.util.PsiTreeUtil;
46 import com.intellij.psi.util.PsiUtilBase;
47 import com.intellij.psi.util.PsiUtilCore;
48 import com.intellij.ui.ComboboxWithBrowseButton;
49 import com.intellij.usages.Usage;
50 import com.intellij.usages.UsageView;
51 import com.intellij.usages.UsageViewManager;
52 import com.intellij.usages.rules.PsiElementUsage;
53 import com.intellij.util.ArrayUtil;
54 import com.intellij.util.PlatformUtils;
55 import org.jetbrains.annotations.NotNull;
56 import org.jetbrains.annotations.Nullable;
59 import java.awt.event.ActionEvent;
60 import java.awt.event.ActionListener;
63 public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Disposable {
64 private Project myProject;
65 private boolean mySuggestSearchInLibs;
66 private boolean myPrevSearchFiles;
68 private NamedScopesHolder.ScopeListener myScopeListener;
69 private NamedScopeManager myNamedScopeManager;
70 private DependencyValidationManager myValidationManager;
72 public ScopeChooserCombo() {
75 public ScopeChooserCombo(final Project project, boolean suggestSearchInLibs, boolean prevSearchWholeFiles, String preselect) {
76 init(project, suggestSearchInLibs, prevSearchWholeFiles, preselect);
79 public void init(final Project project, final String preselect){
80 init(project, false, true, preselect);
83 public void init(final Project project, final boolean suggestSearchInLibs, final boolean prevSearchWholeFiles, final String preselect) {
84 mySuggestSearchInLibs = suggestSearchInLibs;
85 myPrevSearchFiles = prevSearchWholeFiles;
86 final JComboBox combo = getComboBox();
88 myScopeListener = new NamedScopesHolder.ScopeListener() {
89 public void scopesChanged() {
90 final SearchScope selectedScope = getSelectedScope();
92 if (selectedScope != null) {
93 selectScope(selectedScope.getDisplayName());
97 myNamedScopeManager = NamedScopeManager.getInstance(project);
98 myNamedScopeManager.addScopeListener(myScopeListener);
99 myValidationManager = DependencyValidationManager.getInstance(project);
100 myValidationManager.addScopeListener(myScopeListener);
101 addActionListener(createScopeChooserListener());
103 combo.setRenderer(new ListCellRendererWrapper<ScopeDescriptor>(combo.getRenderer()) {
105 public void customize(final JList list, final ScopeDescriptor value, final int index, final boolean selected, final boolean hasFocus) {
106 if (value != null) setText(value.getDisplay());
112 selectScope(preselect);
116 public void dispose() {
118 if (myValidationManager != null) {
119 myValidationManager.removeScopeListener(myScopeListener);
120 myValidationManager = null;
122 if (myNamedScopeManager != null) {
123 myNamedScopeManager.removeScopeListener(myScopeListener);
124 myNamedScopeManager = null;
126 myScopeListener = null;
129 private void selectScope(String preselect) {
130 if (preselect != null) {
131 final JComboBox combo = getComboBox();
132 DefaultComboBoxModel model = (DefaultComboBoxModel)combo.getModel();
133 for (int i = 0; i < model.getSize(); i++) {
134 ScopeDescriptor descriptor = (ScopeDescriptor)model.getElementAt(i);
135 if (preselect.equals(descriptor.getDisplay())) {
136 combo.setSelectedIndex(i);
143 private ActionListener createScopeChooserListener() {
144 return new ActionListener() {
145 public void actionPerformed(ActionEvent e) {
146 final String selection = getSelectedScopeName();
147 final EditScopesDialog dlg = EditScopesDialog.showDialog(myProject, selection);
150 final NamedScope namedScope = dlg.getSelectedScope();
151 if (namedScope != null) {
152 selectScope(namedScope.getName());
159 private void rebuildModel() {
160 getComboBox().setModel(createModel());
163 private DefaultComboBoxModel createModel() {
164 DefaultComboBoxModel model = new DefaultComboBoxModel();
165 createPredefinedScopeDescriptors(model);
167 List<NamedScope> changeLists = ChangeListsScopesProvider.getInstance(myProject).getCustomScopes();
168 for (NamedScope changeListScope : changeLists) {
169 model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, changeListScope)));
171 final NamedScopesHolder[] holders = NamedScopesHolder.getAllNamedScopeHolders(myProject);
172 for (NamedScopesHolder holder : holders) {
173 NamedScope[] scopes = holder.getEditableScopes(); //predefined scopes already included
174 for (NamedScope scope : scopes) {
175 model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, scope)));
183 private void createPredefinedScopeDescriptors(DefaultComboBoxModel model) {
184 for (SearchScope scope : getPredefinedScopes(myProject, DataManager.getInstance().getDataContext(), mySuggestSearchInLibs, myPrevSearchFiles, true, true)) {
185 model.addElement(new ScopeDescriptor(scope));
187 for (ScopeDescriptorProvider provider : Extensions.getExtensions(ScopeDescriptorProvider.EP_NAME)) {
188 for (ScopeDescriptor scopeDescriptor : provider.getScopeDescriptors(myProject)) {
189 model.addElement(scopeDescriptor);
194 public static List<SearchScope> getPredefinedScopes(@NotNull final Project project,
195 @Nullable final DataContext dataContext,
196 boolean suggestSearchInLibs,
197 boolean prevSearchFiles,
198 boolean currentSelection,
200 ArrayList<SearchScope> result = new ArrayList<SearchScope>();
201 result.add(GlobalSearchScope.projectScope(project));
202 if (suggestSearchInLibs) {
203 result.add(GlobalSearchScope.allScope(project));
206 if (!PlatformUtils.isCidr()) { // TODO: fix these scopes in AppCode
207 result.add(GlobalSearchScopes.projectProductionScope(project));
208 result.add(GlobalSearchScopes.projectTestScope(project));
211 if (dataContext != null) {
212 PsiElement dataContextElement = getDataContextElement(dataContext);
214 if (dataContextElement != null) {
215 if (!PlatformUtils.isCidr()) { // TODO: have an API to disable module scopes.
216 Module module = ModuleUtil.findModuleForPsiElement(dataContextElement);
217 if (module == null) {
218 module = LangDataKeys.MODULE.getData(dataContext);
220 if (module != null) {
221 result.add(module.getModuleScope());
224 if (dataContextElement.getContainingFile() != null) {
225 result.add(new LocalSearchScope(dataContextElement, IdeBundle.message("scope.current.file")));
230 if (currentSelection) {
231 FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
232 final Editor selectedTextEditor = fileEditorManager.getSelectedTextEditor();
233 if (selectedTextEditor != null) {
234 final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(selectedTextEditor.getDocument());
235 if (psiFile != null) {
236 if (selectedTextEditor.getSelectionModel().hasSelection()) {
237 final PsiElement startElement = psiFile.findElementAt(selectedTextEditor.getSelectionModel().getSelectionStart());
238 if (startElement != null) {
239 final PsiElement endElement = psiFile.findElementAt(selectedTextEditor.getSelectionModel().getSelectionEnd());
240 if (endElement != null) {
241 final PsiElement parent = PsiTreeUtil.findCommonParent(startElement, endElement);
242 if (parent != null) {
243 final List<PsiElement> elements = new ArrayList<PsiElement>();
244 final PsiElement[] children = parent.getChildren();
245 for (PsiElement child : children) {
246 if (!(child instanceof PsiWhiteSpace) && child.getContainingFile() != null) {
250 if (!elements.isEmpty()) {
251 SearchScope local = new LocalSearchScope(PsiUtilCore.toPsiElementArray(elements), IdeBundle.message("scope.selection"));
263 UsageView selectedUsageView = UsageViewManager.getInstance(project).getSelectedUsageView();
264 if (selectedUsageView != null && !selectedUsageView.isSearchInProgress()) {
265 final Set<Usage> usages = selectedUsageView.getUsages();
266 final List<PsiElement> results = new ArrayList<PsiElement>(usages.size());
268 if (prevSearchFiles) {
269 final Set<VirtualFile> files = new HashSet<VirtualFile>();
270 for (Usage usage : usages) {
271 if (usage instanceof PsiElementUsage) {
272 PsiElement psiElement = ((PsiElementUsage)usage).getElement();
273 if (psiElement != null && psiElement.isValid()) {
274 PsiFile psiFile = psiElement.getContainingFile();
275 if (psiFile != null) {
276 VirtualFile file = psiFile.getVirtualFile();
277 if (file != null) files.add(file);
282 if (!files.isEmpty()) {
283 GlobalSearchScope prev = new GlobalSearchScope(project) {
284 public String getDisplayName() {
285 return IdeBundle.message("scope.files.in.previous.search.result");
288 public boolean contains(VirtualFile file) {
289 return files.contains(file);
292 public int compare(VirtualFile file1, VirtualFile file2) {
296 public boolean isSearchInModuleContent(@NotNull Module aModule) {
300 public boolean isSearchInLibraries() {
308 for (Usage usage : usages) {
309 if (usage instanceof PsiElementUsage) {
310 final PsiElement element = ((PsiElementUsage)usage).getElement();
311 if (element != null && element.isValid() && element.getContainingFile() != null) {
312 results.add(element);
317 if (!results.isEmpty()) {
318 result.add(new LocalSearchScope(PsiUtilBase.toPsiElementArray(results), IdeBundle.message("scope.previous.search.results")));
324 final FavoritesManager favoritesManager = FavoritesManager.getInstance(project);
325 String[] favoritesLists = favoritesManager == null ? ArrayUtil.EMPTY_STRING_ARRAY : favoritesManager.getAvailableFavoritesLists();
326 for (final String favorite : favoritesLists) {
327 final Collection<Pair<AbstractUrl,String>> rootUrls = favoritesManager.getFavoritesListRootUrls(favorite);
328 if (rootUrls.isEmpty()) continue; //ignore unused root
329 result.add(new GlobalSearchScope(project) {
331 public String getDisplayName() {
332 return "Favorite \'" + favorite + "\'";
336 public boolean contains(final VirtualFile file) {
337 return favoritesManager.contains(favorite, file);
341 public int compare(final VirtualFile file1, final VirtualFile file2) {
346 public boolean isSearchInModuleContent(@NotNull final Module aModule) {
351 public boolean isSearchInLibraries() {
357 if (dataContext != null) {
358 final VirtualFile[] files = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
360 final List<VirtualFile> openFiles = Arrays.asList(files);
361 result.add(new DelegatingGlobalSearchScope(GlobalSearchScope.filesScope(project, openFiles)){
363 public String getDisplayName() {
364 return "Selected files";
373 public static PsiElement getDataContextElement(DataContext dataContext) {
374 PsiElement dataContextElement = LangDataKeys.PSI_FILE.getData(dataContext);
376 if (dataContextElement == null) {
377 dataContextElement = LangDataKeys.PSI_ELEMENT.getData(dataContext);
379 return dataContextElement;
384 public SearchScope getSelectedScope() {
385 JComboBox combo = getComboBox();
386 int idx = combo.getSelectedIndex();
387 if (idx < 0) return null;
388 return ((ScopeDescriptor)combo.getSelectedItem()).getScope();
392 public String getSelectedScopeName() {
393 JComboBox combo = getComboBox();
394 int idx = combo.getSelectedIndex();
395 if (idx < 0) return null;
396 return ((ScopeDescriptor)combo.getSelectedItem()).getDisplay();