message
[idea/community.git] / java / execution / impl / src / com / intellij / execution / ui / ClassBrowser.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.execution.ui;
17
18 import com.intellij.execution.ExecutionBundle;
19 import com.intellij.execution.JavaExecutionUtil;
20 import com.intellij.execution.configuration.BrowseModuleValueActionListener;
21 import com.intellij.execution.configurations.ConfigurationUtil;
22 import com.intellij.ide.util.ClassFilter;
23 import com.intellij.ide.util.TreeClassChooser;
24 import com.intellij.ide.util.TreeClassChooserFactory;
25 import com.intellij.openapi.module.Module;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.ex.MessagesEx;
28 import com.intellij.psi.JavaPsiFacade;
29 import com.intellij.psi.PsiClass;
30 import com.intellij.psi.PsiDirectory;
31 import com.intellij.psi.search.GlobalSearchScope;
32 import com.intellij.psi.util.PsiMethodUtil;
33 import org.jetbrains.annotations.Nullable;
34
35 public abstract class ClassBrowser extends BrowseModuleValueActionListener {
36   private final String myTitle;
37
38   public ClassBrowser(final Project project, final String title) {
39     super(project);
40     myTitle = title;
41   }
42
43   @Nullable
44   protected String showDialog() {
45     final ClassFilter.ClassFilterWithScope classFilter;
46     try {
47       classFilter = getFilter();
48     }
49     catch (NoFilterException e) {
50       final MessagesEx.MessageInfo info = e.getMessageInfo();
51       info.showNow();
52       return null;
53     }
54     final TreeClassChooser dialog = createClassChooser(classFilter);
55     configureDialog(dialog);
56     dialog.showDialog();
57     final PsiClass psiClass = dialog.getSelected();
58     if (psiClass == null) return null;
59     onClassChoosen(psiClass);
60     return JavaExecutionUtil.getRuntimeQualifiedName(psiClass);
61   }
62
63   protected TreeClassChooser createClassChooser(ClassFilter.ClassFilterWithScope classFilter) {
64     return TreeClassChooserFactory.getInstance(getProject()).createWithInnerClassesScopeChooser(myTitle, classFilter.getScope(), classFilter, null);
65   }
66
67   protected abstract ClassFilter.ClassFilterWithScope getFilter() throws NoFilterException;
68
69   protected void onClassChoosen(final PsiClass psiClass) { }
70
71   private void configureDialog(final TreeClassChooser dialog) {
72     final String className = getText();
73     final PsiClass psiClass = findClass(className);
74     if (psiClass == null) return;
75     final PsiDirectory directory = psiClass.getContainingFile().getContainingDirectory();
76     if (directory != null) dialog.selectDirectory(directory);
77     dialog.select(psiClass);
78   }
79
80   protected abstract PsiClass findClass(String className);
81
82   public static ClassBrowser createApplicationClassBrowser(final Project project,
83                                                            final ConfigurationModuleSelector moduleSelector) {
84     final ClassFilter applicationClass = new ClassFilter() {
85       public boolean isAccepted(final PsiClass aClass) {
86         return ConfigurationUtil.MAIN_CLASS.value(aClass) && PsiMethodUtil.findMainMethod(aClass) != null;
87       }
88     };
89     return new MainClassBrowser(project, moduleSelector, ExecutionBundle.message("choose.main.class.dialog.title")){
90       protected ClassFilter createFilter(final Module module) {
91         return applicationClass;
92       }
93     };
94   }
95
96   public static ClassBrowser createAppletClassBrowser(final Project project,
97                                                       final ConfigurationModuleSelector moduleSelector) {
98     final String title = ExecutionBundle.message("choose.applet.class.dialog.title");
99     return new MainClassBrowser(project, moduleSelector, title) {
100
101       @Override
102       protected TreeClassChooser createClassChooser(ClassFilter.ClassFilterWithScope classFilter) {
103         final Module module = moduleSelector.getModule();
104         final GlobalSearchScope scope =
105             module == null ? GlobalSearchScope.allScope(myProject) : GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module);
106          final PsiClass appletClass = JavaPsiFacade.getInstance(project).findClass("java.applet.Applet", scope);
107         return TreeClassChooserFactory.getInstance(getProject()).createInheritanceClassChooser(title, classFilter.getScope(), appletClass, false, false, ConfigurationUtil.PUBLIC_INSTANTIATABLE_CLASS);
108       }
109     };
110   }
111
112   private abstract static class MainClassBrowser extends ClassBrowser {
113     protected final Project myProject;
114     private final ConfigurationModuleSelector myModuleSelector;
115
116     public MainClassBrowser(final Project project,
117                             final ConfigurationModuleSelector moduleSelector,
118                             final String title) {
119       super(project, title);
120       myProject = project;
121       myModuleSelector = moduleSelector;
122     }
123
124     protected PsiClass findClass(final String className) {
125       return myModuleSelector.findClass(className);
126     }
127
128     protected ClassFilter.ClassFilterWithScope getFilter() throws NoFilterException {
129       final Module module = myModuleSelector.getModule();
130       final GlobalSearchScope scope;
131       if (module == null) scope = GlobalSearchScope.allScope(myProject);
132       else scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module);
133       final ClassFilter filter = createFilter(module);
134       return new ClassFilter.ClassFilterWithScope() {
135         public GlobalSearchScope getScope() {
136           return scope;
137         }
138
139         public boolean isAccepted(final PsiClass aClass) {
140           return filter == null || filter.isAccepted(aClass);
141         }
142       };
143     }
144
145     protected ClassFilter createFilter(final Module module) { return null; }
146   }
147
148   public static class NoFilterException extends Exception {
149     private final MessagesEx.MessageInfo myMessageInfo;
150
151     public NoFilterException(final MessagesEx.MessageInfo messageInfo) {
152       super(messageInfo.getMessage());
153       myMessageInfo = messageInfo;
154     }
155
156     public MessagesEx.MessageInfo getMessageInfo() {
157       return myMessageInfo;
158     }
159
160     public static NoFilterException noJUnitInModule(final Module module) {
161       return new NoFilterException(new MessagesEx.MessageInfo(
162         module.getProject(),
163         ExecutionBundle.message("junit.not.found.in.module.error.message", module.getName()),
164         ExecutionBundle.message("cannot.browse.test.inheritors.dialog.title")));
165     }
166
167     public static NoFilterException moduleDoesntExist(final ConfigurationModuleSelector moduleSelector) {
168       final Project project = moduleSelector.getProject();
169       final String moduleName = moduleSelector.getModuleName();
170       return new NoFilterException(new MessagesEx.MessageInfo(
171         project,
172         moduleName.isEmpty() ? "No module selected" : ExecutionBundle.message("module.does.not.exists", moduleName, project.getName()),
173         ExecutionBundle.message("cannot.browse.test.inheritors.dialog.title")));
174     }
175   }
176 }