diff --git a/plugins/ant/jps-plugin/src/com/intellij/lang/ant/config/impl/BuildFileProperty.java b/plugins/ant/jps-plugin/src/com/intellij/lang/ant/config/impl/BuildFileProperty.java index 6632212e7223..453bd1ae48d9 100644 --- a/plugins/ant/jps-plugin/src/com/intellij/lang/ant/config/impl/BuildFileProperty.java +++ b/plugins/ant/jps-plugin/src/com/intellij/lang/ant/config/impl/BuildFileProperty.java @@ -23,7 +23,7 @@ import org.jdom.Element; import org.jetbrains.annotations.NonNls; @Tag("build-property") -public final class BuildFileProperty implements JDOMExternalizable { +public final class BuildFileProperty implements JDOMExternalizable, Cloneable { @NonNls private static final String NAME = "name"; @NonNls private static final String VALUE = "value"; private String myPropertyName; @@ -80,4 +80,14 @@ public final class BuildFileProperty implements JDOMExternalizable { return 31 * (myPropertyName != null ? myPropertyName.hashCode() : 0) + (myPropertyValue != null ? myPropertyValue.hashCode() : 0); } + + @Override + public BuildFileProperty clone() { + try { + return (BuildFileProperty)super.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/actions/RunAction.java b/plugins/ant/src/com/intellij/lang/ant/config/actions/RunAction.java index 6332cab27a32..3f4c903c5a0e 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/actions/RunAction.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/actions/RunAction.java @@ -20,13 +20,10 @@ import com.intellij.lang.ant.AntBundle; import com.intellij.lang.ant.config.AntBuildListener; import com.intellij.lang.ant.config.execution.AntBuildMessageView; import com.intellij.lang.ant.config.execution.ExecutionHandler; -import com.intellij.lang.ant.config.impl.BuildFileProperty; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; -import java.util.Collections; - public final class RunAction extends AnAction { private final AntBuildMessageView myAntBuildMessageView; @@ -40,7 +37,7 @@ public final class RunAction extends AnAction { myAntBuildMessageView.getBuildFile(), myAntBuildMessageView.getTargets(), myAntBuildMessageView, - e.getDataContext(), Collections.emptyList(), AntBuildListener.NULL); + e.getDataContext(), myAntBuildMessageView.getAdditionalProperties(), AntBuildListener.NULL); } public void update(AnActionEvent event){ diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java index 82a2addbc7bf..aa31fadc47c8 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java @@ -30,6 +30,7 @@ import com.intellij.lang.ant.config.AntBuildFileBase; import com.intellij.lang.ant.config.AntBuildListener; import com.intellij.lang.ant.config.actions.*; import com.intellij.lang.ant.config.impl.AntBuildFileImpl; +import com.intellij.lang.ant.config.impl.BuildFileProperty; import com.intellij.lang.ant.config.impl.HelpID; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; @@ -65,6 +66,7 @@ import java.awt.*; import java.io.File; import java.util.ArrayList; import java.util.Collections; +import java.util.List; public final class AntBuildMessageView extends JPanel implements DataProvider, OccurenceNavigator { private static final Logger LOG = Logger.getInstance("#com.intellij.ant.execution.AntBuildMessageView"); @@ -92,6 +94,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private final CardLayout myCardLayout; private AntBuildFileBase myBuildFile; private final String[] myTargets; + private final List myAdditionalProperties; private int myPriorityThreshold = PRIORITY_BRIEF; private volatile int myErrorCount; private volatile int myWarningCount; @@ -143,11 +146,12 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O }; @NonNls public static final String FILE_PREFIX = "file:"; - private AntBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets) { + private AntBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets, List additionalProperties) { super(new BorderLayout(2, 0)); myProject = project; myBuildFile = buildFile; myTargets = targets; + myAdditionalProperties = additionalProperties; setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); myPlainTextView = new PlainTextView(project); @@ -235,7 +239,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O * @return can be null if user cancelled operation */ @Nullable - public static AntBuildMessageView openBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets) { + public static AntBuildMessageView openBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets, List additionalProperties) { final VirtualFile antFile = buildFile.getVirtualFile(); if (!LOG.assertTrue(antFile != null)) { return null; @@ -278,7 +282,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O } } - final AntBuildMessageView messageView = new AntBuildMessageView(project, buildFile, targets); + final AntBuildMessageView messageView = new AntBuildMessageView(project, buildFile, targets, additionalProperties); String contentName = buildFile.getPresentableName(); contentName = BUILD_CONTENT_NAME + " (" + contentName + ")"; @@ -767,6 +771,10 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O return myTargets; } + public List getAdditionalProperties() { + return myAdditionalProperties; + } + private int getErrorCount() { return myErrorCount; } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java index d4b6cc8e47a8..d73df2977ad7 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java @@ -19,107 +19,63 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.util.ListTableWithButtons; import com.intellij.lang.ant.config.AntBuildTarget; import com.intellij.lang.ant.config.AntConfiguration; +import com.intellij.lang.ant.config.impl.BuildFileProperty; import com.intellij.lang.ant.config.impl.GlobalAntConfiguration; import com.intellij.lang.ant.config.impl.TargetChooserDialog; import com.intellij.openapi.module.Module; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.ColumnInfo; +import com.intellij.util.ui.ListTableModel; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class AntRunConfiguration extends LocatableConfigurationBase implements RunProfileWithCompileBeforeLaunchOption{ private AntSettings mySettings = new AntSettings(); - public AntRunConfiguration(Project project, - ConfigurationFactory factory, - String name) { + public AntRunConfiguration(Project project, ConfigurationFactory factory, String name) { super(project, factory, name); } @Override public RunConfiguration clone() { - AntRunConfiguration configuration = (AntRunConfiguration)super.clone(); - configuration.mySettings = mySettings.clone(); + final AntRunConfiguration configuration = (AntRunConfiguration)super.clone(); + configuration.mySettings = mySettings.copy(); return configuration; } @NotNull @Override public Module[] getModules() { - return new Module[0]; + return Module.EMPTY_ARRAY; } @NotNull @Override public SettingsEditor getConfigurationEditor() { - return new SettingsEditor() { - private String myFileUrl = null; - private String myTargetName = null; - private final JTextField myTextField = new JTextField(); - private ActionListener myActionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - AntBuildTarget buildTarget = getTarget(); - final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget); - if (dlg.showAndGet()) { - myFileUrl = null; - myTargetName = null; - buildTarget = dlg.getSelectedTarget(); - if (buildTarget != null) { - final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile(); - if (vFile != null) { - myFileUrl = vFile.getUrl(); - myTargetName = buildTarget.getName(); - } - } - updateTextField(); - } - } - }; - - private void updateTextField() { - myTextField.setText(""); - if (myFileUrl != null && myTargetName != null) { - myTextField.setText(myTargetName); - } - fireEditorStateChanged(); - } - - @Override - protected void resetEditorFrom(RunConfiguration s) { - AntRunConfiguration configuration = (AntRunConfiguration)s; - myFileUrl = configuration.mySettings.myFileUrl; - myTargetName = configuration.mySettings.myTargetName; - updateTextField(); - } - - @Override - protected void applyEditorTo(RunConfiguration s) throws ConfigurationException { - AntRunConfiguration configuration = (AntRunConfiguration)s; - configuration.mySettings.myFileUrl = myFileUrl; - configuration.mySettings.myTargetName = myTargetName; - } - - @NotNull - @Override - protected JComponent createEditor() { - myTextField.setEditable(false); - return new TextFieldWithBrowseButton(myTextField, myActionListener); - } - }; + return new AntConfigurationSettingsEditor(); } @Override @@ -156,24 +112,34 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R mySettings.writeExternal(element); } + @Nullable public AntBuildTarget getTarget() { return GlobalAntConfiguration.getInstance().findTarget(getProject(), mySettings.myFileUrl, mySettings.myTargetName); } + @NotNull + public List getProperties() { + return Collections.unmodifiableList(mySettings.myProperties); + } + public boolean acceptSettings(AntBuildTarget target) { VirtualFile virtualFile = target.getModel().getBuildFile().getVirtualFile(); - if (virtualFile == null) return false; + if (virtualFile == null) { + return false; + } mySettings.myFileUrl = virtualFile.getUrl(); mySettings.myTargetName = target.getName(); return true; } - public static class AntSettings implements Cloneable, JDOMExternalizable { + public static class AntSettings implements JDOMExternalizable { private static final String SETTINGS = "antsettings"; + private static final String PROPERTY = "property"; private static final String FILE = "antfile"; private static final String TARGET = "target"; private String myFileUrl = null; private String myTargetName = null; + private final List myProperties = new ArrayList<>(); public AntSettings() { } @@ -188,9 +154,10 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R return myTargetName + "@" + myFileUrl; } - @Override - protected AntSettings clone() { - return new AntSettings(myFileUrl, myTargetName); + public AntSettings copy() { + final AntSettings copy = new AntSettings(myFileUrl, myTargetName); + copyProperties(myProperties, copy.myProperties); + return copy; } @Override @@ -199,17 +166,181 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R if (element != null) { myFileUrl = element.getAttributeValue(FILE); myTargetName = element.getAttributeValue(TARGET); + myProperties.clear(); + for (Element pe : element.getChildren(PROPERTY)) { + BuildFileProperty prop = new BuildFileProperty(); + prop.readExternal(pe); + myProperties.add(prop); + } } } @Override public void writeExternal(Element element) throws WriteExternalException { if (myFileUrl != null && myTargetName != null) { - Element child = new Element(SETTINGS); - child.setAttribute(FILE, myFileUrl); - child.setAttribute(TARGET, myTargetName); - element.addContent(child); + final Element settingsElem = new Element(SETTINGS); + settingsElem.setAttribute(FILE, myFileUrl); + settingsElem.setAttribute(TARGET, myTargetName); + for (BuildFileProperty property : myProperties) { + final Element pe = new Element(PROPERTY); + property.writeExternal(pe); + settingsElem.addContent(pe); + } + element.addContent(settingsElem); } } } + + private class AntConfigurationSettingsEditor extends SettingsEditor { + private String myFileUrl = null; + private String myTargetName = null; + + private final JTextField myTextField = new JTextField(); + private final PropertiesTable myPropTable = new PropertiesTable(); + + private ActionListener myActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + AntBuildTarget buildTarget = getTarget(); + final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget); + if (dlg.showAndGet()) { + myFileUrl = null; + myTargetName = null; + buildTarget = dlg.getSelectedTarget(); + if (buildTarget != null) { + final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile(); + if (vFile != null) { + myFileUrl = vFile.getUrl(); + myTargetName = buildTarget.getName(); + } + } + updateUI(); + } + } + }; + + private void updateUI() { + myTextField.setText(""); + if (myFileUrl != null && myTargetName != null) { + myTextField.setText(myTargetName); + } + myPropTable.refreshValues(); + fireEditorStateChanged(); + } + + @Override + protected void resetEditorFrom(RunConfiguration s) { + final AntRunConfiguration config = (AntRunConfiguration)s; + myFileUrl = config.mySettings.myFileUrl; + myTargetName = config.mySettings.myTargetName; + myPropTable.setValues(config.mySettings.myProperties); + updateUI(); + } + + @Override + protected void applyEditorTo(RunConfiguration s) throws ConfigurationException { + final AntRunConfiguration config = (AntRunConfiguration)s; + config.mySettings.myFileUrl = myFileUrl; + config.mySettings.myTargetName = myTargetName; + copyProperties(ContainerUtil.filter(myPropTable.getElements(), new Condition() { + @Override + public boolean value(BuildFileProperty property) { + return !myPropTable.isEmpty(property); + } + }), config.mySettings.myProperties); + } + + @NotNull + @Override + protected JComponent createEditor() { + myTextField.setEditable(false); + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(LabeledComponent.create(new TextFieldWithBrowseButton(myTextField, myActionListener), "Target name", BorderLayout.WEST), BorderLayout.NORTH); + + final LabeledComponent tableComponent = LabeledComponent.create(myPropTable.getComponent(), "Ant Properties"); + tableComponent.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); + panel.add(tableComponent, BorderLayout.CENTER); + return panel; + } + } + + private static class PropertiesTable extends ListTableWithButtons { + @Override + protected ListTableModel createListModel() { + final ColumnInfo nameColumn = new TableColumn("Name") { + @Nullable + @Override + public String valueOf(BuildFileProperty property) { + return property.getPropertyName(); + } + + @Override + public void setValue(BuildFileProperty property, String value) { + property.setPropertyName(value); + } + }; + final ColumnInfo valueColumn = new TableColumn("Value") { + @Nullable + @Override + public String valueOf(BuildFileProperty property) { + return property.getPropertyValue(); + } + + @Override + public void setValue(BuildFileProperty property, String value) { + property.setPropertyValue(value); + } + }; + return new ListTableModel(nameColumn, valueColumn); + } + + @Override + protected BuildFileProperty createElement() { + return new BuildFileProperty(); + } + + @Override + protected boolean isEmpty(BuildFileProperty element) { + return StringUtil.isEmpty(element.getPropertyName()) && StringUtil.isEmpty(element.getPropertyValue()); + } + + @Override + protected BuildFileProperty cloneElement(BuildFileProperty p) { + return p.clone(); + } + + @Override + protected boolean canDeleteElement(BuildFileProperty selection) { + return true; + } + + @Override + public List getElements() { + return super.getElements(); + } + + private abstract static class TableColumn extends ElementsColumnInfoBase { + public TableColumn(final String name) { + super(name); + } + + @Override + public boolean isCellEditable(BuildFileProperty property) { + return true; + } + + @Nullable + @Override + protected String getDescription(BuildFileProperty element) { + return null; + } + } + } + + private static void copyProperties(final Iterable from, final List to) { + to.clear(); + for (BuildFileProperty p : from) { + to.add(p.clone()); + } + } } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunProfileState.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunProfileState.java index ac12015fd93d..4e049b5169fe 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunProfileState.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunProfileState.java @@ -25,13 +25,9 @@ import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; import com.intellij.lang.ant.config.AntBuildListener; -import com.intellij.lang.ant.config.AntBuildTarget; -import com.intellij.lang.ant.config.impl.BuildFileProperty; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; - public class AntRunProfileState implements RunProfileState { private final ExecutionEnvironment myEnvironment; @@ -42,20 +38,16 @@ public class AntRunProfileState implements RunProfileState { @Nullable @Override public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { - RunProfile profile = myEnvironment.getRunProfile(); + final RunProfile profile = myEnvironment.getRunProfile(); if (profile instanceof AntRunConfiguration) { - AntRunConfiguration antRunConfiguration = (AntRunConfiguration)profile; - AntBuildTarget target = antRunConfiguration.getTarget(); - if (target == null) return null; - ProcessHandler processHandler = ExecutionHandler - .executeRunConfiguration(antRunConfiguration, myEnvironment.getDataContext(), new ArrayList(), - new AntBuildListener() { - @Override - public void buildFinished(int state, int errorCount) { - - } - }); - if (processHandler == null) return null; + final AntRunConfiguration runConfig = (AntRunConfiguration)profile; + if (runConfig.getTarget() == null) { + return null; + } + final ProcessHandler processHandler = ExecutionHandler.executeRunConfiguration(runConfig, myEnvironment.getDataContext(), runConfig.getProperties(), AntBuildListener.NULL); + if (processHandler == null) { + return null; + } return new DefaultExecutionResult(null, processHandler); } return null; diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/ExecutionHandler.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/ExecutionHandler.java index e5be4e2705c2..b72f284b4523 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/ExecutionHandler.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/ExecutionHandler.java @@ -122,7 +122,7 @@ public final class ExecutionHandler { builder.getCommandLine().setCharset(EncodingProjectManager.getInstance(buildFile.getProject()).getDefaultCharset()); - messageView = prepareMessageView(buildMessageViewToReuse, buildFile, targets); + messageView = prepareMessageView(buildMessageViewToReuse, buildFile, targets, additionalProperties); commandLine = CommandLineBuilder.createFromJavaParameters(builder.getCommandLine()); messageView.setBuildCommandLine(commandLine.getCommandLineString()); } @@ -300,14 +300,14 @@ public final class ExecutionHandler { private static AntBuildMessageView prepareMessageView(@Nullable AntBuildMessageView buildMessageViewToReuse, AntBuildFileBase buildFile, - String[] targets) throws RunCanceledException { + String[] targets, List additionalProperties) throws RunCanceledException { AntBuildMessageView messageView; if (buildMessageViewToReuse != null) { messageView = buildMessageViewToReuse; messageView.emptyAll(); } else { - messageView = AntBuildMessageView.openBuildMessageView(buildFile.getProject(), buildFile, targets); + messageView = AntBuildMessageView.openBuildMessageView(buildFile.getProject(), buildFile, targets, additionalProperties); if (messageView == null) { throw new RunCanceledException(AntBundle.message("canceled.by.user.error.message")); }