- annotation processors profiles

- out-of-process build: supported annotation processing configurable via profiles
This commit is contained in:
Eugene Zhuravlev
2012-05-30 14:51:58 +02:00
parent 3fd1d42284
commit 9bed8ccc3b
21 changed files with 1374 additions and 726 deletions
@@ -52,7 +52,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.apache.oro.text.regex.*;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -74,6 +73,12 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompilerConfiguration");
@NonNls public static final String TESTS_EXTERNAL_COMPILER_HOME_PROPERTY_NAME = "tests.external.compiler.home";
public static final int DEPENDENCY_FORMAT_VERSION = 55;
private static final Comparator<String> ALPHA_COMPARATOR = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
};
@SuppressWarnings({"WeakerAccess"}) public String DEFAULT_COMPILER;
@NotNull private BackendCompiler myDefaultJavaCompiler;
@@ -96,15 +101,14 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
{
loadDefaultWildcardPatterns();
}
private boolean myEnableAnnotationProcessors = false;
private final Map<String, String> myProcessorsMap = new HashMap<String, String>(); // map: AnnotationProcessorName -> options
private boolean myObtainProcessorsFromClasspath = true;
private String myProcessorPath = "";
private final Map<Module, String> myProcessedModules = new HashMap<Module, String>();
private final Map<String, String> myModuleNames = new HashMap<String, String>();
private boolean myAddNotNullAssertions = true;
private final ProcessorConfigProfile myDefaultProcessorsProfile = new ProcessorConfigProfile("Default");
private final List<ProcessorConfigProfile> myModuleProcessorProfiles = new ArrayList<ProcessorConfigProfile>();
// the map is calculated by module processor profiles list for faster access to module settings
private Map<Module, ProcessorConfigProfile> myProcessorsProfilesMap = null;
@Nullable
private String myBytecodeTargetLevel = null; // null means compiler default
private final Map<String, String> myModuleBytecodeTarget = new java.util.HashMap<String, String>();
@@ -116,16 +120,11 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
Disposer.register(project, myExcludedEntriesConfiguration);
project.getMessageBus().connect(project).subscribe(ProjectTopics.MODULES, new ModuleAdapter() {
public void beforeModuleRemoved(Project project, Module module) {
myProcessedModules.remove(module);
myModuleNames.remove(module.getName());
getAnnotationProcessingConfiguration(module).removeModuleName(module.getName());
}
public void moduleAdded(Project project, Module module) {
final String moduleName = module.getName();
if (myModuleNames.containsKey(moduleName)) {
final String dirName = myModuleNames.remove(moduleName);
myProcessedModules.put(module, dirName);
}
myProcessorsProfilesMap = null; // clear cache
}
});
}
@@ -376,55 +375,62 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
myAddNotNullAssertions = enabled;
}
@NotNull
public ProcessorConfigProfile getDefaultProcessorProfile() {
return myDefaultProcessorsProfile;
}
public void setDefaultProcessorProfile(ProcessorConfigProfile profile) {
myDefaultProcessorsProfile.initFrom(profile);
}
@NotNull
public List<ProcessorConfigProfile> getModuleProcessorProfiles() {
return myModuleProcessorProfiles;
}
public void setModuleProcessorProfiles(Collection<ProcessorConfigProfile> moduleProfiles) {
myModuleProcessorProfiles.clear();
myModuleProcessorProfiles.addAll(moduleProfiles);
}
@Override
@NotNull
public ProcessorConfigProfile getAnnotationProcessingConfiguration(Module module) {
Map<Module, ProcessorConfigProfile> map = myProcessorsProfilesMap;
if (map == null) {
map = new HashMap<Module, ProcessorConfigProfile>();
final Map<String, Module> namesMap = new HashMap<String, Module>();
for (Module m : ModuleManager.getInstance(module.getProject()).getModules()) {
namesMap.put(m.getName(), m);
}
if (!namesMap.isEmpty()) {
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
for (String name : profile.getModuleNames()) {
final Module mod = namesMap.get(name);
if (mod != null) {
map.put(mod, profile);
}
}
}
}
myProcessorsProfilesMap = map;
}
final ProcessorConfigProfile profile = map.get(module);
return profile != null? profile : myDefaultProcessorsProfile;
}
@Override
public boolean isAnnotationProcessorsEnabled() {
return myEnableAnnotationProcessors;
}
public void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors) {
myEnableAnnotationProcessors = enableAnnotationProcessors;
}
public boolean isObtainProcessorsFromClasspath() {
return myObtainProcessorsFromClasspath;
}
public void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath) {
myObtainProcessorsFromClasspath = obtainProcessorsFromClasspath;
}
public String getProcessorPath() {
return myProcessorPath;
}
public void setProcessorsPath(String processorsPath) {
myProcessorPath = processorsPath;
}
public Map<String, String> getAnnotationProcessorsMap() {
return Collections.unmodifiableMap(myProcessorsMap);
}
public void setAnnotationProcessorsMap(Map<String, String> map) {
myProcessorsMap.clear();
myProcessorsMap.putAll(map);
}
public void setAnotationProcessedModules(Map<Module, String> modules) {
myProcessedModules.clear();
myModuleNames.clear();
myProcessedModules.putAll(modules);
}
public Map<Module, String> getAnotationProcessedModules() {
return Collections.unmodifiableMap(myProcessedModules);
}
public boolean isAnnotationProcessingEnabled(Module module) {
return myProcessedModules.containsKey(module);
}
public String getGeneratedSourceDirName(Module module) {
return myProcessedModules.get(module);
if (myDefaultProcessorsProfile.isEnabled()) {
return true;
}
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
if (profile.isEnabled()) {
return true;
}
}
return false;
}
private void addWildcardResourcePattern(@NonNls final String wildcardPattern) throws MalformedPatternException {
@@ -579,21 +585,26 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
}
// property names
@NonNls private static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile";
@NonNls private static final String RESOURCE_EXTENSIONS = "resourceExtensions";
@NonNls private static final String ANNOTATION_PROCESSING = "annotationProcessing";
@NonNls private static final String BYTECODE_TARGET_LEVEL = "bytecodeTargetLevel";
@NonNls private static final String WILDCARD_RESOURCE_PATTERNS = "wildcardResourcePatterns";
@NonNls private static final String ENTRY = "entry";
@NonNls private static final String NAME = "name";
@NonNls private static final String ADD_NOTNULL_ASSERTIONS = "addNotNullAssertions";
private static final String EXCLUDE_FROM_COMPILE = "excludeFromCompile";
private static final String RESOURCE_EXTENSIONS = "resourceExtensions";
private static final String ANNOTATION_PROCESSING = "annotationProcessing";
private static final String BYTECODE_TARGET_LEVEL = "bytecodeTargetLevel";
private static final String WILDCARD_RESOURCE_PATTERNS = "wildcardResourcePatterns";
private static final String ADD_NOTNULL_ASSERTIONS = "addNotNullAssertions";
private static final String ENTRY = "entry";
private static final String NAME = "name";
private static final String VALUE = "value";
private static final String ENABLED = "enabled";
private static final String OPTION = "option";
private static final String MODULE = "module";
public void readExternal(Element parentNode) throws InvalidDataException {
DefaultJDOMExternalizer.readExternal(this, parentNode);
final Element notNullAssertions = parentNode.getChild(ADD_NOTNULL_ASSERTIONS);
if (notNullAssertions != null) {
myAddNotNullAssertions = Boolean.valueOf(notNullAssertions.getAttributeValue("enabled", "true"));
myAddNotNullAssertions = Boolean.valueOf(notNullAssertions.getAttributeValue(ENABLED, "true"));
}
Element node = parentNode.getChild(EXCLUDE_FROM_COMPILE);
@@ -608,7 +619,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
for (final Object o : node.getChildren(ENTRY)) {
Element element = (Element)o;
String pattern = element.getAttributeValue(NAME);
if (pattern != null && !"".equals(pattern)) {
if (!StringUtil.isEmpty(pattern)) {
addRegexpPattern(pattern);
}
}
@@ -621,7 +632,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
for (final Object o : node.getChildren(ENTRY)) {
final Element element = (Element)o;
String pattern = element.getAttributeValue(NAME);
if (pattern != null && !"".equals(pattern)) {
if (!StringUtil.isEmpty(pattern)) {
addWildcardResourcePattern(pattern);
}
}
@@ -631,69 +642,41 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
throw new InvalidDataException(e);
}
myModuleProcessorProfiles.clear();
myProcessorsProfilesMap = null;
final Element annotationProcessingSettings = parentNode.getChild(ANNOTATION_PROCESSING);
if (annotationProcessingSettings != null) {
myEnableAnnotationProcessors = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("enabled", "false"));
myObtainProcessorsFromClasspath = Boolean.valueOf(annotationProcessingSettings.getAttributeValue("useClasspath", "true"));
final StringBuilder pathBuilder = new StringBuilder();
for (Element pathElement : (Collection<Element>)annotationProcessingSettings.getChildren("processorPath")) {
final String path = pathElement.getAttributeValue("value");
if (path != null) {
if (pathBuilder.length() > 0) {
pathBuilder.append(File.pathSeparator);
}
pathBuilder.append(path);
for (Object elem : annotationProcessingSettings.getChildren("profile")) {
final Element profileElement = (Element)elem;
final boolean isDefault = "true".equals(profileElement.getAttributeValue("default"));
if (isDefault) {
readProfile(profileElement, myDefaultProcessorsProfile);
}
else {
final ProcessorConfigProfile profile = new ProcessorConfigProfile("");
readProfile(profileElement, profile);
myModuleProcessorProfiles.add(profile);
}
}
myProcessorPath = pathBuilder.toString();
}
myProcessorsMap.clear();
for (Element processorChild : (Collection<Element>)annotationProcessingSettings.getChildren("processor")) {
final String name = processorChild.getAttributeValue("name");
final String options = processorChild.getAttributeValue("options", "");
myProcessorsMap.put(name, options);
}
myProcessedModules.clear();
myModuleNames.clear();
final Collection<Element> processed = (Collection<Element>)annotationProcessingSettings.getChildren("processModule");
if (!processed.isEmpty()) {
final Map<String, Module> moduleMap = new HashMap<String, Module>();
for (Module module : myModuleManager.getModules()) {
moduleMap.put(module.getName(), module);
myBytecodeTargetLevel = null;
myModuleBytecodeTarget.clear();
final Element bytecodeTargetElement = parentNode.getChild(BYTECODE_TARGET_LEVEL);
if (bytecodeTargetElement != null) {
myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue("target");
for (Element elem : (Collection<Element>)bytecodeTargetElement.getChildren(MODULE)) {
final String name = elem.getAttributeValue(NAME);
if (name == null) {
continue;
}
for (Element moduleElement : processed) {
final String name = moduleElement.getAttributeValue("name");
final String dirname = moduleElement.getAttributeValue("generatedDirName");
if (name != null) {
final Module module = moduleMap.get(name);
if (module != null) {
myProcessedModules.put(module, dirname);
}
else {
myModuleNames.put(name, dirname);
}
}
}
}
myBytecodeTargetLevel = null;
myModuleBytecodeTarget.clear();
final Element bytecodeTargetElement = parentNode.getChild(BYTECODE_TARGET_LEVEL);
if (bytecodeTargetElement != null) {
myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue("target");
for (Element elem : (Collection<Element>)bytecodeTargetElement.getChildren("module")) {
final String name = elem.getAttributeValue("name");
if (name == null) {
continue;
}
final String target = elem.getAttributeValue("target");
if (target == null) {
continue;
}
myModuleBytecodeTarget.put(name, target);
final String target = elem.getAttributeValue("target");
if (target == null) {
continue;
}
myModuleBytecodeTarget.put(name, target);
}
}
}
@@ -702,88 +685,42 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
DefaultJDOMExternalizer.writeExternal(this, parentNode);
if (myAddNotNullAssertions != true) {
final Element notNullAssertions = new Element(ADD_NOTNULL_ASSERTIONS);
notNullAssertions.setAttribute("enabled", String.valueOf(myAddNotNullAssertions));
parentNode.addContent(notNullAssertions);
addChild(parentNode, ADD_NOTNULL_ASSERTIONS).setAttribute(ENABLED, String.valueOf(myAddNotNullAssertions));
}
if(myExcludedEntriesConfiguration.getExcludeEntryDescriptions().length > 0) {
Element newChild = new Element(EXCLUDE_FROM_COMPILE);
myExcludedEntriesConfiguration.writeExternal(newChild);
parentNode.addContent(newChild);
myExcludedEntriesConfiguration.writeExternal(addChild(parentNode, EXCLUDE_FROM_COMPILE));
}
final Element newChild = new Element(RESOURCE_EXTENSIONS);
final Element newChild = addChild(parentNode, RESOURCE_EXTENSIONS);
for (final String pattern : getRegexpPatterns()) {
final Element entry = new Element(ENTRY);
entry.setAttribute(NAME, pattern);
newChild.addContent(entry);
addChild(newChild, ENTRY).setAttribute(NAME, pattern);
}
parentNode.addContent(newChild);
if (myWildcardPatternsInitialized || !myWildcardPatterns.isEmpty()) {
final Element wildcardPatterns = new Element(WILDCARD_RESOURCE_PATTERNS);
final Element wildcardPatterns = addChild(parentNode, WILDCARD_RESOURCE_PATTERNS);
for (final String wildcardPattern : myWildcardPatterns) {
final Element entry = new Element(ENTRY);
entry.setAttribute(NAME, wildcardPattern);
wildcardPatterns.addContent(entry);
addChild(wildcardPatterns, ENTRY).setAttribute(NAME, wildcardPattern);
}
parentNode.addContent(wildcardPatterns);
}
final Element annotationProcessingSettings = new Element(ANNOTATION_PROCESSING);
parentNode.addContent(annotationProcessingSettings);
annotationProcessingSettings.setAttribute("enabled", String.valueOf(myEnableAnnotationProcessors));
annotationProcessingSettings.setAttribute("useClasspath", String.valueOf(myObtainProcessorsFromClasspath));
if (myProcessorPath.length() > 0) {
final StringTokenizer tokenizer = new StringTokenizer(myProcessorPath, File.pathSeparator, false);
while (tokenizer.hasMoreTokens()) {
final String path = tokenizer.nextToken();
final Element pathElement = new Element("processorPath");
annotationProcessingSettings.addContent(pathElement);
pathElement.setAttribute("value", path);
}
}
for (Map.Entry<String, String> entry : myProcessorsMap.entrySet()) {
final Element processor = new Element("processor");
annotationProcessingSettings.addContent(processor);
processor.setAttribute("name", entry.getKey());
processor.setAttribute("options", entry.getValue());
}
final List<Module> modules = new ArrayList<Module>(myProcessedModules.keySet());
Collections.sort(modules, new Comparator<Module>() {
public int compare(Module o1, Module o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
for (Module module : modules) {
final Element moduleElement = new Element("processModule");
annotationProcessingSettings.addContent(moduleElement);
moduleElement.setAttribute("name", module.getName());
final String dirName = myProcessedModules.get(module);
if (dirName != null && dirName.length() > 0) {
moduleElement.setAttribute("generatedDirName", dirName);
}
final Element annotationProcessingSettings = addChild(parentNode, ANNOTATION_PROCESSING);
writeProfile(addChild(annotationProcessingSettings, "profile").setAttribute("default", "true"), myDefaultProcessorsProfile);
for (ProcessorConfigProfile profile : myModuleProcessorProfiles) {
writeProfile(addChild(annotationProcessingSettings, "profile").setAttribute("default", "false"), profile);
}
if (!StringUtil.isEmpty(myBytecodeTargetLevel) || !myModuleBytecodeTarget.isEmpty()) {
final Element bytecodeTarget = new Element(BYTECODE_TARGET_LEVEL);
parentNode.addContent(bytecodeTarget);
final Element bytecodeTarget = addChild(parentNode, BYTECODE_TARGET_LEVEL);
if (!StringUtil.isEmpty(myBytecodeTargetLevel)) {
bytecodeTarget.setAttribute("target", myBytecodeTargetLevel);
}
if (!myModuleBytecodeTarget.isEmpty()) {
final List<String> moduleNames = new ArrayList<String>(myModuleBytecodeTarget.keySet());
Collections.sort(moduleNames, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
Collections.sort(moduleNames, ALPHA_COMPARATOR);
for (String name : moduleNames) {
final Element moduleElement = new Element("module");
bytecodeTarget.addContent(moduleElement);
moduleElement.setAttribute("name", name);
final Element moduleElement = addChild(bytecodeTarget, MODULE);
moduleElement.setAttribute(NAME, name);
final String value = myModuleBytecodeTarget.get(name);
moduleElement.setAttribute("target", value != null? value : "");
}
@@ -791,6 +728,109 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements
}
}
private static void readProfile(Element element, ProcessorConfigProfile profile) {
profile.setName(element.getAttributeValue(NAME, ""));
profile.setEnabled(Boolean.valueOf(element.getAttributeValue(ENABLED, "false")));
final Element srcOutput = element.getChild("sourceOutputDir");
profile.setGeneratedSourcesDirectoryName(srcOutput != null? srcOutput.getAttributeValue(NAME) : null);
profile.clearProcessorOptions();
for (Object optionElement : element.getChildren(OPTION)) {
final Element elem = (Element)optionElement;
final String key = elem.getAttributeValue(NAME);
final String value = elem.getAttributeValue(VALUE);
if (!StringUtil.isEmptyOrSpaces(key) && value != null) {
profile.setOption(key, value);
}
}
profile.clearProcessors();
for (Object procElement : element.getChildren("processor")) {
final String name = ((Element)procElement).getAttributeValue(NAME);
if (StringUtil.isEmptyOrSpaces(name)) {
profile.addProcessor(name);
}
}
final Element pathElement = element.getChild("processorPath");
if (pathElement != null) {
profile.setObtainProcessorsFromClasspath(Boolean.parseBoolean(pathElement.getAttributeValue("useClasspath", "true")));
final StringBuilder pathBuilder = new StringBuilder();
for (Object entry : pathElement.getChildren(ENTRY)) {
final String path = ((Element)entry).getAttributeValue(NAME);
if (!StringUtil.isEmptyOrSpaces(path)) {
if (pathBuilder.length() > 0) {
pathBuilder.append(File.pathSeparator);
}
pathBuilder.append(FileUtil.toSystemDependentName(path));
}
}
profile.setProcessorPath(pathBuilder.toString());
}
profile.clearModuleNames();
for (Object moduleElement : element.getChildren(MODULE)) {
final String name = ((Element)moduleElement).getAttributeValue(NAME);
if (!StringUtil.isEmptyOrSpaces(name)) {
profile.addModuleName(name);
}
}
}
private static void writeProfile(final Element element, ProcessorConfigProfile profile) {
element.setAttribute(NAME, profile.getName());
element.setAttribute(ENABLED, Boolean.toString(profile.isEnabled()));
final String srcDirName = profile.getGeneratedSourcesDirectoryName();
if (srcDirName != null) {
addChild(element, "sourceOutputDir").setAttribute(NAME, srcDirName);
}
final Map<String, String> options = profile.getProcessorOptions();
if (!options.isEmpty()) {
final List<String> keys = new ArrayList<String>(options.keySet());
Collections.sort(keys, ALPHA_COMPARATOR);
for (String key : keys) {
addChild(element, OPTION).setAttribute(NAME, key).setAttribute(VALUE, options.get(key));
}
}
final Set<String> processors = profile.getProcessors();
if (!processors.isEmpty()) {
final List<String> processorList = new ArrayList<String>(processors);
Collections.sort(processorList, ALPHA_COMPARATOR);
for (String proc : processorList) {
addChild(element, "processor").setAttribute(NAME, proc);
}
}
final Element pathElement = addChild(element, "processorPath").setAttribute("useClasspath", Boolean.toString(profile.isObtainProcessorsFromClasspath()));
final String path = profile.getProcessorPath();
if (!StringUtil.isEmpty(path)) {
final StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator, false);
while (tokenizer.hasMoreTokens()) {
final String token = tokenizer.nextToken();
addChild(pathElement, ENTRY).setAttribute(NAME, FileUtil.toSystemIndependentName(token));
}
}
final Set<String> moduleNames = profile.getModuleNames();
if (!moduleNames.isEmpty()) {
final List<String> names = new ArrayList<String>(moduleNames);
Collections.sort(names, ALPHA_COMPARATOR);
for (String name : names) {
addChild(element, MODULE).setAttribute(NAME, name);
}
}
}
private static Element addChild(Element parent, final String childName) {
final Element child = new Element(childName);
parent.addContent(child);
return child;
}
@NotNull @NonNls
public String getComponentName() {
return "CompilerConfiguration";
@@ -0,0 +1,210 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 5/25/12
*/
public class ProcessorConfigProfile implements AnnotationProcessingConfiguration {
private String myName = "";
private boolean myEnabled = false;
private boolean myObtainProcessorsFromClasspath = true;
private String myProcessorPath = "";
private final Set<String> myProcessors = new HashSet<String>(); // empty list means all discovered
private final Map<String, String> myProcessorOptions = new HashMap<String, String>(); // key=value map of options
@Nullable
private String myGeneratedSourcesDirectoryName = null; // null means 'auto'
private final Set<String> myModuleNames = new HashSet<String>();
public ProcessorConfigProfile(String name) {
myName = name;
}
public ProcessorConfigProfile(ProcessorConfigProfile profile) {
initFrom(profile);
}
public final void initFrom(ProcessorConfigProfile other) {
myName = other.myName;
myEnabled = other.myEnabled;
myObtainProcessorsFromClasspath = other.myObtainProcessorsFromClasspath;
myProcessorPath = other.myProcessorPath;
myProcessors.clear();
myProcessors.addAll(other.myProcessors);
myProcessorOptions.clear();
myProcessorOptions.putAll(other.myProcessorOptions);
myGeneratedSourcesDirectoryName = other.myGeneratedSourcesDirectoryName;
myModuleNames.clear();
myModuleNames.addAll(other.myModuleNames);
}
public String getName() {
return myName;
}
public void setName(String name) {
myName = name;
}
@Override
public boolean isEnabled() {
return myEnabled;
}
public void setEnabled(boolean enabled) {
myEnabled = enabled;
}
@Override
@NotNull
public String getProcessorPath() {
return myProcessorPath;
}
public void setProcessorPath(@Nullable String processorPath) {
myProcessorPath = processorPath != null? processorPath : "";
}
@Override
public boolean isObtainProcessorsFromClasspath() {
return myObtainProcessorsFromClasspath;
}
public void setObtainProcessorsFromClasspath(boolean value) {
myObtainProcessorsFromClasspath = value;
}
@Override
@Nullable
public String getGeneratedSourcesDirectoryName() {
return myGeneratedSourcesDirectoryName;
}
public void setGeneratedSourcesDirectoryName(@Nullable String generatedSourcesDirectoryName) {
myGeneratedSourcesDirectoryName = generatedSourcesDirectoryName;
}
@NotNull
public Set<String> getModuleNames() {
return myModuleNames;
}
public boolean addModuleName(String name) {
return myModuleNames.add(name);
}
public boolean addModuleNames(Collection<String> names) {
return myModuleNames.addAll(names);
}
public boolean removeModuleName(String name) {
return myModuleNames.remove(name);
}
public boolean removeModuleNames(Collection<String> names) {
return myModuleNames.removeAll(names);
}
public void clearModuleNames() {
myModuleNames.clear();
}
public void clearProcessors() {
myProcessors.clear();
}
public boolean addProcessor(String processor) {
return myProcessors.add(processor);
}
public boolean removeProcessor(String processor) {
return myProcessors.remove(processor);
}
@Override
@NotNull
public Set<String> getProcessors() {
return Collections.unmodifiableSet(myProcessors);
}
@Override
@NotNull
public Map<String, String> getProcessorOptions() {
return Collections.unmodifiableMap(myProcessorOptions);
}
public String setOption(String key, String value) {
return myProcessorOptions.put(key, value);
}
@Nullable
public String getOption(String key) {
return myProcessorOptions.get(key);
}
public void clearProcessorOptions() {
myProcessorOptions.clear();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProcessorConfigProfile profile = (ProcessorConfigProfile)o;
if (myEnabled != profile.myEnabled) return false;
if (myObtainProcessorsFromClasspath != profile.myObtainProcessorsFromClasspath) return false;
if (myGeneratedSourcesDirectoryName != null
? !myGeneratedSourcesDirectoryName.equals(profile.myGeneratedSourcesDirectoryName)
: profile.myGeneratedSourcesDirectoryName != null) {
return false;
}
if (!myModuleNames.equals(profile.myModuleNames)) return false;
if (!myProcessorOptions.equals(profile.myProcessorOptions)) return false;
if (myProcessorPath != null ? !myProcessorPath.equals(profile.myProcessorPath) : profile.myProcessorPath != null) return false;
if (!myProcessors.equals(profile.myProcessors)) return false;
if (!myName.equals(profile.myName)) return false;
return true;
}
@Override
public int hashCode() {
int result = myName.hashCode();
result = 31 * result + (myEnabled ? 1 : 0);
result = 31 * result + (myObtainProcessorsFromClasspath ? 1 : 0);
result = 31 * result + (myProcessorPath != null ? myProcessorPath.hashCode() : 0);
result = 31 * result + myProcessors.hashCode();
result = 31 * result + myProcessorOptions.hashCode();
result = 31 * result + (myGeneratedSourcesDirectoryName != null ? myGeneratedSourcesDirectoryName.hashCode() : 0);
result = 31 * result + myModuleNames.hashCode();
return result;
}
@Override
public String toString() {
return myName;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.compiler.actions;
import com.intellij.compiler.AnnotationProcessingConfiguration;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.impl.FileSetCompileScope;
import com.intellij.compiler.impl.ModuleCompileScope;
@@ -82,9 +83,12 @@ public class ProcessAnnotationsAction extends CompileActionBase {
final Module module = LangDataKeys.MODULE.getData(dataContext);
final Module moduleContext = LangDataKeys.MODULE_CONTEXT.getData(dataContext);
if (!compilerConfiguration.isAnnotationProcessorsEnabled() ||
(!compilerConfiguration.isObtainProcessorsFromClasspath() && compilerConfiguration.getAnnotationProcessorsMap().isEmpty()) ||
module != null && StringUtil.isEmpty(compilerConfiguration.getAnotationProcessedModules().get(module))) {
if (module == null) {
presentation.setEnabled(false);
return;
}
final AnnotationProcessingConfiguration profile = compilerConfiguration.getAnnotationProcessingConfiguration(module);
if (!profile.isEnabled() || (!profile.isObtainProcessorsFromClasspath() && profile.getProcessors().isEmpty())) {
presentation.setEnabled(false);
return;
}
@@ -169,12 +169,10 @@ public class CompileDriver {
final Pair<VirtualFile, VirtualFile> outputs = new Pair<VirtualFile, VirtualFile>(productionOutput, testOutput);
myGenerationCompilerModuleToOutputDirMap.put(pair, outputs);
}
if (config.isAnnotationProcessorsEnabled()) {
if (config.isAnnotationProcessingEnabled(module)) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
lookupVFile(lfs, path); // ensure the file is created and added to VFS
}
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
lookupVFile(lfs, path); // ensure the file is created and added to VFS
}
}
}
@@ -395,7 +393,7 @@ public class CompileDriver {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
final Set<Module> affected = new HashSet<Module>(Arrays.asList(context.getCompileScope().getAffectedModules()));
for (Module module : affected) {
if (!config.isAnnotationProcessingEnabled(module)) {
if (!config.getAnnotationProcessingConfiguration(module).isEnabled()) {
continue;
}
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
@@ -1725,7 +1723,7 @@ public class CompileDriver {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
if (context.isAnnotationProcessorsEnabled()) {
for (Module module : modules) {
if (config.isAnnotationProcessingEnabled(module)) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path != null) {
outputDirs.add(new File(path));
@@ -2366,7 +2364,7 @@ public class CompileDriver {
modulesWithoutOutputPathSpecified.add(module.getName());
}
}
if (config.isAnnotationProcessorsEnabled() && config.isAnnotationProcessingEnabled(module)) {
if (config.getAnnotationProcessingConfiguration(module).isEnabled()) {
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
if (path == null) {
final CompilerProjectExtension extension = CompilerProjectExtension.getInstance(module.getProject());
@@ -2458,9 +2456,9 @@ public class CompileDriver {
if (chunkModules.size() <= 1) {
continue; // no need to check one-module chunks
}
if (config.isAnnotationProcessorsEnabled()) {
if (!useOutOfProcessBuild()) {
for (Module chunkModule : chunkModules) {
if (config.isAnnotationProcessingEnabled(chunkModule)) {
if (config.getAnnotationProcessingConfiguration(chunkModule).isEnabled()) {
showCyclesNotSupportedForAnnotationProcessors(chunkModules.toArray(new Module[chunkModules.size()]));
return false;
}
@@ -120,7 +120,7 @@ public class AnnotationProcessingCompiler implements TranslatingCompiler{
}
final Module module = context.getModuleByFile(file);
if (module != null) {
if (!myConfig.isAnnotationProcessingEnabled(module)) {
if (!myConfig.getAnnotationProcessingConfiguration(module).isEnabled()) {
return true;
}
final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module);
@@ -15,10 +15,7 @@
*/
package com.intellij.compiler.impl.javaCompiler.javac;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.CompilerIOUtil;
import com.intellij.compiler.OutputParser;
import com.intellij.compiler.*;
import com.intellij.compiler.impl.CompilerUtil;
import com.intellij.compiler.impl.javaCompiler.ExternalCompiler;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
@@ -283,33 +280,21 @@ public class JavacCompiler extends ExternalCompiler {
annotationProcessorsEnabled = false;
}
if (isAnnotationProcessing) {
final CompilerConfiguration config = CompilerConfiguration.getInstance(chunk.getProject());
final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(chunk.getProject()).getAnnotationProcessingConfiguration(chunk.getModules()[0]);
additionalOptions.add("-Xprefer:source");
additionalOptions.add("-implicit:none");
additionalOptions.add("-proc:only");
if (!config.isObtainProcessorsFromClasspath()) {
final String processorPath = config.getProcessorPath();
if (processorPath.length() > 0) {
additionalOptions.add("-processorpath");
additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
}
additionalOptions.add("-processorpath");
additionalOptions.add(FileUtil.toSystemDependentName(processorPath));
}
for (Map.Entry<String, String> entry : config.getAnnotationProcessorsMap().entrySet()) {
for (String processorName : config.getProcessors()) {
additionalOptions.add("-processor");
additionalOptions.add(entry.getKey());
final String options = entry.getValue();
if (options.length() > 0) {
StringTokenizer optionsTokenizer = new StringTokenizer(options, " ", false);
while (optionsTokenizer.hasMoreTokens()) {
final String token = optionsTokenizer.nextToken();
if (token.startsWith("-A")) {
additionalOptions.add(token.substring("-A".length()));
}
else {
additionalOptions.add("-A" + token);
}
}
}
additionalOptions.add(processorName);
}
for (Map.Entry<String, String> entry : config.getProcessorOptions().entrySet()) {
additionalOptions.add("-A" + entry.getKey() + "=" +entry.getValue());
}
}
else {
@@ -17,41 +17,17 @@ package com.intellij.compiler.options;
import com.intellij.compiler.CompileServerManager;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.compiler.server.BuildManager;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.containers.HashMap;
import com.intellij.util.ui.EditableModel;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
@@ -59,15 +35,9 @@ import java.util.Map;
* Date: Oct 5, 2009
*/
public class AnnotationProcessorsConfigurable implements SearchableConfigurable, Configurable.NoScroll {
private ProcessedModulesTable myModulesTable;
private final Project myProject;
private JRadioButton myRbClasspath;
private JRadioButton myRbProcessorsPath;
private TextFieldWithBrowseButton myProcessorPathField;
private ProcessorTableModel myProcessorsModel;
private JCheckBox myCbEnableProcessing;
private JBTable myProcessorTable;
private JPanel myProcessorPanel;
private AnnotationProcessorsPanel myMainPanel;
public AnnotationProcessorsConfigurable(final Project project) {
myProject = project;
@@ -95,163 +65,39 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
}
public JComponent createComponent() {
final JPanel mainPanel = new JPanel(new GridBagLayout());
myCbEnableProcessing = new JCheckBox("Enable annotation processing");
myRbClasspath = new JRadioButton("Obtain processors from project classpath");
myRbProcessorsPath = new JRadioButton("Processor path:");
ButtonGroup group = new ButtonGroup();
group.add(myRbClasspath);
group.add(myRbProcessorsPath);
myProcessorPathField = new TextFieldWithBrowseButton(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createAllButJarContentsDescriptor();
final VirtualFile[] files = FileChooser.chooseFiles(descriptor, myProcessorPathField, myProject, null);
if (files.length > 0) {
final StringBuilder builder = new StringBuilder();
for (VirtualFile file : files) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
builder.append(FileUtil.toSystemDependentName(file.getPath()));
}
myProcessorPathField.setText(builder.toString());
}
}
});
final JPanel processorTablePanel = new JPanel(new BorderLayout());
myProcessorsModel = new ProcessorTableModel();
processorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false));
myProcessorTable = new JBTable(myProcessorsModel);
myProcessorTable.getEmptyText().setText("No processors configured");
myProcessorPanel = ToolbarDecorator.createDecorator(myProcessorTable)
.disableUpAction()
.disableDownAction()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
final TableCellEditor cellEditor = myProcessorTable.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
final ProcessorTableModel model = (ProcessorTableModel)myProcessorTable.getModel();
model.addRow();
TableUtil.editCellAt(myProcessorTable, model.getRowCount() - 1, ProcessorTableRow.NAME_COLUMN);
}
})
.createPanel();
processorTablePanel.add(myProcessorPanel, BorderLayout.CENTER);
myModulesTable = new ProcessedModulesTable(myProject);
myModulesTable.setBorder(IdeBorderFactory.createTitledBorder("Processed Modules", false));
final JLabel noteMessage = new JLabel("<html>Source files generated by annotation processors will be stored under the project output directory. " +
"To override this behaviour for certain modules you may specify the directory name in the table below. " +
"If specified, the directory will be created under corresponding module's content root.</html>");
final JLabel warning = new JLabel("<html>WARNING!<br>" +
"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +
"If option 'Clear output directory on rebuild' is enabled, " +
"the entire contents of directories specified in the table below WILL BE CLEARED on rebuild.</html>");
warning.setFont(warning.getFont().deriveFont(Font.BOLD));
mainPanel.add(myCbEnableProcessing, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
mainPanel.add(myRbClasspath, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
mainPanel.add(myRbProcessorsPath, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
mainPanel.add(myProcessorPathField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0));
mainPanel.add(processorTablePanel, new GridBagConstraints(0, 3, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
mainPanel.add(noteMessage, new GridBagConstraints(0, 4, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
mainPanel.add(warning, new GridBagConstraints(0, 5, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
mainPanel.add(myModulesTable, new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
//mainPanel.add(new AnnotationProcessorsPanel(myProject), new GridBagConstraints(0, 7, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
myRbClasspath.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
myProcessorTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateEnabledState();
}
}
});
myCbEnableProcessing.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
updateEnabledState();
return mainPanel;
}
private void updateEnabledState() {
final boolean enabled = myCbEnableProcessing.isSelected();
final boolean useProcessorpath = !myRbClasspath.isSelected();
myRbClasspath.setEnabled(enabled);
myRbProcessorsPath.setEnabled(enabled);
myProcessorPathField.setEnabled(enabled && useProcessorpath);
final AnActionButton addButton = ToolbarDecorator.findAddButton(myProcessorPanel);
if (addButton != null) {
addButton.setEnabled(enabled);
}
final AnActionButton removeButton = ToolbarDecorator.findRemoveButton(myProcessorPanel);
if (removeButton != null) {
removeButton.setEnabled(enabled && myProcessorTable.getSelectedRow() >= 0);
}
myProcessorTable.setEnabled(enabled);
final JTableHeader header = myProcessorTable.getTableHeader();
if (header != null) {
header.repaint();
}
myModulesTable.getComponent().setEnabled(enabled);
myMainPanel = new AnnotationProcessorsPanel(myProject);
return myMainPanel;
}
public boolean isModified() {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
if (config.isAnnotationProcessorsEnabled() != myCbEnableProcessing.isSelected()) {
return true;
}
if (config.isObtainProcessorsFromClasspath() != myRbClasspath.isSelected()) {
return true;
}
if (!FileUtil.pathsEqual(config.getProcessorPath(), FileUtil.toSystemIndependentName(myProcessorPathField.getText().trim()))) {
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
if (!config.getDefaultProcessorProfile().equals(myMainPanel.getDefaultProfile())) {
return true;
}
final Map<String, String> map = myProcessorsModel.exportToMap();
if (!map.equals(config.getAnnotationProcessorsMap())) {
final Map<String, ProcessorConfigProfile> configProfiles = new java.util.HashMap<String, ProcessorConfigProfile>();
for (ProcessorConfigProfile profile : config.getModuleProcessorProfiles()) {
configProfiles.put(profile.getName(), profile);
}
final List<ProcessorConfigProfile> panelProfiles = myMainPanel.getModuleProfiles();
if (configProfiles.size() != panelProfiles.size()) {
return true;
}
if (!getMarkedModules().equals(config.getAnotationProcessedModules())) {
return true;
for (ProcessorConfigProfile panelProfile : panelProfiles) {
final ProcessorConfigProfile configProfile = configProfiles.get(panelProfile.getName());
if (configProfile == null || !configProfile.equals(panelProfile)) {
return true;
}
}
return false;
}
public void apply() throws ConfigurationException {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
config.setAnnotationProcessorsEnabled(myCbEnableProcessing.isSelected());
config.setObtainProcessorsFromClasspath(myRbClasspath.isSelected());
config.setProcessorsPath(FileUtil.toSystemIndependentName(myProcessorPathField.getText().trim()));
config.setAnnotationProcessorsMap(myProcessorsModel.exportToMap());
config.setAnotationProcessedModules(getMarkedModules());
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
config.setDefaultProcessorProfile(myMainPanel.getDefaultProfile());
config.setModuleProcessorProfiles(myMainPanel.getModuleProfiles());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CompileServerManager.getInstance().sendReloadRequest(myProject);
@@ -260,161 +106,12 @@ public class AnnotationProcessorsConfigurable implements SearchableConfigurable,
});
}
private Map<Module, String> getMarkedModules() {
final Map<Module, String> result = new HashMap<Module, String>();
for (Pair<Module, String> pair : myModulesTable.getAllModules()) {
result.put(pair.getFirst(), pair.getSecond());
}
return result;
}
public void reset() {
final CompilerConfiguration config = CompilerConfiguration.getInstance(myProject);
myCbEnableProcessing.setSelected(config.isAnnotationProcessorsEnabled());
final boolean obtainFromClasspath = config.isObtainProcessorsFromClasspath();
if (obtainFromClasspath) {
myRbClasspath.setSelected(true);
}
else {
myRbProcessorsPath.setSelected(true);
}
myProcessorPathField.setText(FileUtil.toSystemDependentName(config.getProcessorPath()));
myProcessorsModel.setProcessorMap(config.getAnnotationProcessorsMap());
myModulesTable.removeAllElements();
for (final Module module : ModuleManager.getInstance(myProject).getModules()) {
if (config.isAnnotationProcessingEnabled(module)) {
myModulesTable.addModule(module, config.getGeneratedSourceDirName(module));
}
}
myModulesTable.sort(new Comparator<Module>() {
public int compare(Module o1, Module o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
});
final CompilerConfigurationImpl config = (CompilerConfigurationImpl)CompilerConfiguration.getInstance(myProject);
myMainPanel.initProfiles(config.getDefaultProcessorProfile(), config.getModuleProcessorProfiles());
}
public void disposeUIResources() {
}
private static class ProcessorTableModel extends AbstractTableModel implements EditableModel {
private final java.util.List<ProcessorTableRow> myRows = new ArrayList<ProcessorTableRow>();
public String getColumnName(int column) {
switch (column) {
case ProcessorTableRow.NAME_COLUMN: return "Processor FQ Name";
case ProcessorTableRow.OPTIONS_COLUMN : return "Processor Run Options (space-separated \"key=value\" pairs)";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 2;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == ProcessorTableRow.NAME_COLUMN || columnIndex == ProcessorTableRow.OPTIONS_COLUMN;
}
public Object getValueAt(int rowIndex, int columnIndex) {
final ProcessorTableRow row = myRows.get(rowIndex);
switch (columnIndex) {
case ProcessorTableRow.NAME_COLUMN: return row.name;
case ProcessorTableRow.OPTIONS_COLUMN : return row.options;
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
final ProcessorTableRow row = myRows.get(rowIndex);
switch (columnIndex) {
case ProcessorTableRow.NAME_COLUMN:
row.name = (String)aValue;
break;
case ProcessorTableRow.OPTIONS_COLUMN:
row.options = (String)aValue;
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add(new ProcessorTableRow());
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setProcessorMap(Map<String, String> processorMap) {
clear();
if (processorMap.size() > 0) {
for (Map.Entry<String, String> entry : processorMap.entrySet()) {
myRows.add(new ProcessorTableRow(entry.getKey(), entry.getValue()));
}
Collections.sort(myRows, new Comparator<ProcessorTableRow>() {
public int compare(ProcessorTableRow o1, ProcessorTableRow o2) {
return o1.name.compareToIgnoreCase(o2.name);
}
});
fireTableRowsInserted(0, processorMap.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Map<String, String> exportToMap() {
final Map<String, String> map = new HashMap<String, String>();
for (ProcessorTableRow row : myRows) {
if (row.name != null) {
final String name = row.name.trim();
if (name.length() > 0 && !map.containsKey(name)) {
map.put(name, row.options);
}
}
}
return map;
}
}
private static final class ProcessorTableRow {
public static final int NAME_COLUMN = 0;
public static final int OPTIONS_COLUMN = 1;
public String name = "";
public String options = "";
public ProcessorTableRow() {
}
public ProcessorTableRow(String name, String options) {
this.name = name != null? name : "";
this.options = options != null? options : "";
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.compiler.options;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ShortcutSet;
@@ -25,10 +26,12 @@ import com.intellij.openapi.ui.InputValidatorEx;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.components.JBList;
@@ -52,16 +55,20 @@ import java.util.List;
*/
@SuppressWarnings({"unchecked", "UseOfObsoleteCollectionType"})
public class AnnotationProcessorsPanel extends JPanel {
private final Map<String, List<Module>> profiles = new HashMap<String, List<Module>>();
private static final String DEFAULT_PROFILE = "Default";
private final ProcessorConfigProfile myDefaultProfile = new ProcessorConfigProfile("");
private final List<ProcessorConfigProfile> myModuleProfiles = new ArrayList<ProcessorConfigProfile>();
private final Map<String, Module> myAllModulesMap = new HashMap<String, Module>();
private final Project myProject;
private final Tree myTree;
private JPanel myContentPanel;
private final ProcessorProfilePanel myProfilePanel;
private ProcessorConfigProfile mySelectedProfile = null;
public AnnotationProcessorsPanel(Project project) {
super(new BorderLayout());
myProject = project;
loadProfiles();
for (Module module : ModuleManager.getInstance(project).getModules()) {
myAllModulesMap.put(module.getName(), module);
}
myTree = new Tree(new MyTreeModel());
myTree.setRootVisible(false);
final JPanel treePanel =
@@ -70,37 +77,39 @@ public class AnnotationProcessorsPanel extends JPanel {
public void actionPerformed(AnActionEvent e) {
final MyModuleNode node = (MyModuleNode)myTree.getSelectionPath().getLastPathComponent();
final TreePath[] selectedNodes = myTree.getSelectionPaths();
final String key = ((MyProfileNode)node.getParent()).myKey;
final List<String> profileNames = new ArrayList<String>();
profileNames.add(DEFAULT_PROFILE);
profileNames.addAll(profiles.keySet());
profileNames.remove(key);
final JBList list = new JBList(profileNames);
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node.getParent()).myProfile;
final List<ProcessorConfigProfile> profiles = new ArrayList<ProcessorConfigProfile>();
profiles.add(myDefaultProfile);
for (ProcessorConfigProfile profile : myModuleProfiles) {
profiles.add(profile);
}
profiles.remove(nodeProfile);
final JBList list = new JBList(profiles);
final JBPopup popup = JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle("Move to")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
final Object value = list.getSelectedValue();
if (value instanceof String) {
if (value instanceof ProcessorConfigProfile) {
final ProcessorConfigProfile chosenProfile = (ProcessorConfigProfile)value;
final Module toSelect = (Module)node.getUserObject();
if (selectedNodes != null) {
for (TreePath selectedNode : selectedNodes) {
final Object n = selectedNode.getLastPathComponent();
if (n instanceof MyModuleNode) {
Module module = (Module)((MyModuleNode)n).getUserObject();
if (!DEFAULT_PROFILE.equals(key)) {
profiles.get(key).remove(module);
final Object node = selectedNode.getLastPathComponent();
if (node instanceof MyModuleNode) {
final Module module = (Module)((MyModuleNode)node).getUserObject();
if (nodeProfile != myDefaultProfile) {
nodeProfile.removeModuleName(module.getName());
}
if (!DEFAULT_PROFILE.equals(value)) {
profiles.get(value).add(module);
if (chosenProfile != myDefaultProfile) {
chosenProfile.addModuleName(module.getName());
}
}
}
}
final MyRootNode root = (MyRootNode)myTree.getModel().getRoot();
final RootNode root = (RootNode)myTree.getModel().getRoot();
root.sync();
final DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(root, toSelect);
if (node != null) {
@@ -123,15 +132,13 @@ public class AnnotationProcessorsPanel extends JPanel {
public boolean isEnabled() {
return myTree.getSelectionPath() != null
&& myTree.getSelectionPath().getLastPathComponent() instanceof MyModuleNode
&& !profiles.isEmpty();
&& !myModuleProfiles.isEmpty();
}
}).createPanel();
add(treePanel, BorderLayout.WEST);
myTree.setCellRenderer(new MyCellRenderer());
((MyRootNode)myTree.getModel().getRoot()).sync();
myContentPanel = new JPanel(new BorderLayout());
myTree.addTreeSelectionListener(new TreeSelectionListener() {
String currentProfile = null;
@Override
public void valueChanged(TreeSelectionEvent e) {
final TreePath path = myTree.getSelectionPath();
@@ -140,25 +147,56 @@ public class AnnotationProcessorsPanel extends JPanel {
if (node instanceof MyModuleNode) {
node = ((MyModuleNode)node).getParent();
}
if (node instanceof MyProfileNode) {
if (!StringUtil.equals(currentProfile, ((MyProfileNode)node).myKey)) {
currentProfile = ((MyProfileNode)node).myKey;
myContentPanel.removeAll();
myContentPanel.add(getComponentForProfile(currentProfile), BorderLayout.CENTER);
revalidate();
repaint();
if (node instanceof ProfileNode) {
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node).myProfile;
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (nodeProfile != selectedProfile) {
if (selectedProfile != null) {
myProfilePanel.saveTo(selectedProfile);
}
mySelectedProfile = nodeProfile;
myProfilePanel.setProfile(nodeProfile);
}
}
}
}
});
add(myContentPanel, BorderLayout.CENTER);
myProfilePanel = new ProcessorProfilePanel(project);
myProfilePanel.setBorder(IdeBorderFactory.createEmptyBorder(0, 6, 0, 0));
add(myProfilePanel, BorderLayout.CENTER);
}
public void initProfiles(ProcessorConfigProfile defaultProfile, Collection<ProcessorConfigProfile> moduleProfiles) {
myDefaultProfile.initFrom(defaultProfile);
myModuleProfiles.clear();
for (ProcessorConfigProfile profile : moduleProfiles) {
ProcessorConfigProfile copy = new ProcessorConfigProfile("");
copy.initFrom(profile);
myModuleProfiles.add(copy);
}
final RootNode root = (RootNode)myTree.getModel().getRoot();
root.sync();
final DefaultMutableTreeNode node = TreeUtil.findNodeWithObject(root, myDefaultProfile);
if (node != null) {
TreeUtil.selectNode(myTree, node);
}
private JComponent getComponentForProfile(String profile) {
//TODO[jeka] correct panel
return new JLabel(profile, SwingConstants.CENTER);
}
public ProcessorConfigProfile getDefaultProfile() {
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (myDefaultProfile == selectedProfile) {
myProfilePanel.saveTo(selectedProfile);
}
return myDefaultProfile;
}
public List<ProcessorConfigProfile> getModuleProfiles() {
final ProcessorConfigProfile selectedProfile = mySelectedProfile;
if (myDefaultProfile != selectedProfile) {
myProfilePanel.saveTo(selectedProfile);
}
return myModuleProfiles;
}
private static void expand(JTree tree) {
@@ -174,48 +212,74 @@ public class AnnotationProcessorsPanel extends JPanel {
while (true);
}
private void loadProfiles() {
//TODO[jeka] init profiles map
}
private class MyTreeModel extends DefaultTreeModel implements EditableTreeModel{
public MyTreeModel() {
super(new MyRootNode());
super(new RootNode());
}
@Override
public TreePath addNode(TreePath parentOrNeighbour) {
final String profile = Messages.showInputDialog(myProject, "Profile name", "Create new profile", null, "", new InputValidatorEx() {
@Override
public boolean checkInput(String inputString) {
return !DEFAULT_PROFILE.equals(inputString) && !profiles.containsKey(inputString) && !StringUtil.isEmpty(inputString);
}
final String newProfileName = Messages.showInputDialog(
myProject, "Profile name", "Create new profile", null, "",
new InputValidatorEx() {
@Override
public boolean checkInput(String inputString) {
if (StringUtil.isEmpty(inputString) ||
Comparing.equal(inputString, myDefaultProfile.getName())) {
return false;
}
for (ProcessorConfigProfile profile : myModuleProfiles) {
if (Comparing.equal(inputString, profile.getName())) {
return false;
}
}
return true;
}
@Override
public boolean canClose(String inputString) {
return checkInput(inputString);
}
@Override
public boolean canClose(String inputString) {
return checkInput(inputString);
}
@Override
public String getErrorText(String inputString) {
if (checkInput(inputString)) return null;
return StringUtil.isEmpty(inputString) ? "Profile name shouldn't be empty"
: "Profile " + inputString + " already exists";
@Override
public String getErrorText(String inputString) {
if (checkInput(inputString)) {
return null;
}
return StringUtil.isEmpty(inputString)
? "Profile name shouldn't be empty"
: "Profile " + inputString + " already exists";
}
});
if (newProfileName != null) {
final ProcessorConfigProfile profile = new ProcessorConfigProfile(newProfileName);
myModuleProfiles.add(profile);
((DataSynchronizable)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), profile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
});
if (profile != null) {
profiles.put(profile, new ArrayList<Module>());
}
((SyncWithMap)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), profile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
return null;
}
@Override
public void removeNode(TreePath parent) {
public void removeNode(TreePath nodePath) {
Object node = nodePath.getLastPathComponent();
if (node instanceof ProfileNode) {
final ProcessorConfigProfile nodeProfile = ((ProfileNode)node).myProfile;
if (nodeProfile != myDefaultProfile) {
if (mySelectedProfile == nodeProfile) {
mySelectedProfile = null;
}
myModuleProfiles.remove(nodeProfile);
((DataSynchronizable)getRoot()).sync();
final DefaultMutableTreeNode object = TreeUtil.findNodeWithObject((DefaultMutableTreeNode)getRoot(), myDefaultProfile);
if (object != null) {
TreeUtil.selectNode(myTree, object);
}
}
}
}
@Override
@@ -225,14 +289,14 @@ public class AnnotationProcessorsPanel extends JPanel {
}
private class MyRootNode extends DefaultMutableTreeNode implements SyncWithMap {
private class RootNode extends DefaultMutableTreeNode implements DataSynchronizable {
@Override
public SyncWithMap sync() {
public DataSynchronizable sync() {
final Vector newKids = new Vector();
for (String key : profiles.keySet()) {
newKids.add(new MyProfileNode(key, this).sync());
newKids.add(new ProfileNode(myDefaultProfile, this, true).sync());
for (ProcessorConfigProfile profile : myModuleProfiles) {
newKids.add(new ProfileNode(profile, this, false).sync());
}
newKids.add(new MyProfileNode(DEFAULT_PROFILE, this).sync());
children = newKids;
((DefaultTreeModel)myTree.getModel()).reload();
expand(myTree);
@@ -240,33 +304,44 @@ public class AnnotationProcessorsPanel extends JPanel {
}
}
private interface SyncWithMap {
SyncWithMap sync();
private interface DataSynchronizable {
DataSynchronizable sync();
}
private class MyProfileNode extends DefaultMutableTreeNode implements SyncWithMap {
private final String myKey;
private class ProfileNode extends DefaultMutableTreeNode implements DataSynchronizable {
private final ProcessorConfigProfile myProfile;
private final boolean myIsDefault;
public MyProfileNode(String key, MyRootNode parent) {
super(key);
public ProfileNode(ProcessorConfigProfile profile, RootNode parent, boolean isDefault) {
super(profile);
setParent(parent);
myKey = key;
myIsDefault = isDefault;
myProfile = profile;
}
@Override
public SyncWithMap sync() {
final List<Module> nodeModules;
if (DEFAULT_PROFILE.equals(myKey)) {
final Module[] allModules = ModuleManager.getInstance(myProject).getSortedModules();
nodeModules = new ArrayList<Module>(Arrays.asList(allModules));
for (List<Module> modules : profiles.values()) {
for (Module module : modules) {
nodeModules.remove(module);
public DataSynchronizable sync() {
final List<Module> nodeModules = new ArrayList<Module>();
if (myIsDefault) {
final Set<String> nonDefaultProfileModules = new HashSet<String>();
for (ProcessorConfigProfile profile : myModuleProfiles) {
nonDefaultProfileModules.addAll(profile.getModuleNames());
}
for (Map.Entry<String, Module> entry : myAllModulesMap.entrySet()) {
if (!nonDefaultProfileModules.contains(entry.getKey())) {
nodeModules.add(entry.getValue());
}
}
} else {
nodeModules = profiles.get(myKey);
}
else {
for (String moduleName : myProfile.getModuleNames()) {
final Module module = myAllModulesMap.get(moduleName);
if (module != null) {
nodeModules.add(module);
}
}
}
Collections.sort(nodeModules, ModuleComparator.INSTANCE);
final Vector vector = new Vector();
for (Module module : nodeModules) {
vector.add(new MyModuleNode(module, this));
@@ -274,32 +349,39 @@ public class AnnotationProcessorsPanel extends JPanel {
children = vector;
return this;
}
}
private class MyModuleNode extends DefaultMutableTreeNode {
public MyModuleNode(Module module, MyProfileNode parent) {
private static class MyModuleNode extends DefaultMutableTreeNode {
public MyModuleNode(Module module, ProfileNode parent) {
super(module);
setParent(parent);
setAllowsChildren(false);
}
}
private class MyCellRenderer extends ColoredTreeCellRenderer {
private static class MyCellRenderer extends ColoredTreeCellRenderer {
private static final Icon MODULE_ICON = IconLoader.getIcon("/nodes/ModuleClosed.png");
@Override
public void customizeCellRenderer(JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
if (value instanceof MyProfileNode) {
append(((MyProfileNode)value).myKey);
} else if (value instanceof MyModuleNode) {
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (value instanceof ProfileNode) {
append(((ProfileNode)value).myProfile.getName());
}
else if (value instanceof MyModuleNode) {
final Module module = (Module)((MyModuleNode)value).getUserObject();
setIcon(IconLoader.getIcon("/nodes/ModuleClosed.png"));
setIcon(MODULE_ICON);
append(module.getName());
}
}
}
private static class ModuleComparator implements Comparator<Module> {
static final ModuleComparator INSTANCE = new ModuleComparator();
@Override
public int compare(Module o1, Module o2) {
return o1.getName().compareTo(o2.getName());
}
}
}
@@ -0,0 +1,454 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler.options;
import com.intellij.compiler.ProcessorConfigProfile;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.EditableModel;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.util.*;
import java.util.List;
/**
* @author Eugene Zhuravlev
* Date: 5/28/12
*/
public class ProcessorProfilePanel extends JPanel {
private final Project myProject;
private JRadioButton myRbClasspath;
private JRadioButton myRbProcessorsPath;
private TextFieldWithBrowseButton myProcessorPathField;
private JTextField myGeneratedSourcesDirNameField;
private ProcessorTableModel myProcessorsModel;
private JCheckBox myCbEnableProcessing;
private JBTable myProcessorTable;
private JBTable myOptionsTable;
private JPanel myProcessorPanel;
private JPanel myOptionsPanel;
private OptionsTableModel myOptionsModel;
public ProcessorProfilePanel(Project project) {
super(new GridBagLayout());
myProject = project;
myCbEnableProcessing = new JCheckBox("Enable annotation processing");
myRbClasspath = new JRadioButton("Obtain processors from project classpath");
myRbProcessorsPath = new JRadioButton("Processor path:");
ButtonGroup group = new ButtonGroup();
group.add(myRbClasspath);
group.add(myRbProcessorsPath);
myProcessorPathField = new TextFieldWithBrowseButton(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createAllButJarContentsDescriptor();
final VirtualFile[] files = FileChooser.chooseFiles(descriptor, myProcessorPathField, myProject, null);
if (files.length > 0) {
final StringBuilder builder = new StringBuilder();
for (VirtualFile file : files) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
builder.append(FileUtil.toSystemDependentName(file.getPath()));
}
myProcessorPathField.setText(builder.toString());
}
}
});
final JPanel processorTablePanel = new JPanel(new BorderLayout());
myProcessorsModel = new ProcessorTableModel();
processorTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processors", false));
myProcessorTable = new JBTable(myProcessorsModel);
myProcessorTable.getEmptyText().setText("Compiler will run all automatically discovered processors");
myProcessorPanel = createTablePanel(myProcessorTable);
processorTablePanel.add(myProcessorPanel, BorderLayout.CENTER);
final JPanel optionsTablePanel = new JPanel(new BorderLayout());
myOptionsModel = new OptionsTableModel();
optionsTablePanel.setBorder(IdeBorderFactory.createTitledBorder("Annotation Processor options", false));
myOptionsTable = new JBTable(myOptionsModel);
myOptionsTable.getEmptyText().setText("No processor-specific options configured");
myOptionsPanel = createTablePanel(myOptionsTable);
optionsTablePanel.add(myOptionsPanel, BorderLayout.CENTER);
myGeneratedSourcesDirNameField = new JTextField();
final JLabel warning = new JLabel("<html>WARNING!<br>" +
/*"All source files located in the generated sources output directory WILL BE EXCLUDED from annotation processing. " +*/
"If option 'Clear output directory on rebuild' is enabled, " +
"the entire contents of directories specified in the table below WILL BE CLEARED on rebuild.</html>");
warning.setFont(warning.getFont().deriveFont(Font.BOLD));
add(myCbEnableProcessing,
new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
add(myRbClasspath,
new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(10, 0, 0, 0), 0, 0));
add(myRbProcessorsPath,
new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
add(myProcessorPathField,
new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0));
final JLabel noteMessage = new JLabel("<html>Source files generated by annotation processors will be stored under the project output directory. " +
"To override this behaviour for this profile you may specify the directory name in the field below. " +
"If specified, the directory will be created under corresponding module's content root.</html>");
add(noteMessage,
new GridBagConstraints(0, 3, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(new JLabel("Directory name:"),
new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(myGeneratedSourcesDirNameField,
new GridBagConstraints(1, 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
add(processorTablePanel,
new GridBagConstraints(0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
add(optionsTablePanel,
new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(10, 0, 0, 0), 0, 0));
add(warning,
new GridBagConstraints(0, 7, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(10, 5, 0, 0), 0, 0));
myRbClasspath.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
myProcessorTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateEnabledState();
}
}
});
myCbEnableProcessing.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateEnabledState();
}
});
updateEnabledState();
}
public void setProfile(ProcessorConfigProfile config) {
myCbEnableProcessing.setSelected(config.isEnabled());
(config.isObtainProcessorsFromClasspath()? myRbClasspath : myRbProcessorsPath).setSelected(true);
myProcessorPathField.setText(FileUtil.toSystemDependentName(config.getProcessorPath()));
final String srcDirName = config.getGeneratedSourcesDirectoryName();
myGeneratedSourcesDirNameField.setText(srcDirName != null? srcDirName.trim() : "");
myProcessorsModel.setProcessors(config.getProcessors());
myOptionsModel.setOptions(config.getProcessorOptions());
updateEnabledState();
}
public void saveTo(ProcessorConfigProfile profile) {
profile.setEnabled(myCbEnableProcessing.isSelected());
profile.setObtainProcessorsFromClasspath(myRbClasspath.isSelected());
profile.setProcessorPath(myProcessorPathField.getText().trim());
final String dirName = myGeneratedSourcesDirNameField.getText().trim();
profile.setGeneratedSourcesDirectoryName(StringUtil.isEmpty(dirName)? null : dirName);
profile.clearProcessors();
for (String processor : myProcessorsModel.getProcessors()) {
profile.addProcessor(processor);
}
profile.clearProcessorOptions();
for (Map.Entry<String, String> entry : myOptionsModel.getOptions().entrySet()) {
profile.setOption(entry.getKey(), entry.getValue());
}
}
private static JPanel createTablePanel(final JBTable table) {
return ToolbarDecorator.createDecorator(table)
.disableUpAction()
.disableDownAction()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton anActionButton) {
final TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
final TableModel model = table.getModel();
((EditableModel)model).addRow();
TableUtil.editCellAt(table, model.getRowCount() - 1, 0);
}
})
.createPanel();
}
private void updateEnabledState() {
final boolean enabled = myCbEnableProcessing.isSelected();
final boolean useProcessorpath = !myRbClasspath.isSelected();
myRbClasspath.setEnabled(enabled);
myRbProcessorsPath.setEnabled(enabled);
myProcessorPathField.setEnabled(enabled && useProcessorpath);
updateTable(myProcessorPanel, myProcessorTable, enabled);
updateTable(myOptionsPanel, myOptionsTable, enabled);
myGeneratedSourcesDirNameField.setEnabled(enabled);
}
private static void updateTable(final JPanel tablePanel, final JBTable table, boolean enabled) {
final AnActionButton addButton = ToolbarDecorator.findAddButton(tablePanel);
if (addButton != null) {
addButton.setEnabled(enabled);
}
final AnActionButton removeButton = ToolbarDecorator.findRemoveButton(tablePanel);
if (removeButton != null) {
removeButton.setEnabled(enabled && table.getSelectedRow() >= 0);
}
table.setEnabled(enabled);
final JTableHeader header = table.getTableHeader();
if (header != null) {
header.repaint();
}
}
private static class OptionsTableModel extends AbstractTableModel implements EditableModel {
private final java.util.List<KeyValuePair> myRows = new ArrayList<KeyValuePair>();
public String getColumnName(int column) {
switch (column) {
case 0: return "Option Name";
case 1: return "Value";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 2;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0 || columnIndex == 1;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: return myRows.get(rowIndex).key;
case 1: return myRows.get(rowIndex).value;
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
switch (columnIndex) {
case 0:
myRows.get(rowIndex).key = (String)aValue;
break;
case 1:
myRows.get(rowIndex).value = (String)aValue;
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add(new KeyValuePair());
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setOptions(Map<String, String> options) {
clear();
if (!options.isEmpty()) {
for (Map.Entry<String, String> entry : options.entrySet()) {
myRows.add(new KeyValuePair(entry.getKey(), entry.getValue()));
}
Collections.sort(myRows, new Comparator<KeyValuePair>() {
@Override
public int compare(KeyValuePair o1, KeyValuePair o2) {
return o1.key.compareToIgnoreCase(o2.key);
}
});
fireTableRowsInserted(0, options.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Map<String, String> getOptions() {
final Map<String, String> map = new java.util.HashMap<String, String>();
for (KeyValuePair pair : myRows) {
map.put(pair.key.trim(), pair.value.trim());
}
map.remove("");
return map;
}
private static final class KeyValuePair {
String key;
String value;
KeyValuePair() {
this("", "");
}
KeyValuePair(String key, String value) {
this.key = key;
this.value = value;
}
}
}
private static class ProcessorTableModel extends AbstractTableModel implements EditableModel {
private final List<String> myRows = new ArrayList<String>();
public String getColumnName(int column) {
switch (column) {
case 0: return "Processor FQ Name";
}
return super.getColumnName(column);
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public int getRowCount() {
return myRows.size();
}
public int getColumnCount() {
return 1;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 0;
}
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0: return myRows.get(rowIndex);
}
return null;
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (aValue != null) {
switch (columnIndex) {
case 0:
myRows.set(rowIndex, (String)aValue);
break;
}
}
}
public void removeRow(int idx) {
myRows.remove(idx);
fireTableRowsDeleted(idx, idx);
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
}
public void addRow() {
myRows.add("");
final int index = myRows.size() - 1;
fireTableRowsInserted(index, index);
}
public void setProcessors(Collection<String> processors) {
clear();
if (!processors.isEmpty()) {
for (String processor : processors) {
myRows.add(processor);
}
Collections.sort(myRows, new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
fireTableRowsInserted(0, processors.size()-1);
}
}
public void clear() {
final int count = myRows.size();
if (count > 0) {
myRows.clear();
fireTableRowsDeleted(0, count-1);
}
}
public Collection<String> getProcessors() {
final Set<String> set = new HashSet<String>();
for (String row : myRows) {
if (row != null) {
set.add(row.trim());
}
}
set.remove("");
return set;
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.compiler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Set;
/**
* @author Eugene Zhuravlev
* Date: 5/27/12
*/
public interface AnnotationProcessingConfiguration {
boolean isEnabled();
@NotNull
String getProcessorPath();
@Nullable
String getGeneratedSourcesDirectoryName();
@NotNull
Set<String> getProcessors();
@NotNull
Map<String, String> getProcessorOptions();
boolean isObtainProcessorsFromClasspath();
}
@@ -19,10 +19,9 @@ package com.intellij.compiler;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
public abstract class CompilerConfiguration {
// need this flag for profiling purposes. In production code is always set to 'true'
public static final boolean MAKE_ENABLED = true;
@@ -35,6 +34,14 @@ public abstract class CompilerConfiguration {
public abstract void setBytecodeTargetLevel(Module module, String level);
@NotNull
public abstract AnnotationProcessingConfiguration getAnnotationProcessingConfiguration(Module module);
/**
* @return true if exists at least one enabled annotation processing profile
*/
public abstract boolean isAnnotationProcessorsEnabled();
public static CompilerConfiguration getInstance(Project project) {
return project.getComponent(CompilerConfiguration.class);
}
@@ -50,28 +57,4 @@ public abstract class CompilerConfiguration {
public abstract boolean isAddNotNullAssertions();
public abstract void setAddNotNullAssertions(boolean enabled);
public abstract boolean isAnnotationProcessorsEnabled();
public abstract void setAnnotationProcessorsEnabled(boolean enableAnnotationProcessors);
public abstract boolean isObtainProcessorsFromClasspath();
public abstract void setObtainProcessorsFromClasspath(boolean obtainProcessorsFromClasspath);
public abstract String getProcessorPath();
public abstract void setProcessorsPath(String processorsPath);
public abstract Map<String, String> getAnnotationProcessorsMap();
public abstract void setAnnotationProcessorsMap(Map<String, String> map);
public abstract void setAnotationProcessedModules(Map<Module, String> modules);
public abstract Map<Module, String> getAnotationProcessedModules();
public abstract boolean isAnnotationProcessingEnabled(Module module);
public abstract String getGeneratedSourceDirName(Module module);
}
@@ -216,8 +216,8 @@ public class CompilerPaths {
public static String getAnnotationProcessorsGenerationPath(Module module) {
final CompilerConfiguration config = CompilerConfiguration.getInstance(module.getProject());
final String sourceDirName = config.getGeneratedSourceDirName(module);
if (sourceDirName != null && sourceDirName.length() > 0) {
final String sourceDirName = config.getAnnotationProcessingConfiguration(module).getGeneratedSourcesDirectoryName();
if (!StringUtil.isEmpty(sourceDirName)) {
final String[] roots = ModuleRootManager.getInstance(module).getContentRootUrls();
if (roots.length == 0) {
return null;