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
.ListPopupStep
;
17 import com
.intellij
.openapi
.ui
.popup
.ListSeparator
;
18 import com
.intellij
.openapi
.ui
.popup
.PopupStep
;
19 import com
.intellij
.openapi
.ui
.popup
.util
.BaseListPopupStep
;
20 import com
.intellij
.openapi
.util
.IconLoader
;
21 import com
.intellij
.openapi
.wm
.ToolWindowId
;
22 import com
.intellij
.ui
.popup
.list
.ListPopupImpl
;
23 import com
.intellij
.ui
.popup
.list
.PopupListElementRenderer
;
24 import org
.jetbrains
.annotations
.NotNull
;
25 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.awt
.event
.ActionEvent
;
30 import java
.util
.ArrayList
;
31 import java
.util
.Collections
;
32 import java
.util
.Comparator
;
33 import java
.util
.List
;
38 public class ChooseRunConfigurationAction
extends AnAction
{
39 private static final Icon EDIT_ICON
= IconLoader
.getIcon("/actions/editSource.png");
40 private static final Icon SAVE_ICON
= IconLoader
.getIcon("/runConfigurations/saveTempConfig.png");
42 private Executor myCurrentExecutor
;
43 private boolean myEditConfiguration
;
44 private boolean myDeleteConfiguration
;
47 public void actionPerformed(AnActionEvent e
) {
48 final Project project
= e
.getData(PlatformDataKeys
.PROJECT
);
49 assert project
!= null;
51 final Executor executor
= getDefaultExecutor();
52 assert executor
!= null;
54 final ListPopupImpl popup
= new ListPopupImpl(new ConfigurationListPopupStep(this, project
, String
.format("%s", executor
.getActionName()))) {
56 protected ListCellRenderer
getListElementRenderer() {
57 return new RunListElementRenderer(this);
61 registerActions(popup
);
63 final String adText
= getAdText(getAlternateExecutor());
65 popup
.setAdText(adText
);
68 popup
.showCenteredInCurrentWindow(project
);
71 protected String
getAdKey() {
72 return "run.configuration.alternate.action.ad";
76 protected String
getAdText(final Executor alternateExecutor
) {
77 if (alternateExecutor
!= null && !PropertiesComponent
.getInstance().isTrueValue(getAdKey())) {
79 .format("Hold %s to %s", KeymapUtil
.getKeystrokeText(KeyStroke
.getKeyStroke("SHIFT")), alternateExecutor
.getActionName());
82 if (!PropertiesComponent
.getInstance().isTrueValue("run.configuration.edit.ad")) {
83 return String
.format("Press %s to Edit", KeymapUtil
.getKeystrokeText(KeyStroke
.getKeyStroke("F4")));
89 private void registerActions(final ListPopupImpl popup
) {
90 popup
.registerAction("alternateExecutor", KeyStroke
.getKeyStroke("shift pressed SHIFT"), new AbstractAction() {
91 public void actionPerformed(ActionEvent e
) {
92 myCurrentExecutor
= getAlternateExecutor();
93 updatePresentation(popup
);
97 popup
.registerAction("restoreDefaultExecutor", KeyStroke
.getKeyStroke("released SHIFT"), new AbstractAction() {
98 public void actionPerformed(ActionEvent e
) {
99 myCurrentExecutor
= getDefaultExecutor();
100 updatePresentation(popup
);
105 popup
.registerAction("invokeAction", KeyStroke
.getKeyStroke("shift ENTER"), new AbstractAction() {
106 public void actionPerformed(ActionEvent e
) {
107 popup
.handleSelect(true);
111 popup
.registerAction("editConfiguration", KeyStroke
.getKeyStroke("F4"), new AbstractAction() {
112 public void actionPerformed(ActionEvent e
) {
113 myEditConfiguration
= true;
115 popup
.handleSelect(true);
118 myEditConfiguration
= false;
124 popup
.registerAction("deleteConfiguration", KeyStroke
.getKeyStroke("DELETE"), new AbstractAction() {
125 public void actionPerformed(ActionEvent e
) {
126 myDeleteConfiguration
= true;
128 popup
.handleSelect(true);
131 myDeleteConfiguration
= false;
136 popup
.registerAction("0Action", KeyStroke
.getKeyStroke("0"), createNumberAction(0, popup
, getDefaultExecutor()));
137 popup
.registerAction("0Action_", KeyStroke
.getKeyStroke("shift pressed 0"), createNumberAction(0, popup
, getAlternateExecutor()));
138 popup
.registerAction("1Action", KeyStroke
.getKeyStroke("1"), createNumberAction(1, popup
, getDefaultExecutor()));
139 popup
.registerAction("1Action_", KeyStroke
.getKeyStroke("shift pressed 1"), createNumberAction(1, popup
, getAlternateExecutor()));
140 popup
.registerAction("2Action", KeyStroke
.getKeyStroke("2"), createNumberAction(2, popup
, getDefaultExecutor()));
141 popup
.registerAction("2Action_", KeyStroke
.getKeyStroke("shift pressed 2"), createNumberAction(2, popup
, getAlternateExecutor()));
142 popup
.registerAction("3Action", KeyStroke
.getKeyStroke("3"), createNumberAction(3, popup
, getDefaultExecutor()));
143 popup
.registerAction("3Action_", KeyStroke
.getKeyStroke("shift pressed 3"), createNumberAction(3, popup
, getAlternateExecutor()));
146 private void updatePresentation(ListPopupImpl listPopup
) {
147 final Executor executor
= getCurrentExecutor();
148 if (executor
!= null) {
149 listPopup
.setCaption(executor
.getActionName());
153 static void execute(final ItemWrapper itemWrapper
, final Executor executor
) {
154 if (executor
== null) {
158 final DataContext dataContext
= DataManager
.getInstance().getDataContext();
159 final Project project
= PlatformDataKeys
.PROJECT
.getData(dataContext
);
160 if (project
!= null) {
161 SwingUtilities
.invokeLater(new Runnable() {
163 itemWrapper
.perform(project
, executor
, dataContext
);
169 void editConfiguration(@NotNull final Project project
, @NotNull final RunnerAndConfigurationSettingsImpl configuration
) {
170 final Executor executor
= getCurrentExecutor();
171 assert executor
!= null;
173 PropertiesComponent
.getInstance().setValue("run.configuration.edit.ad", Boolean
.toString(true));
174 if (RunDialog
.editConfiguration(project
, configuration
, "Edit configuration settings", executor
.getActionName(), executor
.getIcon())) {
175 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(configuration
);
176 ExecutionUtil
.executeConfiguration(project
, configuration
, executor
, DataManager
.getInstance().getDataContext());
180 private void deleteConfiguration(final Project project
, final RunnerAndConfigurationSettingsImpl configurationSettings
) {
185 protected Executor
getDefaultExecutor() {
186 return DefaultRunExecutor
.getRunExecutorInstance();
190 protected Executor
getAlternateExecutor() {
191 return ExecutorRegistry
.getInstance().getExecutorById(ToolWindowId
.DEBUG
);
195 protected Executor
getCurrentExecutor() {
196 return myCurrentExecutor
== null ?
getDefaultExecutor() : myCurrentExecutor
;
200 public void update(AnActionEvent e
) {
201 final Presentation presentation
= e
.getPresentation();
202 final Project project
= e
.getData(PlatformDataKeys
.PROJECT
);
204 presentation
.setEnabled(true);
205 if (project
== null || project
.isDisposed()) {
206 presentation
.setEnabled(false);
207 presentation
.setVisible(false);
211 if (null == getDefaultExecutor()) {
212 presentation
.setEnabled(false);
213 presentation
.setVisible(false);
217 presentation
.setEnabled(true);
218 presentation
.setVisible(true);
221 private static Action
createNumberAction(final int number
, final ListPopupImpl listPopup
, final Executor executor
) {
222 return new AbstractAction() {
223 public void actionPerformed(ActionEvent e
) {
224 for (Object item
: listPopup
.getListStep().getValues()) {
225 if (item
instanceof ItemWrapper
&& ((ItemWrapper
)item
).getMnemonic() == number
) {
227 execute((ItemWrapper
)item
, executor
);
234 private abstract static class ItemWrapper
<T
> {
236 private boolean myDynamic
= false;
237 private int myMnemonic
= -1;
239 protected ItemWrapper(@Nullable final T value
) {
243 public int getMnemonic() {
247 public void setMnemonic(int mnemonic
) {
248 myMnemonic
= mnemonic
;
251 public T
getValue() {
255 public boolean isDynamic() {
259 public void setDynamic(final boolean b
) {
264 public boolean equals(Object o
) {
265 if (this == o
) return true;
266 if (o
== null || getClass() != o
.getClass()) return false;
268 ItemWrapper that
= (ItemWrapper
)o
;
270 if (myValue
!= null ?
!myValue
.equals(that
.myValue
) : that
.myValue
!= null) return false;
276 public int hashCode() {
277 return myValue
!= null ? myValue
.hashCode() : 0;
280 public abstract Icon
getIcon();
282 public abstract String
getText();
284 public abstract void perform(@NotNull final Project project
, @NotNull final Executor executor
, @NotNull final DataContext context
);
287 public ConfigurationType
getType() {
291 public boolean available(Executor executor
) {
295 public boolean hasActions() {
299 public PopupStep
getNextStep(Project project
, ChooseRunConfigurationAction action
) {
300 return PopupStep
.FINAL_CHOICE
;
303 public static ItemWrapper
wrap(@NotNull final Project project
,
304 @NotNull final RunnerAndConfigurationSettingsImpl settings
,
305 final boolean dynamic
) {
306 final ItemWrapper result
= wrap(project
, settings
);
307 result
.setDynamic(dynamic
);
311 public static ItemWrapper
wrap(@NotNull final Project project
, @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
312 return new ItemWrapper
<RunnerAndConfigurationSettingsImpl
>(settings
) {
314 public void perform(@NotNull Project project
, @NotNull Executor executor
, @NotNull DataContext context
) {
315 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(getValue());
316 ExecutionUtil
.executeConfiguration(project
, getValue(), executor
, DataManager
.getInstance().getDataContext());
320 public ConfigurationType
getType() {
321 return getValue().getType();
325 public Icon
getIcon() {
326 return ExecutionUtil
.getConfigurationIcon(project
, getValue());
330 public String
getText() {
331 if (getMnemonic() != -1) {
332 return String
.format("%s", getValue().getName());
335 return getValue().getName();
339 public boolean hasActions() {
344 public boolean available(Executor executor
) {
345 return null != ExecutionUtil
.getRunner(executor
.getId(), getValue());
349 public PopupStep
getNextStep(@NotNull final Project project
, @NotNull final ChooseRunConfigurationAction action
) {
350 return new ConfigurationActionsStep(project
, action
, getValue());
357 private static final class ConfigurationListPopupStep
extends BaseListPopupStep
<ItemWrapper
> {
358 private Project myProject
;
359 private ChooseRunConfigurationAction myAction
;
360 private int myDefaultConfiguration
= -1;
362 private ConfigurationListPopupStep(@NotNull final ChooseRunConfigurationAction action
,
363 @NotNull final Project project
,
364 @NotNull final String title
) {
365 super(title
, createSettingsList(project
));
369 if (-1 == getDefaultOptionIndex()) {
370 myDefaultConfiguration
= getDynamicIndex();
374 private int getDynamicIndex() {
376 for (final ItemWrapper wrapper
: getValues()) {
377 if (wrapper
.isDynamic()) {
387 public boolean isAutoSelectionEnabled() {
391 private static ItemWrapper
[] createSettingsList(@NotNull final Project project
) {
392 final RunManagerEx manager
= RunManagerEx
.getInstanceEx(project
);
394 final List
<ItemWrapper
> result
= new ArrayList
<ItemWrapper
>();
396 final RunnerAndConfigurationSettingsImpl selectedConfiguration
= manager
.getSelectedConfiguration();
397 final RunnerAndConfigurationSettingsImpl context
= populateWithDynamicRunners(result
, project
, manager
, selectedConfiguration
);
399 final ConfigurationType
[] factories
= manager
.getConfigurationFactories();
400 for (final ConfigurationType factory
: factories
) {
401 final RunnerAndConfigurationSettingsImpl
[] configurations
= manager
.getConfigurationSettings(factory
);
402 for (final RunnerAndConfigurationSettingsImpl configuration
: configurations
) {
403 if (configuration
!= context
) { // exclude context configuration
404 final ItemWrapper wrapped
= ItemWrapper
.wrap(project
, configuration
);
405 if (configuration
== selectedConfiguration
) {
406 wrapped
.setMnemonic(1);
414 //noinspection unchecked
415 final ItemWrapper edit
= new ItemWrapper(null) {
417 public Icon
getIcon() {
422 public String
getText() {
423 return "Edit configurations...";
427 public void perform(@NotNull final Project project
, @NotNull final Executor executor
, @NotNull DataContext context
) {
428 final EditConfigurationsDialog dialog
= new EditConfigurationsDialog(project
) {
430 protected void init() {
431 setOKButtonText(executor
.getStartActionText());
432 setOKButtonIcon(executor
.getIcon());
440 SwingUtilities
.invokeLater(new Runnable() {
442 final RunnerAndConfigurationSettings configuration
= RunManager
.getInstance(project
).getSelectedConfiguration();
443 if (configuration
instanceof RunnerAndConfigurationSettingsImpl
) {
444 ExecutionUtil
.executeConfiguration(project
, (RunnerAndConfigurationSettingsImpl
) configuration
, executor
, DataManager
.getInstance().getDataContext());
455 return result
.toArray(new ItemWrapper
[result
.size()]);
459 private static RunnerAndConfigurationSettingsImpl
populateWithDynamicRunners(final List
<ItemWrapper
> result
,
460 final Project project
,
461 final RunManagerEx manager
,
462 final RunnerAndConfigurationSettingsImpl selectedConfiguration
) {
463 final DataContext dataContext
= DataManager
.getInstance().getDataContext();
464 final ConfigurationContext context
= new ConfigurationContext(dataContext
);
465 final RunnerAndConfigurationSettingsImpl existing
= context
.findExisting();
466 if (existing
!= null && existing
== selectedConfiguration
) {
470 if (existing
== null) {
471 final List
<RuntimeConfigurationProducer
> producers
= PreferedProducerFind
.findPreferedProducers(context
.getLocation(), context
);
472 if (producers
== null) return null;
474 Collections
.sort(producers
, new Comparator
<RuntimeConfigurationProducer
>() {
475 public int compare(final RuntimeConfigurationProducer p1
, final RuntimeConfigurationProducer p2
) {
476 return p1
.getConfigurationType().getDisplayName().compareTo(p2
.getConfigurationType().getDisplayName());
480 final RunnerAndConfigurationSettingsImpl
[] preferred
= {null};
482 int i
= 2; // selectedConfiguration == null ? 1 : 2;
483 for (final RuntimeConfigurationProducer producer
: producers
) {
484 final RunnerAndConfigurationSettingsImpl configuration
= producer
.getConfiguration();
485 if (configuration
!= null) {
487 if (preferred
[0] == null) {
488 preferred
[0] = configuration
;
491 //noinspection unchecked
492 final ItemWrapper wrapper
= new ItemWrapper(configuration
) {
494 public Icon
getIcon() {
495 return IconLoader
.getTransparentIcon(ExecutionUtil
.getConfigurationIcon(project
, configuration
), 0.3f
);
499 public String
getText() {
500 return producers
.size() == 1
501 ? String
.format("%s", configuration
.getName())
502 : String
.format("%s (%s)", configuration
.getName(), producer
.getConfigurationType().getDisplayName());
506 public void perform(@NotNull Project project
, @NotNull Executor executor
, @NotNull DataContext context
) {
507 manager
.setTemporaryConfiguration(configuration
);
508 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(configuration
);
509 ExecutionUtil
.executeConfiguration(project
, configuration
, executor
, DataManager
.getInstance().getDataContext());
513 public PopupStep
getNextStep(@NotNull final Project project
, @NotNull final ChooseRunConfigurationAction action
) {
514 return new ConfigurationActionsStep(project
, action
, configuration
);
518 public boolean hasActions() {
523 wrapper
.setDynamic(true);
524 wrapper
.setMnemonic(i
);
533 final ItemWrapper wrapper
= ItemWrapper
.wrap(project
, existing
, true);
534 wrapper
.setMnemonic(2); // selectedConfiguration == null ? 1 : 2);
542 public ListSeparator
getSeparatorAbove(ItemWrapper value
) {
543 final List
<ItemWrapper
> configurations
= getValues();
544 final int index
= configurations
.indexOf(value
);
545 if (index
> 0 && index
<= configurations
.size() - 1) {
546 final ItemWrapper aboveConfiguration
= index
== 0 ?
null : configurations
.get(index
- 1);
548 if (aboveConfiguration
!= null && aboveConfiguration
.isDynamic() != value
.isDynamic()) {
549 return new ListSeparator();
552 final ConfigurationType currentType
= value
.getType();
553 final ConfigurationType aboveType
= aboveConfiguration
== null ?
null : aboveConfiguration
.getType();
554 if (aboveType
!= currentType
&& currentType
!= null) {
555 return new ListSeparator(); // new ListSeparator(currentType.getDisplayName());
563 public boolean isSpeedSearchEnabled() {
568 public int getDefaultOptionIndex() {
569 final RunnerAndConfigurationSettings currentConfiguration
= RunManager
.getInstance(myProject
).getSelectedConfiguration();
570 if (currentConfiguration
== null && myDefaultConfiguration
!= -1) {
571 return myDefaultConfiguration
;
574 return currentConfiguration
instanceof RunnerAndConfigurationSettingsImpl ?
getValues()
575 .indexOf(ItemWrapper
.wrap(myProject
, (RunnerAndConfigurationSettingsImpl
)currentConfiguration
)) : -1;
579 public PopupStep
onChosen(final ItemWrapper wrapper
, boolean finalChoice
) {
580 if (myAction
.myEditConfiguration
) {
581 final Object o
= wrapper
.getValue();
582 if (o
instanceof RunnerAndConfigurationSettingsImpl
) {
583 SwingUtilities
.invokeLater(new Runnable() {
585 myAction
.editConfiguration(myProject
, (RunnerAndConfigurationSettingsImpl
)o
);
593 if (myAction
.myDeleteConfiguration
) {
594 final Object o
= wrapper
.getValue();
595 if (o
instanceof RunnerAndConfigurationSettingsImpl
) {
596 SwingUtilities
.invokeLater(new Runnable() {
598 myAction
.deleteConfiguration(myProject
, (RunnerAndConfigurationSettingsImpl
)o
);
606 final Executor executor
= myAction
.getCurrentExecutor();
607 assert executor
!= null;
609 if (finalChoice
&& wrapper
.available(executor
)) {
610 SwingUtilities
.invokeLater(new Runnable() {
612 if (myAction
.getCurrentExecutor() == myAction
.getAlternateExecutor()) {
613 PropertiesComponent
.getInstance().setValue(myAction
.getAdKey(), Boolean
.toString(true));
616 wrapper
.perform(myProject
, executor
, DataManager
.getInstance().getDataContext());
623 return wrapper
.getNextStep(myProject
, myAction
);
628 public boolean hasSubstep(ItemWrapper selectedValue
) {
629 return selectedValue
.hasActions();
634 public String
getTextFor(ItemWrapper value
) {
635 return value
.getText();
639 public Icon
getIconFor(ItemWrapper value
) {
640 return value
.getIcon();
644 private static final class ConfigurationActionsStep
extends BaseListPopupStep
<ActionWrapper
> {
645 private ConfigurationActionsStep(@NotNull final Project project
,
646 ChooseRunConfigurationAction action
,
647 @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
648 super("Actions", buildActions(project
, action
, settings
));
651 private static ActionWrapper
[] buildActions(@NotNull final Project project
,
652 final ChooseRunConfigurationAction action
,
653 @NotNull final RunnerAndConfigurationSettingsImpl settings
) {
654 final List
<ActionWrapper
> result
= new ArrayList
<ActionWrapper
>();
655 final Executor
[] executors
= ExecutorRegistry
.getInstance().getRegisteredExecutors();
656 for (final Executor executor
: executors
) {
657 final ProgramRunner runner
= RunnerRegistry
.getInstance().getRunner(executor
.getId(), settings
.getConfiguration());
658 if (runner
!= null) {
659 result
.add(new ActionWrapper(executor
.getActionName(), executor
.getIcon()) {
661 public void perform() {
662 RunManagerEx
.getInstanceEx(project
).setSelectedConfiguration(settings
);
663 ExecutionUtil
.executeConfiguration(project
, settings
, executor
, DataManager
.getInstance().getDataContext());
669 result
.add(new ActionWrapper("Edit...", EDIT_ICON
) {
671 public void perform() {
672 action
.editConfiguration(project
, settings
);
676 if (RunManager
.getInstance(project
).isTemporary(settings
.getConfiguration())) {
677 result
.add(new ActionWrapper("Save temp configuration", SAVE_ICON
) {
679 public void perform() {
680 RunManager
.getInstance(project
).makeStable(settings
.getConfiguration());
685 return result
.toArray(new ActionWrapper
[result
.size()]);
689 public PopupStep
onChosen(final ActionWrapper selectedValue
, boolean finalChoice
) {
690 SwingUtilities
.invokeLater(new Runnable() {
692 selectedValue
.perform();
700 public Icon
getIconFor(ActionWrapper aValue
) {
701 return aValue
.getIcon();
706 public String
getTextFor(ActionWrapper value
) {
707 return value
.getName();
711 private abstract static class ActionWrapper
{
712 private String myName
;
715 private ActionWrapper(String name
, Icon icon
) {
720 public abstract void perform();
722 public String
getName() {
726 public Icon
getIcon() {
731 private static class RunListElementRenderer
extends PopupListElementRenderer
{
732 private JLabel myLabel
;
733 private ListPopupImpl myPopup1
;
735 private RunListElementRenderer(ListPopupImpl popup
) {
742 protected JComponent
createItemComponent() {
743 if (myLabel
== null) {
744 myLabel
= new JLabel();
745 myLabel
.setPreferredSize(new JLabel("8.").getPreferredSize());
748 final JComponent result
= super.createItemComponent();
749 result
.add(myLabel
, BorderLayout
.WEST
);
754 protected void customizeComponent(JList list
, Object value
, boolean isSelected
) {
755 super.customizeComponent(list
, value
, isSelected
);
757 ListPopupStep
<Object
> step
= myPopup1
.getListStep();
758 boolean isSelectable
= step
.isSelectable(value
);
759 myLabel
.setEnabled(isSelectable
);
762 setSelected(myLabel
);
764 setDeselected(myLabel
);
767 if (value
instanceof ItemWrapper
) {
768 final int mnemonic
= ((ItemWrapper
)value
).getMnemonic();
769 if (mnemonic
!= -1) {
770 myLabel
.setText(mnemonic
+ ".");
771 myLabel
.setDisplayedMnemonicIndex(0);