From 68aade1bf9efaa77f3d140f45224f5a1551b4bd6 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Sat, 4 Jul 2015 00:03:04 +0300 Subject: [PATCH] IDEA-94341 Launch Multiple "Run/Debug Configurations" At Once --- .../compound/CompoundRunConfiguration.java | 142 ++++++++++++++++++ ...ompoundRunConfigurationSettingsEditor.java | 111 ++++++++++++++ .../CompoundRunConfigurationType.java | 51 +++++++ .../UnknownRunConfiguration.java | 2 +- .../WithoutOwnBeforeRunSteps.java | 22 +++ .../WrappingRunConfiguration.java | 2 +- .../ConfigurationSettingsEditorWrapper.java | 4 +- .../RunConfigurationBeforeRunProvider.java | 15 +- .../execution/impl/RunManagerImpl.java | 11 ++ .../src/com/intellij/ui/CheckBoxList.java | 6 +- resources/src/META-INF/IdeaPlugin.xml | 1 + 11 files changed, 348 insertions(+), 19 deletions(-) create mode 100644 java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfiguration.java create mode 100644 java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java create mode 100644 java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationType.java create mode 100644 platform/lang-api/src/com/intellij/execution/configurations/WithoutOwnBeforeRunSteps.java diff --git a/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfiguration.java b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfiguration.java new file mode 100644 index 000000000000..c884cc60c7c2 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfiguration.java @@ -0,0 +1,142 @@ +/* + * Copyright 2000-2015 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.execution.compound; + +import com.intellij.execution.*; +import com.intellij.execution.configurations.*; +import com.intellij.execution.impl.RunManagerImpl; +import com.intellij.execution.impl.RunnerAndConfigurationSettingsImpl; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.runners.ExecutionEnvironmentBuilder; +import com.intellij.execution.runners.ProgramRunner; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.WriteExternalException; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class CompoundRunConfiguration extends RunConfigurationBase implements WithoutOwnBeforeRunSteps { + static final Comparator COMPARATOR = new Comparator() { + @Override + public int compare(RunConfiguration o1, RunConfiguration o2) { + int i = o1.getType().getDisplayName().compareTo(o2.getType().getDisplayName()); + return (i != 0) ? i : o1.getName().compareTo(o2.getName()); + } + }; + private final Set> myPairs = new HashSet>(); + private final Set mySetToRun = new TreeSet(COMPARATOR); + private boolean myInitialized = false; + + public CompoundRunConfiguration(Project project, @NotNull CompoundRunConfigurationType type, String name) { + super(project, type.getConfigurationFactories()[0], name); + } + + public Set getSetToRun() { + initIfNeed(); + return mySetToRun; + } + + private void initIfNeed() { + if (myInitialized) return; + mySetToRun.clear(); + RunManagerImpl manager = RunManagerImpl.getInstanceImpl(getProject()); + for (Pair pair : myPairs) { + RunnerAndConfigurationSettings settings = manager.findConfigurationByTypeAndName(pair.first, pair.second); + if (settings != null) { + mySetToRun.add(settings.getConfiguration()); + } + } + myInitialized = true; + } + + @NotNull + @Override + public SettingsEditor getConfigurationEditor() { + return new CompoundRunConfigurationSettingsEditor(getProject()); + } + + @Override + public void checkConfiguration() throws RuntimeConfigurationException { + if (getSetToRun().isEmpty()) throw new RuntimeConfigurationException("There is nothing to run"); + for (RunConfiguration configuration : getSetToRun()) { + configuration.checkConfiguration(); + } + } + + @Nullable + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull final ExecutionEnvironment environment) throws ExecutionException { + try { + checkConfiguration(); + } + catch (RuntimeConfigurationException e) { + throw new ExecutionException(e.getMessage()); + } + return new RunProfileState() { + @Nullable + @Override + public ExecutionResult execute(final Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + RunManagerImpl manager = RunManagerImpl.getInstanceImpl(getProject()); + for (RunConfiguration configuration : getSetToRun()) { + RunnerAndConfigurationSettings settings = new RunnerAndConfigurationSettingsImpl(manager, configuration, false); + ExecutionEnvironmentBuilder builder = ExecutionEnvironmentBuilder.createOrNull(executor, settings); + if (builder != null) { + ExecutionManager.getInstance(getProject()) + .restartRunProfile(builder.activeTarget().dataContext(null).build()); + } + } + } + }); + return null; + } + }; + } + + @Override + public void readExternal(Element element) throws InvalidDataException { + super.readExternal(element); + myPairs.clear(); + List children = element.getChildren("toRun"); + for (Element child : children) { + String type = child.getAttributeValue("type"); + String name = child.getAttributeValue("name"); + if (type != null && name != null) { + myPairs.add(Pair.create(type, name)); + } + } + } + + @Override + public void writeExternal(Element element) throws WriteExternalException { + super.writeExternal(element); + initIfNeed(); + for (RunConfiguration configuration : getSetToRun()) { + Element child = new Element("toRun"); + child.setAttribute("type", configuration.getType().getId()); + child.setAttribute("name", configuration.getName()); + element.addContent(child); + } + } +} diff --git a/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java new file mode 100644 index 000000000000..92b13c53d24b --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationSettingsEditor.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2015 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.execution.compound; + +import com.intellij.execution.BeforeRunTask; +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.execution.impl.RunConfigurationBeforeRunProvider; +import com.intellij.execution.impl.RunManagerImpl; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.intellij.ui.CheckBoxList; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.*; + +public class CompoundRunConfigurationSettingsEditor extends SettingsEditor{ + @NotNull private final Project myProject; + private final CheckBoxList myList; + private List myChecked = new ArrayList(); + private final RunManagerImpl myRunManager; + + + public CompoundRunConfigurationSettingsEditor(@NotNull Project project) { + myProject = project; + myRunManager = RunManagerImpl.getInstanceImpl(myProject); + myList = new CheckBoxList() { + @Override + protected void adjustRendering(JCheckBox checkBox, int index, boolean selected, boolean hasFocus) { + RunConfiguration configuration = getItemAt(index); + assert configuration != null; + checkBox.setText(configuration.getType().getDisplayName() + " '"+configuration.getName()+"'"); + } + }; + myList.setVisibleRowCount(100); + } + + private void updateModel(@NotNull CompoundRunConfiguration s) { + List list = myRunManager.getAllConfigurationsList(); + Collections.sort(list, CompoundRunConfiguration.COMPARATOR); + for (RunConfiguration configuration : list) { + if (canBeAdded(configuration, s)) { + myList.addItem(configuration, configuration.getName(), myChecked.contains(configuration)); + } + } + } + + private boolean canBeAdded(@NotNull RunConfiguration candidate, @NotNull final CompoundRunConfiguration root) { + if (candidate == root) return false; + List tasks = myRunManager.getBeforeRunTasks(candidate); + for (BeforeRunTask task : tasks) { + if (task instanceof RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask) { + RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask runTask + = (RunConfigurationBeforeRunProvider.RunConfigurableBeforeRunTask)task; + RunnerAndConfigurationSettings settings = runTask.getSettings(); + if (settings != null) { + if (!canBeAdded(settings.getConfiguration(), root)) return false; + } + } + } + if (candidate instanceof CompoundRunConfiguration) { + Set set = ((CompoundRunConfiguration)candidate).getSetToRun(); + for (RunConfiguration configuration : set) { + if (!canBeAdded(configuration, root)) return false; + } + } + return true; + } + + @Override + protected void resetEditorFrom(CompoundRunConfiguration s) { + myChecked.clear(); + myChecked.addAll(s.getSetToRun()); + updateModel(s); + } + + @Override + protected void applyEditorTo(CompoundRunConfiguration s) throws ConfigurationException { + Set checked = new HashSet(); + for (int i = 0; i < myList.getItemsCount(); i++) { + RunConfiguration configuration = myList.getItemAt(i); + if (myList.isItemSelected(configuration)) { + checked.add(configuration); + } + } + Set toRun = s.getSetToRun(); + toRun.clear(); + toRun.addAll(checked); + } + + @NotNull + @Override + protected JComponent createEditor() { + return myList;//new JBScrollPane(myList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + } +} diff --git a/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationType.java b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationType.java new file mode 100644 index 000000000000..250b50545726 --- /dev/null +++ b/java/execution/impl/src/com/intellij/execution/compound/CompoundRunConfigurationType.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2015 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.execution.compound; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationTypeBase; +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import com.intellij.ui.LayeredIcon; + +public class CompoundRunConfigurationType extends ConfigurationTypeBase { + + public static CompoundRunConfigurationType getInstance() { + return ConfigurationTypeUtil.findConfigurationType(CompoundRunConfigurationType.class); + } + + public CompoundRunConfigurationType() { + super("CompoundRunConfigurationType", + "Compound Run Configuration", + "It runs batch of run configurations at once", + LayeredIcon.create(AllIcons.Nodes.Folder, AllIcons.Nodes.RunnableMark)); + addFactory(new ConfigurationFactory(this) { + @Override + public RunConfiguration createTemplateConfiguration(Project project) { + return new CompoundRunConfiguration(project, CompoundRunConfigurationType.this, "Compound Run Configuration"); + } + + @Override + public String getName() { + return super.getName(); + } + }); + } + + +} diff --git a/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java index 926c284e205b..b1face870522 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/UnknownRunConfiguration.java @@ -37,7 +37,7 @@ import java.util.concurrent.atomic.AtomicInteger; /** * @author spleaner */ -public class UnknownRunConfiguration implements RunConfiguration { +public class UnknownRunConfiguration implements RunConfiguration, WithoutOwnBeforeRunSteps { private final ConfigurationFactory myFactory; private Element myStoredElement; private String myName; diff --git a/platform/lang-api/src/com/intellij/execution/configurations/WithoutOwnBeforeRunSteps.java b/platform/lang-api/src/com/intellij/execution/configurations/WithoutOwnBeforeRunSteps.java new file mode 100644 index 000000000000..db60bed5a533 --- /dev/null +++ b/platform/lang-api/src/com/intellij/execution/configurations/WithoutOwnBeforeRunSteps.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2015 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.execution.configurations; + +/** + * Marker interface to NOT show "Before launch" section in Run/Debug Configuration editor + */ +public interface WithoutOwnBeforeRunSteps { +} diff --git a/platform/lang-api/src/com/intellij/execution/configurations/WrappingRunConfiguration.java b/platform/lang-api/src/com/intellij/execution/configurations/WrappingRunConfiguration.java index 35cbd35bad58..c5df2d2c010f 100644 --- a/platform/lang-api/src/com/intellij/execution/configurations/WrappingRunConfiguration.java +++ b/platform/lang-api/src/com/intellij/execution/configurations/WrappingRunConfiguration.java @@ -18,6 +18,6 @@ package com.intellij.execution.configurations; /** * Allow to get before/after steps from wrapped configuration: e.g. to rerun tests with initial tests before options */ -public interface WrappingRunConfiguration { +public interface WrappingRunConfiguration extends WithoutOwnBeforeRunSteps { T getPeer(); } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java index 568e8d20ea16..5d9da6121ca6 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConfigurationSettingsEditorWrapper.java @@ -18,7 +18,7 @@ package com.intellij.execution.impl; import com.intellij.execution.BeforeRunTask; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.configurations.RunConfiguration; -import com.intellij.execution.configurations.UnknownRunConfiguration; +import com.intellij.execution.configurations.WithoutOwnBeforeRunSteps; import com.intellij.execution.runners.ProgramRunner; import com.intellij.ide.DataManager; import com.intellij.ide.util.PropertiesComponent; @@ -92,7 +92,7 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor List getBeforeRunTasks(RunConfiguration settings, Key taskProviderID) { diff --git a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java index 783dd5fcb95d..2df4a3d6f812 100644 --- a/platform/platform-api/src/com/intellij/ui/CheckBoxList.java +++ b/platform/platform-api/src/com/intellij/ui/CheckBoxList.java @@ -127,7 +127,7 @@ public class CheckBoxList extends JBList { } public boolean isItemSelected(int index) { - return ((JCheckBox)getModel().getElementAt(index)).isSelected(); + return ((JCheckBox)getModel().getElementAt(index)).isSelected(); } public boolean isItemSelected(T item) { @@ -163,7 +163,7 @@ public class CheckBoxList extends JBList { this.checkBoxListListener = checkBoxListListener; } - protected void adjustRendering(final JCheckBox checkBox, final boolean selected, final boolean hasFocus) { + protected void adjustRendering(final JCheckBox checkBox, int index, final boolean selected, final boolean hasFocus) { } private class CellRenderer implements ListCellRenderer { @@ -224,7 +224,7 @@ public class CheckBoxList extends JBList { rootComponent.setBorder(isSelected ? mySelectedBorder : myBorder); - adjustRendering(checkbox, isSelected, cellHasFocus); + adjustRendering(checkbox, index, isSelected, cellHasFocus); return rootComponent; } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index ddf7a5d0259b..08e620a08f90 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1291,6 +1291,7 @@ +