package jetbrains.mps.debugger.java.runtime.ui.evaluation; /*Generated by MPS */ import jetbrains.mps.ide.ui.tree.MPSTree; import com.intellij.openapi.actionSystem.DataProvider; import com.sun.jdi.ThreadReference; import java.util.Map; import jetbrains.mps.debugger.java.runtime.evaluation.container.IEvaluationContainer; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import jetbrains.mps.debugger.java.runtime.state.DebugSession; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.application.ApplicationManager; import jetbrains.mps.debugger.java.api.state.proxy.JavaValue; import org.jetbrains.annotations.NotNull; import jetbrains.mps.ide.ui.tree.MPSTreeNode; import jetbrains.mps.ide.ui.tree.TextTreeNode; import jetbrains.mps.internal.collections.runtime.SetSequence; import jetbrains.mps.smodel.ModelAccess; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.Separator; import jetbrains.mps.workbench.action.BaseGroup; import com.intellij.openapi.actionSystem.ActionManager; import javax.swing.tree.TreePath; import org.jetbrains.annotations.NonNls; import jetbrains.mps.debugger.api.ui.tree.VariablesTree; import jetbrains.mps.ide.actions.MPSCommonDataKeys; import java.io.StringWriter; import java.io.PrintWriter; import jetbrains.mps.debugger.java.api.state.watchables.CalculatedWatchable; import jetbrains.mps.debugger.api.ui.tree.WatchableNode; import jetbrains.mps.debug.api.programState.IWatchable; import java.util.List; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import java.awt.Color; import jetbrains.mps.ide.messages.Icons; /*package*/ class EvaluationTree extends MPSTree implements DataProvider { private ThreadReference myThreadReference; private Map<IEvaluationContainer, EvaluationTree.EvaluationState> myStates = MapSequence.fromMap(new HashMap<IEvaluationContainer, EvaluationTree.EvaluationState>()); private final DebugSession myDebugSession; @Nullable private ActionGroup myActionGroup = null; public EvaluationTree(DebugSession session) { super(); myDebugSession = session; setRootVisible(false); setShowsRootHandles(true); rebuildNow(); } public void updateLocation(ThreadReference threadReference) { myThreadReference = threadReference; } /*package*/ void addModel(IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).put(model, new EvaluationTree.InitializedState()); } /*package*/ void removeModel(IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).removeKey(model); } /*package*/ void setResultValue(JavaValue value, IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).put(model, new EvaluationTree.ResultState(model.getPresentation(), value, myThreadReference)); } /*package*/ void setError(@NotNull String text, IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).put(model, new EvaluationTree.FailureState(text)); } /*package*/ void setError(@NotNull Throwable error, IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).put(model, new EvaluationTree.FailureState(error)); } /*package*/ void setEvaluating(IEvaluationContainer model) { ApplicationManager.getApplication().assertIsDispatchThread(); MapSequence.fromMap(myStates).put(model, new EvaluationTree.EvaluationInProgressState()); } @Override protected MPSTreeNode rebuild() { MPSTreeNode rootTreeNode = new TextTreeNode("Evaluation Result"); for (IEvaluationContainer model : SetSequence.fromSet(MapSequence.fromMap(myStates).keySet())) { MapSequence.fromMap(myStates).get(model).rebuild(rootTreeNode, model); } return rootTreeNode; } /*package*/ void rebuildEvaluationTreeNowIfNotDisposed() { ApplicationManager.getApplication().assertIsDispatchThread(); if (!(isDisposed())) { ModelAccess.instance().runReadAction(new Runnable() { public void run() { rebuildNow(); } }); } } @Override protected ActionGroup createPopupActionGroup(MPSTreeNode node) { DefaultActionGroup group = new DefaultActionGroup(); if (myActionGroup != null) { group.add(myActionGroup); group.add(new Separator()); } group.add(((BaseGroup) ActionManager.getInstance().getAction("jetbrains.mps.debugger.api.ui.actions.AbstractWatchableNodeActions_ActionGroup"))); return group; } @Override public void dispose() { MapSequence.fromMap(myStates).clear(); this.clear(); super.dispose(); } @Nullable private MPSTreeNode findSelectedNode() { TreePath path = getSelectionPath(); if (path != null) { Object component = path.getLastPathComponent(); if (component instanceof MPSTreeNode) { return (MPSTreeNode) component; } } return null; } @Nullable @Override public Object getData(@NonNls String dataId) { if (dataId.equals(EvaluationUi.EVALUATION_CONTAINER.getName())) { MPSTreeNode node = findSelectedNode(); if (node != null && node instanceof EvaluationTree.EvaluationModelNode) { return ((EvaluationTree.EvaluationModelNode) node).getModel(); } } else if (dataId.equals(EvaluationUi.DEBUG_SESSION.getName())) { return myDebugSession; } else if (dataId.equals(VariablesTree.MPS_DEBUGGER_VALUE.getName())) { MPSTreeNode node = findSelectedNode(); if (node != null && node instanceof EvaluationTree.ResultState.MyWatchableNode) { return ((EvaluationTree.ResultState.MyWatchableNode) node).getValue(); } } else if (dataId.equals(MPSCommonDataKeys.EXCEPTION.getName())) { MPSTreeNode node = findSelectedNode(); if (node != null && node instanceof EvaluationTree.ErrorTreeNode) { return ((EvaluationTree.ErrorTreeNode) node).getThrowable(); } } return null; } public void setActionGroup(ActionGroup group) { myActionGroup = group; } public static String[] getStackTrace(Throwable t) { StringWriter writer = new StringWriter(); t.printStackTrace(new PrintWriter(writer)); return writer.toString().split("\n"); } private static abstract class EvaluationState { public EvaluationState() { } public abstract void rebuild(MPSTreeNode rootTreeNode, IEvaluationContainer model); } public interface EvaluationModelNode { IEvaluationContainer getModel(); } private static class InitializedState extends EvaluationTree.EvaluationState { public InitializedState() { } @Override public void rebuild(MPSTreeNode rootTreeNode, IEvaluationContainer model) { rootTreeNode.add(new EvaluationTree.InitialTreeNode(model)); // todo? } } private static class EvaluationInProgressState extends EvaluationTree.EvaluationState { public EvaluationInProgressState() { } @Override public void rebuild(MPSTreeNode rootTreeNode, IEvaluationContainer model) { rootTreeNode.add(new EvaluationTree.EvaluatingTreeNode(model)); } } private class ResultState extends EvaluationTree.EvaluationState { @NotNull private final JavaValue myValue; private final ThreadReference myThreadReference; private final String myPresentation; private CalculatedWatchable myCachedWatchable; public ResultState(String presentation, JavaValue value, ThreadReference threadReference) { myPresentation = presentation; myValue = value; myThreadReference = threadReference; } @Override public void rebuild(MPSTreeNode rootTreeNode, IEvaluationContainer model) { final boolean canEvalaute = myDebugSession.getEvaluationProvider().canEvaluate(); if (canEvalaute) { myCachedWatchable = new CalculatedWatchable(myPresentation, myValue, myThreadReference); } if (myCachedWatchable != null) { WatchableNode watchableNode = new EvaluationTree.ResultState.MyWatchableNode(model, myCachedWatchable) { @Override public boolean isLeaf() { if (canEvalaute) { return super.isLeaf(); } return true; } }; rootTreeNode.add(watchableNode); } else { rootTreeNode.add(new EvaluationTree.InitialTreeNode(model)); } } private class MyWatchableNode extends WatchableNode implements EvaluationTree.EvaluationModelNode { private final IEvaluationContainer myModel; public MyWatchableNode(IEvaluationContainer model, @NotNull IWatchable watchable) { super(watchable, myDebugSession.getUiState()); myModel = model; } @Override public IEvaluationContainer getModel() { return myModel; } } } private class FailureState extends EvaluationTree.EvaluationState { @Nullable private String myErrorText; private Throwable myError; public FailureState(String errorText) { myErrorText = errorText; } private FailureState(Throwable error) { myError = error; } @Override public void rebuild(MPSTreeNode rootTreeNode, IEvaluationContainer model) { if (myError != null) { rootTreeNode.add(new EvaluationTree.ErrorTreeNode(model, myError)); } else { rootTreeNode.add(new EvaluationTree.ErrorTreeNode(model, myErrorText)); } } } private class ErrorTreeNode extends TextTreeNode implements EvaluationTree.EvaluationModelNode { private final List<String> myExtendedMessage = ListSequence.fromList(new ArrayList<String>()); private final IEvaluationContainer myModel; private Throwable myThrowable; public ErrorTreeNode(IEvaluationContainer model, @NotNull String text, String... extendedMessage) { super(model.getPresentation() + " = " + text); myModel = model; if (extendedMessage != null && extendedMessage.length > 0) { for (int i = 0; i < extendedMessage.length; i++) { ListSequence.fromList(myExtendedMessage).addElement(extendedMessage[i]); } } doInit(); } public ErrorTreeNode(IEvaluationContainer model, Throwable t) { this(model, (t.getMessage() == null ? t.toString() : t.getMessage()), EvaluationTree.getStackTrace(t)); myThrowable = t; } @Override public boolean isLeaf() { return ListSequence.fromList(myExtendedMessage).isEmpty(); } @Override protected void updatePresentation() { super.updatePresentation(); setColor(Color.RED); setIcon(Icons.ERROR_ICON); } @Override protected void doInit() { for (String messagePart : myExtendedMessage) { TextTreeNode node = new TextTreeNode(messagePart) { @Override public boolean isLeaf() { return true; } }; add(node); node.setIcon(Icons.ERROR_ICON); } } @Override public IEvaluationContainer getModel() { return myModel; } public Throwable getThrowable() { return myThrowable; } } private static class EvaluatingTreeNode extends TextTreeNode implements EvaluationTree.EvaluationModelNode { private final IEvaluationContainer myModel; public EvaluatingTreeNode(IEvaluationContainer model) { super(model.getPresentation() + " = " + "evaluating..."); myModel = model; } @Override public boolean isLeaf() { return true; } @Override protected void updatePresentation() { super.updatePresentation(); setColor(Color.GRAY); setIcon(Icons.INFORMATION_ICON); } @Override public IEvaluationContainer getModel() { return myModel; } } private static class InitialTreeNode extends TextTreeNode { public InitialTreeNode(IEvaluationContainer model) { super(model.getPresentation() + " = "); setIcon(jetbrains.mps.debugger.java.api.ui.Icons.WATCH); } @Override public boolean isLeaf() { return true; } } }