From 7c2a175d1ad2ba7882b04b24c33795f44af7314e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 10 May 2012 22:30:58 +0200 Subject: [PATCH] per-module "-target" setting (IDEA-51666) --- .../compiler/CompilerConfigurationImpl.java | 81 +++- .../intellij/compiler/impl/CompilerUtil.java | 29 ++ .../javaCompiler/BackendCompilerWrapper.java | 1 + .../javaCompiler/eclipse/EclipseCompiler.java | 1 + .../javaCompiler/javac/JavacCompiler.java | 1 + .../compiler/options/JavaCompilersTab.form | 17 +- .../compiler/options/JavaCompilersTab.java | 20 + .../options/TargetOptionsComponent.java | 399 ++++++++++++++++++ .../compiler/CompilerConfiguration.java | 7 + 9 files changed, 549 insertions(+), 7 deletions(-) create mode 100644 java/compiler/impl/src/com/intellij/compiler/options/TargetOptionsComponent.java diff --git a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java index a5031543612a..1ae478adfae8 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompilerConfigurationImpl.java @@ -42,7 +42,6 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.ModuleAdapter; -import com.intellij.openapi.project.ModuleListener; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.ui.InputValidator; @@ -105,6 +104,9 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements private final Map myModuleNames = new HashMap(); private boolean myAddNotNullAssertions = true; + @Nullable + private String myBytecodeTargetLevel = null; // null means compiler default + private final Map myModuleBytecodeTarget = new java.util.HashMap(); public CompilerConfigurationImpl(Project project, ModuleManager moduleManager) { myProject = project; @@ -148,6 +150,35 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } } + public void setProjectBytecodeTarget(@Nullable String level) { + myBytecodeTargetLevel = level; + } + + @Override + @Nullable + public String getProjectBytecodeTarget() { + return myBytecodeTargetLevel; + } + + public void setModulesBytecodeTargetMap(@NotNull Map mapping) { + myModuleBytecodeTarget.clear(); + myModuleBytecodeTarget.putAll(mapping); + } + + public Map getModulesBytecodeTargetMap() { + return myModuleBytecodeTarget; + } + + @Override + @Nullable + public String getBytecodeTargetLevel(Module module) { + final String level = myModuleBytecodeTarget.get(module.getName()); + if (level != null) { + return "".equals(level)? null : level; + } + return myBytecodeTargetLevel; + } + private void loadDefaultWildcardPatterns() { if (!myWildcardPatterns.isEmpty()) { removeWildcardPatterns(); @@ -210,7 +241,9 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } private void createCompilers() { - if (JAVAC_EXTERNAL_BACKEND != null) return; + if (JAVAC_EXTERNAL_BACKEND != null) { + return; + } JAVAC_EXTERNAL_BACKEND = new JavacCompiler(myProject); myRegisteredCompilers.add(JAVAC_EXTERNAL_BACKEND); @@ -528,6 +561,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements @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"; @@ -622,6 +656,24 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements } } } + + myBytecodeTargetLevel = null; + myModuleBytecodeTarget.clear(); + final Element bytecodeTargetElement = parentNode.getChild(BYTECODE_TARGET_LEVEL); + if (bytecodeTargetElement != null) { + myBytecodeTargetLevel = bytecodeTargetElement.getAttributeValue("target"); + for (Element elem : (Collection)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); + } + } } } @@ -692,6 +744,29 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements moduleElement.setAttribute("generatedDirName", dirName); } } + + if (!StringUtil.isEmpty(myBytecodeTargetLevel) || !myModuleBytecodeTarget.isEmpty()) { + final Element bytecodeTarget = new Element(BYTECODE_TARGET_LEVEL); + parentNode.addContent(bytecodeTarget); + if (!StringUtil.isEmpty(myBytecodeTargetLevel)) { + bytecodeTarget.setAttribute("target", myBytecodeTargetLevel); + } + if (!myModuleBytecodeTarget.isEmpty()) { + final List moduleNames = new ArrayList(myModuleBytecodeTarget.keySet()); + Collections.sort(moduleNames, new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); + for (String name : moduleNames) { + final Element moduleElement = new Element("module"); + bytecodeTarget.addContent(moduleElement); + moduleElement.setAttribute("name", name); + moduleElement.setAttribute("target", myModuleBytecodeTarget.get(name)); + } + } + } } @NotNull @NonNls @@ -706,7 +781,7 @@ public class CompilerConfigurationImpl extends CompilerConfiguration implements /** * @param defaultCompiler The compiler that is passed as a parameter to setDefaultCompiler() - * must be one of the registered compilers in compiler configuration. + * must be one of the registered compilers in compiler configuration. * Otherwise because of lazy compiler initialization, the value of default compiler will point to some other compiler instance */ public void setDefaultCompiler(BackendCompiler defaultCompiler) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java index 4cd1ce584ef3..5cc1d5940de7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompilerUtil.java @@ -21,6 +21,8 @@ package com.intellij.compiler.impl; import com.intellij.CommonBundle; +import com.intellij.compiler.CompilerConfiguration; +import com.intellij.compiler.impl.javaCompiler.ModuleChunk; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.compiler.CompileContext; import com.intellij.openapi.compiler.CompilerBundle; @@ -158,6 +160,33 @@ public class CompilerUtil { } } + public static void addTargetCommandLineSwitch(final ModuleChunk chunk, final List commandLine) { + String optionValue = null; + CompilerConfiguration config = null; + final Module[] modules = chunk.getModules(); + for (Module module : modules) { + if (config == null) { + config = CompilerConfiguration.getInstance(module.getProject()); + } + final String moduleTarget = config.getBytecodeTargetLevel(module); + if (moduleTarget == null) { + continue; + } + if (optionValue == null) { + optionValue = moduleTarget; + } + else { + if (moduleTarget.compareTo(optionValue) < 0) { + optionValue = moduleTarget; // use the lower possible target among modules that form the chunk + } + } + } + if (optionValue != null) { + commandLine.add("-target"); + commandLine.add(optionValue); + } + } + public static void addSourceCommandLineSwitch(final Sdk jdk, LanguageLevel chunkLanguageLevel, @NonNls final List commandLine) { final String versionString = jdk.getVersionString(); if (StringUtil.isEmpty(versionString)) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/BackendCompilerWrapper.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/BackendCompilerWrapper.java index 213f5736c2ab..1790fa0e08a7 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/BackendCompilerWrapper.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/BackendCompilerWrapper.java @@ -190,6 +190,7 @@ public class BackendCompilerWrapper { // validate encodings if (chunk.getModuleCount() > 1) { validateEncoding(chunk, chunkPresentableName); + // todo: validation for bytecode target? } runTransformingCompilers(chunk); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java index 5cd786eecd78..e043fbe9423c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/eclipse/EclipseCompiler.java @@ -164,6 +164,7 @@ public class EclipseCompiler extends ExternalCompiler { boolean quoteBootClasspath) throws IOException { final Sdk jdk = chunk.getJdk(); CompilerUtil.addSourceCommandLineSwitch(jdk, chunk.getLanguageLevel(), commandLine); + CompilerUtil.addTargetCommandLineSwitch(chunk, commandLine); final String bootCp = chunk.getCompilationBootClasspath(); diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java index 724dcdd01fc4..140cd7316644 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/javac/JavacCompiler.java @@ -363,6 +363,7 @@ public class JavacCompiler extends ExternalCompiler { LanguageLevel languageLevel = chunk.getLanguageLevel(); CompilerUtil.addSourceCommandLineSwitch(jdk, languageLevel, commandLine); + CompilerUtil.addTargetCommandLineSwitch(chunk, commandLine); commandLine.add("-verbose"); diff --git a/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.form b/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.form index 39e3c2df03f9..40c0fc0a7da0 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.form +++ b/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.form @@ -1,6 +1,6 @@
- + @@ -36,15 +36,24 @@ - + - + + - + + + + + + + + + diff --git a/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.java b/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.java index 41cfe3ecd685..abdb45a6dc31 100644 --- a/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.java +++ b/java/compiler/impl/src/com/intellij/compiler/options/JavaCompilersTab.java @@ -45,6 +45,7 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No private JPanel myPanel; private JPanel myContentPanel; private JComboBox myCompiler; + private JPanel myTargetOptionsPanel; private final CardLayout myCardLayout; private final Project myProject; @@ -52,6 +53,7 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No private BackendCompiler mySelectedCompiler; private final CompilerConfigurationImpl myCompilerConfiguration; private final Collection myConfigurables; + private final TargetOptionsComponent myTargetLevelComponent; public JavaCompilersTab(final Project project, Collection compilers, BackendCompiler defaultCompiler) { myProject = project; @@ -62,6 +64,10 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No myCardLayout = new CardLayout(); myContentPanel.setLayout(myCardLayout); + myTargetOptionsPanel.setLayout(new BorderLayout()); + myTargetLevelComponent = new TargetOptionsComponent(project); + myTargetOptionsPanel.add(myTargetLevelComponent, BorderLayout.CENTER); + for (BackendCompiler compiler : compilers) { Configurable configurable = compiler.createConfigurable(); myConfigurables.add(configurable); @@ -118,6 +124,12 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No return true; } } + if (!Comparing.equal(myTargetLevelComponent.getProjectBytecodeTarget(), myCompilerConfiguration.getProjectBytecodeTarget())) { + return true; + } + if (!Comparing.equal(myTargetLevelComponent.getModulesBytecodeTargetMap(), myCompilerConfiguration.getModulesBytecodeTargetMap())) { + return true; + } return false; } @@ -126,6 +138,12 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No configurable.apply(); } myCompilerConfiguration.setDefaultCompiler(mySelectedCompiler); + myCompilerConfiguration.setProjectBytecodeTarget(myTargetLevelComponent.getProjectBytecodeTarget()); + myCompilerConfiguration.setModulesBytecodeTargetMap(myTargetLevelComponent.getModulesBytecodeTargetMap()); + + myTargetLevelComponent.setProjectBytecodeTargetLevel(myCompilerConfiguration.getProjectBytecodeTarget()); + myTargetLevelComponent.setModuleTargetLevels(myCompilerConfiguration.getModulesBytecodeTargetMap()); + SwingUtilities.invokeLater(new Runnable() { public void run() { CompileServerManager.getInstance().sendReloadRequest(myProject); @@ -139,6 +157,8 @@ public class JavaCompilersTab implements SearchableConfigurable, Configurable.No configurable.reset(); } selectCompiler(myCompilerConfiguration.getDefaultCompiler()); + myTargetLevelComponent.setProjectBytecodeTargetLevel(myCompilerConfiguration.getProjectBytecodeTarget()); + myTargetLevelComponent.setModuleTargetLevels(myCompilerConfiguration.getModulesBytecodeTargetMap()); } public void disposeUIResources() { diff --git a/java/compiler/impl/src/com/intellij/compiler/options/TargetOptionsComponent.java b/java/compiler/impl/src/com/intellij/compiler/options/TargetOptionsComponent.java new file mode 100644 index 000000000000..2d57886089ca --- /dev/null +++ b/java/compiler/impl/src/com/intellij/compiler/options/TargetOptionsComponent.java @@ -0,0 +1,399 @@ +/* + * 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.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.ChooseModulesDialog; +import com.intellij.openapi.ui.ComboBox; +import com.intellij.ui.AnActionButton; +import com.intellij.ui.AnActionButtonRunnable; +import com.intellij.ui.TableUtil; +import com.intellij.ui.ToolbarDecorator; +import com.intellij.ui.table.JBTable; +import com.intellij.util.ui.ItemRemovable; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableColumn; +import java.awt.*; +import java.util.*; +import java.util.List; + +/** + * @author Eugene Zhuravlev + * Date: 5/9/12 + */ +public class TargetOptionsComponent extends JPanel { + private static final String[] KNOWN_TARGETS = new String[] {"1.1", "1.2", "1.3","1.4","1.5", "1.6", "1.7", "1.8"}; + private static final String COMPILER_DEFAULT = "compiler default"; + + private ComboBox myCbProjectTargetLevel; + private JBTable myTable; + private final Project myProject; + + public TargetOptionsComponent(Project project) { + super(new GridBagLayout()); + myProject = project; + //setBorder(BorderFactory.createTitledBorder("Bytecode target level")); + myCbProjectTargetLevel = createTargetOptionsCombo(); + + myTable = new JBTable(new TargetLevelTableModel()); + myTable.setRowHeight(22); + myTable.getEmptyText().setText("All modules will be compiled with project bytecode version"); + + final TableColumn moduleColumn = myTable.getColumnModel().getColumn(0); + moduleColumn.setHeaderValue("Module"); + moduleColumn.setCellRenderer(new ModuleCellRenderer()); + + final TableColumn targetLevelColumn = myTable.getColumnModel().getColumn(1); + final String columnTitle = "Target bytecode version"; + targetLevelColumn.setHeaderValue(columnTitle); + targetLevelColumn.setCellEditor(new TargetLevelCellEditor()); + targetLevelColumn.setCellRenderer(new TargetLevelCellRenderer()); + final int width = myTable.getFontMetrics(myTable.getFont()).stringWidth(columnTitle) + 10; + targetLevelColumn.setPreferredWidth(width); + targetLevelColumn.setMinWidth(width); + targetLevelColumn.setMaxWidth(width); + + add(new JLabel("Project bytecode version (leave blank for compiler default): "), + constraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NONE)); + add(myCbProjectTargetLevel, constraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NONE)); + add(new JLabel("Per-module bytecode version:"), constraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.NONE)); + final JPanel tableComp = ToolbarDecorator.createDecorator(myTable) + .disableUpAction() + .disableDownAction() + .setAddAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton anActionButton) { + addModules(); + } + }) + .setRemoveAction(new AnActionButtonRunnable() { + @Override + public void run(AnActionButton anActionButton) { + removeSelectedModules(); + } + }).createPanel(); + + tableComp.setPreferredSize(new Dimension(myTable.getWidth(), 150)); + add(tableComp, constraints(0, 2, 2, 1, 1.0, 1.0, GridBagConstraints.BOTH)); + } + + private void removeSelectedModules() { + final int[] rows = myTable.getSelectedRows(); + if (rows.length > 0) { + TableUtil.removeSelectedItems(myTable); + } + } + + private void addModules() { + final TargetLevelTableModel model = (TargetLevelTableModel)myTable.getModel(); + final List items = new ArrayList(Arrays.asList(ModuleManager.getInstance(myProject).getModules())); + Set alreadyAdded = new HashSet(); + for (TargetLevelTableModel.Item item : model.getItems()) { + alreadyAdded.add(item.module); + } + for (Iterator it = items.iterator(); it.hasNext(); ) { + Module module = it.next(); + if (alreadyAdded.contains(module)) { + it.remove(); + } + } + Collections.sort(items, new Comparator() { + @Override + public int compare(Module o1, Module o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + final ChooseModulesDialog chooser = new ChooseModulesDialog(this, items, "Choose module"); + chooser.show(); + final List elements = chooser.getChosenElements(); + if (!elements.isEmpty()) { + model.addItems(elements); + } + } + + public void setProjectBytecodeTargetLevel(String level) { + myCbProjectTargetLevel.setSelectedItem(level == null? "" : level); + } + + @Nullable + public String getProjectBytecodeTarget() { + final String item = ((String)myCbProjectTargetLevel.getSelectedItem()).trim(); + return "".equals(item)? null : item; + } + + public Map getModulesBytecodeTargetMap() { + TargetLevelTableModel model = (TargetLevelTableModel)myTable.getModel(); + final Map map = new HashMap(); + for (TargetLevelTableModel.Item item : model.getItems()) { + map.put(item.module.getName(), item.targetLevel); + } + return map; + } + + public void setModuleTargetLevels(Map moduleLevels) { + final Map map = new HashMap(); + for (Module module : ModuleManager.getInstance(myProject).getModules()) { + final String target = moduleLevels.get(module.getName()); + if (target != null) { + map.put(module, target); + } + } + ((TargetLevelTableModel)myTable.getModel()).setItems(map); + } + + private static GridBagConstraints constraints(final int gridx, final int gridy, final int gridwidth, final int gridheight, final double weightx, final double weighty, final int fill) { + return new GridBagConstraints(gridx, gridy, gridwidth, gridheight, weightx, weighty, GridBagConstraints.WEST, fill, new Insets(5, 5, 0, 0), 0, 0); + } + + private static final class TargetLevelTableModel extends AbstractTableModel implements ItemRemovable{ + private final List myItems = new ArrayList(); + @Override + public int getRowCount() { + return myItems.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex != 0; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + final Item item = myItems.get(rowIndex); + return columnIndex == 0? item.module : item.targetLevel; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + final Item item = myItems.get(rowIndex); + item.targetLevel = ((String)aValue).trim(); + fireTableCellUpdated(rowIndex, columnIndex); + } + + //public void addItem(Module module) { + // final int size = myItems.size(); + // myItems.add(new Item(module.getName())); + // fireTableRowsInserted(size, size); + //} + + public void addItems(Collection modules) { + for (Module module : modules) { + myItems.add(new Item(module)); + } + sorItems(); + fireTableDataChanged(); + } + + private void sorItems() { + Collections.sort(myItems, new Comparator() { + @Override + public int compare(Item o1, Item o2) { + return o1.module.getName().compareTo(o2.module.getName()); + } + }); + } + + public List getItems() { + return myItems; + } + + @Override + public void removeRow(int idx) { + myItems.remove(idx); + } + + public void setItems(Map items) { + myItems.clear(); + for (Map.Entry entry : items.entrySet()) { + myItems.add(new Item(entry.getKey(), entry.getValue())); + } + sorItems(); + fireTableDataChanged(); + } + + private static final class Item { + final Module module; + String targetLevel = ""; + + Item(Module module) { + this.module = module; + } + + Item(Module module, String targetLevel) { + this.module = module; + this.targetLevel = targetLevel; + } + } + } + + private static final class TargetLevelComboboxModel extends AbstractListModel implements ComboBoxModel{ + + private final List myOptions = new ArrayList(); + private String mySelectedItem = ""; + + TargetLevelComboboxModel() { + //myOptions.add(""); + for (int i = KNOWN_TARGETS.length - 1; i >= 0; i--) { + myOptions.add(KNOWN_TARGETS[i]); + } + } + + @Override + public int getSize() { + return myOptions.size(); + } + + @Override + public void setSelectedItem(Object anItem) { + mySelectedItem = toModelItem((String)anItem); + fireContentsChanged(this, 0, myOptions.size()); + } + + @Override + public Object getSelectedItem() { + return mySelectedItem; + } + + @Override + public Object getElementAt(int index) { + return myOptions.get(index); + } + + private String toModelItem(String item) { + item = item.trim(); + for (String option : myOptions) { + if (option.equals(item)) { + return option; + } + } + return item; + } + } + + private static ComboBox createTargetOptionsCombo() { + final ComboBox combo = new ComboBox(new TargetLevelComboboxModel()); + //combo.setRenderer(new DefaultListCellRenderer() { + // @Override + // public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + // try { + // return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + // } + // finally { + // //if ("".equals(value)) { + // // setText(COMPILER_DEFAULT); + // //} + // } + // } + //}); + combo.setEditable(true); + combo.setEditor(new BasicComboBoxEditor() { + @Override + protected JTextField createEditorComponent() { + return new HintTextField(COMPILER_DEFAULT, 10); + } + }); + return combo; + } + + private static class ModuleCellRenderer extends DefaultTableCellRenderer { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + try { + return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + } + finally { + final Module module = (Module)value; + setText(module.getName()); + setIcon(ModuleType.get(module).getNodeIcon(false)); + } + } + } + + private static class TargetLevelCellEditor extends DefaultCellEditor { + private TargetLevelCellEditor() { + super(createTargetOptionsCombo()); + setClickCountToStart(0); + } + } + + private static class TargetLevelCellRenderer extends DefaultTableCellRenderer { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (component instanceof JLabel) { + final JLabel comp = (JLabel)component; + comp.setHorizontalAlignment(SwingConstants.CENTER); + if ("".equals(value)) { + comp.setForeground(Color.gray); + comp.setText(COMPILER_DEFAULT); + } + else { + comp.setForeground(table.getForeground()); + } + } + return component; + } + } + + static class HintTextField extends JTextField { + private final char[] myHint; + + public HintTextField(final String hint) { + this(hint, 0); + } + + public HintTextField(final String hint, final int columns) { + super(hint, columns); + myHint = hint.toCharArray(); + setBorder(null); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + final boolean isFocused = isFocusOwner(); + if (!isFocused && getText().isEmpty()) { + final Color oldColor = g.getColor(); + final Font oldFont = g.getFont(); + try { + g.setColor(Color.gray); + //g.setFont(oldFont.deriveFont(Font.ITALIC)); + final FontMetrics metrics = g.getFontMetrics(); + int x = Math.abs(getWidth() - metrics.charsWidth(myHint, 0, myHint.length)) / 2; + int y = Math.abs(getHeight() - metrics.getHeight()) / 2 + metrics.getAscent(); + g.drawChars(myHint, 0, myHint.length, x, y); + } + finally { + g.setColor(oldColor); + g.setFont(oldFont); + } + } + } + } +} diff --git a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java index 1068be4c8fc7..f2b8d46c24ea 100644 --- a/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java +++ b/java/compiler/openapi/src/com/intellij/compiler/CompilerConfiguration.java @@ -19,6 +19,7 @@ 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.Nullable; import java.util.Map; @@ -26,6 +27,12 @@ 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; + @Nullable + public abstract String getProjectBytecodeTarget(); + + @Nullable + public abstract String getBytecodeTargetLevel(Module module); + public static CompilerConfiguration getInstance(Project project) { return project.getComponent(CompilerConfiguration.class); }