1 /* 2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * This source code is provided to illustrate the usage of a given feature 28 * or technique and has been deliberately simplified. Additional steps 29 * required for a production-quality application, such as security checks, 30 * input validation and proper error handling, might not be present in 31 * this sample code. 32 */ 33 34 35 package com.sun.tools.example.debug.gui; 36 37 import javax.swing.*; 38 import javax.swing.event.*; 39 import java.awt.*; 40 import com.sun.jdi.*; 41 import com.sun.tools.example.debug.bdi.*; 42 43 public class StackTraceTool extends JPanel { 44 45 private static final long serialVersionUID = 9140041989427965718L; 46 47 private Environment env; 48 49 private ExecutionManager runtime; 50 private ContextManager context; 51 52 private ThreadInfo tinfo; 53 54 private JList list; 55 private ListModel stackModel; 56 57 public StackTraceTool(Environment env) { 58 59 super(new BorderLayout()); 60 61 this.env = env; 62 this.runtime = env.getExecutionManager(); 63 this.context = env.getContextManager(); 64 65 stackModel = new DefaultListModel(); // empty 66 67 list = new JList(stackModel); 68 list.setCellRenderer(new StackFrameRenderer()); 69 70 JScrollPane listView = new JScrollPane(list); 71 add(listView); 72 73 // Create listener. 74 StackTraceToolListener listener = new StackTraceToolListener(); 75 context.addContextListener(listener); 76 list.addListSelectionListener(listener); 77 78 //### remove listeners on exit! 79 } 80 81 private class StackTraceToolListener 82 implements ContextListener, ListSelectionListener 83 { 84 85 // ContextListener 86 87 // If the user selects a new current frame, display it in 88 // this view. 89 90 //### I suspect we handle the case badly that the VM is not interrupted. 91 92 @Override 93 public void currentFrameChanged(CurrentFrameChangedEvent e) { 94 // If the current frame of the thread appearing in this 95 // view is changed, move the selection to track it. 96 int frameIndex = e.getIndex(); 97 ThreadInfo ti = e.getThreadInfo(); 98 if (e.getInvalidate() || tinfo != ti) { 99 tinfo = ti; 100 showStack(ti, frameIndex); 101 } else { 102 if (frameIndex < stackModel.getSize()) { 103 list.setSelectedIndex(frameIndex); 104 list.ensureIndexIsVisible(frameIndex); 105 } 106 } 107 } 108 109 // ListSelectionListener 110 111 @Override 112 public void valueChanged(ListSelectionEvent e) { 113 int index = list.getSelectedIndex(); 114 if (index != -1) { 115 //### should use listener? 116 try { 117 context.setCurrentFrameIndex(index); 118 } catch (VMNotInterruptedException exc) { 119 } 120 } 121 } 122 } 123 124 private class StackFrameRenderer extends DefaultListCellRenderer { 125 126 @Override 127 public Component getListCellRendererComponent(JList list, 128 Object value, 129 int index, 130 boolean isSelected, 131 boolean cellHasFocus) { 132 133 //### We should indicate the current thread independently of the 134 //### selection, e.g., with an icon, because the user may change 135 //### the selection graphically without affecting the current 136 //### thread. 137 138 super.getListCellRendererComponent(list, value, index, 139 isSelected, cellHasFocus); 140 if (value == null) { 141 this.setText("<unavailable>"); 142 } else { 143 StackFrame frame = (StackFrame)value; 144 Location loc = frame.location(); 145 Method meth = loc.method(); 146 String methName = 147 meth.declaringType().name() + '.' + meth.name(); 148 String position = ""; 149 if (meth.isNative()) { 150 position = " (native method)"; 151 } else if (loc.lineNumber() != -1) { 152 position = ":" + loc.lineNumber(); 153 } else { 154 long pc = loc.codeIndex(); 155 if (pc != -1) { 156 position = ", pc = " + pc; 157 } 158 } 159 // Indices are presented to the user starting from 1, not 0. 160 this.setText("[" + (index+1) +"] " + methName + position); 161 } 162 return this; 163 } 164 } 165 166 // Point this view at the given thread and frame. 167 168 private void showStack(ThreadInfo tinfo, int selectFrame) { 169 StackTraceListModel model = new StackTraceListModel(tinfo); 170 stackModel = model; 171 list.setModel(stackModel); 172 list.setSelectedIndex(selectFrame); 173 list.ensureIndexIsVisible(selectFrame); 174 } 175 176 private static class StackTraceListModel extends AbstractListModel { 177 178 private final ThreadInfo tinfo; 179 180 public StackTraceListModel(ThreadInfo tinfo) { 181 this.tinfo = tinfo; 182 } 183 184 @Override 185 public Object getElementAt(int index) { 186 try { 187 return tinfo == null? null : tinfo.getFrame(index); 188 } catch (VMNotInterruptedException e) { 189 //### Is this the right way to handle this? 190 //### Would happen if user scrolled stack trace 191 //### while not interrupted -- should probably 192 //### block user interaction in this case. 193 return null; 194 } 195 } 196 197 @Override 198 public int getSize() { 199 try { 200 return tinfo == null? 1 : tinfo.getFrameCount(); 201 } catch (VMNotInterruptedException e) { 202 //### Is this the right way to handle this? 203 return 0; 204 } 205 } 206 } 207 }