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;
import java.util.List;
import java.util.Properties;
import org.teavm.tooling.TeaVMTargetType;
import org.teavm.vm.TeaVMProgressListener;
@ -44,5 +45,7 @@ public interface TeaVMBuildStrategy {
void setIncremental(boolean incremental);
void setProperties(Properties properties);
TeaVMBuildResult build();
}

View File

@ -15,10 +15,13 @@
*/
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.ex.JpsElementBase;
@ -38,9 +41,9 @@ public class TeaVMJpsConfiguration extends JpsElementBase<TeaVMJpsConfiguration>
private String mainClass;
private String targetDirectory;
private boolean minifying;
private boolean sourceMapsFileGenerated = true;
private boolean sourceFilesCopied = true;
private List<TeaVMProperty> properties = new ArrayList<>();
public TeaVMTargetType getTargetType() {
return targetType;
@ -82,6 +85,16 @@ public class TeaVMJpsConfiguration extends JpsElementBase<TeaVMJpsConfiguration>
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) {
List<TeaVMJpsConfiguration> configurations = new ArrayList<>();
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) {
mainClass = modified.mainClass;
targetDirectory = modified.targetDirectory;
minifying = modified.minifying;
sourceMapsFileGenerated = modified.sourceMapsFileGenerated;
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.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.teavm.tooling.TeaVMTargetType;
public class TeaVMRemoteBuildRequest implements Serializable {
@ -31,4 +32,5 @@ public class TeaVMRemoteBuildRequest implements Serializable {
public boolean debugInformationGenerated;
public boolean sourceFilesCopied;
public boolean incremental;
public Properties properties;
}

View File

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

View File

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

View File

@ -31,6 +31,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
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.TeaVMBuildStrategy;
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.TeaVMElementLocation;
import org.teavm.model.CallLocation;
@ -114,6 +116,13 @@ class TeaVMBuild {
buildStrategy.setTargetDirectory(config.getTargetDirectory());
buildStrategy.setProgressListener(createProgressListener(context));
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();
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.setDebugInformationGenerated(request.debugInformationGenerated);
tool.setSourceFilesCopied(request.sourceFilesCopied);
tool.getProperties().putAll(request.properties);
tool.setMinifying(false);

View File

@ -20,6 +20,7 @@ import com.intellij.facet.FacetType;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.module.Module;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -37,6 +38,7 @@ import org.teavm.idea.TeaVMFacetConfiguration;
import org.teavm.idea.TeaVMFacetType;
import org.teavm.idea.TeaVMWebAssemblyFacetType;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.idea.jps.model.TeaVMProperty;
import org.teavm.tooling.TeaVMTargetType;
public class TeaVMMavenImporter extends MavenImporter {
@ -127,12 +129,26 @@ public class TeaVMMavenImporter extends MavenImporter {
case "mainClass":
configuration.setMainClass(child.getTextTrim());
break;
case "properties":
configuration.setProperties(extractProperties(child));
break;
}
}
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) {
for (Element child : source.getChildren()) {
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.search.GlobalSearchScope;
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.table.JBTable;
import com.intellij.util.ui.EditableModel;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@ -37,16 +43,21 @@ import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.table.AbstractTableModel;
import org.teavm.idea.jps.model.TeaVMJpsConfiguration;
import org.teavm.idea.jps.model.TeaVMProperty;
class TeaVMConfigurationPanel extends JPanel {
private final TextFieldWithBrowseButton mainClassField = new TextFieldWithBrowseButton(event -> chooseMainClass());
private final TextFieldWithBrowseButton targetDirectoryField = new TextFieldWithBrowseButton();
private final JComboBox<ComboBoxItem<Boolean>> sourceMapsField = 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 Project project;
@ -73,6 +84,7 @@ class TeaVMConfigurationPanel extends JPanel {
TeaVMConfigurationPanel(Project project) {
this.project = project;
propertiesTable.setModel(propertiesModel);
setupLayout();
FileChooserDescriptor targetDirectoryChooserDescriptor = FileChooserDescriptorFactory
@ -134,7 +146,12 @@ class TeaVMConfigurationPanel extends JPanel {
constraints.fill = GridBagConstraints.BOTH;
constraints.weighty = 100;
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) {
@ -150,27 +167,54 @@ class TeaVMConfigurationPanel extends JPanel {
for (Field<?> field : fields) {
loadField(field, config);
}
copyProperties(config.getProperties(), propertiesModel.getProperties());
}
void save(TeaVMJpsConfiguration config) {
for (Field<?> field : fields) {
saveField(field, config);
}
copyProperties(propertiesModel.getProperties(), config.getProperties());
updateInitialConfiguration(config);
}
boolean isModified() {
return fields.stream().anyMatch(this::isFieldModified);
return fields.stream().anyMatch(this::isFieldModified) || arePropertiesModified();
}
private <T> boolean isFieldModified(Field<T> field) {
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) {
for (Field<?> field : fields) {
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) {
@ -232,4 +276,87 @@ class TeaVMConfigurationPanel extends JPanel {
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;
}
}
}