NotNull, dispose
[fedora-idea.git] / platform / lang-impl / src / com / intellij / execution / impl / RunConfigurable.java
blob7c110e3d68780cc24b497a591b862533025f5b08
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.intellij.execution.impl;
19 import com.intellij.execution.*;
20 import com.intellij.execution.configurations.ConfigurationFactory;
21 import com.intellij.execution.configurations.ConfigurationType;
22 import com.intellij.execution.configurations.RunConfiguration;
23 import com.intellij.execution.configurations.UnknownRunConfiguration;
24 import com.intellij.openapi.actionSystem.*;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.options.BaseConfigurable;
27 import com.intellij.openapi.options.ConfigurationException;
28 import com.intellij.openapi.options.SettingsEditor;
29 import com.intellij.openapi.options.SettingsEditorListener;
30 import com.intellij.openapi.options.ex.SingleConfigurableEditor;
31 import com.intellij.openapi.project.Project;
32 import com.intellij.openapi.ui.Messages;
33 import com.intellij.openapi.ui.Splitter;
34 import com.intellij.openapi.ui.popup.JBPopupFactory;
35 import com.intellij.openapi.ui.popup.ListPopup;
36 import com.intellij.openapi.ui.popup.ListPopupStep;
37 import com.intellij.openapi.ui.popup.PopupStep;
38 import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
39 import com.intellij.openapi.util.Comparing;
40 import com.intellij.openapi.util.IconLoader;
41 import com.intellij.openapi.util.Key;
42 import com.intellij.openapi.wm.IdeFocusManager;
43 import com.intellij.ui.*;
44 import com.intellij.ui.treeStructure.Tree;
45 import com.intellij.util.ArrayUtil;
46 import com.intellij.util.config.StorageAccessors;
47 import com.intellij.util.ui.UIUtil;
48 import com.intellij.util.ui.tree.TreeUtil;
49 import org.jetbrains.annotations.NonNls;
50 import org.jetbrains.annotations.NotNull;
51 import org.jetbrains.annotations.Nullable;
53 import javax.swing.*;
54 import javax.swing.event.*;
55 import javax.swing.text.html.HTMLEditorKit;
56 import javax.swing.tree.DefaultMutableTreeNode;
57 import javax.swing.tree.DefaultTreeModel;
58 import javax.swing.tree.TreeNode;
59 import javax.swing.tree.TreePath;
60 import java.awt.*;
61 import java.awt.event.ActionEvent;
62 import java.awt.event.ActionListener;
63 import java.awt.event.KeyEvent;
64 import java.net.URL;
65 import java.util.*;
67 class RunConfigurable extends BaseConfigurable {
68 private static final Icon ICON = IconLoader.getIcon("/general/configurableRunDebug.png");
69 @NonNls private static final String GENERAL_ADD_ICON_PATH = "/general/add.png";
70 private static final Icon ADD_ICON = IconLoader.getIcon(GENERAL_ADD_ICON_PATH);
71 private static final Icon REMOVE_ICON = IconLoader.getIcon("/general/remove.png");
72 private static final Icon COPY_ICON = IconLoader.getIcon("/actions/copy.png");
73 private static final Icon SAVE_ICON = IconLoader.getIcon("/runConfigurations/saveTempConfig.png");
74 @NonNls private static final String EDIT_DEFAULTS_ICON_PATH = "/general/ideOptions.png";
75 private static final Icon EDIT_DEFAULTS_ICON = IconLoader.getIcon(EDIT_DEFAULTS_ICON_PATH);
76 @NonNls private static final String DIVIDER_PROPORTION = "dividerProportion";
78 private final Project myProject;
79 private final RunDialog myRunDialog;
80 @NonNls private final DefaultMutableTreeNode myRoot = new DefaultMutableTreeNode("Root");
81 private final Tree myTree = new Tree(myRoot);
82 private final JPanel myRightPanel = new JPanel(new BorderLayout());
83 private JComponent myToolbarComponent;
84 private final Splitter myPanel = new Splitter();
85 private JPanel myWholePanel;
86 private StorageAccessors myConfig;
87 private SingleConfigurationConfigurable<RunConfiguration> mySelectedConfigurable = null;
88 private static final Logger LOG = Logger.getInstance("#com.intellij.execution.impl.RunConfigurable");
89 private JTextField myRecentsLimit = new JTextField("5");
91 public RunConfigurable(final Project project) {
92 this(project, null);
95 public RunConfigurable(final Project project, final RunDialog runDialog) {
96 myProject = project;
97 myRunDialog = runDialog;
100 public String getDisplayName() {
101 return ExecutionBundle.message("run.configurable.display.name");
104 private void initTree() {
105 myTree.setRootVisible(false);
106 myTree.setShowsRootHandles(true);
107 UIUtil.setLineStyleAngled(myTree);
108 TreeToolTipHandler.install(myTree);
109 TreeUtil.installActions(myTree);
110 PopupHandler.installFollowingSelectionTreePopup(myTree, createActionsGroup(), ActionPlaces.UNKNOWN, ActionManager.getInstance());
111 myTree.setCellRenderer(new ColoredTreeCellRenderer() {
112 public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row,
113 boolean hasFocus) {
114 if (value instanceof DefaultMutableTreeNode) {
115 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
116 final Object userObject = node.getUserObject();
117 if (userObject instanceof ConfigurationType) {
118 final ConfigurationType configurationType = (ConfigurationType)userObject;
119 append(configurationType.getDisplayName(), SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
120 setIcon(configurationType.getIcon());
122 else {
123 final RunManager runManager = getRunManager();
124 RunConfiguration configuration = null;
125 String name = null;
126 if (userObject instanceof SingleConfigurationConfigurable) {
127 final SingleConfigurationConfigurable<?> settings = (SingleConfigurationConfigurable)userObject;
128 setIcon(ExecutionUtil.getConfigurationIcon(getProject(), settings.getSettings(), !settings.isValid()));
129 configuration = settings.getConfiguration();
130 name = settings.getNameText();
132 else if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
133 RunnerAndConfigurationSettingsImpl settings = (RunnerAndConfigurationSettingsImpl)userObject;
134 setIcon(ExecutionUtil.getConfigurationIcon(getProject(), settings));
135 configuration = settings.getConfiguration();
136 name = configuration.getName();
138 if (configuration != null) {
139 append(name, runManager.isTemporary(configuration)
140 ? SimpleTextAttributes.GRAY_ATTRIBUTES
141 : SimpleTextAttributes.REGULAR_ATTRIBUTES);
147 final RunManagerEx manager = getRunManager();
148 final ConfigurationType[] factories = manager.getConfigurationFactories();
149 for (ConfigurationType type : factories) {
150 final RunnerAndConfigurationSettingsImpl[] configurations = manager.getConfigurationSettings(type);
151 if (configurations != null && configurations.length > 0) {
152 final DefaultMutableTreeNode typeNode = new DefaultMutableTreeNode(type);
153 myRoot.add(typeNode);
154 for (RunnerAndConfigurationSettingsImpl configuration : configurations) {
155 typeNode.add(new DefaultMutableTreeNode(configuration));
160 myTree.addTreeSelectionListener(new TreeSelectionListener() {
161 public void valueChanged(TreeSelectionEvent e) {
162 final TreePath selectionPath = myTree.getSelectionPath();
163 if (selectionPath != null) {
164 DefaultMutableTreeNode node = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
165 final Object userObject = node.getUserObject();
166 if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
167 final SingleConfigurationConfigurable<RunConfiguration> configurationConfigurable =
168 SingleConfigurationConfigurable.editSettings((RunnerAndConfigurationSettingsImpl)userObject);
169 installUpdateListeners(configurationConfigurable);
170 node.setUserObject(configurationConfigurable);
171 updateRightPanel(configurationConfigurable);
173 else if (userObject instanceof SingleConfigurationConfigurable) {
174 updateRightPanel((SingleConfigurationConfigurable<RunConfiguration>)userObject);
176 else if (userObject instanceof ConfigurationType) {
177 drawPressAddButtonMessage((ConfigurationType)userObject);
180 updateDialog();
183 myTree.registerKeyboardAction(new ActionListener() {
184 public void actionPerformed(ActionEvent e) {
185 clickDefaultButton();
187 }, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
188 SwingUtilities.invokeLater(new Runnable() {
189 public void run() {
190 myTree.requestFocusInWindow();
191 final RunnerAndConfigurationSettings settings = manager.getSelectedConfiguration();
192 if (settings != null) {
193 final Enumeration enumeration = myRoot.breadthFirstEnumeration();
194 while (enumeration.hasMoreElements()) {
195 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)enumeration.nextElement();
196 final Object userObject = node.getUserObject();
197 if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
198 final RunnerAndConfigurationSettingsImpl runnerAndConfigurationSettings = (RunnerAndConfigurationSettingsImpl)userObject;
199 final ConfigurationType configurationType = settings.getType();
200 if (configurationType != null &&
201 Comparing.strEqual(runnerAndConfigurationSettings.getConfiguration().getType().getId(), configurationType.getId()) &&
202 Comparing.strEqual(runnerAndConfigurationSettings.getConfiguration().getName(), settings.getName())) {
203 TreeUtil.selectInTree(node, true, myTree);
204 return;
209 else {
210 mySelectedConfigurable = null;
212 TreeUtil.selectFirstNode(myTree);
213 drawPressAddButtonMessage(null);
216 sortTree(myRoot);
217 ((DefaultTreeModel)myTree.getModel()).reload();
220 private void updateRightPanel(final SingleConfigurationConfigurable<RunConfiguration> userObject) {
221 myRightPanel.removeAll();
222 mySelectedConfigurable = userObject;
223 myRightPanel.add(mySelectedConfigurable.createComponent(), BorderLayout.CENTER);
224 setupDialogBounds();
228 public static void sortTree(DefaultMutableTreeNode root) {
229 TreeUtil.sort(root, new Comparator() {
230 public int compare(final Object o1, final Object o2) {
231 final Object userObject1 = ((DefaultMutableTreeNode)o1).getUserObject();
232 final Object userObject2 = ((DefaultMutableTreeNode)o2).getUserObject();
233 if (userObject1 instanceof ConfigurationType && userObject2 instanceof ConfigurationType) {
234 return ((ConfigurationType)userObject1).getDisplayName().compareTo(((ConfigurationType)userObject2).getDisplayName());
236 return 0;
241 private void update() {
242 updateDialog();
243 final TreePath selectionPath = myTree.getSelectionPath();
244 if (selectionPath != null) {
245 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
246 ((DefaultTreeModel)myTree.getModel()).reload(node);
250 private void installUpdateListeners(final SingleConfigurationConfigurable<RunConfiguration> info) {
251 info.getEditor().addSettingsEditorListener(new SettingsEditorListener<RunnerAndConfigurationSettingsImpl>() {
252 public void stateChanged(final SettingsEditor<RunnerAndConfigurationSettingsImpl> editor) {
253 update();
254 setupDialogBounds();
258 info.addNameListner(new DocumentListener() {
259 public void insertUpdate(DocumentEvent e) {
260 update();
263 public void removeUpdate(DocumentEvent e) {
264 update();
267 public void changedUpdate(DocumentEvent e) {
268 update();
273 private void drawPressAddButtonMessage(final ConfigurationType configurationType) {
274 final JEditorPane browser = new JEditorPane();
275 browser.setBorder(null);
276 browser.setEditable(false);
277 browser.setEditorKit(new HTMLEditorKit());
278 browser.setBackground(myRightPanel.getBackground());
279 final URL addUrl = getClass().getResource(GENERAL_ADD_ICON_PATH);
280 final URL defaultsURL = getClass().getResource(EDIT_DEFAULTS_ICON_PATH);
281 final Font font = UIUtil.getLabelFont();
282 final String configurationTypeDescription = configurationType != null
283 ? configurationType.getConfigurationTypeDescription()
284 : ExecutionBundle.message("run.configuration.default.type.description");
285 browser.setText(ExecutionBundle.message("empty.run.configuration.panel.text.label", font.getFontName(), addUrl, defaultsURL,
286 configurationTypeDescription));
287 browser.setPreferredSize(new Dimension(200, 50));
288 browser.addHyperlinkListener(new HyperlinkListener() {
289 public void hyperlinkUpdate(final HyperlinkEvent e) {
290 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
291 if (Comparing.strEqual(e.getDescription(), "add")) {
292 new MyToolbarAddAction().actionPerformed(null);
294 else {
295 editDefaultsConfiguration();
300 myRightPanel.removeAll();
301 myRightPanel.add(browser, BorderLayout.CENTER);
302 myRightPanel.revalidate();
303 myRightPanel.repaint();
306 private JPanel createLeftPanel() {
307 final JPanel leftPanel = new JPanel(new BorderLayout());
308 myToolbarComponent = ActionManager.getInstance().
309 createActionToolbar(ActionPlaces.UNKNOWN,
310 createActionsGroup(),
311 true).getComponent();
312 leftPanel.add(myToolbarComponent, BorderLayout.NORTH);
313 initTree();
314 final JScrollPane pane = ScrollPaneFactory.createScrollPane(myTree);
315 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
316 leftPanel.add(pane, BorderLayout.CENTER);
317 final JButton editDefaultsButton = new JButton(ExecutionBundle.message("run.configuration.edit.default.configuration.settings.button"));
318 editDefaultsButton.addActionListener(new ActionListener() {
319 public void actionPerformed(ActionEvent e) {
320 editDefaultsConfiguration();
324 final JPanel bottomPanel = new JPanel(new BorderLayout());
325 bottomPanel.add(editDefaultsButton, BorderLayout.NORTH);
326 bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
328 Box box = new Box(BoxLayout.LINE_AXIS);
329 box.setBorder(BorderFactory.createEmptyBorder(7, 5, 3, 0));
330 box.add(new JLabel("Temporary configurations limit:"));
331 Dimension size = new Dimension(25, myRecentsLimit.getPreferredSize().height);
332 myRecentsLimit.setPreferredSize(size);
333 myRecentsLimit.setMaximumSize(size);
334 myRecentsLimit.setMinimumSize(size);
335 box.add(myRecentsLimit);
336 myRecentsLimit.getDocument().addDocumentListener(new DocumentAdapter() {
337 @Override
338 protected void textChanged(DocumentEvent e) {
339 setModified(true);
342 box.add(Box.createHorizontalGlue());
343 bottomPanel.add(box, BorderLayout.CENTER);
345 leftPanel.add(bottomPanel, BorderLayout.SOUTH);
346 return leftPanel;
349 private void editDefaultsConfiguration() {
350 new SingleConfigurableEditor(getProject(),
351 new DefaultConfigurationSettingsEditor(myProject,
352 getSelectedConfigurationType())).show();
355 private DefaultActionGroup createActionsGroup() {
356 DefaultActionGroup group = new DefaultActionGroup();
357 group.add(new MyToolbarAddAction());
358 group.add(new MyRemoveAction());
359 group.add(new MyCopyAction());
360 group.add(new MySaveAction());
361 group.add(new AnAction(ExecutionBundle.message("run.configuration.edit.default.configuration.settings.button"),
362 ExecutionBundle.message("run.configuration.edit.default.configuration.settings.button"), EDIT_DEFAULTS_ICON) {
363 public void actionPerformed(final AnActionEvent e) {
364 editDefaultsConfiguration();
367 group.add(new MyMoveAction(ExecutionBundle.message("move.up.action.name"), null, IconLoader.getIcon("/actions/moveUp.png"), -1));
368 group.add(new MyMoveAction(ExecutionBundle.message("move.down.action.name"), null, IconLoader.getIcon("/actions/moveDown.png"), 1));
369 return group;
372 @Nullable
373 private ConfigurationType getSelectedConfigurationType() {
374 final TreePath selectionPath = myTree.getSelectionPath();
375 if (selectionPath == null) return null;
376 final DefaultMutableTreeNode configurationTypeNode = getSelectedConfigurationTypeNode();
377 return configurationTypeNode != null ? (ConfigurationType)configurationTypeNode.getUserObject() : null;
380 public JComponent createComponent() {
381 myWholePanel = new JPanel(new BorderLayout());
382 myPanel.setHonorComponentsMinimumSize(true);
383 myConfig = StorageAccessors.createGlobal("runConfigurationTab");
384 myPanel.setShowDividerControls(true);
385 myPanel.setProportion(myConfig.getFloat(DIVIDER_PROPORTION, 0.2f));
386 myPanel.setHonorComponentsMinimumSize(true);
387 myPanel.setFirstComponent(createLeftPanel());
388 myPanel.setSecondComponent(myRightPanel);
389 myWholePanel.add(myPanel, BorderLayout.CENTER);
391 updateDialog();
393 Dimension d = myWholePanel.getPreferredSize();
394 d.width = Math.max(d.width, 800);
395 d.height = Math.max(d.height, 600);
396 myWholePanel.setPreferredSize(d);
398 return myWholePanel;
401 public Icon getIcon() {
402 return ICON;
405 public void reset() {
406 final RunManagerEx manager = getRunManager();
407 final RunManagerConfig config = manager.getConfig();
408 myRecentsLimit.setText(Integer.toString(config.getRecentsLimit()));
409 setModified(false);
412 private Project getProject() {
413 return myProject;
416 public void apply() throws ConfigurationException {
417 final RunManagerImpl manager = getRunManager();
418 final ConfigurationType[] configurationTypes = manager.getConfigurationFactories();
419 for (ConfigurationType configurationType : configurationTypes) {
420 applyByType(configurationType);
423 if (mySelectedConfigurable != null) {
424 manager.setSelectedConfiguration(mySelectedConfigurable.getSettings());
426 else {
427 manager.setSelectedConfiguration(null);
430 String recentsLimit = myRecentsLimit.getText();
431 try {
432 int i = Integer.parseInt(recentsLimit);
433 int oldLimit = manager.getConfig().getRecentsLimit();
434 if (oldLimit != i) {
435 manager.getConfig().setRecentsLimit(i);
436 manager.checkRecentsLimit();
439 catch (NumberFormatException e) {
440 // ignore
443 setModified(false);
446 private void applyByType(ConfigurationType type) throws ConfigurationException {
447 DefaultMutableTreeNode typeNode = getConfigurationTypeNode(type);
448 final RunManagerImpl manager = getRunManager();
449 final ArrayList<RunConfigurationBean> stableConfigurations = new ArrayList<RunConfigurationBean>();
450 if (typeNode != null) {
451 for (int i = 0; i < typeNode.getChildCount(); i++) {
452 final Object userObject = ((DefaultMutableTreeNode)typeNode.getChildAt(i)).getUserObject();
453 if (userObject instanceof SingleConfigurationConfigurable) {
454 final SingleConfigurationConfigurable configurable = (SingleConfigurationConfigurable)userObject;
455 final RunnerAndConfigurationSettingsImpl settings = (RunnerAndConfigurationSettingsImpl)configurable.getSettings();
456 if (manager.isTemporary(settings)) {
457 applyConfiguration(typeNode, configurable);
459 stableConfigurations.add(new RunConfigurationBean(configurable));
461 else if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
462 RunnerAndConfigurationSettingsImpl settings = (RunnerAndConfigurationSettingsImpl)userObject;
463 stableConfigurations.add(new RunConfigurationBean(settings,
464 manager.isConfigurationShared(settings),
465 manager.getBeforeRunTasks(settings.getConfiguration())));
469 // try to apply all
470 for (RunConfigurationBean bean : stableConfigurations) {
471 final SingleConfigurationConfigurable configurable = bean.getConfigurable();
472 if (configurable != null) {
473 applyConfiguration(typeNode, configurable);
477 // if apply succeeded, update the list of configurations in RunManager
478 manager.removeConfigurations(type);
479 for (final RunConfigurationBean stableConfiguration : stableConfigurations) {
480 manager.addConfiguration(stableConfiguration.getSettings(),
481 stableConfiguration.isShared(),
482 stableConfiguration.getStepsBeforeLaunch());
486 @Nullable
487 private DefaultMutableTreeNode getConfigurationTypeNode(final ConfigurationType type) {
488 for (int i = 0; i < myRoot.getChildCount(); i++) {
489 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)myRoot.getChildAt(i);
490 if (node.getUserObject() == type) return node;
492 return null;
495 private void applyConfiguration(DefaultMutableTreeNode typeNode, SingleConfigurationConfigurable configurable)
496 throws ConfigurationException {
497 try {
498 if (configurable != null) configurable.apply();
500 catch (ConfigurationException e) {
501 for (int i = 0; i < typeNode.getChildCount(); i++) {
502 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)typeNode.getChildAt(i);
503 if (Comparing.equal(configurable, node.getUserObject())) {
504 TreeUtil.selectNode(myTree, node);
505 break;
508 throw e;
512 public boolean isModified() {
513 if (super.isModified()) return true;
514 final RunManagerImpl runManager = getRunManager();
515 final RunnerAndConfigurationSettingsImpl settings = runManager.getSelectedConfiguration();
516 if (mySelectedConfigurable == null) {
517 return settings != null;
519 if (settings == null ||
520 !Comparing.strEqual(mySelectedConfigurable.getConfiguration().getType().getId(), settings.getType().getId()) ||
521 (Comparing.strEqual(mySelectedConfigurable.getConfiguration().getType().getId(), settings.getType().getId()) &&
522 !Comparing.strEqual(mySelectedConfigurable.getNameText(), settings.getConfiguration().getName()))) {
523 return true;
525 final RunConfiguration[] allConfigurations = runManager.getAllConfigurations();
526 final Set<RunConfiguration> currentConfigurations = new HashSet<RunConfiguration>();
527 for (int i = 0; i < myRoot.getChildCount(); i++) {
528 DefaultMutableTreeNode typeNode = (DefaultMutableTreeNode)myRoot.getChildAt(i);
529 final RunnerAndConfigurationSettingsImpl[] configurationSettings =
530 runManager.getConfigurationSettings((ConfigurationType)typeNode.getUserObject());
531 if (configurationSettings.length != typeNode.getChildCount()) return true;
532 for (int j = 0; j < typeNode.getChildCount(); j++) {
533 final Object userObject = ((DefaultMutableTreeNode)typeNode.getChildAt(j)).getUserObject();
534 if (userObject instanceof SingleConfigurationConfigurable) {
535 SingleConfigurationConfigurable configurable = (SingleConfigurationConfigurable)userObject;
536 if (!Comparing.strEqual(configurationSettings[j].getConfiguration().getName(), configurable.getConfiguration().getName())) {
537 return true;
539 if (configurable.isModified()) return true;
540 currentConfigurations.add(configurable.getConfiguration());
542 else if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
543 currentConfigurations.add(((RunnerAndConfigurationSettingsImpl)userObject).getConfiguration());
547 for (RunConfiguration configuration : allConfigurations) {
548 if (!currentConfigurations.contains(configuration)) return true;
550 return false;
553 public void disposeUIResources() {
554 TreeUtil.traverseDepth(myRoot, new TreeUtil.Traverse() {
555 public boolean accept(Object node) {
556 if (node instanceof DefaultMutableTreeNode) {
557 final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node;
558 final Object userObject = treeNode.getUserObject();
559 if (userObject instanceof SingleConfigurationConfigurable) {
560 ((SingleConfigurationConfigurable)userObject).disposeUIResources();
563 return true;
566 myRightPanel.removeAll();
567 myConfig.setFloat(DIVIDER_PROPORTION, myPanel.getProportion());
568 myPanel.dispose();
571 private void updateDialog() {
572 if (myRunDialog == null) return;
573 final StringBuilder buffer = new StringBuilder();
574 Executor executor = myRunDialog.getExecutor();
575 buffer.append(executor.getId());
576 final SingleConfigurationConfigurable<RunConfiguration> configuration = getSelectedConfiguration();
577 if (configuration != null) {
578 buffer.append(" - ");
579 buffer.append(configuration.getNameText());
581 myRunDialog.setOKActionEnabled(canRunConfiguration(configuration, executor));
582 myRunDialog.setTitle(buffer.toString());
585 private void setupDialogBounds() {
586 SwingUtilities.invokeLater(new Runnable() {
587 public void run() {
588 UIUtil.setupEnclosingDialogBounds(myWholePanel);
593 @Nullable
594 private SingleConfigurationConfigurable<RunConfiguration> getSelectedConfiguration() {
595 final TreePath selectionPath = myTree.getSelectionPath();
596 if (selectionPath != null) {
597 final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
598 final Object userObject = treeNode.getUserObject();
599 if (userObject instanceof SingleConfigurationConfigurable) {
600 return (SingleConfigurationConfigurable<RunConfiguration>)userObject;
603 return null;
606 private static boolean canRunConfiguration(@Nullable SingleConfigurationConfigurable<RunConfiguration> configuration, final @NotNull Executor executor) {
607 try {
608 return configuration != null && RunManagerImpl.canRunConfiguration(configuration.getSnapshot(), executor);
610 catch (ConfigurationException e) {
611 return false;
615 private RunManagerImpl getRunManager() {
616 return RunManagerImpl.getInstanceImpl(myProject);
619 public String getHelpTopic() {
620 final ConfigurationType type = getSelectedConfigurationType();
621 if (type != null) {
622 return "reference.dialogs.rundebug." + type.getId();
624 return "reference.dialogs.rundebug";
627 private void clickDefaultButton() {
628 if (myRunDialog != null) myRunDialog.clickDefaultButton();
631 private DefaultMutableTreeNode getSelectedConfigurationTypeNode() {
632 final DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getSelectionPath().getLastPathComponent();
633 final Object userObject = node.getUserObject();
634 if (userObject instanceof ConfigurationType) {
635 return node;
637 else {
638 return (DefaultMutableTreeNode)node.getParent();
642 private static String createUniqueName(DefaultMutableTreeNode typeNode) {
643 String str = ExecutionBundle.message("run.configuration.unnamed.name.prefix");
644 final ArrayList<String> currentNames = new ArrayList<String>();
645 for (int i = 0; i < typeNode.getChildCount(); i++) {
646 final Object userObject = ((DefaultMutableTreeNode)typeNode.getChildAt(i)).getUserObject();
647 if (userObject instanceof SingleConfigurationConfigurable) {
648 currentNames.add(((SingleConfigurationConfigurable)userObject).getNameText());
650 else if (userObject instanceof RunnerAndConfigurationSettingsImpl) {
651 currentNames.add(((RunnerAndConfigurationSettingsImpl)userObject).getName());
654 if (!currentNames.contains(str)) return str;
655 int i = 1;
656 while (true) {
657 if (!currentNames.contains(str + i)) return str + i;
658 i++;
662 private SingleConfigurationConfigurable<RunConfiguration> createNewConfiguration(final RunnerAndConfigurationSettingsImpl settings, final DefaultMutableTreeNode node) {
663 final SingleConfigurationConfigurable<RunConfiguration> configurationConfigurable =
664 SingleConfigurationConfigurable.editSettings(settings);
665 installUpdateListeners(configurationConfigurable);
666 DefaultMutableTreeNode nodeToAdd = new DefaultMutableTreeNode(configurationConfigurable);
667 node.add(nodeToAdd);
668 ((DefaultTreeModel)myTree.getModel()).reload(node);
669 TreeUtil.selectNode(myTree, nodeToAdd);
670 return configurationConfigurable;
673 private void createNewConfiguration(final ConfigurationFactory factory) {
674 DefaultMutableTreeNode node = null;
675 for (int i = 0; i < myRoot.getChildCount(); i++) {
676 final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)myRoot.getChildAt(i);
677 if (treeNode.getUserObject() == factory.getType()) {
678 node = treeNode;
679 break;
682 if (node == null) {
683 node = new DefaultMutableTreeNode(factory.getType());
684 myRoot.add(node);
685 sortTree(myRoot);
686 ((DefaultTreeModel)myTree.getModel()).reload();
688 final RunnerAndConfigurationSettingsImpl settings = getRunManager().createConfiguration(createUniqueName(node), factory);
689 createNewConfiguration(settings, node);
692 private class MyToolbarAddAction extends AnAction {
693 public MyToolbarAddAction() {
694 super(ExecutionBundle.message("add.new.run.configuration.acrtion.name"),
695 ExecutionBundle.message("add.new.run.configuration.acrtion.name"), ADD_ICON);
696 registerCustomShortcutSet(CommonShortcuts.INSERT, myTree);
699 public void actionPerformed(AnActionEvent e) {
700 final JBPopupFactory popupFactory = JBPopupFactory.getInstance();
701 final ConfigurationType[] configurationTypes = getRunManager().getConfigurationFactories(false);
702 Arrays.sort(configurationTypes, new Comparator<ConfigurationType>() {
703 public int compare(final ConfigurationType type1, final ConfigurationType type2) {
704 return type1.getDisplayName().compareTo(type2.getDisplayName());
707 final ListPopup popup =
708 popupFactory.createWizardStep(new BaseListPopupStep<ConfigurationType>(
709 ExecutionBundle.message("add.new.run.configuration.acrtion.name"), configurationTypes) {
711 @NotNull
712 public String getTextFor(final ConfigurationType type) {
713 return type.getDisplayName();
717 public Icon getIconFor(final ConfigurationType type) {
718 return type.getIcon();
721 public PopupStep onChosen(final ConfigurationType type, final boolean finalChoice) {
722 if (hasSubstep(type)) {
723 return getSupStep(type);
725 final ConfigurationFactory[] factories = type.getConfigurationFactories();
726 if (factories.length > 0) {
727 createNewConfiguration(factories[0]);
729 return PopupStep.FINAL_CHOICE;
732 public int getDefaultOptionIndex() {
733 final TreePath selectionPath = myTree.getSelectionPath();
734 if (selectionPath != null) {
735 DefaultMutableTreeNode node = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
736 final Object userObject = node.getUserObject();
737 ConfigurationType type = null;
738 if (userObject instanceof SingleConfigurationConfigurable) {
739 final SingleConfigurationConfigurable configurable = (SingleConfigurationConfigurable)userObject;
740 type = configurable.getConfiguration().getType();
742 else if (userObject instanceof ConfigurationType) {
743 type = (ConfigurationType)userObject;
745 return ArrayUtil.find(configurationTypes, type);
747 return super.getDefaultOptionIndex();
750 private ListPopupStep getSupStep(final ConfigurationType type) {
751 final ConfigurationFactory[] factories = type.getConfigurationFactories();
752 Arrays.sort(factories, new Comparator<ConfigurationFactory>() {
753 public int compare(final ConfigurationFactory factory1, final ConfigurationFactory factory2) {
754 return factory1.getName().compareTo(factory2.getName());
757 return new BaseListPopupStep<ConfigurationFactory>(
758 ExecutionBundle.message("add.new.run.configuration.action.name", type.getDisplayName()), factories) {
760 @NotNull
761 public String getTextFor(final ConfigurationFactory value) {
762 return value.getName();
765 public Icon getIconFor(final ConfigurationFactory factory) {
766 return factory.getIcon();
769 public PopupStep onChosen(final ConfigurationFactory factory, final boolean finalChoice) {
770 createNewConfiguration(factory);
771 return PopupStep.FINAL_CHOICE;
777 public boolean hasSubstep(final ConfigurationType type) {
778 return type.getConfigurationFactories().length > 1;
782 popup.showUnderneathOf(myToolbarComponent);
787 private class MyRemoveAction extends AnAction {
789 public MyRemoveAction() {
790 super(ExecutionBundle.message("remove.run.configuration.action.name"),
791 ExecutionBundle.message("remove.run.configuration.action.name"), REMOVE_ICON);
792 registerCustomShortcutSet(CommonShortcuts.DELETE, myTree);
795 public void actionPerformed(AnActionEvent e) {
796 TreePath[] selections = myTree.getSelectionPaths();
797 myTree.clearSelection();
799 int nodeIndexToSelect = -1;
800 DefaultMutableTreeNode parentToSelect = null;
802 Set<DefaultMutableTreeNode> changedParents = new HashSet<DefaultMutableTreeNode>();
803 boolean wasRootChanged = false;
805 for (TreePath each : selections) {
806 DefaultMutableTreeNode node = (DefaultMutableTreeNode)each.getLastPathComponent();
807 if (node.getUserObject() instanceof ConfigurationType) continue;
809 if (node.getUserObject() instanceof SingleConfigurationConfigurable) {
810 ((SingleConfigurationConfigurable)node.getUserObject()).disposeUIResources();
813 DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent();
814 nodeIndexToSelect = parent.getIndex(node);
815 parentToSelect = parent;
816 parent.remove(node);
817 changedParents.add(parent);
819 if (parent.getChildCount() == 0) {
820 changedParents.remove(parent);
821 wasRootChanged = true;
823 nodeIndexToSelect = myRoot.getIndex(parent);
824 parentToSelect = myRoot;
825 myRoot.remove(parent);
829 if (wasRootChanged) {
830 ((DefaultTreeModel)myTree.getModel()).reload();
831 } else {
832 for (DefaultMutableTreeNode each : changedParents) {
833 ((DefaultTreeModel)myTree.getModel()).reload(each);
834 myTree.expandPath(new TreePath(each));
838 mySelectedConfigurable = null;
839 if (myRoot.getChildCount() == 0) {
840 drawPressAddButtonMessage(null);
842 else {
843 TreeNode nodeToSelect = nodeIndexToSelect < parentToSelect.getChildCount()
844 ? parentToSelect.getChildAt(nodeIndexToSelect)
845 : parentToSelect.getChildAt(nodeIndexToSelect - 1);
846 TreeUtil.selectInTree((DefaultMutableTreeNode)nodeToSelect, true, myTree);
851 public void update(AnActionEvent e) {
852 boolean enabled = false;
853 TreePath[] selections = myTree.getSelectionPaths();
854 if (selections != null) {
855 for (TreePath each : selections) {
856 DefaultMutableTreeNode node = (DefaultMutableTreeNode)each.getLastPathComponent();
857 if (!(node.getUserObject() instanceof ConfigurationType)) {
858 enabled = true;
859 break;
863 e.getPresentation().setEnabled(enabled);
867 private class MyCopyAction extends AnAction {
868 public MyCopyAction() {
869 super(ExecutionBundle.message("copy.configuration.action.name"),
870 ExecutionBundle.message("copy.configuration.action.name"),
871 COPY_ICON);
873 final AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_EDITOR_DUPLICATE);
874 registerCustomShortcutSet(action.getShortcutSet(), myTree);
878 public void actionPerformed(AnActionEvent e) {
879 final SingleConfigurationConfigurable<RunConfiguration> configuration = getSelectedConfiguration();
880 LOG.assertTrue(configuration != null);
881 try {
882 final DefaultMutableTreeNode typeNode = getSelectedConfigurationTypeNode();
883 final RunnerAndConfigurationSettingsImpl settings = configuration.getSnapshot();
884 final String copyName = createUniqueName(typeNode);
885 settings.setName(copyName);
886 final SingleConfigurationConfigurable<RunConfiguration> configurable = createNewConfiguration(settings, typeNode);
887 IdeFocusManager.getInstance(myProject).requestFocus(configurable.getNameTextField(), true);
888 configurable.getNameTextField().setSelectionStart(0);
889 configurable.getNameTextField().setSelectionEnd(copyName.length());
891 catch (ConfigurationException e1) {
892 Messages.showErrorDialog(myToolbarComponent, e1.getMessage(), e1.getTitle());
896 public void update(AnActionEvent e) {
897 final SingleConfigurationConfigurable<RunConfiguration> configuration = getSelectedConfiguration();
898 e.getPresentation().setEnabled(configuration != null && !(configuration.getConfiguration() instanceof UnknownRunConfiguration));
902 private class MySaveAction extends AnAction {
904 public MySaveAction() {
905 super(ExecutionBundle.message("action.name.save.configuration"), null, SAVE_ICON);
908 public void actionPerformed(final AnActionEvent e) {
909 final SingleConfigurationConfigurable<RunConfiguration> configurationConfigurable = getSelectedConfiguration();
910 LOG.assertTrue(configurationConfigurable != null);
911 try {
912 configurationConfigurable.apply();
914 catch (ConfigurationException e1) {
915 //do nothing
917 final RunnerAndConfigurationSettingsImpl originalConfiguration = configurationConfigurable.getSettings();
918 if (getRunManager().isTemporary(originalConfiguration)) {
919 getRunManager().makeStable(originalConfiguration.getConfiguration());
921 myTree.repaint();
924 public void update(final AnActionEvent e) {
925 final SingleConfigurationConfigurable<RunConfiguration> configuration = getSelectedConfiguration();
926 final Presentation presentation = e.getPresentation();
927 final boolean enabled = configuration != null && getRunManager().isTemporary(configuration.getSettings());
928 presentation.setEnabled(enabled);
929 presentation.setVisible(enabled);
933 private class MyMoveAction extends AnAction {
934 private final int myDirection;
936 protected MyMoveAction(String text, String description, Icon icon, int direction) {
937 super(text, description, icon);
938 myDirection = direction;
941 public void actionPerformed(final AnActionEvent e) {
942 TreeUtil.moveSelectedRow(myTree, myDirection);
945 public void update(final AnActionEvent e) {
946 final Presentation presentation = e.getPresentation();
947 presentation.setEnabled(false);
948 final TreePath selectionPath = myTree.getSelectionPath();
949 if (selectionPath != null) {
950 final DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)selectionPath.getLastPathComponent();
951 if (treeNode.getUserObject() instanceof SingleConfigurationConfigurable) {
952 if (myDirection < 0) {
953 presentation.setEnabled(treeNode.getPreviousSibling() != null);
955 else {
956 presentation.setEnabled(treeNode.getNextSibling() != null);
963 private static class RunConfigurationBean {
964 private final RunnerAndConfigurationSettingsImpl mySettings;
965 private final boolean myShared;
966 private final Map<Key<? extends BeforeRunTask>, BeforeRunTask> myStepsBeforeLaunch;
967 private final SingleConfigurationConfigurable myConfigurable;
969 public RunConfigurationBean(final RunnerAndConfigurationSettingsImpl settings,
970 final boolean shared,
971 final Map<Key<? extends BeforeRunTask>, BeforeRunTask> stepsBeforeLaunch) {
972 mySettings = settings;
973 myShared = shared;
974 myStepsBeforeLaunch = Collections.unmodifiableMap(stepsBeforeLaunch);
975 myConfigurable = null;
978 public RunConfigurationBean(final SingleConfigurationConfigurable configurable) {
979 myConfigurable = configurable;
980 mySettings = (RunnerAndConfigurationSettingsImpl)myConfigurable.getSettings();
981 final ConfigurationSettingsEditorWrapper editorWrapper = (ConfigurationSettingsEditorWrapper)myConfigurable.getEditor();
982 myShared = editorWrapper.isStoreProjectConfiguration();
983 myStepsBeforeLaunch = editorWrapper.getStepsBeforeLaunch();
986 public RunnerAndConfigurationSettingsImpl getSettings() {
987 return mySettings;
990 public boolean isShared() {
991 return myShared;
994 public Map<Key<? extends BeforeRunTask>, BeforeRunTask> getStepsBeforeLaunch() {
995 return myStepsBeforeLaunch;
998 public SingleConfigurationConfigurable getConfigurable() {
999 return myConfigurable;