Use Tree Navigation
public class

SourceTool

extends JPanel
/*
 * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package com.sun.tools.example.debug.gui;

import java.io.*;
import java.util.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import com.sun.jdi.*;
import com.sun.jdi.request.*;

import com.sun.tools.example.debug.event.*;
import com.sun.tools.example.debug.bdi.*;

import java.util.List;

public class SourceTool extends JPanel {

   
private Environment env;

   
private ExecutionManager runtime;
   
private ContextManager context;
   
private SourceManager sourceManager;

   
private JList list;
   
private ListModel sourceModel;

   
// Information on source file that is on display, or failed to be
   
// displayed due to inaccessible source.  Used to update display
   
// when sourcepath is changed.

   
private String sourceName;          // relative path name, if showSourceFile
   
private Location sourceLocn;        // location, if showSourceForLocation
   
private CommandInterpreter interpreter;

   
public SourceTool(Environment env) {

       
super(new BorderLayout());

       
this.env = env;

        runtime
= env.getExecutionManager();
        sourceManager
= env.getSourceManager();
       
this.context = env.getContextManager();
       
this.interpreter = new CommandInterpreter(env, true);

        sourceModel
= new DefaultListModel();  // empty

        list
= new JList(sourceModel);
        list
.setCellRenderer(new SourceLineRenderer());

        list
.setPrototypeCellValue(SourceModel.prototypeCellValue);

       
SourceToolListener listener = new SourceToolListener();
        context
.addContextListener(listener);
        runtime
.addSpecListener(listener);
        sourceManager
.addSourceListener(listener);

       
MouseListener squeek = new STMouseListener();
        list
.addMouseListener(squeek);

        add
(new JScrollPane(list));
   
}

   
public void setTextFont(Font f) {
        list
.setFont(f);
        list
.setPrototypeCellValue(SourceModel.prototypeCellValue);
   
}

   
private class SourceToolListener
               
implements ContextListener, SourceListener, SpecListener
   
{

       
// ContextListener

       
public void currentFrameChanged(CurrentFrameChangedEvent e) {
            showSourceContext
(e.getThread(), e.getIndex());
       
}

           
// Clear source view.
           
//      sourceModel = new DefaultListModel();  // empty

       
// SourceListener

       
public void sourcepathChanged(SourcepathChangedEvent e) {
           
// Reload source view if its contents depend
           
// on the source path.
           
if (sourceName != null) {
                showSourceFile
(sourceName);
           
} else if (sourceLocn != null) {
                showSourceForLocation
(sourceLocn);
           
}
       
}

       
// SpecListener

       
public void breakpointSet(SpecEvent e) {
            breakpointResolved
(e);
       
}

       
public void breakpointDeferred(SpecEvent e) { }

       
public void breakpointDeleted(SpecEvent e) {
           
BreakpointRequest req = (BreakpointRequest)e.getEventRequest();
           
Location loc = req.location();
           
if (loc != null) {
               
try {
                   
SourceModel sm = sourceManager.sourceForLocation(loc);
                    sm
.showBreakpoint(loc.lineNumber(), false);
                    showSourceForLocation
(loc);
               
} catch (Exception exc) {
               
}
           
}
       
}

       
public void breakpointResolved(SpecEvent e) {
           
BreakpointRequest req = (BreakpointRequest)e.getEventRequest();
           
Location loc = req.location();
           
try {
               
SourceModel sm = sourceManager.sourceForLocation(loc);
                sm
.showBreakpoint(loc.lineNumber(), true);
                showSourceForLocation
(loc);
           
} catch (Exception exc) {
           
}
       
}

       
public void breakpointError(SpecErrorEvent e) {
            breakpointDeleted
(e);
       
}

       
public void watchpointSet(SpecEvent e) {
       
}
       
public void watchpointDeferred(SpecEvent e) {
       
}
       
public void watchpointDeleted(SpecEvent e) {
       
}
       
public void watchpointResolved(SpecEvent e) {
       
}
       
public void watchpointError(SpecErrorEvent e) {
       
}

       
public void exceptionInterceptSet(SpecEvent e) {
       
}
       
public void exceptionInterceptDeferred(SpecEvent e) {
       
}
       
public void exceptionInterceptDeleted(SpecEvent e) {
       
}
       
public void exceptionInterceptResolved(SpecEvent e) {
       
}
       
public void exceptionInterceptError(SpecErrorEvent e) {
       
}
   
}

   
private void showSourceContext(ThreadReference thread, int index) {
       
//### Should use ThreadInfo here.
       
StackFrame frame = null;
       
if (thread != null) {
           
try {
                frame
= thread.frame(index);
           
} catch (IncompatibleThreadStateException e) {}
       
}
       
if (frame == null) {
           
return;
       
}
       
Location locn = frame.location();
       
/*****
        if (!showSourceForLocation(locn)) {
            env.notice("Could not display source for "
                       + Utils.locationString(locn));
        }
        *****/

        showSourceForLocation
