3ed374732fc0db0a76c2b0c6c4ac9f123b6efb8d
[idea/community.git] / java / compiler / impl / src / com / intellij / compiler / actions / ProcessAnnotationsAction.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.compiler.actions;
17
18 import com.intellij.compiler.CompilerConfiguration;
19 import com.intellij.compiler.CompilerWorkspaceConfiguration;
20 import com.intellij.compiler.impl.FileSetCompileScope;
21 import com.intellij.compiler.impl.ModuleCompileScope;
22 import com.intellij.compiler.impl.javaCompiler.AnnotationProcessingCompiler;
23 import com.intellij.compiler.impl.resourceCompiler.ResourceCompiler;
24 import com.intellij.idea.ActionsBundle;
25 import com.intellij.openapi.actionSystem.*;
26 import com.intellij.openapi.compiler.CompilerBundle;
27 import com.intellij.openapi.compiler.CompilerFilter;
28 import com.intellij.openapi.compiler.CompilerManager;
29 import com.intellij.openapi.fileTypes.FileType;
30 import com.intellij.openapi.fileTypes.FileTypeManager;
31 import com.intellij.openapi.module.Module;
32 import com.intellij.openapi.project.Project;
33 import com.intellij.openapi.roots.ProjectFileIndex;
34 import com.intellij.openapi.roots.ProjectRootManager;
35 import com.intellij.openapi.util.text.StringUtil;
36 import com.intellij.openapi.vfs.VirtualFile;
37 import com.intellij.psi.*;
38 import com.intellij.util.containers.ContainerUtil;
39 import org.jetbrains.annotations.Nullable;
40 import org.jetbrains.jps.model.java.compiler.AnnotationProcessingConfiguration;
41
42 import java.text.MessageFormat;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.List;
46
47 public class ProcessAnnotationsAction extends CompileActionBase {
48
49   protected void doAction(DataContext dataContext, Project project) {
50     final Module module = LangDataKeys.MODULE_CONTEXT.getData(dataContext);
51     final CompilerFilter filter = new CompilerFilter() {
52       public boolean acceptCompiler(com.intellij.openapi.compiler.Compiler compiler) {
53         // EclipseLink CanonicalModelProcessor reads input from output hence adding ResourcesCompiler
54         return compiler instanceof AnnotationProcessingCompiler || compiler instanceof ResourceCompiler;
55       }
56     };
57     if (module != null) {
58       CompilerManager.getInstance(project).make(new ModuleCompileScope(module, false), filter, null);
59     }
60     else {
61       final FileSetCompileScope scope = getCompilableFiles(project, PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext));
62       if (scope != null) {
63         CompilerManager.getInstance(project).make(scope, filter, null);
64       }
65     }
66   }
67
68   public void update(AnActionEvent event) {
69     super.update(event);
70     Presentation presentation = event.getPresentation();
71     if (!presentation.isEnabled()) {
72       return;
73     }
74     DataContext dataContext = event.getDataContext();
75     presentation.setVisible(false);
76
77     Project project = PlatformDataKeys.PROJECT.getData(dataContext);
78     if (project == null) {
79       presentation.setEnabled(false);
80       return;
81     }
82
83     if (CompilerWorkspaceConfiguration.getInstance(project).useOutOfProcessBuild()) {
84       presentation.setEnabled(false);
85       return;
86     }
87     
88     final CompilerConfiguration compilerConfiguration = CompilerConfiguration.getInstance(project);
89     
90     final Module module = LangDataKeys.MODULE.getData(dataContext);
91     final Module moduleContext = LangDataKeys.MODULE_CONTEXT.getData(dataContext);
92
93     if (module == null) {
94       presentation.setEnabled(false);
95       return;
96     }
97     final AnnotationProcessingConfiguration profile = compilerConfiguration.getAnnotationProcessingConfiguration(module);
98     if (!profile.isEnabled() || (!profile.isObtainProcessorsFromClasspath() && profile.getProcessors().isEmpty())) {
99       presentation.setEnabled(false);
100       return;
101     }
102
103     presentation.setVisible(true);
104     presentation.setText(createPresentationText(""), true);
105     final FileSetCompileScope scope = getCompilableFiles(project, PlatformDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext));
106     if (moduleContext == null && scope == null) {
107       presentation.setEnabled(false);
108       return;
109     }
110
111     String elementDescription = null;
112     if (moduleContext != null) {
113       elementDescription = CompilerBundle.message("action.compile.description.module", moduleContext.getName());
114     }
115     else {
116       PsiPackage aPackage = null;
117       final Collection<VirtualFile> files = scope.getRootFiles();
118       if (files.size() == 1) {
119         final PsiDirectory directory = PsiManager.getInstance(project).findDirectory(files.iterator().next());
120         if (directory != null) {
121           aPackage = JavaDirectoryService.getInstance().getPackage(directory);
122         }
123       }
124       else {
125         PsiElement element = LangDataKeys.PSI_ELEMENT.getData(dataContext);
126         if (element instanceof PsiPackage) {
127           aPackage = (PsiPackage)element;
128         }
129       }
130
131       if (aPackage != null) {
132         String name = aPackage.getQualifiedName();
133         if (name.length() == 0) {
134           //noinspection HardCodedStringLiteral
135           name = "<default>";
136         }
137         elementDescription = "'" + name + "'";
138       }
139       else if (files.size() == 1) {
140         final VirtualFile file = files.iterator().next();
141         FileType fileType = file.getFileType();
142         if (CompilerManager.getInstance(project).isCompilableFileType(fileType)) {
143           elementDescription = "'" + file.getName() + "'";
144         }
145         else {
146           if (!ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
147             // the action should be invisible in popups for non-java files
148             presentation.setEnabled(false);
149             presentation.setVisible(false);
150             return;
151           }
152         }
153       }
154       else {
155         elementDescription = CompilerBundle.message("action.compile.description.selected.files");
156       }
157     }
158
159     if (elementDescription == null) {
160       presentation.setEnabled(false);
161       return;
162     }
163
164     presentation.setText(createPresentationText(elementDescription), true);
165     presentation.setEnabled(true);
166   }
167
168   private static String createPresentationText(final String elementDescription) {
169     int length = elementDescription.length();
170     String target = length > 23 ? (StringUtil.startsWithChar(elementDescription, '\'') ? "'..." : "...") + elementDescription.substring(length - 20, length) : elementDescription;
171     return MessageFormat.format(ActionsBundle.actionText(StringUtil.isEmpty(target)? "RunAPT" : "RunAPT.1"), target);
172   }
173
174   @Nullable
175   private static FileSetCompileScope getCompilableFiles(Project project, VirtualFile[] files) {
176     if (files == null || files.length == 0) {
177       return null;
178     }
179     final PsiManager psiManager = PsiManager.getInstance(project);
180     final FileTypeManager typeManager = FileTypeManager.getInstance();
181     final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
182     final CompilerManager compilerManager = CompilerManager.getInstance(project);
183     final List<VirtualFile> filesToCompile = new ArrayList<VirtualFile>();
184     final List<Module> affectedModules = new ArrayList<Module>();
185     for (final VirtualFile file : files) {
186       if (!fileIndex.isInSourceContent(file)) {
187         continue;
188       }
189       if (!file.isInLocalFileSystem()) {
190         continue;
191       }
192       if (file.isDirectory()) {
193         final PsiDirectory directory = psiManager.findDirectory(file);
194         if (directory == null || JavaDirectoryService.getInstance().getPackage(directory) == null) {
195           continue;
196         }
197       }
198       else {
199         FileType fileType = file.getFileType();
200         if (!(compilerManager.isCompilableFileType(fileType))) {
201           continue;
202         }
203       }
204       filesToCompile.add(file);
205       ContainerUtil.addIfNotNull(fileIndex.getModuleForFile(file), affectedModules);
206     }
207     if (filesToCompile.isEmpty()) return null;
208     return new FileSetCompileScope(filesToCompile, affectedModules.toArray(new Module[affectedModules.size()]));
209   }
210 }