move fileScope and filesScope back from GlobalSearchScopes to GlobalSearchScope
[idea/community.git] / platform / lang-impl / src / com / intellij / ide / util / scopeChooser / ScopeChooserCombo.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.ide.util.scopeChooser;
17
18 import com.intellij.ide.DataManager;
19 import com.intellij.ide.IdeBundle;
20 import com.intellij.ide.favoritesTreeView.FavoritesManager;
21 import com.intellij.ide.ui.ListCellRendererWrapper;
22 import com.intellij.openapi.Disposable;
23 import com.intellij.openapi.actionSystem.DataContext;
24 import com.intellij.openapi.actionSystem.LangDataKeys;
25 import com.intellij.openapi.actionSystem.PlatformDataKeys;
26 import com.intellij.openapi.editor.Editor;
27 import com.intellij.openapi.extensions.Extensions;
28 import com.intellij.openapi.fileEditor.FileEditorManager;
29 import com.intellij.openapi.module.Module;
30 import com.intellij.openapi.module.ModuleUtil;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.vfs.VirtualFile;
33 import com.intellij.packageDependencies.ChangeListsScopesProvider;
34 import com.intellij.packageDependencies.DependencyValidationManager;
35 import com.intellij.psi.PsiDocumentManager;
36 import com.intellij.psi.PsiElement;
37 import com.intellij.psi.PsiFile;
38 import com.intellij.psi.PsiWhiteSpace;
39 import com.intellij.psi.search.*;
40 import com.intellij.psi.search.scope.packageSet.NamedScope;
41 import com.intellij.psi.search.scope.packageSet.NamedScopeManager;
42 import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
43 import com.intellij.psi.util.PsiTreeUtil;
44 import com.intellij.psi.util.PsiUtilBase;
45 import com.intellij.ui.ComboboxWithBrowseButton;
46 import com.intellij.usages.Usage;
47 import com.intellij.usages.UsageView;
48 import com.intellij.usages.UsageViewManager;
49 import com.intellij.usages.rules.PsiElementUsage;
50 import com.intellij.util.ArrayUtil;
51 import org.jetbrains.annotations.NotNull;
52 import org.jetbrains.annotations.Nullable;
53
54 import javax.swing.*;
55 import java.awt.event.ActionEvent;
56 import java.awt.event.ActionListener;
57 import java.util.*;
58
59 public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Disposable {
60   private Project myProject;
61   private boolean mySuggestSearchInLibs;
62   private boolean myPrevSearchFiles;
63
64   private NamedScopesHolder.ScopeListener myScopeListener;
65   private NamedScopeManager myNamedScopeManager;
66   private DependencyValidationManager myValidationManager;
67
68   public ScopeChooserCombo() {
69   }
70
71   public ScopeChooserCombo(final Project project, boolean suggestSearchInLibs, boolean prevSearchWholeFiles, String preselect) {
72     init(project, suggestSearchInLibs, prevSearchWholeFiles,  preselect);
73   }
74
75   public void init(final Project project, final String preselect){
76     init(project, false, true, preselect);    
77   }
78
79   public void init(final Project project, final boolean suggestSearchInLibs, final boolean prevSearchWholeFiles,  final String preselect) {
80     mySuggestSearchInLibs = suggestSearchInLibs;
81     myPrevSearchFiles = prevSearchWholeFiles;
82     final JComboBox combo = getComboBox();
83     myProject = project;
84     myScopeListener = new NamedScopesHolder.ScopeListener() {
85       public void scopesChanged() {
86         final SearchScope selectedScope = getSelectedScope();
87         rebuildModel();
88         if (selectedScope != null) {
89           selectScope(selectedScope.getDisplayName());
90         }
91       }
92     };
93     myNamedScopeManager = NamedScopeManager.getInstance(project);
94     myNamedScopeManager.addScopeListener(myScopeListener);
95     myValidationManager = DependencyValidationManager.getInstance(project);
96     myValidationManager.addScopeListener(myScopeListener);
97     addActionListener(createScopeChooserListener());
98
99     combo.setRenderer(new ListCellRendererWrapper<ScopeDescriptor>(combo.getRenderer()) {
100       @Override
101       public void customize(final JList list, final ScopeDescriptor value, final int index, final boolean selected, final boolean hasFocus) {
102         if (value != null) setText(value.getDisplay());
103       }
104     });
105
106     rebuildModel();
107
108     selectScope(preselect);
109   }
110
111   @Override
112   public void dispose() {
113     super.dispose();
114     if (myValidationManager != null) {
115       myValidationManager.removeScopeListener(myScopeListener);
116       myValidationManager = null;
117     }
118     if (myNamedScopeManager != null) {
119       myNamedScopeManager.removeScopeListener(myScopeListener);
120       myNamedScopeManager = null;
121     }
122     myScopeListener = null;
123   }
124
125   private void selectScope(String preselect) {
126     if (preselect != null) {
127       final JComboBox combo = getComboBox();
128       DefaultComboBoxModel model = (DefaultComboBoxModel)combo.getModel();
129       for (int i = 0; i < model.getSize(); i++) {
130         ScopeDescriptor descriptor = (ScopeDescriptor)model.getElementAt(i);
131         if (preselect.equals(descriptor.getDisplay())) {
132           combo.setSelectedIndex(i);
133           break;
134         }
135       }
136     }
137   }
138
139   private ActionListener createScopeChooserListener() {
140     return new ActionListener() {
141       public void actionPerformed(ActionEvent e) {
142         final String selection = getSelectedScopeName();
143         final EditScopesDialog dlg = EditScopesDialog.showDialog(myProject, selection);
144         if (dlg.isOK()){
145           rebuildModel();
146           final NamedScope namedScope = dlg.getSelectedScope();
147           if (namedScope != null) {
148             selectScope(namedScope.getName());
149           }
150         }
151       }
152     };
153   }
154
155   private void rebuildModel() {
156     getComboBox().setModel(createModel());
157   }
158
159   private DefaultComboBoxModel createModel() {
160     DefaultComboBoxModel model = new DefaultComboBoxModel();
161     createPredefinedScopeDescriptors(model);
162
163     List<NamedScope> changeLists = ChangeListsScopesProvider.getInstance(myProject).getCustomScopes();
164     for (NamedScope changeListScope : changeLists) {
165       model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, changeListScope)));
166     }
167     final NamedScopesHolder[] holders = NamedScopesHolder.getAllNamedScopeHolders(myProject);
168     for (NamedScopesHolder holder : holders) {
169       NamedScope[] scopes = holder.getEditableScopes(); //predefined scopes already included
170       for (NamedScope scope : scopes) {
171         model.addElement(new ScopeDescriptor(GlobalSearchScopes.filterScope(myProject, scope)));
172       }
173     }
174
175     return model;
176   }
177
178
179   private void createPredefinedScopeDescriptors(DefaultComboBoxModel model) {
180     for (SearchScope scope : getPredefinedScopes(myProject, DataManager.getInstance().getDataContext(), mySuggestSearchInLibs, myPrevSearchFiles, true, true)) {
181       model.addElement(new ScopeDescriptor(scope));
182     }
183     for (ScopeDescriptorProvider provider : Extensions.getExtensions(ScopeDescriptorProvider.EP_NAME)) {
184       for (ScopeDescriptor scopeDescriptor : provider.getScopeDescriptors(myProject)) {
185         model.addElement(scopeDescriptor);
186       }
187     }
188   }
189
190   public static List<SearchScope> getPredefinedScopes(@NotNull final Project project,
191                                                       @Nullable final DataContext dataContext,
192                                                       boolean suggestSearchInLibs,
193                                                       boolean prevSearchFiles,
194                                                       boolean currentSelection,
195                                                       boolean usageView) {
196     ArrayList<SearchScope> result = new ArrayList<SearchScope>();
197     result.add(GlobalSearchScope.projectScope(project));
198     if (suggestSearchInLibs) {
199       result.add(GlobalSearchScope.allScope(project));
200     }
201     result.add(GlobalSearchScopes.projectProductionScope(project));
202     result.add(GlobalSearchScopes.projectTestScope(project));
203
204     if (dataContext != null) {
205       PsiElement dataContextElement = getDataContextElement(dataContext);
206
207       if (dataContextElement != null) {
208         Module module = ModuleUtil.findModuleForPsiElement(dataContextElement);
209         if (module == null) {
210           module = LangDataKeys.MODULE.getData(dataContext);
211         }
212         if (module != null) {
213           result.add(module.getModuleScope());
214         }
215         if (dataContextElement.getContainingFile() != null) {
216           result.add(new LocalSearchScope(dataContextElement, IdeBundle.message("scope.current.file")));
217         }
218       }
219     }
220
221     if (currentSelection) {
222       FileEditorManager fileEditorManager = FileEditorManager.getInstance(project);
223       final Editor selectedTextEditor = fileEditorManager.getSelectedTextEditor();
224       if (selectedTextEditor != null) {
225         final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(selectedTextEditor.getDocument());
226         if (psiFile != null) {
227           if (selectedTextEditor.getSelectionModel().hasSelection()) {
228             final PsiElement startElement = psiFile.findElementAt(selectedTextEditor.getSelectionModel().getSelectionStart());
229             if (startElement != null) {
230               final PsiElement endElement = psiFile.findElementAt(selectedTextEditor.getSelectionModel().getSelectionEnd());
231               if (endElement != null) {
232                 final PsiElement parent = PsiTreeUtil.findCommonParent(startElement, endElement);
233                 if (parent != null) {
234                   final List<PsiElement> elements = new ArrayList<PsiElement>();
235                   final PsiElement[] children = parent.getChildren();
236                   for (PsiElement child : children) {
237                     if (!(child instanceof PsiWhiteSpace)) {
238                       elements.add(child);
239                     }
240                   }
241                   if (!elements.isEmpty()) {
242                     SearchScope local = new LocalSearchScope(PsiUtilBase.toPsiElementArray(elements), IdeBundle.message("scope.selection"));
243                     result.add(local);
244                   }
245                 }
246               }
247             }
248           }
249         }
250       }
251     }
252
253     if (usageView) {
254       UsageView selectedUsageView = UsageViewManager.getInstance(project).getSelectedUsageView();
255       if (selectedUsageView != null && !selectedUsageView.isSearchInProgress()) {
256         final Set<Usage> usages = selectedUsageView.getUsages();
257         final List<PsiElement> results = new ArrayList<PsiElement>(usages.size());
258
259         if (prevSearchFiles) {
260           final Set<VirtualFile> files = new HashSet<VirtualFile>();
261           for (Usage usage : usages) {
262             if (usage instanceof PsiElementUsage) {
263               PsiElement psiElement = ((PsiElementUsage)usage).getElement();
264               if (psiElement != null && psiElement.isValid()) {
265                 PsiFile psiFile = psiElement.getContainingFile();
266                 if (psiFile != null) {
267                   VirtualFile file = psiFile.getVirtualFile();
268                   if (file != null) files.add(file);
269                 }
270               }
271             }
272           }
273           if (!files.isEmpty()) {
274             GlobalSearchScope prev = new GlobalSearchScope(project) {
275               public String getDisplayName() {
276                 return IdeBundle.message("scope.files.in.previous.search.result");
277               }
278
279               public boolean contains(VirtualFile file) {
280                 return files.contains(file);
281               }
282
283               public int compare(VirtualFile file1, VirtualFile file2) {
284                 return 0;
285               }
286
287               public boolean isSearchInModuleContent(@NotNull Module aModule) {
288                 return true;
289               }
290
291               public boolean isSearchInLibraries() {
292                 return true;
293               }
294             };
295             result.add(prev);
296           }
297         }
298         else {
299           for (Usage usage : usages) {
300             if (usage instanceof PsiElementUsage) {
301               final PsiElement element = ((PsiElementUsage)usage).getElement();
302               if (element != null && element.isValid() && element.getContainingFile() != null) {
303                 results.add(element);
304               }
305             }
306           }
307
308           if (!results.isEmpty()) {
309             result.add(new LocalSearchScope(PsiUtilBase.toPsiElementArray(results), IdeBundle.message("scope.previous.search.results")));
310           }
311         }
312       }
313     }
314
315     final FavoritesManager favoritesManager = FavoritesManager.getInstance(project);
316     String[] favoritesLists = favoritesManager == null ? ArrayUtil.EMPTY_STRING_ARRAY : favoritesManager.getAvailableFavoritesLists();
317     for (final String favorite : favoritesLists) {
318       result.add(new GlobalSearchScope(project) {
319         @Override
320         public String getDisplayName() {
321           return "Favorite \'" + favorite + "\'";
322         }
323
324         @Override
325         public boolean contains(final VirtualFile file) {
326           return favoritesManager.contains(favorite, file);
327         }
328
329         @Override
330         public int compare(final VirtualFile file1, final VirtualFile file2) {
331           return 0;
332         }
333
334         @Override
335         public boolean isSearchInModuleContent(@NotNull final Module aModule) {
336           return true;
337         }
338
339         @Override
340         public boolean isSearchInLibraries() {
341           return true;
342         }
343       });
344     }
345
346     if (dataContext != null) {
347       final VirtualFile[] files = PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
348       if (files != null) {
349         final List<VirtualFile> openFiles = Arrays.asList(files);
350         result.add(new DelegatingGlobalSearchScope(GlobalSearchScope.filesScope(project, openFiles)){
351           @Override
352           public String getDisplayName() {
353             return "Selected files";
354           }
355         });
356       }
357     }
358
359     return result;
360   }
361
362   public static PsiElement getDataContextElement(DataContext dataContext) {
363     PsiElement dataContextElement = LangDataKeys.PSI_FILE.getData(dataContext);
364
365     if (dataContextElement == null) {
366       dataContextElement = LangDataKeys.PSI_ELEMENT.getData(dataContext);
367     }
368     return dataContextElement;
369   }
370
371
372   @Nullable
373   public SearchScope getSelectedScope() {
374     JComboBox combo = getComboBox();
375     int idx = combo.getSelectedIndex();
376     if (idx < 0) return null;
377     return ((ScopeDescriptor)combo.getSelectedItem()).getScope();
378   }
379
380   @Nullable
381   public String getSelectedScopeName() {
382     JComboBox combo = getComboBox();
383     int idx = combo.getSelectedIndex();
384     if (idx < 0) return null;
385     return ((ScopeDescriptor)combo.getSelectedItem()).getDisplay();
386   }
387 }