1 package com
.intellij
.execution
.actions
;
3 import com
.intellij
.execution
.*;
4 import com
.intellij
.execution
.configurations
.ConfigurationType
;
5 import com
.intellij
.execution
.executors
.DefaultRunExecutor
;
6 import com
.intellij
.execution
.impl
.EditConfigurationsDialog
;
7 import com
.intellij
.execution
.impl
.RunDialog
;
8 import com
.intellij
.execution
.impl
.RunnerAndConfigurationSettingsImpl
;
9 import com
.intellij
.execution
.junit
.RuntimeConfigurationProducer
;
10 import com
.intellij
.execution
.runners
.ProgramRunner
;
11 import com
.intellij
.ide
.DataManager
;
12 import com
.intellij
.ide
.util
.PropertiesComponent
;
13 import com
.intellij
.openapi
.actionSystem
.*;
14 import com
.intellij
.openapi
.keymap
.KeymapUtil
;
15 import com
.intellij
.openapi
.project
.Project
;
16 import com
.intellij
.openapi
.ui
.popup
.JBPopupFactory
;
17 import com
.intellij
.openapi
.ui
.popup
.ListPopup
;
18 import com
.intellij
.openapi
.ui
.popup
.ListSeparator
;
19 import com
.intellij
.openapi
.ui
.popup
.PopupStep
;
20 import com
.intellij
.openapi
.ui
.popup
.util
.BaseListPopupStep
;
21 import com
.intellij
.openapi
.util
.IconLoader
;
22 import com
.intellij
.openapi
.wm
.ToolWindowId
;
23 import com
.intellij
.ui
.LayeredIcon
;
24 import com
.intellij
.ui
.popup
.AbstractPopup
;
25 import com
.intellij
.ui
.popup
.list
.ListPopupImpl
;
26 import org
.jetbrains
.annotations
.NotNull
;
27 import org
.jetbrains
.annotations
.Nullable
;
30 import java
.awt
.event
.ActionEvent
;
31 import java
.util
.ArrayList
;
32 import java
.util
.Collections
;
33 import java
.util
.Comparator
;
34 import java
.util
.List
;
39 public class ChooseRunConfigurationAction
extends AnAction
{
40 private static final Icon EDIT_ICON
= IconLoader
.getIcon("/actions/editSource.png");
41 private static final Icon SAVE_ICON
= IconLoader
.getIcon("/runConfigurations/saveTempConfig.png");
43 private static final Icon _00_ICON
= IconLoader
.getIcon("/ide/numbers/00.png");
44 private static final Icon _01_ICON
= IconLoader
.getIcon("/ide/numbers/01.png");
45 private static final Icon _02_ICON
= IconLoader
.getIcon("/ide/numbers/02.png");
46 private static final Icon _03_ICON
= IconLoader
.getIcon("/ide/numbers/03.png");
48 private Executor myCurrentExecutor
;
49 private boolean myEditConfiguration
;
50 private boolean myDeleteConfiguration
;
53 public void actionPerformed(AnActionEvent e
) {
54 final Project project
= e
.getData(PlatformDataKeys
.PROJECT
);
55 assert project
!= null;
57 final Executor executor
= getDefaultExecutor();
58 assert executor
!= null;
60 final ListPopup popup
= JBPopupFactory
.getInstance()
61 .createListPopup(new ConfigurationListPopupStep(this, project
, String
.format("%s", executor
.getActionName())));
63 if (popup
instanceof ListPopupImpl
) {
64 registerActions((ListPopupImpl
)popup
);
67 final String adText
= getAdText(getAlternateExecutor());
69 ((AbstractPopup
)popup
).setAdText(adText
);
72 popup
.showCenteredInCurrentWindow(project
);
75 protected String
getAdKey() {
76 return "run.configuration.alternate.action.ad";
80 protected String
getAdText(final Executor alternateExecutor
) {
81 if (alternateExecutor
!= null && !PropertiesComponent
.getInstance().isTrueValue(getAdKey())) {
83 .format("Hold %s to %s", KeymapUtil
.getKeystrokeText(KeyStroke
.getKeyStroke("SHIFT")), alternateExecutor
.getActionName());
86 if (!PropertiesComponent
.getInstance().isTrueValue("run.configuration.edit.ad")) {
87 return String
.format("Press %s to Edit", KeymapUtil
.getKeystrokeText(KeyStroke
.getKeyStroke("F4")));
93 private static Icon
getNumberIcon(final Icon base
, final int number
) {
96 return LayeredIcon
.create(base
, _00_ICON
);
98 return LayeredIcon
.create(base
, _01_ICON
);
100 return LayeredIcon
.create(base
, _02_ICON
);
102 return LayeredIcon
.create(base
, _03_ICON
);
108 private void registerActions(final ListPopupImpl popup
) {
109 popup
.registerAction("alternateExecutor", KeyStroke
.getKeyStroke("shift pressed SHIFT"), new AbstractAction() {
110 public void actionPerformed(ActionEvent e
) {
111 myCurrentExecutor
= getAlternateExecutor();
112 updatePresentation(popup
);
116 popup
.registerAction("restoreDefaultExecutor", KeyStroke
.getKeyStroke("released SHIFT"), new AbstractAction() {
117 public void actionPerformed(ActionEvent e
) {
118 myCurrentExecutor
= getDefaultExecutor();
119 updatePresentation(popup
);
124 popup
.registerAction("invokeAction", KeyStroke
.getKeyStroke("shift ENTER"), new AbstractAction() {
125 public void actionPerformed(ActionEvent e
) {
126 popup
.handleSelect(true);
130 popup
.registerAction("editConfiguration", KeyStroke
.getKeyStroke("F4"), new AbstractAction() {
131 public void actionPerformed(ActionEvent e
) {
132 myEditConfiguration
= true;
134 popup
.handleSelect(true);
137 myEditConfiguration
= false;
143 popup
.registerAction("deleteConfiguration", KeyStroke
.getKeyStroke("DELETE"), new AbstractAction() {
144 public void actionPerformed(ActionEvent e
) {
145 myDeleteConfiguration
= true;
147 popup
.handleSelect(true);
150 myDeleteConfiguration
= false;
155 popup
.registerAction("0Action", KeyStroke
.getKeyStroke("0"), createNumberAction(0, popup
, getDefaultExecutor()));
156 popup
.registerAction("0Action_", KeyStroke
.getKeyStroke("shift pressed 0"), createNumberAction(0, popup
, getAlternateExecutor()));
157 popup
.registerAction("1Action", KeyStroke
.getKeyStroke("1"), createNumberAction(1, popup
, getDefaultExecutor()));
158 popup
.registerAction("1Action_", KeyStroke
.getKeyStroke("shift pressed 1"), createNumberAction(1, popup
, getAlternateExecutor()));
159 popup
.registerAction("2Action", KeyStroke
.getKeyStroke("2"), createNumberAction(2, popup
, getDefaultExecutor()));
160 popup
.registerAction("2Action_", KeyStroke
.getKeyStroke("shift pressed 2"), createNumberAction(2, popup
, getAlternateExecutor()));
161 popup
.registerAction("3Action", KeyStroke
.getKeyStroke("3"), createNumberAction(3, popup
, getDefaultExecutor()));
162 popup
.registerAction("3Action_", KeyStroke
.getKeyStroke("shift pressed 3"), createNumberAction(3, popup
, getAlternateExecutor()));
165 private void updatePresentation(ListPopupImpl listPopup
) {
166 final Executor executor
= getCurrentExecutor();
167 if (executor
!= null) {
168 listPopup
.setCaption(executor
.getActionName());
172 static void execute(final ItemWrapper itemWrapper
, final Executor executor
) {
173 if (executor
== null) {
177 final DataContext dataContext
= DataManager
.getInstance().getDataContext();
178 final Project project
= PlatformDataKeys
.PROJECT
.getData(dataContext
);
179 if (project
!= null) {
180 SwingUtilities
.invokeLater(new Runnable() {
182 itemWrapper
.perform(project
, executor
, dataContext
);
188 void editConfiguration(@NotNull final Project project
, @NotNull final RunnerAndConfigurationSettingsImpl configuration
) {
189 final Executor executor
= getCurrentExecutor();
190 assert executor
!= null;
192 PropertiesComponent
.getInstance().setValue("run.configuration.edit.ad", Boolean
.toString(true));
193 if (RunDialog
.editConfiguration(project
, configuration
, "Edit configuration settings", executor
.getActionName(), executor
.getIcon())) {
194 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(configuration
);
195 ExecutionUtil
.executeConfiguration(project
, configuration
, executor
, DataManager
.getInstance().getDataContext());
199 private void deleteConfiguration(final Project project
, final RunnerAndConfigurationSettingsImpl configurationSettings
) {
204 protected Executor
getDefaultExecutor() {
205 return DefaultRunExecutor
.getRunExecutorInstance();
209 protected Executor
getAlternateExecutor() {
210 return ExecutorRegistry
.getInstance().getExecutorById(ToolWindowId
.DEBUG
);
214 protected Executor
getCurrentExecutor() {
215 return myCurrentExecutor
== null ?
getDefaultExecutor() : myCurrentExecutor
;
219 public void update(AnActionEvent e
) {
220 final Presentation presentation
= e
.getPresentation();
221 final Project project
= e
.getData(PlatformDataKeys
.PROJECT
);
223 presentation
.setEnabled(true);
224 if (project
== null || project
.isDisposed()) {
225 presentation
.setEnabled(false);
226 presentation
.setVisible(false);
230 if (null == getDefaultExecutor()) {
231 presentation
.setEnabled(false);
232 presentation
.setVisible(false);
236 presentation
.setEnabled(true);
237 presentation
.setVisible(true);
240 private static Action
createNumberAction(final int number
, final ListPopupImpl listPopup
, final Executor executor
) {
241 return new AbstractAction() {
242 public void actionPerformed(ActionEvent e
) {
243 for (Object item
: listPopup
.getListStep().getValues()) {
244 if (item
instanceof ItemWrapper
&& ((ItemWrapper
)item
).getMnemonic() == number
) {
246 execute((ItemWrapper
)item
, executor
);
253 private abstract static class ItemWrapper
<T
> {
255 private boolean myDynamic
= false;
256 private int myMnemonic
= -1;
258 protected ItemWrapper(@Nullable final T value
) {
262 public int getMnemonic() {
266 public void setMnemonic(int mnemonic
) {
267 myMnemonic
= mnemonic
;
270 public T
getValue() {
274 public boolean isDynamic() {
278 public void setDynamic(final boolean b
) {
283 public boolean equals(Object o
) {
284 if (this == o
) return true;
285 if (o
== null || getClass() != o
.getClass()) return false;
287 ItemWrapper that
= (ItemWrapper
)o
;
289 if (myValue
!= null ?
!myValue
.equals(that
.myValue
) : that
.myValue
!= null) return false;
295 public int hashCode() {
296 return myValue
!= null ? myValue
.hashCode() : 0;
299 public abstract Icon
getIcon();
301 public abstract String
getText();
303 public abstract void perform(@NotNull final Project project
, @NotNull final Executor executor
, @NotNull final DataContext context
);
306 public ConfigurationType
getType() {
310 public boolean available(Executor executor
) {
314 public boolean hasActions() {
318 public PopupStep
getNextStep(Project project
, ChooseRunConfigurationAction action
) {
319 return PopupStep
.FINAL_CHOICE
;
322 public static ItemWrapper
wrap(@NotNull final Project project
,
323 @NotNull final RunnerAndConfigurationSettingsImpl settings
,
324 final boolean dynamic
) {
325 final ItemWrapper result
= wrap(project
, settings
);
326 result
.setDynamic(dynamic
);
330 public static ItemWrapper
wrap(@NotNull final Project project
, @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
331 return new ItemWrapper
<RunnerAndConfigurationSettingsImpl
>(settings
) {
333 public void perform(@NotNull Project project
, @NotNull Executor executor
, @NotNull DataContext context
) {
334 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(getValue());
335 ExecutionUtil
.executeConfiguration(project
, getValue(), executor
, DataManager
.getInstance().getDataContext());
339 public ConfigurationType
getType() {
340 return getValue().getType();
344 public Icon
getIcon() {
345 final Icon result
= ExecutionUtil
.getConfigurationIcon(project
, getValue());
346 if (getMnemonic() != -1) {
347 return getNumberIcon(result
, getMnemonic());
354 public String
getText() {
355 if (getMnemonic() != -1) {
356 return String
.format("%s", getValue().getName());
359 return getValue().getName();
363 public boolean hasActions() {
368 public boolean available(Executor executor
) {
369 return null != ExecutionUtil
.getRunner(executor
.getId(), getValue());
373 public PopupStep
getNextStep(@NotNull final Project project
, @NotNull final ChooseRunConfigurationAction action
) {
374 return new ConfigurationActionsStep(project
, action
, getValue());
381 private static final class ConfigurationListPopupStep
extends BaseListPopupStep
<ItemWrapper
> {
382 private Project myProject
;
383 private ChooseRunConfigurationAction myAction
;
384 private int myDefaultConfiguration
= -1;
386 private ConfigurationListPopupStep(@NotNull final ChooseRunConfigurationAction action
,
387 @NotNull final Project project
,
388 @NotNull final String title
) {
389 super(title
, createSettingsList(project
));
393 if (-1 == getDefaultOptionIndex()) {
394 myDefaultConfiguration
= getDynamicIndex();
398 private int getDynamicIndex() {
400 for (final ItemWrapper wrapper
: getValues()) {
401 if (wrapper
.isDynamic()) {
411 public boolean isAutoSelectionEnabled() {
415 private static ItemWrapper
[] createSettingsList(@NotNull final Project project
) {
416 final RunManagerEx manager
= RunManagerEx
.getInstanceEx(project
);
418 final List
<ItemWrapper
> result
= new ArrayList
<ItemWrapper
>();
420 final RunnerAndConfigurationSettingsImpl selectedConfiguration
= manager
.getSelectedConfiguration();
421 final RunnerAndConfigurationSettingsImpl context
= populateWithDynamicRunners(result
, project
, manager
, selectedConfiguration
);
423 final ConfigurationType
[] factories
= manager
.getConfigurationFactories();
424 for (final ConfigurationType factory
: factories
) {
425 final RunnerAndConfigurationSettingsImpl
[] configurations
= manager
.getConfigurationSettings(factory
);
426 for (final RunnerAndConfigurationSettingsImpl configuration
: configurations
) {
427 if (configuration
!= context
) { // exclude context configuration
428 final ItemWrapper wrapped
= ItemWrapper
.wrap(project
, configuration
);
429 if (configuration
== selectedConfiguration
) {
430 wrapped
.setMnemonic(1);
438 //noinspection unchecked
439 final ItemWrapper edit
= new ItemWrapper(null) {
441 public Icon
getIcon() {
442 return getNumberIcon(EDIT_ICON
, 0);
446 public String
getText() {
447 return "Edit configurations...";
451 public void perform(@NotNull Project project
, @NotNull Executor executor
, @NotNull DataContext context
) {
452 new EditConfigurationsDialog(project
).show();
459 return result
.toArray(new ItemWrapper
[result
.size()]);
463 private static RunnerAndConfigurationSettingsImpl
populateWithDynamicRunners(final List
<ItemWrapper
> result
,
464 final Project project
,
465 final RunManagerEx manager
,
466 final RunnerAndConfigurationSettingsImpl selectedConfiguration
) {
467 final DataContext dataContext
= DataManager
.getInstance().getDataContext();
468 final ConfigurationContext context
= new ConfigurationContext(dataContext
);
469 final RunnerAndConfigurationSettingsImpl existing
= context
.findExisting();
470 if (existing
!= null && existing
== selectedConfiguration
) {
474 if (existing
== null) {
475 final List
<RuntimeConfigurationProducer
> producers
= PreferedProducerFind
.findPreferedProducers(context
.getLocation(), context
);
476 if (producers
== null) return null;
478 Collections
.sort(producers
, new Comparator
<RuntimeConfigurationProducer
>() {
479 public int compare(final RuntimeConfigurationProducer p1
, final RuntimeConfigurationProducer p2
) {
480 return p1
.getConfigurationType().getDisplayName().compareTo(p2
.getConfigurationType().getDisplayName());
484 final RunnerAndConfigurationSettingsImpl
[] preferred
= {null};
486 int i
= 2; // selectedConfiguration == null ? 1 : 2;
487 for (final RuntimeConfigurationProducer producer
: producers
) {
488 final RunnerAndConfigurationSettingsImpl configuration
= producer
.getConfiguration();
489 if (configuration
!= null) {
491 if (preferred
[0] == null) {
492 preferred
[0] = configuration
;
495 //noinspection unchecked
496 final ItemWrapper wrapper
= new ItemWrapper(null) {
498 public Icon
getIcon() {
499 Icon result
= IconLoader
.getTransparentIcon(ExecutionUtil
.getConfigurationIcon(project
, configuration
), 0.3f
);
500 if (getMnemonic() != -1) {
501 result
= getNumberIcon(result
, getMnemonic());
508 public String
getText() {
509 return producers
.size() == 1
510 ? String
.format("%s", configuration
.getName())
511 : String
.format("%s (%s)", configuration
.getName(), producer
.getConfigurationType().getDisplayName());
515 public void perform(@NotNull Project project
, @NotNull Executor executor
, @NotNull DataContext context
) {
516 manager
.setTemporaryConfiguration(configuration
);
517 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(configuration
);
518 ExecutionUtil
.executeConfiguration(project
, configuration
, executor
, DataManager
.getInstance().getDataContext());
522 public PopupStep
getNextStep(@NotNull final Project project
, @NotNull final ChooseRunConfigurationAction action
) {
523 return new ConfigurationActionsStep(project
, action
, configuration
);
527 public boolean hasActions() {
532 wrapper
.setDynamic(true);
533 wrapper
.setMnemonic(i
);
542 final ItemWrapper wrapper
= ItemWrapper
.wrap(project
, existing
, true);
543 wrapper
.setMnemonic(2); // selectedConfiguration == null ? 1 : 2);
551 public ListSeparator
getSeparatorAbove(ItemWrapper value
) {
552 final List
<ItemWrapper
> configurations
= getValues();
553 final int index
= configurations
.indexOf(value
);
554 if (index
> 0 && index
<= configurations
.size() - 1) {
555 final ItemWrapper aboveConfiguration
= index
== 0 ?
null : configurations
.get(index
- 1);
557 if (aboveConfiguration
!= null && aboveConfiguration
.isDynamic() != value
.isDynamic()) {
558 return new ListSeparator();
561 final ConfigurationType currentType
= value
.getType();
562 final ConfigurationType aboveType
= aboveConfiguration
== null ?
null : aboveConfiguration
.getType();
563 if (aboveType
!= currentType
&& currentType
!= null) {
564 return new ListSeparator(); // new ListSeparator(currentType.getDisplayName());
572 public boolean isSpeedSearchEnabled() {
577 public int getDefaultOptionIndex() {
578 final RunnerAndConfigurationSettings currentConfiguration
= RunManager
.getInstance(myProject
).getSelectedConfiguration();
579 if (currentConfiguration
== null && myDefaultConfiguration
!= -1) {
580 return myDefaultConfiguration
;
583 return currentConfiguration
instanceof RunnerAndConfigurationSettingsImpl ?
getValues()
584 .indexOf(ItemWrapper
.wrap(myProject
, (RunnerAndConfigurationSettingsImpl
)currentConfiguration
)) : -1;
588 public PopupStep
onChosen(final ItemWrapper wrapper
, boolean finalChoice
) {
589 if (myAction
.myEditConfiguration
) {
590 final Object o
= wrapper
.getValue();
591 if (o
instanceof RunnerAndConfigurationSettingsImpl
) {
592 SwingUtilities
.invokeLater(new Runnable() {
594 myAction
.editConfiguration(myProject
, (RunnerAndConfigurationSettingsImpl
)o
);
602 if (myAction
.myDeleteConfiguration
) {
603 final Object o
= wrapper
.getValue();
604 if (o
instanceof RunnerAndConfigurationSettingsImpl
) {
605 SwingUtilities
.invokeLater(new Runnable() {
607 myAction
.deleteConfiguration(myProject
, (RunnerAndConfigurationSettingsImpl
)o
);
615 final Executor executor
= myAction
.getCurrentExecutor();
616 assert executor
!= null;
618 if (finalChoice
&& wrapper
.available(executor
)) {
619 SwingUtilities
.invokeLater(new Runnable() {
621 if (myAction
.getCurrentExecutor() == myAction
.getAlternateExecutor()) {
622 PropertiesComponent
.getInstance().setValue(myAction
.getAdKey(), Boolean
.toString(true));
625 wrapper
.perform(myProject
, executor
, DataManager
.getInstance().getDataContext());
632 return wrapper
.getNextStep(myProject
, myAction
);
637 public boolean hasSubstep(ItemWrapper selectedValue
) {
638 return selectedValue
.hasActions();
643 public String
getTextFor(ItemWrapper value
) {
644 return value
.getText();
648 public Icon
getIconFor(ItemWrapper value
) {
649 return value
.getIcon();
653 private static final class ConfigurationActionsStep
extends BaseListPopupStep
<ActionWrapper
> {
654 private ConfigurationActionsStep(@NotNull final Project project
,
655 ChooseRunConfigurationAction action
,
656 @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
657 super("Actions", buildActions(project
, action
, settings
));
660 private static ActionWrapper
[] buildActions(@NotNull final Project project
,
661 final ChooseRunConfigurationAction action
,
662 @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
663 final List
<ActionWrapper
> result
= new ArrayList
<ActionWrapper
>();
664 final Executor
[] executors
= ExecutorRegistry
.getInstance().getRegisteredExecutors();
665 for (final Executor executor
: executors
) {
666 final ProgramRunner runner
= RunnerRegistry
.getInstance().getRunner(executor
.getId(), settings
.getConfiguration());
667 if (runner
!= null) {
668 result
.add(new ActionWrapper(executor
.getActionName(), executor
.getIcon()) {
670 public void perform() {
671 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(settings
);
672 ExecutionUtil
.executeConfiguration(project
, settings
, executor
, DataManager
.getInstance().getDataContext());
678 result
.add(new ActionWrapper("Edit...", EDIT_ICON
) {
680 public void perform() {
681 action
.editConfiguration(project
, settings
);
685 if (RunManager
.getInstance(project
).isTemporary(settings
.getConfiguration())) {
686 result
.add(new ActionWrapper("Save temp configuration", SAVE_ICON
) {
688 public void perform() {
689 RunManager
.getInstance(project
).makeStable(settings
.getConfiguration());
694 return result
.toArray(new ActionWrapper
[result
.size()]);
698 public PopupStep
onChosen(final ActionWrapper selectedValue
, boolean finalChoice
) {
699 SwingUtilities
.invokeLater(new Runnable() {
701 selectedValue
.perform();
709 public Icon
getIconFor(ActionWrapper aValue
) {
710 return aValue
.getIcon();
715 public String
getTextFor(ActionWrapper value
) {
716 return value
.getName();
720 private abstract static class ActionWrapper
{
721 private String myName
;
724 private ActionWrapper(String name
, Icon icon
) {
729 public abstract void perform();
731 public String
getName() {
735 public Icon
getIcon() {