001 package nl.cwi.sen1.tide.tool.stackviewer; 002 003 //{{{ imports 004 005 import java.awt.BorderLayout; 006 import java.awt.Dimension; 007 import java.awt.GridLayout; 008 import java.awt.event.ActionEvent; 009 import java.util.Iterator; 010 import java.util.Vector; 011 012 import javax.swing.AbstractAction; 013 import javax.swing.Action; 014 import javax.swing.JLabel; 015 import javax.swing.JList; 016 import javax.swing.JPanel; 017 import javax.swing.JScrollPane; 018 import javax.swing.JSplitPane; 019 import javax.swing.JToolBar; 020 import javax.swing.ListSelectionModel; 021 import javax.swing.event.ListSelectionEvent; 022 import javax.swing.event.ListSelectionListener; 023 024 import nl.cwi.sen1.tide.tool.ProcessTool; 025 import nl.cwi.sen1.tide.tool.ToolManager; 026 import nl.cwi.sen1.tide.tool.support.DebugAdapter; 027 import nl.cwi.sen1.tide.tool.support.DebugAdapterListener; 028 import nl.cwi.sen1.tide.tool.support.DebugProcess; 029 import nl.cwi.sen1.tide.tool.support.DebugProcessListener; 030 import nl.cwi.sen1.tide.tool.support.Expr; 031 import nl.cwi.sen1.tide.tool.support.Port; 032 import nl.cwi.sen1.tide.tool.support.ProcessStatusChangeListener; 033 import nl.cwi.sen1.tide.tool.support.Rule; 034 035 //}}} 036 037 public class StackViewer 038 extends ProcessTool 039 implements 040 DebugProcessListener, 041 ProcessStatusChangeListener, 042 DebugAdapterListener, 043 ListSelectionListener { 044 //{{{ Constants 045 046 private static final String TAG_STACK_TRACE = "stack-trace"; 047 private static final String TAG_STACK_UNWIND = "stack-unwind"; 048 049 //}}} 050 051 //{{{ Attributes 052 053 private JList trace; 054 055 private JToolBar tools; 056 private JLabel frameName; 057 private JLabel frameDepth; 058 private JLabel frameLocation; 059 private JList frameVars; 060 061 private String tag_stack_trace; 062 private String tag_stack_unwind; 063 064 private Action unwind; 065 private Action viewSource; 066 private Action inspectVar; 067 068 private DebugProcess process; 069 private Rule ruleStackTrace; 070 private Rule ruleStackUnwind; 071 072 private StackFrame selectedFrame; 073 074 //}}} 075 076 //{{{ public StackViewer(final DebugProcess process, ToolManager manager) 077 078 public StackViewer(ToolManager manager, final DebugProcess process) { 079 super(manager, process); 080 081 //{{{ Build tags 082 083 tag_stack_trace = TAG_STACK_TRACE + "-" + getId(); 084 tag_stack_unwind = TAG_STACK_UNWIND + "-" + getId(); 085 086 //}}} 087 //{{{ Build actions 088 089 unwind = new AbstractAction("Unwind", loadIcon("unwind.gif")) { 090 public void actionPerformed(ActionEvent event) { 091 if (selectedFrame == null) { 092 getManager().displayError("Select a stackframe."); 093 } 094 else if (process.isStopped()) { 095 process.requestRuleModification( 096 ruleStackUnwind, 097 Port.makeStep(), 098 Expr.make( 099 "higher-equal(" 100 + selectedFrame.getDepth() 101 + ",stack-level)"), 102 Expr.makeBreak(), 103 true); 104 105 process.requestResume(); 106 } 107 } 108 }; 109 110 viewSource = 111 new AbstractAction("View Source", loadIcon("view-source.gif")) { 112 public void actionPerformed(ActionEvent event) { 113 getManager().displayError("Not implemented yet!"); 114 } 115 }; 116 117 inspectVar = 118 new AbstractAction("Inspect Variable", loadIcon("inspect-var.gif")) { 119 public void actionPerformed(ActionEvent event) { 120 getManager().displayError("Not implemented yet!"); 121 } 122 }; 123 124 unwind.setEnabled(false); 125 viewSource.setEnabled(false); 126 inspectVar.setEnabled(false); 127 128 tools = new JToolBar(); 129 tools.add(unwind).setToolTipText("Unwind stack upto selected frame"); 130 tools.add(viewSource).setToolTipText( 131 "View source associated with selected frame"); 132 tools.add(inspectVar).setToolTipText("Inspect selected variable"); 133 134 //}}} 135 //{{{ Build UI 136 137 setLayout(new BorderLayout()); 138 139 trace = new JList(); 140 trace.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 141 trace.setPreferredSize(new Dimension(120, 100)); 142 JPanel framePanel = new JPanel(); 143 144 JSplitPane pane = 145 new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, trace, framePanel); 146 add("Center", pane); 147 148 trace.addListSelectionListener(this); 149 150 framePanel.setLayout(new BorderLayout()); 151 Dimension dim = new Dimension(100, 100); 152 153 framePanel.setMinimumSize(dim); 154 framePanel.setPreferredSize(dim); 155 trace.setMinimumSize(dim); 156 157 frameName = new JLabel("-"); 158 frameDepth = new JLabel("-"); 159 frameLocation = new JLabel("-"); 160 161 JPanel frameLabels = new JPanel(); 162 frameLabels.setLayout(new BorderLayout()); 163 JPanel leftLabels = new JPanel(); 164 leftLabels.setLayout(new GridLayout(0, 1)); 165 leftLabels.add(new JLabel("Selected:")); 166 leftLabels.add(new JLabel("Depth:")); 167 leftLabels.add(new JLabel("Location:")); 168 169 JPanel rightLabels = new JPanel(); 170 rightLabels.setLayout(new GridLayout(0, 1)); 171 rightLabels.add(frameName); 172 rightLabels.add(frameDepth); 173 rightLabels.add(frameLocation); 174 175 frameLabels.add("South", tools); 176 frameLabels.add("West", leftLabels); 177 frameLabels.add("Center", rightLabels); 178 179 frameVars = new JList(); 180 JScrollPane scrollFrameVars = new JScrollPane(frameVars); 181 182 framePanel.add("North", frameLabels); 183 framePanel.add("Center", scrollFrameVars); 184 185 //}}} 186 187 //{{{ Listen to process events 188 189 this.process = process; 190 process.addDebugProcessListener(this); 191 process.addProcessStatusChangeListener(this); 192 193 DebugAdapter adapter = process.getAdapter(); 194 adapter.addDebugAdapterListener(this); 195 196 //}}} 197 //{{{ Create appropriate debugging events 198 199 process.requestRuleCreation( 200 Port.makeStopped(), 201 Expr.makeTrue(), 202 Expr.makeStackTrace(), 203 tag_stack_trace, 204 true); 205 206 process.requestRuleCreation( 207 Port.makeStep(), 208 Expr.makeTrue(), 209 Expr.makeBreak(), 210 tag_stack_unwind, 211 false); 212 213 process.requestEvaluation(Expr.makeStackTrace(), tag_stack_trace); 214 215 //}}} 216 } 217 218 //}}} 219 220 //{{{ public void processDestroyed(DebugAdapter adapter, DebugProcess 221 // proc) 222 223 public void processDestroyed(DebugAdapter adapter, DebugProcess proc) { 224 if (proc == process) { 225 // Rules do not need to be removed! 226 ruleStackTrace = null; 227 ruleStackUnwind = null; 228 destroy(); 229 } 230 } 231 232 //}}} 233 //{{{ public void processCreated(DebugAdapter adapter, DebugProcess proc) 234 235 public void processCreated(DebugAdapter adapter, DebugProcess proc) {} 236 237 //}}} 238 239 //{{{ public void displayStackTrace(Expr stackTrace) 240 241 public void displayStackTrace(Expr stackTrace) { 242 Vector<StackFrame> frames = new Vector<StackFrame>(); 243 244 if (!stackTrace.isStackTrace()) { 245 getManager().displayError("not a stacktrace: " + stackTrace); 246 return; 247 } 248 249 Iterator<Expr> iter = stackTrace.frameIterator(); 250 while (iter.hasNext()) { 251 Expr frame = iter.next(); 252 253 if (!frame.isStackFrame()) { 254 getManager().displayError("not a stackframe: " + frame); 255 continue; 256 } 257 int depth = frame.getFrameDepth(); 258 String name = frame.getFrameName(); 259 Expr location = frame.getFrameLocation(); 260 Expr variables = frame.getFrameVariables(); 261 StackFrame stackFrame = 262 new StackFrame(depth, name, location, variables); 263 frames.addElement(stackFrame); 264 } 265 displayStackFrame(frames.firstElement()); 266 trace.setListData(frames); 267 } 268 269 //}}} 270 //{{{ public void displayStackFrame(StackFrame frame) 271 272 public void displayStackFrame(StackFrame frame) { 273 selectedFrame = frame; 274 275 if (frame == null) { 276 frameName.setText("-"); 277 frameDepth.setText("-"); 278 frameLocation.setText("-"); 279 unwind.setEnabled(false); 280 viewSource.setEnabled(false); 281 inspectVar.setEnabled(false); 282 frameVars.removeAll(); 283 } else { 284 String name = frame.getName(); 285 int depth = frame.getDepth(); 286 Expr location = frame.getLocation(); 287 frameName.setText(name); 288 frameDepth.setText(String.valueOf(depth)); 289 frameLocation.setText(location.toString()); 290 unwind.setEnabled(true); 291 viewSource.setEnabled(!location.isLocationUnknown()); 292 inspectVar.setEnabled(false); 293 294 Vector<Expr> variables = new Vector<Expr>(); 295 Iterator<Expr> iter = frame.variableIterator(); 296 while (iter.hasNext()) { 297 Expr var = iter.next(); 298 variables.addElement(var); 299 } 300 frameVars.setListData(variables); 301 } 302 } 303 304 //}}} 305 306 //{{{ public void ruleCreated(DebugProcess process, Rule rule) 307 308 public void ruleCreated(DebugProcess process, Rule rule) { 309 if (rule.getTag().equals(tag_stack_trace)) { 310 ruleStackTrace = rule; 311 } else if (rule.getTag().equals(tag_stack_unwind)) { 312 ruleStackUnwind = rule; 313 } 314 } 315 316 //}}} 317 //{{{ public void ruleDeleted(DebugProcess process, Rule rule) 318 319 public void ruleDeleted(DebugProcess process, Rule rule) { 320 if (rule == ruleStackTrace) { 321 ruleStackTrace = null; 322 } 323 324 if (rule == ruleStackUnwind) { 325 ruleStackUnwind = null; 326 } 327 } 328 329 //}}} 330 //{{{ public void ruleModified(DebugProcess process, Rule rule) 331 332 public void ruleModified(DebugProcess process, Rule rule) {} 333 334 //}}} 335 //{{{ public void ruleTriggered(DebugProcess process, Rule rule, Expr 336 // value) 337 338 public void ruleTriggered(DebugProcess process, Rule rule, Expr value) { 339 if (rule == ruleStackTrace) { 340 displayStackTrace(value); 341 } 342 } 343 344 //}}} 345 //{{{ public void evaluationResult(process, expr, value, tag) 346 347 public void evaluationResult(DebugProcess process, Expr expr, Expr value, String tag) { 348 if (tag.equals(tag_stack_trace)) { 349 displayStackTrace(value); 350 } else if (tag.equals(tag_stack_unwind)) {} 351 } 352 353 //}}} 354 355 //{{{ public void processStatusChanged(DebugProcess process) 356 357 public void processStatusChanged(DebugProcess process) { 358 boolean stopped = process.isStopped(); 359 360 unwind.setEnabled(stopped); 361 362 if (stopped) { 363 if (ruleStackUnwind.isEnabled()) { 364 process.requestRuleEnabling(ruleStackUnwind, false); 365 } 366 } 367 } 368 369 //}}} 370 //{{{ public void valueChanged(ListSelectionEvent evt) 371 372 public void valueChanged(ListSelectionEvent evt) { 373 if (evt.getSource() == trace) { 374 displayStackFrame((StackFrame) trace.getSelectedValue()); 375 } 376 } 377 } 378 379 class StackFrame { 380 private int depth; 381 private String name; 382 private Expr location; 383 private Expr vars; 384 385 //{{{ public StackFrame(int depth, String name, Expr location, Expr vars) 386 387 public StackFrame(int depth, String name, Expr location, Expr vars) { 388 this.depth = depth; 389 this.name = name; 390 this.location = location; 391 this.vars = vars; 392 } 393 394 //}}} 395 396 //{{{ public String toString() 397 398 public String toString() { 399 return String.valueOf(depth) + " " + name; 400 } 401 402 //}}} 403 //{{{ public int getDepth() 404 405 public int getDepth() { 406 return depth; 407 } 408 409 //}}} 410 //{{{ public String getName() 411 412 public String getName() { 413 return name; 414 } 415 416 //}}} 417 //{{{ public Expr getLocation() 418 419 public Expr getLocation() { 420 return location; 421 } 422 423 //}}} 424 //{{{ public Iterator variableIterator() 425 426 public Iterator<Expr> variableIterator() { 427 return vars.iterator(); 428 } 429 430 //}}} 431 }