2996a63f2b5021906556e626a7cd0cbc4b1f9218
[fedora-idea.git] / java / debugger / impl / src / com / intellij / debugger / actions / SetValueAction.java
blob2996a63f2b5021906556e626a7cd0cbc4b1f9218
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.
16 package com.intellij.debugger.actions;
18 import com.intellij.debugger.DebuggerBundle;
19 import com.intellij.debugger.DebuggerInvocationUtil;
20 import com.intellij.debugger.DebuggerManagerEx;
21 import com.intellij.debugger.engine.ContextUtil;
22 import com.intellij.debugger.engine.evaluation.*;
23 import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
24 import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
25 import com.intellij.debugger.engine.evaluation.expression.Modifier;
26 import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
27 import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
28 import com.intellij.debugger.impl.*;
29 import com.intellij.debugger.jdi.LocalVariableProxyImpl;
30 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
31 import com.intellij.debugger.ui.DebuggerExpressionComboBox;
32 import com.intellij.debugger.ui.EditorEvaluationCommand;
33 import com.intellij.debugger.ui.impl.DebuggerTreeRenderer;
34 import com.intellij.debugger.ui.impl.watch.*;
35 import com.intellij.debugger.ui.tree.render.HexRenderer;
36 import com.intellij.debugger.ui.tree.render.NodeRenderer;
37 import com.intellij.debugger.ui.tree.render.ValueLabelRenderer;
38 import com.intellij.openapi.actionSystem.AnActionEvent;
39 import com.intellij.openapi.editor.Editor;
40 import com.intellij.openapi.progress.ProcessCanceledException;
41 import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter;
42 import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
43 import com.intellij.openapi.project.Project;
44 import com.intellij.openapi.ui.Messages;
45 import com.intellij.psi.PsiDocumentManager;
46 import com.intellij.psi.PsiFile;
47 import com.intellij.ui.SimpleColoredComponent;
48 import com.intellij.util.IJSwingUtilities;
49 import com.sun.jdi.*;
51 import javax.swing.*;
54 * Class SetValueAction
55 * @author Jeka
57 public class SetValueAction extends DebuggerAction {
58 public void update(AnActionEvent e) {
59 boolean enable = false;
60 DebuggerTreeNodeImpl node = getSelectedNode(e.getDataContext());
61 if (node != null) {
62 NodeDescriptorImpl descriptor = node.getDescriptor();
63 if(descriptor instanceof ValueDescriptorImpl){
64 ValueDescriptorImpl valueDescriptor = ((ValueDescriptorImpl)descriptor);
65 enable = valueDescriptor.canSetValue();
68 e.getPresentation().setVisible(enable);
71 private void update(final DebuggerContextImpl context) {
72 DebuggerInvocationUtil.swingInvokeLater(context.getProject(), new Runnable() {
73 public void run() {
74 context.getDebuggerSession().refresh(false);
76 });
77 //node.setState(context);
80 public void actionPerformed(final AnActionEvent event) {
81 final DebuggerTreeNodeImpl node = getSelectedNode(event.getDataContext());
82 if (node == null) {
83 return;
85 final NodeDescriptorImpl descriptor = node.getDescriptor();
86 if (!(descriptor instanceof ValueDescriptorImpl)) {
87 return;
89 if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
90 return;
93 final DebuggerTree tree = getTree(event.getDataContext());
94 final DebuggerContextImpl debuggerContext = getDebuggerContext(event.getDataContext());
95 tree.saveState(node);
97 if (descriptor instanceof FieldDescriptorImpl) {
98 FieldDescriptorImpl fieldDescriptor = (FieldDescriptorImpl)descriptor;
99 final Field field = fieldDescriptor.getField();
100 if (!field.isStatic()) {
101 final ObjectReference object = fieldDescriptor.getObject();
102 if (object != null) {
103 askAndSet(node, debuggerContext, new SetValueRunnable() {
104 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
105 object.setValue(field, preprocessValue(evaluationContext, newValue, field.type()));
106 update(debuggerContext);
109 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
110 ClassNotLoadedException,
111 IncompatibleThreadStateException,
112 InvalidTypeException,
113 EvaluateException {
114 return evaluationContext.getDebugProcess().loadClass(evaluationContext, className, field.declaringType().classLoader());
119 else {
120 // field is static
121 ReferenceType refType = field.declaringType();
122 if (refType instanceof ClassType) {
123 final ClassType classType = (ClassType)refType;
124 askAndSet(node, debuggerContext, new SetValueRunnable() {
125 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
126 classType.setValue(field, preprocessValue(evaluationContext, newValue, field.type()));
127 update(debuggerContext);
130 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
131 ClassNotLoadedException,
132 IncompatibleThreadStateException,
133 InvalidTypeException,
134 EvaluateException {
135 return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
136 field.declaringType().classLoader());
142 else if (descriptor instanceof LocalVariableDescriptorImpl) {
143 LocalVariableDescriptorImpl localDescriptor = (LocalVariableDescriptorImpl)descriptor;
144 final LocalVariableProxyImpl local = localDescriptor.getLocalVariable();
145 if (local != null) {
146 askAndSet(node, debuggerContext, new SetValueRunnable() {
147 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
148 InvalidTypeException,
149 EvaluateException {
150 debuggerContext.getFrameProxy().setValue(local, preprocessValue(evaluationContext, newValue, local.getType()));
151 update(debuggerContext);
154 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
155 ClassNotLoadedException,
156 IncompatibleThreadStateException,
157 InvalidTypeException,
158 EvaluateException {
159 return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
160 evaluationContext.getClassLoader());
165 else if (descriptor instanceof ArrayElementDescriptorImpl) {
166 final ArrayElementDescriptorImpl elementDescriptor = (ArrayElementDescriptorImpl)descriptor;
167 final ArrayReference array = elementDescriptor.getArray();
168 if (array != null) {
169 if (VirtualMachineProxyImpl.isCollected(array)) {
170 // will only be the case if debugger does not use ObjectReference.disableCollection() because of Patches.IBM_JDK_DISABLE_COLLECTION_BUG
171 Messages.showWarningDialog(tree, DebuggerBundle.message("evaluation.error.array.collected") + "\n"+ DebuggerBundle.message("warning.recalculate"), DebuggerBundle.message("title.set.value"));
172 node.getParent().calcValue();
173 return;
175 final ArrayType arrType = (ArrayType)array.referenceType();
176 askAndSet(node, debuggerContext, new SetValueRunnable() {
177 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
178 array.setValue(elementDescriptor.getIndex(), preprocessValue(evaluationContext, newValue, arrType.componentType()));
179 update(debuggerContext);
182 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
183 ClassNotLoadedException,
184 IncompatibleThreadStateException,
185 InvalidTypeException,
186 EvaluateException {
187 return evaluationContext.getDebugProcess().loadClass(evaluationContext, className, arrType.classLoader());
192 else if (descriptor instanceof EvaluationDescriptor) {
193 final EvaluationDescriptor evaluationDescriptor = (EvaluationDescriptor)descriptor;
194 if (evaluationDescriptor.canSetValue()) {
195 askAndSet(node, debuggerContext, new SetValueRunnable() {
196 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException, InvalidTypeException, EvaluateException {
197 final Modifier modifier = evaluationDescriptor.getModifier();
198 modifier.setValue(preprocessValue(evaluationContext, newValue, modifier.getExpectedType()));
199 update(debuggerContext);
202 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
203 ClassNotLoadedException,
204 IncompatibleThreadStateException,
205 InvalidTypeException,
206 EvaluateException {
207 return evaluationContext.getDebugProcess().loadClass(evaluationContext, className,
208 evaluationContext.getClassLoader());
215 private Value preprocessValue(EvaluationContextImpl context, Value value, Type varType) throws EvaluateException {
216 if (value != null && "java.lang.String".equals(varType.name()) && !(value instanceof StringReference)) {
217 String v = DebuggerUtilsEx.getValueAsString(context, value);
218 if (v != null) {
219 value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf(v);
222 if(value instanceof DoubleValue) {
223 double dValue = ((DoubleValue) value).doubleValue();
224 if(varType instanceof FloatType && Float.MIN_VALUE <= dValue && dValue <= Float.MAX_VALUE){
225 value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf((float)dValue);
228 return value;
231 private static interface SetValueRunnable {
232 void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
233 InvalidTypeException,
234 EvaluateException,
235 IncompatibleThreadStateException;
236 ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws EvaluateException,
237 InvocationException,
238 ClassNotLoadedException,
239 IncompatibleThreadStateException,
240 InvalidTypeException;
243 private static void setValue(String expressionToShow, ExpressionEvaluator evaluator, EvaluationContextImpl evaluationContext, SetValueRunnable setValueRunnable) throws EvaluateException {
244 Value value;
245 try {
246 value = evaluator.evaluate(evaluationContext);
248 setValueRunnable.setValue(evaluationContext, value);
250 catch (IllegalArgumentException ex) {
251 throw EvaluateExceptionUtil.createEvaluateException(ex.getMessage());
253 catch (InvalidTypeException ex) {
254 throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.type.mismatch"));
256 catch (IncompatibleThreadStateException e) {
257 throw EvaluateExceptionUtil.createEvaluateException(e);
259 catch (ClassNotLoadedException ex) {
260 if (!evaluationContext.isAutoLoadClasses()) {
261 throw EvaluateExceptionUtil.createEvaluateException(ex);
263 final ReferenceType refType;
264 try {
265 refType = setValueRunnable.loadClass(evaluationContext, ex.className());
266 if (refType != null) {
267 //try again
268 setValue(expressionToShow, evaluator, evaluationContext, setValueRunnable);
271 catch (InvocationException e) {
272 throw EvaluateExceptionUtil.createEvaluateException(e);
274 catch (ClassNotLoadedException e) {
275 throw EvaluateExceptionUtil.createEvaluateException(e);
277 catch (IncompatibleThreadStateException e) {
278 throw EvaluateExceptionUtil.createEvaluateException(e);
280 catch (InvalidTypeException e) {
281 throw EvaluateExceptionUtil.createEvaluateException(e);
283 catch (ObjectCollectedException e) {
284 throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
289 private void askAndSet(final DebuggerTreeNodeImpl node, final DebuggerContextImpl debuggerContext, final SetValueRunnable setValueRunnable) {
290 ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, debuggerContext.getProject());
292 SuspendContextCommandImpl askSetAction = new DebuggerContextCommandImpl(debuggerContext) {
293 public Priority getPriority() {
294 return Priority.HIGH;
297 public void threadAction() {
298 final NodeDescriptorImpl descriptor = node.getDescriptor();
299 String initialString = "";
300 if (descriptor instanceof ValueDescriptorImpl) {
301 Value currentValue = ((ValueDescriptorImpl) descriptor).getValue();
302 if (currentValue instanceof StringReference) {
303 initialString = DebuggerUtilsEx.getValueOrErrorAsString(debuggerContext.createEvaluationContext(), currentValue);
304 initialString = initialString == null ? "" : "\"" + DebuggerUtilsEx.translateStringValue(initialString) + "\"";
306 else if (currentValue instanceof PrimitiveValue) {
307 ValueLabelRenderer renderer = ((ValueDescriptorImpl) descriptor).getRenderer(debuggerContext.getDebugProcess());
308 initialString = getDisplayableString((PrimitiveValue) currentValue, renderer instanceof NodeRenderer && HexRenderer.UNIQUE_ID.equals(renderer.getUniqueId()));
311 final String initialString1 = initialString;
312 final Project project = debuggerContext.getProject();
313 DebuggerInvocationUtil.swingInvokeLater(project, new Runnable() {
314 public void run() {
315 showEditor(new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, initialString1), node, debuggerContext, setValueRunnable);
322 progressWindow.setTitle(DebuggerBundle.message("title.evaluating"));
323 debuggerContext.getDebugProcess().getManagerThread().startProgress(askSetAction, progressWindow);
326 private void showEditor(final TextWithImports initialString,
327 final DebuggerTreeNodeImpl node,
328 final DebuggerContextImpl debuggerContext,
329 final SetValueRunnable setValueRunnable) {
330 final JPanel editorPanel = new JPanel();
331 editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
332 SimpleColoredComponent label = new SimpleColoredComponent();
333 label.setIcon(node.getIcon());
334 DebuggerTreeRenderer.getDescriptorTitle(debuggerContext, node.getDescriptor()).appendToComponent(label);
335 editorPanel.add(label);
337 final DebuggerExpressionComboBox comboBox = new DebuggerExpressionComboBox(
338 debuggerContext.getProject(),
339 PositionUtil.getContextElement(debuggerContext),
340 "setValue", DefaultCodeFragmentFactory.getInstance());
341 comboBox.setText(initialString);
342 comboBox.selectAll();
343 editorPanel.add(comboBox);
345 final DebuggerTreeInplaceEditor editor = new DebuggerTreeInplaceEditor(node) {
346 public JComponent createInplaceEditorComponent() {
347 return editorPanel;
350 public JComponent getPreferredFocusedComponent() {
351 return comboBox;
354 public Editor getEditor() {
355 return comboBox.getEditor();
358 public JComponent getEditorComponent() {
359 return comboBox.getEditorComponent();
362 private void flushValue() {
363 Editor editor = getEditor();
364 if(editor == null) {
365 return;
368 final TextWithImports text = comboBox.getText();
370 PsiFile psiFile = PsiDocumentManager.getInstance(debuggerContext.getProject()).getPsiFile(editor.getDocument());
372 final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, getProject());
373 EditorEvaluationCommand evaluationCommand = new EditorEvaluationCommand(getEditor(), psiFile, debuggerContext, progressWindow) {
374 public void threadAction() {
375 try {
376 evaluate();
378 catch(EvaluateException e) {
379 progressWindow.cancel();
381 catch(ProcessCanceledException e) {
382 progressWindow.cancel();
384 finally{
385 if (!progressWindow.isCanceled()) {
386 DebuggerInvocationUtil.swingInvokeLater(debuggerContext.getProject(), new Runnable() {
387 public void run() {
388 comboBox.addRecent(text);
389 cancelEditing();
396 protected Object evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
397 ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(evaluationContext.getProject(), new com.intellij.debugger.EvaluatingComputable<ExpressionEvaluator>() {
398 public ExpressionEvaluator compute() throws EvaluateException {
399 return EvaluatorBuilderImpl.getInstance().build(text, ContextUtil.getContextElement(evaluationContext), ContextUtil.getSourcePosition(evaluationContext));
403 SetValueAction.setValue(text.getText(), evaluator, evaluationContext, new SetValueRunnable() {
404 public void setValue(EvaluationContextImpl evaluationContext, Value newValue) throws ClassNotLoadedException,
405 InvalidTypeException,
406 EvaluateException,
407 IncompatibleThreadStateException {
408 if(!progressWindow.isCanceled()) {
409 setValueRunnable.setValue(evaluationContext, newValue);
410 node.calcValue();
414 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String className) throws InvocationException,
415 ClassNotLoadedException,
416 EvaluateException,
417 IncompatibleThreadStateException,
418 InvalidTypeException {
419 return setValueRunnable.loadClass(evaluationContext, className);
423 return null;
427 progressWindow.addListener(new ProgressIndicatorListenerAdapter() {
428 //should return whether to stop processing
429 public void stopped() {
430 if(!progressWindow.isCanceled()) {
431 IJSwingUtilities.invoke(new Runnable() {
432 public void run() {
433 cancelEditing();
442 progressWindow.setTitle(DebuggerBundle.message("progress.set.value"));
443 debuggerContext.getDebugProcess().getManagerThread().startProgress(evaluationCommand, progressWindow);
446 public void cancelEditing() {
447 try {
448 super.cancelEditing();
450 finally {
451 comboBox.dispose();
455 public void doOKAction() {
456 try {
457 flushValue();
459 finally {
460 comboBox.dispose();
466 final DebuggerStateManager stateManager = DebuggerManagerEx.getInstanceEx(debuggerContext.getProject()).getContextManager();
468 stateManager.addListener(new DebuggerContextListener() {
469 public void changeEvent(DebuggerContextImpl newContext, int event) {
470 stateManager.removeListener(this);
471 editor.cancelEditing();
475 node.getTree().hideTooltip();
477 editor.show();
480 @SuppressWarnings({"HardCodedStringLiteral"})
481 private static String getDisplayableString(PrimitiveValue value, boolean showAsHex) {
482 if (value instanceof CharValue) {
483 long longValue = value.longValue();
484 return showAsHex ? "0x" + Long.toHexString(longValue).toUpperCase() : Long.toString(longValue);
486 if (value instanceof ByteValue) {
487 byte val = value.byteValue();
488 String strValue = Integer.toHexString(val).toUpperCase();
489 if (strValue.length() > 2) {
490 strValue = strValue.substring(strValue.length() - 2);
492 return showAsHex ? "0x" + strValue : value.toString();
494 if (value instanceof ShortValue) {
495 short val = value.shortValue();
496 String strValue = Integer.toHexString(val).toUpperCase();
497 if (strValue.length() > 4) {
498 strValue = strValue.substring(strValue.length() - 4);
500 return showAsHex ? "0x" + strValue : value.toString();
502 if (value instanceof IntegerValue) {
503 int val = value.intValue();
504 return showAsHex ? "0x" + Integer.toHexString(val).toUpperCase() : value.toString();
506 if (value instanceof LongValue) {
507 long val = value.longValue();
508 return showAsHex ? "0x" + Long.toHexString(val).toUpperCase() + "L" : value.toString() + "L";
510 return DebuggerUtilsEx.translateStringValue(value.toString());