Add debugger example
This commit is contained in:
59
scripting/examples/java/debugger/DebugRunner.java
Normal file
59
scripting/examples/java/debugger/DebugRunner.java
Normal file
@@ -0,0 +1,59 @@
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import drafts.com.sun.star.script.framework.runtime.XScriptContext;
|
||||
|
||||
public class DebugRunner {
|
||||
|
||||
private static final String FILE_URL_PREFIX =
|
||||
System.getProperty("os.name").startsWith("Windows") == true ?
|
||||
"file:///" : "file://";
|
||||
|
||||
public void go(final XScriptContext xsctxt, String language, String uri,
|
||||
String filename) {
|
||||
|
||||
OOScriptDebugger debugger;
|
||||
InputStream is = null;
|
||||
String path = "";
|
||||
|
||||
System.out.println("uri: " + uri + ", language: " + language);
|
||||
|
||||
if (language.equals("Rhino"))
|
||||
debugger = new OORhinoDebugger();
|
||||
else if (language.equals("BeanShell"))
|
||||
debugger = new OOBeanShellDebugger();
|
||||
else
|
||||
return;
|
||||
|
||||
if (uri.startsWith(FILE_URL_PREFIX)) {
|
||||
uri = URLDecoder.decode(uri);
|
||||
String s = uri.substring(FILE_URL_PREFIX.length());
|
||||
File f = new File(s);
|
||||
|
||||
if (f.exists()) {
|
||||
if (f.isDirectory()) {
|
||||
if (!filename.equals("")) {
|
||||
path = new File(f, filename).getAbsolutePath();
|
||||
}
|
||||
}
|
||||
else {
|
||||
path = f.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uri.startsWith("http://")) {
|
||||
try {
|
||||
if (!filename.equals(""))
|
||||
uri = uri + "/" + filename;
|
||||
|
||||
URL url = new URL(uri);
|
||||
is = url.openStream();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("path: " + path);
|
||||
debugger.go(xsctxt, path);
|
||||
}
|
||||
}
|
465
scripting/examples/java/debugger/OOBeanShellDebugger.java
Normal file
465
scripting/examples/java/debugger/OOBeanShellDebugger.java
Normal file
@@ -0,0 +1,465 @@
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import javax.swing.event.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
|
||||
import drafts.com.sun.star.script.framework.runtime.XScriptContext;
|
||||
import bsh.*;
|
||||
|
||||
public class OOBeanShellDebugger implements OOScriptDebugger, ActionListener, DocumentListener {
|
||||
|
||||
private JFrame frame;
|
||||
private JTextArea ta;
|
||||
private GlyphGutter gg;
|
||||
private XScriptContext context;
|
||||
private int currentPosition = -1;
|
||||
private ArrayList breakpoints;
|
||||
private int linecount;
|
||||
private BufferedReader bufReader;
|
||||
private Interpreter sessionInterpreter;
|
||||
private Thread execThread = null;
|
||||
private String filename = null;
|
||||
|
||||
public void go(XScriptContext context, String filename) {
|
||||
this.context = context;
|
||||
this.breakpoints = new ArrayList();
|
||||
initUI();
|
||||
|
||||
if (filename != null && filename != "") {
|
||||
try {
|
||||
loadFile(filename);
|
||||
this.filename = filename;
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error loading file: " + ioe.getMessage(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void go(XScriptContext context, InputStream in) {
|
||||
this.context = context;
|
||||
this.breakpoints = new ArrayList();
|
||||
initUI();
|
||||
|
||||
if (in != null) {
|
||||
try {
|
||||
loadFile(in);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error loading stream: " + ioe.getMessage(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void loadFile(String filename) throws IOException {
|
||||
FileInputStream fis = new FileInputStream(filename);
|
||||
loadFile(fis);
|
||||
}
|
||||
|
||||
public void loadFile(InputStream in) throws IOException {
|
||||
ta.getDocument().removeDocumentListener(this);
|
||||
|
||||
byte[] contents = new byte[1024];
|
||||
int len = 0, pos = 0;
|
||||
|
||||
while ((len = in.read(contents, 0, 1024)) != -1) {
|
||||
ta.insert(new String(contents, 0, len), pos);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
gg.update();
|
||||
ta.getDocument().addDocumentListener(this);
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
frame = new JFrame("BeanShell Debug Window");
|
||||
ta = new JTextArea();
|
||||
ta.setRows(15);
|
||||
ta.setColumns(40);
|
||||
ta.setLineWrap(false);
|
||||
linecount = ta.getLineCount();
|
||||
|
||||
gg = new GlyphGutter(this);
|
||||
|
||||
final JScrollPane sp = new JScrollPane();
|
||||
sp.setViewportView(ta);
|
||||
sp.setRowHeaderView(gg);
|
||||
|
||||
ta.getDocument().addDocumentListener(this);
|
||||
String[] labels = {"Run", /* "Stop", */ "Clear", "Save", "Close"};
|
||||
JPanel p = new JPanel();
|
||||
p.setLayout(new FlowLayout());
|
||||
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
JButton b = new JButton(labels[i]);
|
||||
b.addActionListener(this);
|
||||
p.add(b);
|
||||
}
|
||||
|
||||
frame.getContentPane().add(sp, "Center");
|
||||
frame.getContentPane().add(p, "South");
|
||||
frame.pack();
|
||||
frame.show();
|
||||
}
|
||||
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
doChanged(e);
|
||||
}
|
||||
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
doChanged(e);
|
||||
}
|
||||
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
doChanged(e);
|
||||
}
|
||||
|
||||
public void doChanged(DocumentEvent e) {
|
||||
if (linecount != ta.getLineCount()) {
|
||||
gg.update();
|
||||
linecount = ta.getLineCount();
|
||||
}
|
||||
}
|
||||
|
||||
private void startExecution() {
|
||||
execThread = new Thread() {
|
||||
public void run() {
|
||||
Interpreter interpreter = new Interpreter();
|
||||
interpreter.getNameSpace().clear();
|
||||
|
||||
currentPosition = -1;
|
||||
gg.repaint();
|
||||
|
||||
try {
|
||||
interpreter.set("context", context);
|
||||
interpreter.eval(ta.getText());
|
||||
}
|
||||
catch (bsh.EvalError err) {
|
||||
currentPosition = err.getErrorLineNumber() - 1;
|
||||
try {
|
||||
int line = ta.getLineStartOffset(currentPosition);
|
||||
Rectangle rect = ta.modelToView(line);
|
||||
ta.scrollRectToVisible(rect);
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println("error: " + e.getMessage());
|
||||
}
|
||||
gg.repaint();
|
||||
|
||||
JOptionPane.showMessageDialog(frame, "Error at line " +
|
||||
String.valueOf(err.getErrorLineNumber()) +
|
||||
"\n\n: " + err.getErrorText(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
catch (Exception e) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error: " + e.getMessage(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
execThread.start();
|
||||
}
|
||||
|
||||
private void stopExecution() {
|
||||
if (execThread != null) {
|
||||
execThread.interrupt();
|
||||
execThread = null;
|
||||
}
|
||||
|
||||
ta.setEditable(true);
|
||||
if (bufReader != null) {
|
||||
try {
|
||||
bufReader.close();
|
||||
}
|
||||
catch (IOException ioe) {}
|
||||
}
|
||||
bufReader = null;
|
||||
currentPosition = -1;
|
||||
gg.repaint();
|
||||
}
|
||||
|
||||
private void startSession() {
|
||||
/* Reader reader = new StringReader(ta.getText());
|
||||
bsh.Parser parser = new bsh.Parser(reader);
|
||||
boolean eof = false;
|
||||
|
||||
try {
|
||||
Interpreter interpreter = new Interpreter();
|
||||
interpreter.getNameSpace().clear();
|
||||
interpreter.set("context", context);
|
||||
|
||||
CallStack callstack = new CallStack();
|
||||
callstack.push(interpreter.getNameSpace());
|
||||
|
||||
bsh.SimpleNode node = null;
|
||||
while(!eof) {
|
||||
eof = parser.Line();
|
||||
node = parser.popNode();
|
||||
System.out.println("Executing: " + node.getText());
|
||||
node.eval(callstack, interpreter);
|
||||
}
|
||||
}
|
||||
catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} */
|
||||
|
||||
/* try {
|
||||
sessionInterpreter = new Interpreter();
|
||||
sessionInterpreter.getNameSpace().clear();
|
||||
sessionInterpreter.set("context", context);
|
||||
}
|
||||
catch (bsh.EvalError err) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error at line " + String.valueOf(err.getErrorLineNumber()) +
|
||||
"\n\n: " + err.getErrorText(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
stopExecution();
|
||||
}
|
||||
|
||||
ta.setEditable(false);
|
||||
Reader reader = new StringReader(ta.getText());
|
||||
bufReader = new BufferedReader(reader);
|
||||
currentPosition = 0;
|
||||
gg.repaint(); */
|
||||
}
|
||||
|
||||
private void doStep() {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
line = bufReader.readLine();
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error reading line " + currentPosition +
|
||||
"\n\n: " + ioe.getMessage(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
stopExecution();
|
||||
}
|
||||
|
||||
if (line != null) {
|
||||
try {
|
||||
sessionInterpreter.eval(line);
|
||||
currentPosition++;
|
||||
gg.repaint();
|
||||
}
|
||||
catch (bsh.EvalError err) {
|
||||
gg.repaint();
|
||||
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error at line " + String.valueOf(err.getErrorLineNumber()) +
|
||||
"\n\n: " + err.getErrorText(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
else
|
||||
stopExecution();
|
||||
}
|
||||
|
||||
private void promptForSaveName() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
|
||||
public boolean accept(File f) {
|
||||
if (f.isDirectory() || f.getName().endsWith(".bsh"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return ("BeanShell files: *.bsh");
|
||||
}
|
||||
});
|
||||
|
||||
int ret = chooser.showSaveDialog(frame);
|
||||
|
||||
if (ret == JFileChooser.APPROVE_OPTION) {
|
||||
filename = chooser.getSelectedFile().getAbsolutePath();
|
||||
if (!filename.endsWith(".bsh"))
|
||||
filename += ".bsh";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void saveTextArea() {
|
||||
if (filename == null)
|
||||
promptForSaveName();
|
||||
|
||||
if (filename != null) {
|
||||
try {
|
||||
File f = new File(filename);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
String s = ta.getText();
|
||||
fos.write(s.getBytes(), 0, s.length());
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
JOptionPane.showMessageDialog(frame,
|
||||
"Error saving file: " + ioe.getMessage(),
|
||||
"Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getActionCommand().equals("Run"))
|
||||
startExecution();
|
||||
else if (e.getActionCommand().equals("Stop"))
|
||||
stopExecution();
|
||||
else if (e.getActionCommand().equals("Close"))
|
||||
frame.dispose();
|
||||
else if (e.getActionCommand().equals("Save"))
|
||||
saveTextArea();
|
||||
else if (e.getActionCommand().equals("Clear"))
|
||||
ta.setText("");
|
||||
}
|
||||
|
||||
public JTextArea getTextArea() {
|
||||
return ta;
|
||||
}
|
||||
|
||||
public int getCurrentPosition() {
|
||||
return currentPosition;
|
||||
}
|
||||
|
||||
public void toggleBreakPoint(int line) {
|
||||
Integer lineObj = new Integer(line);
|
||||
int idx = breakpoints.indexOf(lineObj);
|
||||
if (idx != -1)
|
||||
breakpoints.remove(lineObj);
|
||||
else
|
||||
breakpoints.add(lineObj);
|
||||
}
|
||||
|
||||
public boolean isBreakPoint(int line) {
|
||||
if (breakpoints.contains(new Integer(line)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class GlyphGutter extends JComponent implements MouseListener {
|
||||
|
||||
private OOBeanShellDebugger debugger;
|
||||
private boolean isError = false;
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
public void mousePressed(MouseEvent e) {
|
||||
}
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getComponent() == this &&
|
||||
(e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
|
||||
int x = e.getX();
|
||||
int y = e.getY();
|
||||
Font font = debugger.getTextArea().getFont();
|
||||
FontMetrics metrics = getFontMetrics(font);
|
||||
int h = metrics.getHeight();
|
||||
int line = y/h;
|
||||
debugger.toggleBreakPoint(line + 1);
|
||||
}
|
||||
}
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
}
|
||||
|
||||
GlyphGutter(OOBeanShellDebugger debugger) {
|
||||
this.debugger = debugger;
|
||||
// addMouseListener(this);
|
||||
update();
|
||||
}
|
||||
|
||||
public void update() {
|
||||
JTextArea textArea = debugger.getTextArea();
|
||||
Font font = textArea.getFont();
|
||||
setFont(font);
|
||||
FontMetrics metrics = getFontMetrics(font);
|
||||
int h = metrics.getHeight();
|
||||
int lineCount = textArea.getLineCount() + 1;
|
||||
String dummy = Integer.toString(lineCount);
|
||||
if (dummy.length() < 2) {
|
||||
dummy = "99";
|
||||
}
|
||||
Dimension d = new Dimension();
|
||||
d.width = metrics.stringWidth(dummy) + 16;
|
||||
d.height = lineCount * h + 100;
|
||||
setPreferredSize(d);
|
||||
setSize(d);
|
||||
}
|
||||
|
||||
public void paintComponent(Graphics g) {
|
||||
JTextArea textArea = debugger.getTextArea();
|
||||
|
||||
Font font = textArea.getFont();
|
||||
g.setFont(font);
|
||||
|
||||
FontMetrics metrics = getFontMetrics(font);
|
||||
Rectangle clip = g.getClipBounds();
|
||||
|
||||
g.setColor(getBackground());
|
||||
g.fillRect(clip.x, clip.y, clip.width, clip.height);
|
||||
|
||||
int ascent = metrics.getMaxAscent();
|
||||
int h = metrics.getHeight();
|
||||
int lineCount = textArea.getLineCount() + 1;
|
||||
|
||||
int startLine = clip.y / h;
|
||||
int endLine = (clip.y + clip.height) / h + 1;
|
||||
int width = getWidth();
|
||||
if (endLine > lineCount) endLine = lineCount;
|
||||
|
||||
for (int i = startLine; i < endLine; i++) {
|
||||
String text;
|
||||
text = Integer.toString(i + 1) + " ";
|
||||
int w = metrics.stringWidth(text);
|
||||
int y = i * h;
|
||||
g.setColor(Color.blue);
|
||||
g.drawString(text, 0, y + ascent);
|
||||
int x = width - ascent;
|
||||
|
||||
if (debugger.isBreakPoint(i + 1))
|
||||
drawBreakPoint(g, ascent, x, y);
|
||||
|
||||
if (i == debugger.getCurrentPosition())
|
||||
drawArrow(g, ascent, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBreakPoint(Graphics g, int ascent, int x, int y) {
|
||||
g.setColor(new Color(0x80, 0x00, 0x00));
|
||||
int dy = y + ascent - 9;
|
||||
g.fillOval(x, dy, 9, 9);
|
||||
g.drawOval(x, dy, 8, 8);
|
||||
g.drawOval(x, dy, 9, 9);
|
||||
}
|
||||
|
||||
private void drawArrow(Graphics g, int ascent, int x, int y) {
|
||||
Polygon arrow = new Polygon();
|
||||
int dx = x;
|
||||
y += ascent - 10;
|
||||
int dy = y;
|
||||
arrow.addPoint(dx, dy + 3);
|
||||
arrow.addPoint(dx + 5, dy + 3);
|
||||
for (x = dx + 5; x <= dx + 10; x++, y++) {
|
||||
arrow.addPoint(x, y);
|
||||
}
|
||||
for (x = dx + 9; x >= dx + 5; x--, y++) {
|
||||
arrow.addPoint(x, y);
|
||||
}
|
||||
arrow.addPoint(dx + 5, dy + 7);
|
||||
arrow.addPoint(dx, dy + 7);
|
||||
|
||||
g.setColor(Color.red);
|
||||
g.fillPolygon(arrow);
|
||||
g.setColor(Color.black);
|
||||
g.drawPolygon(arrow);
|
||||
}
|
||||
};
|
||||
|
51
scripting/examples/java/debugger/OORhinoDebugger.java
Normal file
51
scripting/examples/java/debugger/OORhinoDebugger.java
Normal file
@@ -0,0 +1,51 @@
|
||||
import drafts.com.sun.star.script.framework.runtime.XScriptContext;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.mozilla.javascript.*;
|
||||
import org.mozilla.javascript.tools.debugger.*;
|
||||
|
||||
public class OORhinoDebugger implements OOScriptDebugger {
|
||||
|
||||
public void go(final XScriptContext xsctxt, String filename) {
|
||||
try {
|
||||
final Main sdb = new Main("Rhino JavaScript Debugger");
|
||||
swingInvoke(new Runnable() {
|
||||
public void run() {
|
||||
sdb.pack();
|
||||
sdb.setSize(640, 640);
|
||||
sdb.setVisible(true);
|
||||
}
|
||||
});
|
||||
sdb.setExitAction(new Runnable() {
|
||||
public void run() {
|
||||
sdb.dispose();
|
||||
}
|
||||
});
|
||||
Context.addContextListener(sdb);
|
||||
sdb.setScopeProvider(new ScopeProvider() {
|
||||
public Scriptable getScope() {
|
||||
Context ctxt = Context.enter();
|
||||
ImporterTopLevel scope = new ImporterTopLevel(ctxt);
|
||||
Scriptable jsArgs = Context.toObject(xsctxt, scope);
|
||||
scope.put("XSCRIPTCONTEXT", scope, jsArgs);
|
||||
Context.exit();
|
||||
return scope;
|
||||
}
|
||||
});
|
||||
sdb.openFile(filename);
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static void swingInvoke(Runnable f) {
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
f.run();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(f);
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
5
scripting/examples/java/debugger/OOScriptDebugger.java
Normal file
5
scripting/examples/java/debugger/OOScriptDebugger.java
Normal file
@@ -0,0 +1,5 @@
|
||||
import drafts.com.sun.star.script.framework.runtime.XScriptContext;
|
||||
|
||||
public interface OOScriptDebugger {
|
||||
public void go(XScriptContext ctxt, String filename);
|
||||
}
|
17
scripting/examples/java/debugger/parcel-descriptor.xml
Normal file
17
scripting/examples/java/debugger/parcel-descriptor.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<parcel language="Java">
|
||||
|
||||
<script language="Java">
|
||||
<locale lang="en">
|
||||
<displayname value="asdf.doMethod" />
|
||||
<description>asdf.doMethod</description>
|
||||
</locale>
|
||||
<logicalname value="DebugRunner.Debug" />
|
||||
<functionname value="DebugRunner.go" />
|
||||
<languagedepprops>
|
||||
<prop name="classpath" value="debugger.jar"/>
|
||||
</languagedepprops>
|
||||
</script>
|
||||
</parcel>
|
||||
|
Reference in New Issue
Block a user