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
;
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
;
61 import java
.awt
.event
.ActionEvent
;
62 import java
.awt
.event
.ActionListener
;
63 import java
.awt
.event
.KeyEvent
;
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
) {
95 public RunConfigurable(final Project project
, final RunDialog runDialog
) {
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
,
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());
123 final RunManager runManager
= getRunManager();
124 RunConfiguration configuration
= 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
);
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() {
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
);
210 mySelectedConfigurable
= null;
212 TreeUtil
.selectFirstNode(myTree
);
213 drawPressAddButtonMessage(null);
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
);
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());
241 private void update() {
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
) {
258 info
.addNameListner(new DocumentListener() {
259 public void insertUpdate(DocumentEvent e
) {
263 public void removeUpdate(DocumentEvent e
) {
267 public void changedUpdate(DocumentEvent e
) {
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);
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
);
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() {
338 protected void textChanged(DocumentEvent e
) {
342 box
.add(Box
.createHorizontalGlue());
343 bottomPanel
.add(box
, BorderLayout
.CENTER
);
345 leftPanel
.add(bottomPanel
, BorderLayout
.SOUTH
);
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));
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
);
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
);
401 public Icon
getIcon() {
405 public void reset() {
406 final RunManagerEx manager
= getRunManager();
407 final RunManagerConfig config
= manager
.getConfig();
408 myRecentsLimit
.setText(Integer
.toString(config
.getRecentsLimit()));
412 private Project
getProject() {
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());
427 manager
.setSelectedConfiguration(null);
430 String recentsLimit
= myRecentsLimit
.getText();
432 int i
= Integer
.parseInt(recentsLimit
);
433 int oldLimit
= manager
.getConfig().getRecentsLimit();
435 manager
.getConfig().setRecentsLimit(i
);
436 manager
.checkRecentsLimit();
439 catch (NumberFormatException e
) {
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())));
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());
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
;
495 private void applyConfiguration(DefaultMutableTreeNode typeNode
, SingleConfigurationConfigurable configurable
)
496 throws ConfigurationException
{
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
);
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()))) {
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())) {
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;
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();
566 myRightPanel
.removeAll();
567 myConfig
.setFloat(DIVIDER_PROPORTION
, myPanel
.getProportion());
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() {
588 UIUtil
.setupEnclosingDialogBounds(myWholePanel
);
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
;
606 private static boolean canRunConfiguration(@Nullable SingleConfigurationConfigurable
<RunConfiguration
> configuration
, final @NotNull Executor executor
) {
608 return configuration
!= null && RunManagerImpl
.canRunConfiguration(configuration
.getSnapshot(), executor
);
610 catch (ConfigurationException e
) {
615 private RunManagerImpl
getRunManager() {
616 return RunManagerImpl
.getInstanceImpl(myProject
);
619 public String
getHelpTopic() {
620 final ConfigurationType type
= getSelectedConfigurationType();
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
) {
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
;
657 if (!currentNames
.contains(str
+ i
)) return str
+ 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
);
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()) {
683 node
= new DefaultMutableTreeNode(factory
.getType());
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
) {
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
) {
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
;
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();
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);
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
)) {
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"),
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);
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);
912 configurationConfigurable
.apply();
914 catch (ConfigurationException e1
) {
917 final RunnerAndConfigurationSettingsImpl originalConfiguration
= configurationConfigurable
.getSettings();
918 if (getRunManager().isTemporary(originalConfiguration
)) {
919 getRunManager().makeStable(originalConfiguration
.getConfiguration());
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);
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
;
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() {
990 public boolean isShared() {
994 public Map
<Key
<?
extends BeforeRunTask
>, BeforeRunTask
> getStepsBeforeLaunch() {
995 return myStepsBeforeLaunch
;
998 public SingleConfigurationConfigurable
getConfigurable() {
999 return myConfigurable
;