51a96197ba488fec67959a95550a926bef71a252
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / ui / DebuggerSessionTab.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.debugger.ui;
17
18 import com.intellij.debugger.DebugUIEnvironment;
19 import com.intellij.debugger.DebuggerBundle;
20 import com.intellij.debugger.actions.DebuggerActions;
21 import com.intellij.debugger.engine.DebugProcessImpl;
22 import com.intellij.debugger.engine.evaluation.EvaluateException;
23 import com.intellij.debugger.engine.evaluation.TextWithImports;
24 import com.intellij.debugger.impl.DebuggerContextImpl;
25 import com.intellij.debugger.impl.DebuggerContextListener;
26 import com.intellij.debugger.impl.DebuggerSession;
27 import com.intellij.debugger.impl.DebuggerStateManager;
28 import com.intellij.debugger.settings.DebuggerSettings;
29 import com.intellij.debugger.ui.impl.MainWatchPanel;
30 import com.intellij.debugger.ui.impl.ThreadsPanel;
31 import com.intellij.debugger.ui.impl.VariablesPanel;
32 import com.intellij.debugger.ui.impl.WatchDebuggerTree;
33 import com.intellij.debugger.ui.impl.watch.*;
34 import com.intellij.execution.DefaultExecutionResult;
35 import com.intellij.execution.ExecutionManager;
36 import com.intellij.execution.ExecutionResult;
37 import com.intellij.execution.configurations.RunProfile;
38 import com.intellij.execution.executors.DefaultDebugExecutor;
39 import com.intellij.execution.filters.ExceptionFilters;
40 import com.intellij.execution.filters.TextConsoleBuilder;
41 import com.intellij.execution.filters.TextConsoleBuilderFactory;
42 import com.intellij.execution.ui.ConsoleView;
43 import com.intellij.execution.ui.ExecutionConsoleEx;
44 import com.intellij.execution.ui.RunnerLayoutUi;
45 import com.intellij.execution.ui.layout.PlaceInGrid;
46 import com.intellij.icons.AllIcons;
47 import com.intellij.idea.ActionsBundle;
48 import com.intellij.openapi.Disposable;
49 import com.intellij.openapi.actionSystem.*;
50 import com.intellij.openapi.application.ApplicationManager;
51 import com.intellij.openapi.diagnostic.Logger;
52 import com.intellij.openapi.project.Project;
53 import com.intellij.openapi.util.Disposer;
54 import com.intellij.ui.content.AlertIcon;
55 import com.intellij.ui.content.Content;
56 import com.intellij.ui.content.ContentManagerAdapter;
57 import com.intellij.ui.content.ContentManagerEvent;
58 import com.intellij.ui.content.tabs.PinToolwindowTabAction;
59 import com.intellij.unscramble.ThreadDumpPanel;
60 import com.intellij.unscramble.ThreadState;
61 import com.intellij.xdebugger.XDebuggerBundle;
62 import com.intellij.xdebugger.impl.actions.XDebuggerActions;
63 import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager;
64 import com.intellij.xdebugger.impl.ui.DebuggerSessionTabBase;
65 import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants;
66 import org.jetbrains.annotations.NotNull;
67 import org.jetbrains.annotations.Nullable;
68
69 import javax.swing.*;
70 import javax.swing.tree.TreePath;
71 import java.util.List;
72
73 public class DebuggerSessionTab extends DebuggerSessionTabBase implements Disposable {
74   private static final Logger LOG = Logger.getInstance(DebuggerSessionTab.class);
75
76   private final VariablesPanel myVariablesPanel;
77   private final MainWatchPanel myWatchPanel;
78
79   private volatile DebuggerSession myDebuggerSession;
80
81   private final MyDebuggerStateManager myStateManager = new MyDebuggerStateManager();
82
83   private final FramesPanel myFramesPanel;
84   private final DebugUIEnvironment myDebugUIEnvironment;
85
86   private final ThreadsPanel myThreadsPanel;
87   private static final String THREAD_DUMP_CONTENT_PREFIX = "Dump";
88
89   public DebuggerSessionTab(final Project project, final String sessionName, @NotNull final DebugUIEnvironment environment,
90                             @NotNull DebuggerSession debuggerSession) {
91     super(project, "JavaDebugger", sessionName, debuggerSession.getSearchScope());
92
93     myDebuggerSession = debuggerSession;
94     myDebugUIEnvironment = environment;
95
96     final DefaultActionGroup focus = new DefaultActionGroup();
97     focus.add(ActionManager.getInstance().getAction("Debugger.FocusOnBreakpoint"));
98     myUi.getOptions().setAdditionalFocusActions(focus);
99
100     final DebuggerSettings debuggerSettings = DebuggerSettings.getInstance();
101     if (!ApplicationManager.getApplication().isUnitTestMode()) {
102       getContextManager().addListener(new DebuggerContextListener() {
103         @Override
104         public void changeEvent(DebuggerContextImpl newContext, int event) {
105           switch (event) {
106             case DebuggerSession.EVENT_DETACHED:
107               myUi.updateActionsNow();
108
109               if (XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().isHideDebuggerOnProcessTermination()) {
110                 try {
111                   ExecutionManager.getInstance(project).getContentManager().hideRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
112                 }
113                 catch (NullPointerException e) {
114                   //if we can get closeProcess after the project have been closed
115                   LOG.debug(e);
116                 }
117               }
118               break;
119           }
120         }
121       });
122     }
123
124     DefaultActionGroup topToolbar = new DefaultActionGroup();
125     ActionManager actionManager = ActionManager.getInstance();
126     topToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP));
127     topToolbar.add(actionManager.getAction(DebuggerActions.POP_FRAME), new Constraints(Anchor.AFTER, XDebuggerActions.STEP_OUT));
128     topToolbar.add(Separator.getInstance(), new Constraints(Anchor.BEFORE, DebuggerActions.POP_FRAME));
129     topToolbar.add(Separator.getInstance(), new Constraints(Anchor.AFTER, DebuggerActions.POP_FRAME));
130     myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
131
132     myWatchPanel = new MainWatchPanel(project, getContextManager());
133     myFramesPanel = new FramesPanel(project, getContextManager());
134
135     final AlertIcon breakpointAlert = new AlertIcon(AllIcons.Debugger.BreakpointAlert);
136
137     // watches
138     Content watches = myUi.createContent(DebuggerContentInfo.WATCHES_CONTENT, myWatchPanel, XDebuggerBundle.message("debugger.session.tab.watches.title"),
139                                          AllIcons.Debugger.Watches, null);
140     watches.setCloseable(false);
141     watches.setAlertIcon(breakpointAlert);
142     myUi.addContent(watches, 0, PlaceInGrid.right, false);
143
144     // frames
145     Content framesContent = myUi.createContent(DebuggerContentInfo.FRAME_CONTENT, myFramesPanel, XDebuggerBundle.message("debugger.session.tab.frames.title"),
146                                                AllIcons.Debugger.Frame, myFramesPanel.getFramesList());
147     framesContent.setCloseable(false);
148     framesContent.setAlertIcon(breakpointAlert);
149
150     myUi.addContent(framesContent, 0, PlaceInGrid.left, false);
151
152     // variables
153     myVariablesPanel = new VariablesPanel(project, myStateManager, this);
154     myVariablesPanel.getFrameTree().setAutoVariablesMode(debuggerSettings.AUTO_VARIABLES_MODE);
155     Content vars = myUi.createContent(DebuggerContentInfo.VARIABLES_CONTENT, myVariablesPanel, XDebuggerBundle.message("debugger.session.tab.variables.title"),
156                                       AllIcons.Debugger.Value, null);
157     vars.setCloseable(false);
158     vars.setAlertIcon(breakpointAlert);
159     myUi.addContent(vars, 0, PlaceInGrid.center, false);
160
161     // threads
162     myThreadsPanel = new ThreadsPanel(project, getContextManager());
163     Content threadsContent = myUi.createContent(DebuggerContentInfo.THREADS_CONTENT, myThreadsPanel, XDebuggerBundle.message("debugger.session.tab.threads.title"),
164                                                 AllIcons.Debugger.Threads, null);
165     threadsContent.setCloseable(false);
166     //threadsContent.setAlertIcon(breakpointAlert);
167
168     //final DefaultActionGroup threadsGroup = new DefaultActionGroup();
169     //threadsContent.setActions(threadsGroup, ActionPlaces.DEBUGGER_TOOLBAR, threadsPanel.getThreadsTree());
170
171     myUi.addContent(threadsContent, 0, PlaceInGrid.left, true);
172
173     for (Content each : myUi.getContents()) {
174       updateStatus(each);
175     }
176
177     myUi.addListener(new ContentManagerAdapter() {
178       @Override
179       public void selectionChanged(ContentManagerEvent event) {
180         updateStatus(event.getContent());
181       }
182     }, this);
183
184     debuggerSession.getContextManager().addListener(new DebuggerContextListener() {
185       @Override
186       public void changeEvent(DebuggerContextImpl newContext, int event) {
187         if (!myUi.isDisposed()) {
188           attractFramesOnPause(event);
189           myStateManager.fireStateChanged(newContext, event);
190           SwingUtilities.invokeLater(new Runnable() {
191             @Override
192             public void run() {
193               if (!myUi.isDisposed()) {
194                 myUi.updateActionsNow();
195               }
196             }
197           });
198         }
199       }
200     });
201
202 //    ExecutionResult executionResult = debuggerSession.getProcess().getExecutionResult();
203 //    myConsole = executionResult.getExecutionConsole();
204 //    myRunContentDescriptor = new RunContentDescriptor(myConsole, executionResult.getProcessHandler(), myUi.getComponent(), getSessionName(),
205 //                                                      environment.getIcon());
206 //    initUI(executionResult);
207   }
208
209   private static void updateStatus(final Content content) {
210     if (content.getComponent() instanceof DebuggerView) {
211       final DebuggerView view = (DebuggerView)content.getComponent();
212       if (content.isSelected()) {
213         view.setUpdateEnabled(true);
214         if (view.isRefreshNeeded()) {
215           view.rebuildIfVisible(DebuggerSession.EVENT_CONTEXT);
216         }
217       }
218       else {
219         view.setUpdateEnabled(false);
220       }
221     }
222   }
223
224   public MainWatchPanel getWatchPanel() {
225     return myWatchPanel;
226   }
227
228   private void initUI(ExecutionResult executionResult) {
229     if (ApplicationManager.getApplication().isUnitTestMode()) {
230       return;
231     }
232
233
234     myUi.removeContent(myUi.findContent(DebuggerContentInfo.CONSOLE_CONTENT), true);
235
236     Content console = null;
237     if (myConsole instanceof ExecutionConsoleEx) {
238       ((ExecutionConsoleEx)myConsole).buildUi(myUi);
239       console = myUi.findContent(DebuggerContentInfo.CONSOLE_CONTENT);
240       if (console == null) {
241         LOG.debug("Reuse console created with non-debug runner");
242       }
243     }
244     if (console == null) {
245       console = myUi.createContent(DebuggerContentInfo.CONSOLE_CONTENT, myConsole.getComponent(),
246                                            XDebuggerBundle.message("debugger.session.tab.console.content.name"),
247                                            AllIcons.Debugger.Console, myConsole.getPreferredFocusableComponent());
248
249       console.setCloseable(false);
250       myUi.addContent(console, 1, PlaceInGrid.bottom, false);
251     }
252     attachNotificationTo(console);
253
254     if (myConsole != null) {
255       Disposer.register(this, myConsole);
256     }
257
258     final DefaultActionGroup consoleActions = new DefaultActionGroup();
259     if (myConsole instanceof ConsoleView) {
260       AnAction[] actions = ((ConsoleView)myConsole).createConsoleActions();
261       for (AnAction goAction : actions) {
262         consoleActions.add(goAction);
263       }
264     }
265     console.setActions(consoleActions, ActionPlaces.DEBUGGER_TOOLBAR, myConsole.getPreferredFocusableComponent());
266
267 //    myDebugUIEnvironment.initLogs(myRunContentDescriptor, myManager);
268
269     DefaultActionGroup leftToolbar = new DefaultActionGroup();
270
271     if (executionResult instanceof DefaultExecutionResult) {
272       final AnAction[] actions = ((DefaultExecutionResult)executionResult).getRestartActions();
273         leftToolbar.addAll(actions);
274         if (actions.length > 0) {
275           leftToolbar.addSeparator();
276         }
277     }
278     final AnAction[] profileActions = executionResult.getActions();
279     leftToolbar.addAll(profileActions);
280
281     leftToolbar.add(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_LEFT_TOOLBAR_GROUP));
282     if (executionResult instanceof DefaultExecutionResult) {
283       AnAction[] actions = ((DefaultExecutionResult)executionResult).getAdditionalStopActions();
284       for (AnAction action : actions) {
285         leftToolbar.add(action, new Constraints(Anchor.AFTER, IdeActions.ACTION_STOP_PROGRAM));
286       }
287     }
288
289     leftToolbar.addSeparator();
290     addAction(leftToolbar, DebuggerActions.DUMP_THREADS);
291     leftToolbar.addSeparator();
292
293     leftToolbar.add(myUi.getOptions().getLayoutActions());
294
295     final AnAction[] commonSettings = myUi.getOptions().getSettingsActionsList();
296     final AnAction commonSettingsList = myUi.getOptions().getSettingsActions();
297
298     final DefaultActionGroup settings = new DefaultActionGroup("DebuggerSettings", true) {
299       @Override
300       public void update(AnActionEvent e) {
301         e.getPresentation().setText(ActionsBundle.message("group.XDebugger.settings.text"));
302         e.getPresentation().setIcon(commonSettingsList.getTemplatePresentation().getIcon());
303       }
304
305       @Override
306       public boolean isDumbAware() {
307         return true;
308       }
309     };
310     for (AnAction each : commonSettings) {
311       settings.add(each);
312     }
313     if (commonSettings.length > 0) {
314       settings.addSeparator();
315     }
316     settings.add(new WatchLastMethodReturnValueAction());
317     settings.add(new AutoVarsSwitchAction());
318     settings.addSeparator();
319     addActionToGroup(settings, XDebuggerActions.INLINE_DEBUGGER);
320     addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP);
321     addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP_ON_SELECTION);
322
323     leftToolbar.add(settings);
324
325     leftToolbar.addSeparator();
326
327     addActionToGroup(leftToolbar, PinToolwindowTabAction.ACTION_NAME);
328
329     myDebugUIEnvironment.initActions(myRunContentDescriptor, leftToolbar);
330
331     myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
332   }
333
334   private static void addAction(DefaultActionGroup group, String actionId) {
335     group.add(ActionManager.getInstance().getAction(actionId));
336   }
337
338   private static void addActionToGroup(final DefaultActionGroup group, final String actionId) {
339     AnAction action = ActionManager.getInstance().getAction(actionId);
340     if (action != null) group.add(action);
341   }
342
343   @Override
344   public void dispose() {
345     disposeSession();
346     myFramesPanel.dispose();
347     myVariablesPanel.dispose();
348     myWatchPanel.dispose();
349     myThreadsPanel.dispose();
350     myConsole = null;
351     super.dispose();
352   }
353
354   private void disposeSession() {
355     final DebuggerSession session = myDebuggerSession;
356     myDebuggerSession = null;
357     if (session != null) {
358       session.dispose();
359     }
360   }
361
362   @Nullable
363   private DebugProcessImpl getDebugProcess() {
364     final DebuggerSession session = myDebuggerSession;
365     return session != null ? session.getProcess() : null;
366   }
367
368   public void reuse(DebuggerSessionTab reuseSession) {
369     DebuggerTreeNodeImpl[] watches = reuseSession.getWatchPanel().getWatchTree().getWatches();
370
371     final WatchDebuggerTree watchTree = getWatchPanel().getWatchTree();
372     for (DebuggerTreeNodeImpl watch : watches) {
373       watchTree.addWatch((WatchItemDescriptor)watch.getDescriptor());
374     }
375
376     DebugProcessImpl process = getDebugProcess();
377     DebugProcessImpl reuseProcess = reuseSession.getDebugProcess();
378     if (process != null && reuseProcess != null) {
379       //process.setBreakpointsMuted(reuseProcess.areBreakpointsMuted());
380     }
381   }
382
383   public String getSessionName() {
384     return myDebugUIEnvironment.getEnvironment().getSessionName();
385   }
386
387   public DebuggerStateManager getContextManager() {
388     return myStateManager;
389   }
390
391   @Nullable
392   public TextWithImports getSelectedExpression() {
393     final DebuggerSession session = myDebuggerSession;
394     if (session == null || session.getState() != DebuggerSession.STATE_PAUSED) {
395       return null;
396     }
397     JTree tree = myVariablesPanel.getFrameTree();
398     if (tree == null || !tree.hasFocus()) {
399       tree = myWatchPanel.getWatchTree();
400       if (tree == null || !tree.hasFocus()) {
401         return null;
402       }
403     }
404     TreePath path = tree.getSelectionPath();
405     if (path == null) {
406       return null;
407     }
408     DebuggerTreeNodeImpl node = (DebuggerTreeNodeImpl)path.getLastPathComponent();
409     if (node == null) {
410       return null;
411     }
412     NodeDescriptorImpl descriptor = node.getDescriptor();
413     if (!(descriptor instanceof ValueDescriptorImpl)) {
414       return null;
415     }
416     if (descriptor instanceof WatchItemDescriptor) {
417       return ((WatchItemDescriptor)descriptor).getEvaluationText();
418     }
419     try {
420       return DebuggerTreeNodeExpression.createEvaluationText(node, getContextManager().getContext());
421     }
422     catch (EvaluateException e) {
423       return null;
424     }
425   }
426
427   @Nullable
428   @Override
429   protected RunProfile getRunProfile() {
430     return myDebugUIEnvironment.getRunProfile();
431   }
432
433   private void attractFramesOnPause(final int event) {
434     if (DebuggerSession.EVENT_PAUSE == event) {
435       myUi.attractBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
436     }
437     else if (DebuggerSession.EVENT_RESUME == event) {
438       myUi.clearAttractionBy(XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION);
439     }
440   }
441
442   public DebuggerSession getSession() {
443     return myDebuggerSession;
444   }
445
446   public void showFramePanel() {
447     myUi.selectAndFocus(myUi.findContent(DebuggerContentInfo.FRAME_CONTENT), true, false);
448   }
449
450   private static int myThreadDumpsCount = 0;
451   private static int myCurrentThreadDumpId = 1;
452
453   public static void addThreadDump(Project project, List<ThreadState> threads, final RunnerLayoutUi ui, DebuggerSession session) {
454     final TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
455     consoleBuilder.filters(ExceptionFilters.getFilters(session.getSearchScope()));
456     final ConsoleView consoleView = consoleBuilder.getConsole();
457     final DefaultActionGroup toolbarActions = new DefaultActionGroup();
458     consoleView.allowHeavyFilters();
459     final ThreadDumpPanel panel = new ThreadDumpPanel(project, consoleView, toolbarActions, threads);
460
461     final String id = createThreadDumpContentId();
462     final Content content = ui.createContent(id, panel, id, null, null);
463     content.setCloseable(true);
464     content.setDescription("Thread Dump");
465     ui.addContent(content);
466     ui.selectAndFocus(content, true, true);
467     myThreadDumpsCount += 1;
468     myCurrentThreadDumpId += 1;
469     //Disposer.register(this, new Disposable() {
470     //  @Override
471     //  public void dispose() {
472     //    ui.removeContent(content, true);
473     //  }
474     //});
475     Disposer.register(content, new Disposable() {
476       @Override
477       public void dispose() {
478         myThreadDumpsCount -= 1;
479         if (myThreadDumpsCount == 0) {
480           myCurrentThreadDumpId = 1;
481         }
482       }
483     });
484     Disposer.register(content, consoleView);
485     ui.selectAndFocus(content, true, false);
486     if (threads.size() > 0) {
487       panel.selectStackFrame(0);
488     }
489   }
490
491   private static String createThreadDumpContentId() {
492     return THREAD_DUMP_CONTENT_PREFIX + " #" + myCurrentThreadDumpId;
493   }
494
495   private class MyDebuggerStateManager extends DebuggerStateManager {
496     @Override
497     public void fireStateChanged(DebuggerContextImpl newContext, int event) {
498       super.fireStateChanged(newContext, event);
499     }
500
501     @Override
502     public DebuggerContextImpl getContext() {
503       final DebuggerSession session = myDebuggerSession;
504       return session != null ? session.getContextManager().getContext() : DebuggerContextImpl.EMPTY_CONTEXT;
505     }
506
507     @Override
508     public void setState(DebuggerContextImpl context, int state, int event, String description) {
509       final DebuggerSession session = myDebuggerSession;
510       if (session != null) {
511         session.getContextManager().setState(context, state, event, description);
512       }
513     }
514   }
515
516   private class AutoVarsSwitchAction extends ToggleAction {
517     private volatile boolean myAutoModeEnabled;
518
519     public AutoVarsSwitchAction() {
520       super("", "", AllIcons.Debugger.AutoVariablesMode);
521       myAutoModeEnabled = DebuggerSettings.getInstance().AUTO_VARIABLES_MODE;
522     }
523
524     @Override
525     public void update(@NotNull final AnActionEvent e) {
526       super.update(e);
527       final Presentation presentation = e.getPresentation();
528       final boolean autoModeEnabled = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY));
529       presentation.setText(autoModeEnabled ? "All-Variables Mode" : "Auto-Variables Mode");
530     }
531
532     @Override
533     public boolean isSelected(AnActionEvent e) {
534       return myAutoModeEnabled;
535     }
536
537     @Override
538     public void setSelected(AnActionEvent e, boolean enabled) {
539       myAutoModeEnabled = enabled;
540       DebuggerSettings.getInstance().AUTO_VARIABLES_MODE = enabled;
541       myVariablesPanel.getFrameTree().setAutoVariablesMode(enabled);
542     }
543   }
544
545   private class WatchLastMethodReturnValueAction extends ToggleAction {
546     private volatile boolean myWatchesReturnValues;
547     private final String myTextEnable;
548     private final String myTextUnavailable;
549     private final String myMyTextDisable;
550
551     public WatchLastMethodReturnValueAction() {
552       super("", DebuggerBundle.message("action.watch.method.return.value.description"), null);
553       myWatchesReturnValues = DebuggerSettings.getInstance().WATCH_RETURN_VALUES;
554       myTextEnable = DebuggerBundle.message("action.watches.method.return.value.enable");
555       myMyTextDisable = DebuggerBundle.message("action.watches.method.return.value.disable");
556       myTextUnavailable = DebuggerBundle.message("action.watches.method.return.value.unavailable.reason");
557     }
558
559     @Override
560     public void update(@NotNull final AnActionEvent e) {
561       super.update(e);
562       final Presentation presentation = e.getPresentation();
563       final boolean watchValues = Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY));
564       final DebugProcessImpl process = getDebugProcess();
565       final String actionText = watchValues ? myMyTextDisable : myTextEnable;
566       if (process != null && process.canGetMethodReturnValue()) {
567         presentation.setEnabled(true);
568         presentation.setText(actionText);
569       }
570       else {
571         presentation.setEnabled(false);
572         presentation.setText(process == null ? actionText : myTextUnavailable);
573       }
574     }
575
576     @Override
577     public boolean isSelected(AnActionEvent e) {
578       return myWatchesReturnValues;
579     }
580
581     @Override
582     public void setSelected(AnActionEvent e, boolean watch) {
583       myWatchesReturnValues = watch;
584       DebuggerSettings.getInstance().WATCH_RETURN_VALUES = watch;
585       final DebugProcessImpl process = getDebugProcess();
586       if (process != null) {
587         process.setWatchMethodReturnValuesEnabled(watch);
588       }
589     }
590   }
591 }