Allow to edit TeaVM build properties from IDEA UI

This commit is contained in:
Alexey Andreev 2017-06-16 00:57:06 +03:00
parent f0637fda41
commit 6653118dd8
10 changed files with 246 additions and 4 deletions

View File

@ -16,6 +16,7 @@
package org.teavm.idea.jps.model; package org.teavm.idea.jps.model;
import java.util.List; import java.util.List;
import java.util.Properties;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
import org.teavm.vm.TeaVMProgressListener; import org.teavm.vm.TeaVMProgressListener;
@ -44,5 +45,7 @@ public interface TeaVMBuildStrategy {
void setIncremental(boolean incremental); void setIncremental(boolean incremental);
void setProperties(Properties properties);
TeaVMBuildResult build(); TeaVMBuildResult build();
} }

View File

@ -15,10 +15,13 @@
*/ */
package org.teavm.idea.jps.model; package org.teavm.idea.jps.model;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Tag;
import com.intellij.util.xmlb.annotations.Transient; import com.intellij.util.xmlb.annotations.Transient;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsElementChildRole; import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.ex.JpsElementBase; import org.jetbrains.jps.model.ex.JpsElementBase;
@ -38,9 +41,9 @@ public class TeaVMJpsConfiguration extends JpsElementBase<TeaVMJpsConfiguration>
private String mainClass; private String mainClass;
private String targetDirectory; private String targetDirectory;
private boolean minifying;
private boolean sourceMapsFileGenerated = true; private boolean sourceMapsFileGenerated = true;
private boolean sourceFilesCopied = true; private boolean sourceFilesCopied = true;
private List<TeaVMProperty> properties = new ArrayList<>();
public TeaVMTargetType getTargetType() { public TeaVMTargetType getTargetType() {
return targetType; return targetType;
@ -82,6 +85,16 @@ public class TeaVMJpsConfiguration extends JpsElementBase<TeaVMJpsConfiguration>
this.sourceFilesCopied = sourceFilesCopied; this.sourceFilesCopied = sourceFilesCopied;
} }
@Tag("properties")
@AbstractCollection(surroundWithTag = false)
public List<TeaVMProperty> getProperties() {
return properties;
}
public void setProperties(List<TeaVMProperty> properties) {
this.properties = properties;
}
public static List<TeaVMJpsConfiguration> getAll(JpsModule module) { public static List<TeaVMJpsConfiguration> getAll(JpsModule module) {
List<TeaVMJpsConfiguration> configurations = new ArrayList<>(); List<TeaVMJpsConfiguration> configurations = new ArrayList<>();
for (JpsElementChildRole<TeaVMJpsConfiguration> role : Arrays.asList(JS_ROLE, WEBASSEMBLY_ROLE)) { for (JpsElementChildRole<TeaVMJpsConfiguration> role : Arrays.asList(JS_ROLE, WEBASSEMBLY_ROLE)) {
@ -105,8 +118,12 @@ public class TeaVMJpsConfiguration extends JpsElementBase<TeaVMJpsConfiguration>
public void applyChanges(@NotNull TeaVMJpsConfiguration modified) { public void applyChanges(@NotNull TeaVMJpsConfiguration modified) {
mainClass = modified.mainClass; mainClass = modified.mainClass;
targetDirectory = modified.targetDirectory; targetDirectory = modified.targetDirectory;
minifying = modified.minifying;
sourceMapsFileGenerated = modified.sourceMapsFileGenerated; sourceMapsFileGenerated = modified.sourceMapsFileGenerated;
sourceFilesCopied = modified.sourceFilesCopied; sourceFilesCopied = modified.sourceFilesCopied;
properties.clear();
properties.addAll(modified.properties.stream()
.map(property -> property.createCopy())
.collect(Collectors.toList()));
} }
} }

View File

@ -0,0 +1,50 @@
/*
* Copyright 2017 Alexey Andreev.
*
* 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 org.teavm.idea.jps.model;
import com.intellij.util.xmlb.annotations.Attribute;
import com.intellij.util.xmlb.annotations.Tag;
@Tag("property")
public class TeaVMProperty {
private String key = "";
private String value = "";
@Attribute("key")
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@Attribute("value")
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public TeaVMProperty createCopy() {
TeaVMProperty copy = new TeaVMProperty();
copy.key = key;
copy.value = value;
return copy;
}
}

View File

@ -18,6 +18,7 @@ package org.teavm.idea.jps.remote;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
public class TeaVMRemoteBuildRequest implements Serializable { public class TeaVMRemoteBuildRequest implements Serializable {
@ -31,4 +32,5 @@ public class TeaVMRemoteBuildRequest implements Serializable {
public boolean debugInformationGenerated; public boolean debugInformationGenerated;
public boolean sourceFilesCopied; public boolean sourceFilesCopied;
public boolean incremental; public boolean incremental;
public Properties properties;
} }

View File

@ -21,6 +21,7 @@ import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jetbrains.jps.incremental.CompileContext; import org.jetbrains.jps.incremental.CompileContext;
@ -50,6 +51,7 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
private boolean sourceFilesCopied; private boolean sourceFilesCopied;
private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>(); private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
private TeaVMProgressListener progressListener; private TeaVMProgressListener progressListener;
private Properties properties = new Properties();
public InProcessBuildStrategy(CompileContext context) { public InProcessBuildStrategy(CompileContext context) {
this.context = context; this.context = context;
@ -115,6 +117,12 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
public void setIncremental(boolean incremental) { public void setIncremental(boolean incremental) {
} }
@Override
public void setProperties(Properties properties) {
this.properties.clear();
this.properties.putAll(properties);
}
@Override @Override
public TeaVMBuildResult build() { public TeaVMBuildResult build() {
TeaVMTool tool = new TeaVMTool(); TeaVMTool tool = new TeaVMTool();
@ -131,6 +139,8 @@ public class InProcessBuildStrategy implements TeaVMBuildStrategy {
tool.setMinifying(false); tool.setMinifying(false);
tool.getProperties().putAll(properties);
for (SourceFileProvider fileProvider : sourceFileProviders) { for (SourceFileProvider fileProvider : sourceFileProviders) {
tool.addSourceFileProvider(fileProvider); tool.addSourceFileProvider(fileProvider);
} }

View File

@ -19,6 +19,7 @@ import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject; import java.rmi.server.UnicastRemoteObject;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Properties;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.Problem;
import org.teavm.diagnostics.ProblemProvider; import org.teavm.diagnostics.ProblemProvider;
@ -102,6 +103,12 @@ public class RemoteBuildStrategy implements TeaVMBuildStrategy {
request.incremental = incremental; request.incremental = incremental;
} }
@Override
public void setProperties(Properties properties) {
request.properties = new Properties();
request.properties.putAll(properties);
}
@Override @Override
public TeaVMBuildResult build() { public TeaVMBuildResult build() {
TeaVMRemoteBuildResponse response; TeaVMRemoteBuildResponse response;

View File

@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Properties;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -59,6 +60,7 @@ import org.teavm.diagnostics.ProblemProvider;
import org.teavm.idea.jps.model.TeaVMBuildResult; import org.teavm.idea.jps.model.TeaVMBuildResult;
import org.teavm.idea.jps.model.TeaVMBuildStrategy; import org.teavm.idea.jps.model.TeaVMBuildStrategy;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration; import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.idea.jps.model.TeaVMProperty;
import org.teavm.idea.jps.remote.TeaVMBuilderAssistant; import org.teavm.idea.jps.remote.TeaVMBuilderAssistant;
import org.teavm.idea.jps.remote.TeaVMElementLocation; import org.teavm.idea.jps.remote.TeaVMElementLocation;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
@ -114,6 +116,13 @@ class TeaVMBuild {
buildStrategy.setTargetDirectory(config.getTargetDirectory()); buildStrategy.setTargetDirectory(config.getTargetDirectory());
buildStrategy.setProgressListener(createProgressListener(context)); buildStrategy.setProgressListener(createProgressListener(context));
buildStrategy.setIncremental(!isRebuild(target)); buildStrategy.setIncremental(!isRebuild(target));
Properties properties = new Properties();
for (TeaVMProperty property : config.getProperties()) {
properties.put(property.getKey(), property.getValue());
}
buildStrategy.setProperties(properties);
TeaVMBuildResult buildResult = buildStrategy.build(); TeaVMBuildResult buildResult = buildStrategy.build();
if (!buildResult.isErrorOccurred() && buildResult.getProblems().getSevereProblems().isEmpty()) { if (!buildResult.isErrorOccurred() && buildResult.getProblems().getSevereProblems().isEmpty()) {

View File

@ -181,6 +181,7 @@ public class TeaVMBuildDaemon extends UnicastRemoteObject implements TeaVMRemote
tool.setSourceMapsFileGenerated(request.sourceMapsFileGenerated); tool.setSourceMapsFileGenerated(request.sourceMapsFileGenerated);
tool.setDebugInformationGenerated(request.debugInformationGenerated); tool.setDebugInformationGenerated(request.debugInformationGenerated);
tool.setSourceFilesCopied(request.sourceFilesCopied); tool.setSourceFilesCopied(request.sourceFilesCopied);
tool.getProperties().putAll(request.properties);
tool.setMinifying(false); tool.setMinifying(false);

View File

@ -20,6 +20,7 @@ import com.intellij.facet.FacetType;
import com.intellij.facet.ModifiableFacetModel; import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider; import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -37,6 +38,7 @@ import org.teavm.idea.TeaVMFacetConfiguration;
import org.teavm.idea.TeaVMFacetType; import org.teavm.idea.TeaVMFacetType;
import org.teavm.idea.TeaVMWebAssemblyFacetType; import org.teavm.idea.TeaVMWebAssemblyFacetType;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration; import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.idea.jps.model.TeaVMProperty;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
public class TeaVMMavenImporter extends MavenImporter { public class TeaVMMavenImporter extends MavenImporter {
@ -127,12 +129,26 @@ public class TeaVMMavenImporter extends MavenImporter {
case "mainClass": case "mainClass":
configuration.setMainClass(child.getTextTrim()); configuration.setMainClass(child.getTextTrim());
break; break;
case "properties":
configuration.setProperties(extractProperties(child));
break;
} }
} }
facet.getConfiguration().loadState(configuration); facet.getConfiguration().loadState(configuration);
} }
private List<TeaVMProperty> extractProperties(Element element) {
List<TeaVMProperty> properties = new ArrayList<>();
for (Element child : element.getChildren()) {
TeaVMProperty property = new TeaVMProperty();
property.setKey(child.getName());
property.setValue(child.getTextTrim());
properties.add(property);
}
return properties;
}
private TeaVMTargetType getTargetType(Element source) { private TeaVMTargetType getTargetType(Element source) {
for (Element child : source.getChildren()) { for (Element child : source.getChildren()) {
if (child.getName().equals("targetType")) { if (child.getName().equals("targetType")) {

View File

@ -26,10 +26,16 @@ import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiClass; import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiMethodUtil; import com.intellij.psi.util.PsiMethodUtil;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBLabel;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.EditableModel;
import java.awt.BorderLayout;
import java.awt.Font; import java.awt.Font;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -37,16 +43,21 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.table.AbstractTableModel;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration; import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.idea.jps.model.TeaVMProperty;
class TeaVMConfigurationPanel extends JPanel { class TeaVMConfigurationPanel extends JPanel {
private final TextFieldWithBrowseButton mainClassField = new TextFieldWithBrowseButton(event -> chooseMainClass()); private final TextFieldWithBrowseButton mainClassField = new TextFieldWithBrowseButton(event -> chooseMainClass());
private final TextFieldWithBrowseButton targetDirectoryField = new TextFieldWithBrowseButton(); private final TextFieldWithBrowseButton targetDirectoryField = new TextFieldWithBrowseButton();
private final JComboBox<ComboBoxItem<Boolean>> sourceMapsField = new JComboBox<>(new DefaultComboBoxModel<>()); private final JComboBox<ComboBoxItem<Boolean>> sourceMapsField = new JComboBox<>(new DefaultComboBoxModel<>());
private final JComboBox<ComboBoxItem<Boolean>> copySourcesField = new JComboBox<>(new DefaultComboBoxModel<>()); private final JComboBox<ComboBoxItem<Boolean>> copySourcesField = new JComboBox<>(new DefaultComboBoxModel<>());
private final JBTable propertiesTable = new JBTable();
private final PropertiesModel propertiesModel = new PropertiesModel();
private final TeaVMJpsConfiguration initialConfiguration = new TeaVMJpsConfiguration(); private final TeaVMJpsConfiguration initialConfiguration = new TeaVMJpsConfiguration();
private final Project project; private final Project project;
@ -73,6 +84,7 @@ class TeaVMConfigurationPanel extends JPanel {
TeaVMConfigurationPanel(Project project) { TeaVMConfigurationPanel(Project project) {
this.project = project; this.project = project;
propertiesTable.setModel(propertiesModel);
setupLayout(); setupLayout();
FileChooserDescriptor targetDirectoryChooserDescriptor = FileChooserDescriptorFactory FileChooserDescriptor targetDirectoryChooserDescriptor = FileChooserDescriptorFactory
@ -134,7 +146,12 @@ class TeaVMConfigurationPanel extends JPanel {
constraints.fill = GridBagConstraints.BOTH; constraints.fill = GridBagConstraints.BOTH;
constraints.weighty = 100; constraints.weighty = 100;
constraints.weightx = 1; constraints.weightx = 1;
add(new JPanel(), constraints);
JPanel propertiesPanel = new JPanel(new BorderLayout());
propertiesPanel.setBorder(IdeBorderFactory.createTitledBorder("Properties"));
propertiesPanel.add(ToolbarDecorator.createDecorator(propertiesTable).createPanel(), BorderLayout.CENTER);
add(propertiesPanel, constraints);
} }
private static JBLabel bold(JBLabel label) { private static JBLabel bold(JBLabel label) {
@ -150,27 +167,54 @@ class TeaVMConfigurationPanel extends JPanel {
for (Field<?> field : fields) { for (Field<?> field : fields) {
loadField(field, config); loadField(field, config);
} }
copyProperties(config.getProperties(), propertiesModel.getProperties());
} }
void save(TeaVMJpsConfiguration config) { void save(TeaVMJpsConfiguration config) {
for (Field<?> field : fields) { for (Field<?> field : fields) {
saveField(field, config); saveField(field, config);
} }
copyProperties(propertiesModel.getProperties(), config.getProperties());
updateInitialConfiguration(config); updateInitialConfiguration(config);
} }
boolean isModified() { boolean isModified() {
return fields.stream().anyMatch(this::isFieldModified); return fields.stream().anyMatch(this::isFieldModified) || arePropertiesModified();
} }
private <T> boolean isFieldModified(Field<T> field) { private <T> boolean isFieldModified(Field<T> field) {
return !Objects.equals(field.dataSupplier.apply(initialConfiguration), field.editSupplier.get()); return !Objects.equals(field.dataSupplier.apply(initialConfiguration), field.editSupplier.get());
} }
private boolean arePropertiesModified() {
if (initialConfiguration.getProperties().size() != propertiesModel.getProperties().size()) {
return true;
}
for (int i = 0; i < initialConfiguration.getProperties().size(); ++i) {
TeaVMProperty initialProperty = initialConfiguration.getProperties().get(i);
TeaVMProperty property = propertiesModel.getProperties().get(i);
if (!initialProperty.getKey().equals(property.getKey())
|| !initialProperty.getValue().equals(property.getValue())) {
return true;
}
}
return false;
}
private void updateInitialConfiguration(TeaVMJpsConfiguration config) { private void updateInitialConfiguration(TeaVMJpsConfiguration config) {
for (Field<?> field : fields) { for (Field<?> field : fields) {
copyField(field, config); copyField(field, config);
} }
copyProperties(config.getProperties(), initialConfiguration.getProperties());
}
private void copyProperties(List<TeaVMProperty> from, List<TeaVMProperty> to) {
to.clear();
to.addAll(from.stream().map(property -> property.createCopy()).collect(Collectors.toList()));
} }
private <T> void copyField(Field<T> field, TeaVMJpsConfiguration config) { private <T> void copyField(Field<T> field, TeaVMJpsConfiguration config) {
@ -232,4 +276,87 @@ class TeaVMConfigurationPanel extends JPanel {
this.editSupplier = editSupplier; this.editSupplier = editSupplier;
} }
} }
class PropertiesModel extends AbstractTableModel implements EditableModel {
private List<TeaVMProperty> properties = new ArrayList<>();
List<TeaVMProperty> getProperties() {
return properties;
}
@Override
public void addRow() {
properties.add(new TeaVMProperty());
}
@Override
public void exchangeRows(int oldIndex, int newIndex) {
TeaVMProperty old = properties.get(oldIndex);
properties.set(oldIndex, properties.get(newIndex));
properties.set(newIndex, old);
}
@Override
public boolean canExchangeRows(int oldIndex, int newIndex) {
return true;
}
@Override
public void removeRow(int idx) {
properties.remove(idx);
}
@Override
public int getRowCount() {
return properties.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Name";
case 1:
return "Value";
default:
throw new IllegalArgumentException();
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return properties.get(rowIndex).getKey();
case 1:
return properties.get(rowIndex).getValue();
default:
throw new IllegalArgumentException();
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
properties.get(rowIndex).setKey((String) aValue);
break;
case 1:
properties.get(rowIndex).setValue((String) aValue);
break;
default:
throw new IllegalArgumentException();
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
}
}
} }