(locn);
   
}

   
public boolean showSourceForLocation(Location locn) {
        sourceName
= null;
        sourceLocn
= locn;
       
int lineNo = locn.lineNumber();
       
if (lineNo != -1) {
           
SourceModel source = sourceManager.sourceForLocation(locn);
           
if (source != null) {
                showSourceAtLine
(source, lineNo-1);
               
return true;
           
}
       
}
       
// Here if we could not display source.
        showSourceUnavailable
();
       
return false;
   
}

   
public boolean showSourceFile(String fileName) {
        sourceLocn
= null;
       
File file;
       
if (!fileName.startsWith(File.separator)) {
            sourceName
= fileName;
           
SearchPath sourcePath = sourceManager.getSourcePath();
            file
= sourcePath.resolve(fileName);
           
if (file == null) {
               
//env.failure("Source not found on current source path.");
                showSourceUnavailable
();
               
return false;
           
}
       
} else {
            sourceName
= null;  // Absolute pathname does not depend on sourcepath.
            file
= new File(fileName);
       
}
       
SourceModel source = sourceManager.sourceForFile(file);
       
if (source != null) {
            showSource
(source);
           
return true;
       
}
        showSourceUnavailable
();
       
return false;
   
}

   
private void showSource(SourceModel model) {
        setViewModel
(model);
   
}

   
private void showSourceAtLine(SourceModel model, int lineNo) {
        setViewModel
(model);
       
if (model.isActuallySource && (lineNo < model.getSize())) {
            list
.setSelectedIndex(lineNo);
           
if (lineNo+4 < model.getSize()) {
                list
.ensureIndexIsVisible(lineNo+4);  // give some context
           
}
            list
.ensureIndexIsVisible(lineNo);
       
}
   
}

   
private void showSourceUnavailable() {
       
SourceModel model = new SourceModel("[Source code is not available]");
        setViewModel
(model);
   
}

   
private void setViewModel(SourceModel model) {
       
if (model != sourceModel) {
           
// install new model
            list
.setModel(model);
            sourceModel
= model;
       
}
   
}

   
private class SourceLineRenderer extends DefaultListCellRenderer {

       
public Component getListCellRendererComponent(JList list,
                                                     
Object value,
                                                     
int index,
                                                     
boolean isSelected,
                                                     
boolean cellHasFocus) {

           
//### Should set background highlight and/or icon if breakpoint on this line.
           
// Configures "this"
           
super.getListCellRendererComponent(list, value, index,
                                               isSelected
, cellHasFocus);

           
SourceModel.Line line = (SourceModel.Line)value;

           
//### Tab expansion is now done when source file is read in,
           
//### to speed up display.  This costs a lot of space, slows
           
//### down source file loading, and has not been demonstrated
           
//### to yield an observable improvement in display performance.
           
//### Measurements may be appropriate here.
           
//String sourceLine = expandTabs((String)value);
            setText
(line.text);
           
if (line.hasBreakpoint) {
                setIcon
(Icons.stopSignIcon);
           
} else if (line.isExecutable()) {
                setIcon
(Icons.execIcon);
           
} else {
                setIcon
(Icons.blankIcon);
           
}


           
return this;
       
}

       
public Dimension getPreferredSize() {
           
Dimension dim = super.getPreferredSize();
           
return new Dimension(dim.width, dim.height-5);
       
}

   
}

   
private class STMouseListener extends MouseAdapter implements MouseListener {
       
public void mousePressed(MouseEvent e) {
           
if (e.isPopupTrigger()) {
                showPopupMenu
((Component)e.getSource(),
                              e
.getX(), e.getY());
           
}
       
}

       
public void mouseReleased(MouseEvent e) {
           
if (e.isPopupTrigger()) {
                showPopupMenu
((Component)e.getSource(),
                              e
.getX(), e.getY());
           
}
       
}

       
private void showPopupMenu(Component invoker, int x, int y) {
           
JList list = (JList)invoker;
           
int ln = list.getSelectedIndex() + 1;
           
SourceModel.Line line =
               
(SourceModel.Line)list.getSelectedValue();
           
JPopupMenu popup = new JPopupMenu();

           
if (line == null) {
                popup
.add(new JMenuItem("please select a line"));
           
} else if (line.isExecutable()) {
               
String className = line.refType.name();
               
if (line.hasBreakpoint()) {
                    popup
.add(commandItem("Clear Breakpoint",
                                         
"clear " + className +
                                         
":" + ln));
               
} else {
                    popup
.add(commandItem("Set Breakpoint",
                                         
"stop at " + className +
                                         
":" + ln));
               
}
           
} else {
                popup
.add(new JMenuItem("not an executable line"));
           
}

            popup
.show(invoker,
                       x
+ popup.getWidth()/2, y + popup.getHeight()/2);
       
}

       
private JMenuItem commandItem(String label, final String cmd) {
           
JMenuItem item = new JMenuItem(label);
            item
.addActionListener(new ActionListener() {
               
public void actionPerformed(ActionEvent e) {
                    interpreter
.executeCommand(cmd);
               
}
           
});
           
return item;
       
}
   
}
}