IDEA-131991 Debugger: Referring Objects can't update on View As
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / actions / ViewAsGroup.java
1 /*
2  * Copyright 2000-2014 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.actions;
17
18 import com.intellij.debugger.engine.DebugProcessImpl;
19 import com.intellij.debugger.engine.JavaValue;
20 import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
21 import com.intellij.debugger.impl.DebuggerContextImpl;
22 import com.intellij.debugger.settings.NodeRendererSettings;
23 import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
24 import com.intellij.debugger.ui.tree.render.NodeRenderer;
25 import com.intellij.openapi.actionSystem.*;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.project.DumbAware;
28 import com.intellij.xdebugger.frame.XValue;
29 import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
30 import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
33
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.List;
37
38 /**
39  * User: lex
40  * Date: Sep 26, 2003
41  * Time: 11:05:57 PM
42  */
43 public class ViewAsGroup extends ActionGroup implements DumbAware {
44   private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.ViewAsGroup");
45
46   private AnAction[] myChildren = AnAction.EMPTY_ARRAY;
47
48   public ViewAsGroup() {
49     super(null, true);
50   }
51
52   private static class RendererAction extends ToggleAction {
53     private final NodeRenderer myNodeRenderer;
54
55     public RendererAction(NodeRenderer nodeRenderer) {
56       super(nodeRenderer.getName());
57       myNodeRenderer = nodeRenderer;
58     }
59
60     public boolean isSelected(AnActionEvent e) {
61       List<JavaValue> values = getSelectedValues(e);
62       if (values.isEmpty()) {
63         return false;
64       }
65       for (JavaValue value : values) {
66         if (value.getDescriptor().getLastRenderer() != myNodeRenderer) {
67           return false;
68         }
69       }
70       return true;
71     }
72
73     public void setSelected(final AnActionEvent e, final boolean state) {
74       if (!state) return;
75
76       final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
77       final List<JavaValue> values = getSelectedValues(e);
78       final List<XValueNodeImpl> selectedNodes = XDebuggerTreeActionBase.getSelectedNodes(e.getDataContext());
79
80       LOG.assertTrue(debuggerContext != null && !values.isEmpty());
81
82       DebugProcessImpl process = debuggerContext.getDebugProcess();
83       if (process == null) {
84         return;
85       }
86
87       process.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
88           public void threadAction() {
89             for (final XValueNodeImpl node : selectedNodes) {
90               final XValue container = node.getValueContainer();
91               if (container instanceof JavaValue) {
92                 ((JavaValue)container).setRenderer(myNodeRenderer, node);
93               }
94             }
95           }
96         }
97       );
98     }
99   }
100
101   @NotNull
102   public AnAction[] getChildren(@Nullable final AnActionEvent e) {
103     return myChildren;
104   }
105
106   private static AnAction [] calcChildren(List<JavaValue> values) {
107     List<AnAction> renderers = new ArrayList<AnAction>();
108
109     List<NodeRenderer> allRenderers = NodeRendererSettings.getInstance().getAllRenderers();
110
111     boolean anyValueDescriptor = false;
112
113     for (NodeRenderer nodeRenderer : allRenderers) {
114       boolean allApp = true;
115
116       for (JavaValue value : values) {
117         if (value instanceof JavaReferringObjectsValue) { // disable for any referrers at all
118           return AnAction.EMPTY_ARRAY;
119         }
120         ValueDescriptorImpl valueDescriptor = value.getDescriptor();
121         anyValueDescriptor = true;
122         if (!valueDescriptor.isValueValid() || !nodeRenderer.isApplicable(valueDescriptor.getType())) {
123           allApp = false;
124           break;
125         }
126       }
127
128       if (!anyValueDescriptor) {
129         return AnAction.EMPTY_ARRAY;
130       }
131
132       if (allApp) {
133         renderers.add(new RendererAction(nodeRenderer));
134       }
135     }
136
137     List<AnAction> children = new ArrayList<AnAction>();
138     AnAction[] viewAsActions = ((DefaultActionGroup) ActionManager.getInstance().getAction(DebuggerActions.REPRESENTATION_LIST)).getChildren(null);
139     for (AnAction viewAsAction : viewAsActions) {
140       if (viewAsAction instanceof AutoRendererAction) {
141         if (renderers.size() > 1) {
142           viewAsAction.getTemplatePresentation().setVisible(true);
143           children.add(viewAsAction);
144         }
145       }
146       else {
147         children.add(viewAsAction);
148       }
149     }
150
151     if (!children.isEmpty()) {
152       children.add(Separator.getInstance());
153     }
154     children.addAll(renderers);
155
156     return children.toArray(new AnAction[children.size()]);
157   }
158
159   public void update(final AnActionEvent event) {
160     if(!DebuggerAction.isFirstStart(event)) {
161       return;
162     }
163
164     final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(event.getDataContext());
165     final List<JavaValue> values = getSelectedValues(event);
166     if (values.isEmpty()) {
167       return;
168     }
169
170     final DebugProcessImpl process = debuggerContext.getDebugProcess();
171     if (process == null) {
172       event.getPresentation().setEnabled(false);
173       return;
174     }
175     
176     process.getManagerThread().schedule(new DebuggerContextCommandImpl(debuggerContext) {
177       public void threadAction() {
178         myChildren = calcChildren(values);
179         DebuggerAction.enableAction(event, myChildren.length > 0);
180       }
181     });
182   }
183
184   public static List<JavaValue> getSelectedValues(AnActionEvent event) {
185     List<XValueNodeImpl> selectedNodes = XDebuggerTreeActionBase.getSelectedNodes(event.getDataContext());
186     if (selectedNodes.isEmpty()) return Collections.emptyList();
187
188     List<JavaValue> res = new ArrayList<JavaValue>(selectedNodes.size());
189     for (XValueNodeImpl node : selectedNodes) {
190       XValue container = node.getValueContainer();
191       if (container instanceof JavaValue) {
192         res.add((JavaValue)container);
193       }
194     }
195     return res;
196   }
197 }