Implement our own RhinoDebugger subclass to display scripts in a nice table.
The current implementation is merged from helma_1_4 branch and a bit quirky in regard to repository script source names
This commit is contained in:
parent
fb04c05289
commit
f7e929441c
3 changed files with 276 additions and 11 deletions
|
@ -17,6 +17,8 @@
|
||||||
package helma.scripting.rhino;
|
package helma.scripting.rhino;
|
||||||
|
|
||||||
import helma.scripting.rhino.extensions.*;
|
import helma.scripting.rhino.extensions.*;
|
||||||
|
import helma.scripting.rhino.debug.HelmaDebugger;
|
||||||
|
import helma.scripting.rhino.debug.ScopeProvider;
|
||||||
import helma.framework.core.*;
|
import helma.framework.core.*;
|
||||||
import helma.framework.repository.Resource;
|
import helma.framework.repository.Resource;
|
||||||
import helma.objectmodel.*;
|
import helma.objectmodel.*;
|
||||||
|
@ -27,8 +29,6 @@ import helma.util.CacheMap;
|
||||||
import helma.util.SystemMap;
|
import helma.util.SystemMap;
|
||||||
import helma.util.WrappedMap;
|
import helma.util.WrappedMap;
|
||||||
import org.mozilla.javascript.*;
|
import org.mozilla.javascript.*;
|
||||||
import org.mozilla.javascript.tools.debugger.Main;
|
|
||||||
import org.mozilla.javascript.tools.debugger.ScopeProvider;
|
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.text.*;
|
import java.text.*;
|
||||||
|
@ -65,7 +65,7 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
// Any error that may have been found in global code
|
// Any error that may have been found in global code
|
||||||
String globalError;
|
String globalError;
|
||||||
|
|
||||||
Main debugger = null;
|
HelmaDebugger debugger = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Rhino evaluator for the given application and request evaluator.
|
* Create a Rhino evaluator for the given application and request evaluator.
|
||||||
|
@ -86,12 +86,7 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
|
|
||||||
// Set up visual debugger if rhino.debug = true
|
// Set up visual debugger if rhino.debug = true
|
||||||
if ("true".equals(app.getProperty("rhino.debug"))) {
|
if ("true".equals(app.getProperty("rhino.debug"))) {
|
||||||
debugger = new Main(app.getName() + " Debugger");
|
initDebugger(context);
|
||||||
debugger.setScopeProvider(this);
|
|
||||||
debugger.pack();
|
|
||||||
debugger.setVisible(true);
|
|
||||||
debugger.contextCreated(context);
|
|
||||||
debugger.contextEntered(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default optimization level according to whether debugger is on
|
// Set default optimization level according to whether debugger is on
|
||||||
|
@ -153,6 +148,19 @@ public final class RhinoCore implements ScopeProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void initDebugger(Context context) {
|
||||||
|
if (debugger == null) {
|
||||||
|
debugger = new HelmaDebugger(app.getName());
|
||||||
|
debugger.setScopeProvider(this);
|
||||||
|
debugger.pack();
|
||||||
|
debugger.setLocation(60, 60);
|
||||||
|
}
|
||||||
|
if (!debugger.isVisible())
|
||||||
|
debugger.setVisible(true);
|
||||||
|
debugger.contextCreated(context);
|
||||||
|
debugger.contextEntered(context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the evaluator, making sure the minimum type information
|
* Initialize the evaluator, making sure the minimum type information
|
||||||
* necessary to bootstrap the rest is parsed.
|
* necessary to bootstrap the rest is parsed.
|
||||||
|
|
|
@ -156,8 +156,7 @@ public class RhinoEngine implements ScriptingEngine {
|
||||||
|
|
||||||
// if visual debugger is on let it know we're entering a context
|
// if visual debugger is on let it know we're entering a context
|
||||||
if (core.debugger != null) {
|
if (core.debugger != null) {
|
||||||
core.debugger.contextCreated(context);
|
core.initDebugger(context);
|
||||||
core.debugger.contextEntered(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("true".equals(app.getProperty("rhino.trace"))) {
|
if ("true".equals(app.getProperty("rhino.trace"))) {
|
||||||
|
|
258
src/helma/scripting/rhino/debug/HelmaDebugger.java
Normal file
258
src/helma/scripting/rhino/debug/HelmaDebugger.java
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* Helma License Notice
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Helma License
|
||||||
|
* Version 2.0 (the "License"). You may not use this file except in
|
||||||
|
* compliance with the License. A copy of the License is available at
|
||||||
|
* http://adele.helma.org/download/helma/license.txt
|
||||||
|
*
|
||||||
|
* Copyright 1998-2003 Helma Software. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* $RCSfile$
|
||||||
|
* $Author$
|
||||||
|
* $Revision$
|
||||||
|
* $Date$
|
||||||
|
*/
|
||||||
|
|
||||||
|
package helma.scripting.rhino.debug;
|
||||||
|
|
||||||
|
import org.mozilla.javascript.Context;
|
||||||
|
import org.mozilla.javascript.Scriptable;
|
||||||
|
import org.mozilla.javascript.debug.DebuggableScript;
|
||||||
|
import org.mozilla.javascript.debug.DebugFrame;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.TreeSelectionListener;
|
||||||
|
import javax.swing.event.TreeSelectionEvent;
|
||||||
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
import javax.swing.event.ListSelectionEvent;
|
||||||
|
import javax.swing.tree.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import helma.util.StringUtils;
|
||||||
|
|
||||||
|
public class HelmaDebugger extends Main implements TreeSelectionListener {
|
||||||
|
|
||||||
|
JTree tree;
|
||||||
|
JList list;
|
||||||
|
DebuggerTreeNode treeRoot;
|
||||||
|
DefaultTreeModel treeModel;
|
||||||
|
HashMap treeNodes = new HashMap();
|
||||||
|
HashMap scripts = new HashMap();
|
||||||
|
|
||||||
|
public HelmaDebugger(String name) {
|
||||||
|
super(name);
|
||||||
|
Container contentPane = getContentPane();
|
||||||
|
Component main = contentPane.getComponent(1);
|
||||||
|
contentPane.remove(main);
|
||||||
|
|
||||||
|
treeRoot = new DebuggerTreeNode(name);
|
||||||
|
tree = new JTree(treeRoot);
|
||||||
|
treeModel = new DefaultTreeModel(treeRoot);
|
||||||
|
tree.setModel(treeModel);
|
||||||
|
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
|
tree.addTreeSelectionListener(this);
|
||||||
|
// tree.setRootVisible(false);
|
||||||
|
// track double clicks
|
||||||
|
tree.addMouseListener(new MouseAdapter() {
|
||||||
|
public void mouseClicked(MouseEvent evt) {
|
||||||
|
openScript(tree.getSelectionPath());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// track enter key
|
||||||
|
tree.addKeyListener(new KeyAdapter() {
|
||||||
|
public void keyPressed(KeyEvent evt) {
|
||||||
|
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
|
||||||
|
openScript(tree.getSelectionPath());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JScrollPane treeScroller = new JScrollPane(tree);
|
||||||
|
treeScroller.setPreferredSize(new Dimension(180, 300));
|
||||||
|
|
||||||
|
list = new JList();
|
||||||
|
// no bold font lists for me, thanks
|
||||||
|
list.setFont(list.getFont().deriveFont(Font.PLAIN));
|
||||||
|
list.addMouseListener(new MouseAdapter() {
|
||||||
|
public void mouseClicked(MouseEvent evt) {
|
||||||
|
openFunction((String) list.getSelectedValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
list.addKeyListener(new KeyAdapter() {
|
||||||
|
public void keyPressed(KeyEvent evt) {
|
||||||
|
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
|
||||||
|
openFunction((String) list.getSelectedValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JScrollPane listScroller = new JScrollPane(list);
|
||||||
|
listScroller.setPreferredSize(new Dimension(180, 200));
|
||||||
|
|
||||||
|
JSplitPane split1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||||
|
split1.setTopComponent(treeScroller);
|
||||||
|
split1.setBottomComponent(listScroller);
|
||||||
|
split1.setOneTouchExpandable(true);
|
||||||
|
Main.setResizeWeight(split1, 0.66);
|
||||||
|
|
||||||
|
JSplitPane split2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||||
|
split2.setLeftComponent(split1);
|
||||||
|
split2.setRightComponent(main);
|
||||||
|
split2.setOneTouchExpandable(true);
|
||||||
|
contentPane.add(split2, BorderLayout.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(boolean b) {
|
||||||
|
super.setVisible(b);
|
||||||
|
// hide console window
|
||||||
|
console.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleCompilationDone(Context cx, DebuggableScript fnOrScript,
|
||||||
|
String source) {
|
||||||
|
String sourceName = fnOrScript.getSourceName();
|
||||||
|
if (!treeNodes.containsKey(sourceName)) {
|
||||||
|
createTreeNode(sourceName);
|
||||||
|
}
|
||||||
|
super.handleCompilationDone(cx, fnOrScript, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void createTreeNode(String sourceName) {
|
||||||
|
String[] path = StringUtils.split(sourceName, ":/\\");
|
||||||
|
DebuggerTreeNode node = treeRoot;
|
||||||
|
DebuggerTreeNode newNode = null;
|
||||||
|
for (int i = 1; i < path.length; i++) {
|
||||||
|
DebuggerTreeNode n = node.get(path[i]);
|
||||||
|
if (n == null) {
|
||||||
|
n = new DebuggerTreeNode(path[i]);
|
||||||
|
node.add(n);
|
||||||
|
if (newNode == null) newNode = n;
|
||||||
|
}
|
||||||
|
node = n;
|
||||||
|
}
|
||||||
|
treeNodes.put(sourceName, node);
|
||||||
|
scripts.put(node, sourceName);
|
||||||
|
if (newNode != null) {
|
||||||
|
SwingUtilities.invokeLater(new NodeInserter(newNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void openScript(TreePath path) {
|
||||||
|
if (path == null)
|
||||||
|
return;
|
||||||
|
Object node = path.getLastPathComponent();
|
||||||
|
if (node == null)
|
||||||
|
return;
|
||||||
|
String script = (String) scripts.get(node);
|
||||||
|
if (script == null)
|
||||||
|
return;
|
||||||
|
JInternalFrame w = (JInternalFrame) fileWindows.get(script);
|
||||||
|
if (w != null) {
|
||||||
|
try {
|
||||||
|
if (w.isIcon())
|
||||||
|
w.setMaximum(true);
|
||||||
|
w.show();
|
||||||
|
w.setSelected(true);
|
||||||
|
} catch (Exception exc) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SourceInfo si = (SourceInfo) sourceNames.get(script);
|
||||||
|
if (si == null) {
|
||||||
|
System.out.println("debugger error: Couldn't find source: " + script);
|
||||||
|
}
|
||||||
|
swingInvoke(CreateFileWindow.action(this, si, -1));
|
||||||
|
}
|
||||||
|
// display functions for opened script file
|
||||||
|
Vector functions = new Vector();
|
||||||
|
Iterator it = functionNames.entrySet().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Map.Entry entry = (Map.Entry) it.next();
|
||||||
|
ScriptItem si = (ScriptItem) entry.getValue();
|
||||||
|
if (script.equals(si.getSourceInfo().getUrl())) {
|
||||||
|
functions.add(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(functions);
|
||||||
|
list.setListData(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openFunction(String function) {
|
||||||
|
if (function == null)
|
||||||
|
return;
|
||||||
|
ScriptItem item = (ScriptItem) functionNames.get(function);
|
||||||
|
if (item != null) {
|
||||||
|
SourceInfo si = item.getSourceInfo();
|
||||||
|
String url = si.getUrl();
|
||||||
|
int lineNumber = item.getFirstLine();
|
||||||
|
FileWindow w = getFileWindow(url);
|
||||||
|
if (w == null) {
|
||||||
|
CreateFileWindow.action(this, si, lineNumber).run();
|
||||||
|
w = getFileWindow(url);
|
||||||
|
w.setPosition(-1);
|
||||||
|
}
|
||||||
|
int start = w.getPosition(lineNumber - 1);
|
||||||
|
int end = w.getPosition(lineNumber) - 1;
|
||||||
|
w.textArea.select(start);
|
||||||
|
w.textArea.setCaretPosition(start);
|
||||||
|
w.textArea.moveCaretPosition(end);
|
||||||
|
try {
|
||||||
|
if (w.isIcon())
|
||||||
|
w.setMaximum(true);
|
||||||
|
w.show();
|
||||||
|
requestFocus();
|
||||||
|
w.requestFocus();
|
||||||
|
w.textArea.requestFocus();
|
||||||
|
} catch (Exception exc) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void valueChanged(TreeSelectionEvent e) {
|
||||||
|
DefaultMutableTreeNode node = (DefaultMutableTreeNode)
|
||||||
|
tree.getLastSelectedPathComponent();
|
||||||
|
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
|
Object script = scripts.get(node);
|
||||||
|
if (script != null) {
|
||||||
|
// openScript(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DebuggerTreeNode extends DefaultMutableTreeNode {
|
||||||
|
|
||||||
|
public DebuggerTreeNode(Object obj) {
|
||||||
|
super(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DebuggerTreeNode get(String name) {
|
||||||
|
Enumeration children = this.children();
|
||||||
|
while (children.hasMoreElements()) {
|
||||||
|
DebuggerTreeNode node = (DebuggerTreeNode) children.nextElement();
|
||||||
|
if (node != null && name.equals(node.getUserObject()))
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NodeInserter implements Runnable {
|
||||||
|
MutableTreeNode node;
|
||||||
|
|
||||||
|
NodeInserter(MutableTreeNode node) {
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
MutableTreeNode parent = (MutableTreeNode) node.getParent();
|
||||||
|
if (parent == treeRoot && treeRoot.getChildCount() == 1) {
|
||||||
|
tree.makeVisible(new TreePath(new Object[]{parent, node}));
|
||||||
|
}
|
||||||
|
treeModel.insertNodeInto(node, parent, parent.getIndex(node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue