Mnemonics for Run.../Debug...
[fedora-idea.git] / lang-impl / src / com / intellij / execution / actions / ChooseRunConfigurationAction.java
blob482edcac657b16470e663f9efc80199d46e27d6c
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;
29 import javax.swing.*;
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;
36 /**
37 * @author spleaner
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;
52 @Override
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());
68 if (adText != null) {
69 ((AbstractPopup)popup).setAdText(adText);
72 popup.showCenteredInCurrentWindow(project);
75 protected String getAdKey() {
76 return "run.configuration.alternate.action.ad";
79 @Nullable
80 protected String getAdText(final Executor alternateExecutor) {
81 if (alternateExecutor != null && !PropertiesComponent.getInstance().isTrueValue(getAdKey())) {
82 return String
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")));
90 return null;
93 private static Icon getNumberIcon(final Icon base, final int number) {
94 switch (number) {
95 case 0:
96 return LayeredIcon.create(base, _00_ICON);
97 case 1:
98 return LayeredIcon.create(base, _01_ICON);
99 case 2:
100 return LayeredIcon.create(base, _02_ICON);
101 case 3:
102 return LayeredIcon.create(base, _03_ICON);
103 default:
104 return base;
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;
133 try {
134 popup.handleSelect(true);
136 finally {
137 myEditConfiguration = false;
143 popup.registerAction("deleteConfiguration", KeyStroke.getKeyStroke("DELETE"), new AbstractAction() {
144 public void actionPerformed(ActionEvent e) {
145 myDeleteConfiguration = true;
146 try {
147 popup.handleSelect(true);
149 finally {
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) {
174 return;
177 final DataContext dataContext = DataManager.getInstance().getDataContext();
178 final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
179 if (project != null) {
180 SwingUtilities.invokeLater(new Runnable() {
181 public void run() {
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) {
200 // TODO:
203 @Nullable
204 protected Executor getDefaultExecutor() {
205 return DefaultRunExecutor.getRunExecutorInstance();
208 @Nullable
209 protected Executor getAlternateExecutor() {
210 return ExecutorRegistry.getInstance().getExecutorById(ToolWindowId.DEBUG);
213 @Nullable
214 protected Executor getCurrentExecutor() {
215 return myCurrentExecutor == null ? getDefaultExecutor() : myCurrentExecutor;
218 @Override
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);
227 return;
230 if (null == getDefaultExecutor()) {
231 presentation.setEnabled(false);
232 presentation.setVisible(false);
233 return;
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) {
245 listPopup.cancel();
246 execute((ItemWrapper)item, executor);
253 private abstract static class ItemWrapper<T> {
254 private T myValue;
255 private boolean myDynamic = false;
256 private int myMnemonic = -1;
258 protected ItemWrapper(@Nullable final T value) {
259 myValue = value;
262 public int getMnemonic() {
263 return myMnemonic;
266 public void setMnemonic(int mnemonic) {
267 myMnemonic = mnemonic;
270 public T getValue() {
271 return myValue;
274 public boolean isDynamic() {
275 return myDynamic;
278 public void setDynamic(final boolean b) {
279 myDynamic = b;
282 @Override
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;
291 return true;
294 @Override
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);
305 @Nullable
306 public ConfigurationType getType() {
307 return null;
310 public boolean available(Executor executor) {
311 return true;
314 public boolean hasActions() {
315 return false;
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);
327 return result;
330 public static ItemWrapper wrap(@NotNull final Project project, @NotNull final RunnerAndConfigurationSettingsImpl settings) {
331 return new ItemWrapper<RunnerAndConfigurationSettingsImpl>(settings) {
332 @Override
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());
338 @Override
339 public ConfigurationType getType() {
340 return getValue().getType();
343 @Override
344 public Icon getIcon() {
345 final Icon result = ExecutionUtil.getConfigurationIcon(project, getValue());
346 if (getMnemonic() != -1) {
347 return getNumberIcon(result, getMnemonic());
350 return result;
353 @Override
354 public String getText() {
355 if (getMnemonic() != -1) {
356 return String.format("%s", getValue().getName());
359 return getValue().getName();
362 @Override
363 public boolean hasActions() {
364 return true;
367 @Override
368 public boolean available(Executor executor) {
369 return null != ExecutionUtil.getRunner(executor.getId(), getValue());
372 @Override
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));
390 myProject = project;
391 myAction = action;
393 if (-1 == getDefaultOptionIndex()) {
394 myDefaultConfiguration = getDynamicIndex();
398 private int getDynamicIndex() {
399 int i = 0;
400 for (final ItemWrapper wrapper : getValues()) {
401 if (wrapper.isDynamic()) {
402 return i;
404 i++;
407 return -1;
410 @Override
411 public boolean isAutoSelectionEnabled() {
412 return false;
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);
433 result.add(wrapped);
438 //noinspection unchecked
439 final ItemWrapper edit = new ItemWrapper(null) {
440 @Override
441 public Icon getIcon() {
442 return getNumberIcon(EDIT_ICON, 0);
445 @Override
446 public String getText() {
447 return "Edit configurations...";
450 @Override
451 public void perform(@NotNull Project project, @NotNull Executor executor, @NotNull DataContext context) {
452 new EditConfigurationsDialog(project).show();
456 edit.setMnemonic(0);
457 result.add(0, edit);
459 return result.toArray(new ItemWrapper[result.size()]);
462 @Nullable
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) {
471 return null;
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) {
497 @Override
498 public Icon getIcon() {
499 Icon result = IconLoader.getTransparentIcon(ExecutionUtil.getConfigurationIcon(project, configuration), 0.3f);
500 if (getMnemonic() != -1) {
501 result = getNumberIcon(result, getMnemonic());
504 return result;
507 @Override
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());
514 @Override
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());
521 @Override
522 public PopupStep getNextStep(@NotNull final Project project, @NotNull final ChooseRunConfigurationAction action) {
523 return new ConfigurationActionsStep(project, action, configuration);
526 @Override
527 public boolean hasActions() {
528 return true;
532 wrapper.setDynamic(true);
533 wrapper.setMnemonic(i);
534 result.add(wrapper);
535 i++;
539 return preferred[0];
541 else {
542 final ItemWrapper wrapper = ItemWrapper.wrap(project, existing, true);
543 wrapper.setMnemonic(2); // selectedConfiguration == null ? 1 : 2);
544 result.add(wrapper);
547 return existing;
550 @Override
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());
568 return null;
571 @Override
572 public boolean isSpeedSearchEnabled() {
573 return true;
576 @Override
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;
587 @Override
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() {
593 public void run() {
594 myAction.editConfiguration(myProject, (RunnerAndConfigurationSettingsImpl)o);
598 return FINAL_CHOICE;
602 if (myAction.myDeleteConfiguration) {
603 final Object o = wrapper.getValue();
604 if (o instanceof RunnerAndConfigurationSettingsImpl) {
605 SwingUtilities.invokeLater(new Runnable() {
606 public void run() {
607 myAction.deleteConfiguration(myProject, (RunnerAndConfigurationSettingsImpl)o);
611 return FINAL_CHOICE;
615 final Executor executor = myAction.getCurrentExecutor();
616 assert executor != null;
618 if (finalChoice && wrapper.available(executor)) {
619 SwingUtilities.invokeLater(new Runnable() {
620 public void run() {
621 if (myAction.getCurrentExecutor() == myAction.getAlternateExecutor()) {
622 PropertiesComponent.getInstance().setValue(myAction.getAdKey(), Boolean.toString(true));
625 wrapper.perform(myProject, executor, DataManager.getInstance().getDataContext());
629 return FINAL_CHOICE;
631 else {
632 return wrapper.getNextStep(myProject, myAction);
636 @Override
637 public boolean hasSubstep(ItemWrapper selectedValue) {
638 return selectedValue.hasActions();
641 @NotNull
642 @Override
643 public String getTextFor(ItemWrapper value) {
644 return value.getText();
647 @Override
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()) {
669 @Override
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) {
679 @Override
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) {
687 @Override
688 public void perform() {
689 RunManager.getInstance(project).makeStable(settings.getConfiguration());
694 return result.toArray(new ActionWrapper[result.size()]);
697 @Override
698 public PopupStep onChosen(final ActionWrapper selectedValue, boolean finalChoice) {
699 SwingUtilities.invokeLater(new Runnable() {
700 public void run() {
701 selectedValue.perform();
705 return FINAL_CHOICE;
708 @Override
709 public Icon getIconFor(ActionWrapper aValue) {
710 return aValue.getIcon();
713 @NotNull
714 @Override
715 public String getTextFor(ActionWrapper value) {
716 return value.getName();
720 private abstract static class ActionWrapper {
721 private String myName;
722 private Icon myIcon;
724 private ActionWrapper(String name, Icon icon) {
725 myName = name;
726 myIcon = icon;
729 public abstract void perform();
731 public String getName() {
732 return myName;
735 public Icon getIcon() {
736 return myIcon;