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.
16 package com
.intellij
.debugger
.actions
;
18 import com
.intellij
.debugger
.engine
.DebugProcessImpl
;
19 import com
.intellij
.debugger
.engine
.DebuggerUtils
;
20 import com
.intellij
.debugger
.engine
.events
.DebuggerContextCommandImpl
;
21 import com
.intellij
.debugger
.impl
.DebuggerContextImpl
;
22 import com
.intellij
.debugger
.impl
.DebuggerSession
;
23 import com
.intellij
.debugger
.ui
.impl
.watch
.DebuggerTree
;
24 import com
.intellij
.debugger
.ui
.impl
.watch
.DebuggerTreeNodeImpl
;
25 import com
.intellij
.debugger
.ui
.impl
.watch
.NodeDescriptorImpl
;
26 import com
.intellij
.debugger
.ui
.impl
.watch
.ValueDescriptorImpl
;
27 import com
.intellij
.debugger
.ui
.tree
.ValueDescriptor
;
28 import com
.intellij
.debugger
.ui
.tree
.ValueMarkup
;
29 import com
.intellij
.idea
.ActionsBundle
;
30 import com
.intellij
.openapi
.actionSystem
.AnActionEvent
;
31 import com
.intellij
.openapi
.actionSystem
.Presentation
;
32 import com
.intellij
.openapi
.diagnostic
.Logger
;
33 import com
.intellij
.openapi
.util
.Pair
;
34 import com
.intellij
.openapi
.util
.Ref
;
35 import com
.intellij
.util
.containers
.HashMap
;
40 import java
.lang
.reflect
.InvocationTargetException
;
41 import java
.util
.Collections
;
42 import java
.util
.List
;
46 * Class SetValueAction
49 public class MarkObjectAction
extends DebuggerAction
{
50 private static final Logger LOG
= Logger
.getInstance("#com.intellij.debugger.actions.MarkObjectAction");
51 private final String MARK_TEXT
= ActionsBundle
.message("action.Debugger.MarkObject.text");
52 private final String UNMARK_TEXT
= ActionsBundle
.message("action.Debugger.MarkObject.unmark.text");
54 public void actionPerformed(final AnActionEvent event
) {
55 final DebuggerTreeNodeImpl node
= getSelectedNode(event
.getDataContext());
59 final NodeDescriptorImpl descriptor
= node
.getDescriptor();
60 if (!(descriptor
instanceof ValueDescriptorImpl
)) {
64 final DebuggerTree tree
= node
.getTree();
67 final ValueDescriptorImpl valueDescriptor
= ((ValueDescriptorImpl
)descriptor
);
68 final DebuggerContextImpl debuggerContext
= tree
.getDebuggerContext();
69 final DebugProcessImpl debugProcess
= debuggerContext
.getDebugProcess();
70 final ValueMarkup markup
= valueDescriptor
.getMarkup(debugProcess
);
71 debugProcess
.getManagerThread().invoke(new DebuggerContextCommandImpl(debuggerContext
) {
72 public Priority
getPriority() {
75 public void threadAction() {
76 boolean sessionRefreshNeeded
= true;
79 valueDescriptor
.setMarkup(debugProcess
, null);
82 final ValueMarkup suggestedMarkup
= new ValueMarkup(valueDescriptor
.getName(), Color
.RED
);
83 final Ref
<Pair
<ValueMarkup
,Boolean
>> result
= new Ref
<Pair
<ValueMarkup
, Boolean
>>(null);
85 final boolean suggestAdditionalMarkup
= canSuggestAdditionalMarkup(debugProcess
, valueDescriptor
.getValue());
86 SwingUtilities
.invokeAndWait(new Runnable() {
88 result
.set(ObjectMarkupPropertiesDialog
.chooseMarkup(suggestedMarkup
, suggestAdditionalMarkup
));
92 catch (InterruptedException ignored
) {
94 catch (InvocationTargetException e
) {
97 final Pair
<ValueMarkup
, Boolean
> pair
= result
.get();
99 valueDescriptor
.setMarkup(debugProcess
, pair
.first
);
101 final Value value
= valueDescriptor
.getValue();
102 final Map
<Long
, ValueMarkup
> additionalMarkup
= suggestMarkup((ObjectReference
)value
);
103 if (!additionalMarkup
.isEmpty()) {
104 final Map
<Long
, ValueMarkup
> map
= NodeDescriptorImpl
.getMarkupMap(debugProcess
);
106 for (Map
.Entry
<Long
,ValueMarkup
> entry
: additionalMarkup
.entrySet()) {
107 final Long key
= entry
.getKey();
108 if (!map
.containsKey(key
)) {
109 map
.put(key
, entry
.getValue());
117 sessionRefreshNeeded
= false;
122 final boolean _sessionRefreshNeeded
= sessionRefreshNeeded
;
123 SwingUtilities
.invokeLater(new Runnable() {
125 tree
.restoreState(node
);
127 if (_sessionRefreshNeeded
) {
128 final DebuggerSession session
= debuggerContext
.getDebuggerSession();
129 if (session
!= null) {
130 session
.refresh(true);
140 private static boolean canSuggestAdditionalMarkup(DebugProcessImpl debugProcess
, Value value
) {
141 if (!debugProcess
.getVirtualMachineProxy().canGetInstanceInfo()) {
144 if (!(value
instanceof ObjectReference
)) {
147 final ObjectReference objRef
= (ObjectReference
)value
;
148 if (objRef
instanceof ArrayReference
|| objRef
instanceof ClassObjectReference
|| objRef
instanceof ThreadReference
|| objRef
instanceof ThreadGroupReference
|| objRef
instanceof ClassLoaderReference
) {
154 private static Map
<Long
, ValueMarkup
> suggestMarkup(ObjectReference objRef
) {
155 final Map
<Long
, ValueMarkup
> result
= new HashMap
<Long
, ValueMarkup
>();
156 for (ObjectReference ref
: getReferringObjects(objRef
)) {
157 if (!(ref
instanceof ClassObjectReference
)) {
158 // consider references from statisc fields only
161 final ReferenceType refType
= ((ClassObjectReference
)ref
).reflectedType();
162 if (!refType
.isAbstract()) {
165 for (Field field
: refType
.visibleFields()) {
166 if (!(field
.isStatic() && field
.isFinal())) {
169 if (DebuggerUtils
.isPrimitiveType(field
.typeName())) {
172 final Value fieldValue
= refType
.getValue(field
);
173 if (!(fieldValue
instanceof ObjectReference
)) {
176 final long id
= ((ObjectReference
)fieldValue
).uniqueID();
177 final ValueMarkup markup
= result
.get(id
);
179 final String fieldName
= field
.name();
180 final Color autoMarkupColor
= ValueMarkup
.getAutoMarkupColor();
181 if (markup
== null) {
182 result
.put(id
, new ValueMarkup(fieldName
, autoMarkupColor
, createMarkupTooltipText(null, refType
, fieldName
)));
185 final String currentText
= markup
.getText();
186 if (!currentText
.contains(fieldName
)) {
187 final String currentTooltip
= markup
.getToolTipText();
188 final String tooltip
= createMarkupTooltipText(currentTooltip
, refType
, fieldName
);
189 result
.put(id
, new ValueMarkup(currentText
+ ", " + fieldName
, autoMarkupColor
, tooltip
));
197 private static List
<ObjectReference
> getReferringObjects(ObjectReference value
) {
198 // invoke the following method using Reflection in order to remain compilable on jdk 1.5
199 // java.util.List<com.sun.jdi.ObjectReference> referringObjects(long l);
201 final java
.lang
.reflect
.Method apiMethod
= ObjectReference
.class.getMethod("referringObjects", long.class);
202 return (List
<ObjectReference
>)apiMethod
.invoke(value
, ValueMarkup
.AUTO_MARKUP_REFERRING_OBJECTS_LIMIT
);
204 catch (IllegalAccessException e
) {
205 LOG
.error(e
); // should not happen
207 catch (InvocationTargetException e
) {
208 throw new RuntimeException(e
);
210 catch (NoSuchMethodException ignored
) {
212 return Collections
.emptyList();
215 private static String
createMarkupTooltipText(String prefix
, ReferenceType refType
, String fieldName
) {
216 final StringBuilder builder
= new StringBuilder();
217 if (prefix
== null) {
218 builder
.append("Value referenced from:");
221 builder
.append(prefix
);
223 return builder
.append("<br><b>").append(refType
.name()).append(".").append(fieldName
).append("</b>").toString();
227 public void update(AnActionEvent e
) {
228 boolean enable
= false;
229 String text
= MARK_TEXT
;
230 final DebuggerTreeNodeImpl node
= getSelectedNode(e
.getDataContext());
232 final NodeDescriptorImpl descriptor
= node
.getDescriptor();
233 enable
= (descriptor
instanceof ValueDescriptor
);
235 final ValueMarkup markup
= ((ValueDescriptor
)descriptor
).getMarkup(node
.getTree().getDebuggerContext().getDebugProcess());
236 if (markup
!= null) { // already exists
241 final Presentation presentation
= e
.getPresentation();
242 presentation
.setVisible(enable
);
243 presentation
.setText(text
);