0N/A/*
2362N/A * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/Apackage com.sun.tools.example.debug.gui;
0N/A
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.event.*;
0N/Aimport java.awt.*;
0N/Aimport com.sun.jdi.*;
0N/Aimport com.sun.tools.example.debug.bdi.*;
0N/A
0N/Apublic class StackTraceTool extends JPanel {
0N/A
4123N/A private static final long serialVersionUID = 9140041989427965718L;
4123N/A
0N/A private Environment env;
0N/A
0N/A private ExecutionManager runtime;
0N/A private ContextManager context;
0N/A
0N/A private ThreadInfo tinfo;
0N/A
0N/A private JList list;
0N/A private ListModel stackModel;
0N/A
0N/A public StackTraceTool(Environment env) {
0N/A
0N/A super(new BorderLayout());
0N/A
0N/A this.env = env;
0N/A this.runtime = env.getExecutionManager();
0N/A this.context = env.getContextManager();
0N/A
0N/A stackModel = new DefaultListModel(); // empty
0N/A
0N/A list = new JList(stackModel);
0N/A list.setCellRenderer(new StackFrameRenderer());
0N/A
0N/A JScrollPane listView = new JScrollPane(list);
0N/A add(listView);
0N/A
0N/A // Create listener.
0N/A StackTraceToolListener listener = new StackTraceToolListener();
0N/A context.addContextListener(listener);
0N/A list.addListSelectionListener(listener);
0N/A
0N/A //### remove listeners on exit!
0N/A }
0N/A
0N/A private class StackTraceToolListener
0N/A implements ContextListener, ListSelectionListener
0N/A {
0N/A
0N/A // ContextListener
0N/A
0N/A // If the user selects a new current frame, display it in
0N/A // this view.
0N/A
0N/A //### I suspect we handle the case badly that the VM is not interrupted.
0N/A
4123N/A @Override
0N/A public void currentFrameChanged(CurrentFrameChangedEvent e) {
0N/A // If the current frame of the thread appearing in this
0N/A // view is changed, move the selection to track it.
0N/A int frameIndex = e.getIndex();
0N/A ThreadInfo ti = e.getThreadInfo();
0N/A if (e.getInvalidate() || tinfo != ti) {
0N/A tinfo = ti;
0N/A showStack(ti, frameIndex);
0N/A } else {
0N/A if (frameIndex < stackModel.getSize()) {
0N/A list.setSelectedIndex(frameIndex);
0N/A list.ensureIndexIsVisible(frameIndex);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // ListSelectionListener
0N/A
4123N/A @Override
0N/A public void valueChanged(ListSelectionEvent e) {
0N/A int index = list.getSelectedIndex();
0N/A if (index != -1) {
0N/A //### should use listener?
0N/A try {
0N/A context.setCurrentFrameIndex(index);
0N/A } catch (VMNotInterruptedException exc) {
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A private class StackFrameRenderer extends DefaultListCellRenderer {
0N/A
4123N/A @Override
0N/A public Component getListCellRendererComponent(JList list,
0N/A Object value,
0N/A int index,
0N/A boolean isSelected,
0N/A boolean cellHasFocus) {
0N/A
0N/A //### We should indicate the current thread independently of the
0N/A //### selection, e.g., with an icon, because the user may change
0N/A //### the selection graphically without affecting the current
0N/A //### thread.
0N/A
0N/A super.getListCellRendererComponent(list, value, index,
0N/A isSelected, cellHasFocus);
0N/A if (value == null) {
0N/A this.setText("<unavailable>");
0N/A } else {
0N/A StackFrame frame = (StackFrame)value;
0N/A Location loc = frame.location();
0N/A Method meth = loc.method();
0N/A String methName =
0N/A meth.declaringType().name() + '.' + meth.name();
0N/A String position = "";
28N/A if (meth.isNative()) {
0N/A position = " (native method)";
0N/A } else if (loc.lineNumber() != -1) {
0N/A position = ":" + loc.lineNumber();
0N/A } else {
0N/A long pc = loc.codeIndex();
0N/A if (pc != -1) {
0N/A position = ", pc = " + pc;
0N/A }
0N/A }
0N/A // Indices are presented to the user starting from 1, not 0.
0N/A this.setText("[" + (index+1) +"] " + methName + position);
0N/A }
0N/A return this;
0N/A }
0N/A }
0N/A
0N/A // Point this view at the given thread and frame.
0N/A
0N/A private void showStack(ThreadInfo tinfo, int selectFrame) {
0N/A StackTraceListModel model = new StackTraceListModel(tinfo);
0N/A stackModel = model;
0N/A list.setModel(stackModel);
0N/A list.setSelectedIndex(selectFrame);
0N/A list.ensureIndexIsVisible(selectFrame);
0N/A }
0N/A
0N/A private static class StackTraceListModel extends AbstractListModel {
0N/A
0N/A private final ThreadInfo tinfo;
0N/A
0N/A public StackTraceListModel(ThreadInfo tinfo) {
0N/A this.tinfo = tinfo;
0N/A }
0N/A
4123N/A @Override
0N/A public Object getElementAt(int index) {
0N/A try {
0N/A return tinfo == null? null : tinfo.getFrame(index);
0N/A } catch (VMNotInterruptedException e) {
0N/A //### Is this the right way to handle this?
0N/A //### Would happen if user scrolled stack trace
0N/A //### while not interrupted -- should probably
0N/A //### block user interaction in this case.
0N/A return null;
0N/A }
0N/A }
0N/A
4123N/A @Override
0N/A public int getSize() {
0N/A try {
0N/A return tinfo == null? 1 : tinfo.getFrameCount();
0N/A } catch (VMNotInterruptedException e) {
0N/A //### Is this the right way to handle this?
0N/A return 0;
0N/A }
0N/A }
0N/A }
0N/A}