Hack: Move over Rhino debugger to helma.scripting.rhino.debug because most of the internals
are defined as package-private so there's no way to subclass unless we're in the same package.
This commit is contained in:
parent
2373d63719
commit
fb04c05289
8 changed files with 4838 additions and 0 deletions
63
src/helma/scripting/rhino/debug/AbstractCellEditor.java
Normal file
63
src/helma/scripting/rhino/debug/AbstractCellEditor.java
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
package helma.scripting.rhino.debug;
|
||||
import java.awt.Component;
|
||||
|
||||
import java.awt.event.*;
|
||||
import java.awt.AWTEvent;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
import java.util.EventObject;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class AbstractCellEditor implements CellEditor {
|
||||
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
public Object getCellEditorValue() { return null; }
|
||||
public boolean isCellEditable(EventObject e) { return true; }
|
||||
public boolean shouldSelectCell(EventObject anEvent) { return false; }
|
||||
public boolean stopCellEditing() { return true; }
|
||||
public void cancelCellEditing() {}
|
||||
|
||||
public void addCellEditorListener(CellEditorListener l) {
|
||||
listenerList.add(CellEditorListener.class, l);
|
||||
}
|
||||
|
||||
public void removeCellEditorListener(CellEditorListener l) {
|
||||
listenerList.remove(CellEditorListener.class, l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireEditingStopped() {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==CellEditorListener.class) {
|
||||
((CellEditorListener)listeners[i+1]).editingStopped(new ChangeEvent(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireEditingCanceled() {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==CellEditorListener.class) {
|
||||
((CellEditorListener)listeners[i+1]).editingCanceled(new ChangeEvent(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
198
src/helma/scripting/rhino/debug/AbstractTreeTableModel.java
Normal file
198
src/helma/scripting/rhino/debug/AbstractTreeTableModel.java
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* @(#)AbstractTreeTableModel.java 1.2 98/10/27
|
||||
*
|
||||
* Copyright 1997, 1998 by Sun Microsystems, Inc.,
|
||||
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is the confidential and proprietary information
|
||||
* of Sun Microsystems, Inc. ("Confidential Information"). You
|
||||
* shall not disclose such Confidential Information and shall use
|
||||
* it only in accordance with the terms of the license agreement
|
||||
* you entered into with Sun.
|
||||
*/
|
||||
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
import javax.swing.tree.*;
|
||||
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* @version 1.2 10/27/98
|
||||
* An abstract implementation of the TreeTableModel interface, handling the list
|
||||
* of listeners.
|
||||
* @author Philip Milne
|
||||
*/
|
||||
|
||||
public abstract class AbstractTreeTableModel implements TreeTableModel {
|
||||
protected Object root;
|
||||
protected EventListenerList listenerList = new EventListenerList();
|
||||
|
||||
public AbstractTreeTableModel(Object root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
//
|
||||
// Default implmentations for methods in the TreeModel interface.
|
||||
//
|
||||
|
||||
public Object getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
public boolean isLeaf(Object node) {
|
||||
return getChildCount(node) == 0;
|
||||
}
|
||||
|
||||
public void valueForPathChanged(TreePath path, Object newValue) {}
|
||||
|
||||
// This is not called in the JTree's default mode: use a naive implementation.
|
||||
public int getIndexOfChild(Object parent, Object child) {
|
||||
for (int i = 0; i < getChildCount(parent); i++) {
|
||||
if (getChild(parent, i).equals(child)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void addTreeModelListener(TreeModelListener l) {
|
||||
listenerList.add(TreeModelListener.class, l);
|
||||
}
|
||||
|
||||
public void removeTreeModelListener(TreeModelListener l) {
|
||||
listenerList.remove(TreeModelListener.class, l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireTreeNodesChanged(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireTreeNodesInserted(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireTreeNodesRemoved(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify all listeners that have registered interest for
|
||||
* notification on this event type. The event instance
|
||||
* is lazily created using the parameters passed into
|
||||
* the fire method.
|
||||
* @see EventListenerList
|
||||
*/
|
||||
protected void fireTreeStructureChanged(Object source, Object[] path,
|
||||
int[] childIndices,
|
||||
Object[] children) {
|
||||
// Guaranteed to return a non-null array
|
||||
Object[] listeners = listenerList.getListenerList();
|
||||
TreeModelEvent e = null;
|
||||
// Process the listeners last to first, notifying
|
||||
// those that are interested in this event
|
||||
for (int i = listeners.length-2; i>=0; i-=2) {
|
||||
if (listeners[i]==TreeModelListener.class) {
|
||||
// Lazily create the event:
|
||||
if (e == null)
|
||||
e = new TreeModelEvent(source, path,
|
||||
childIndices, children);
|
||||
((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Default impelmentations for methods in the TreeTableModel interface.
|
||||
//
|
||||
|
||||
public Class getColumnClass(int column) { return Object.class; }
|
||||
|
||||
/** By default, make the column with the Tree in it the only editable one.
|
||||
* Making this column editable causes the JTable to forward mouse
|
||||
* and keyboard events in the Tree column to the underlying JTree.
|
||||
*/
|
||||
public boolean isCellEditable(Object node, int column) {
|
||||
return getColumnClass(column) == TreeTableModel.class;
|
||||
}
|
||||
|
||||
public void setValueAt(Object aValue, Object node, int column) {}
|
||||
|
||||
|
||||
// Left to be implemented in the subclass:
|
||||
|
||||
/*
|
||||
* public Object getChild(Object parent, int index)
|
||||
* public int getChildCount(Object parent)
|
||||
* public int getColumnCount()
|
||||
* public String getColumnName(Object node, int column)
|
||||
* public Object getValueAt(Object node, int column)
|
||||
*/
|
||||
}
|
356
src/helma/scripting/rhino/debug/JTreeTable.java
Normal file
356
src/helma/scripting/rhino/debug/JTreeTable.java
Normal file
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* @(#)JTreeTable.java 1.2 98/10/27
|
||||
*
|
||||
* Copyright 1997, 1998 by Sun Microsystems, Inc.,
|
||||
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is the confidential and proprietary information
|
||||
* of Sun Microsystems, Inc. ("Confidential Information"). You
|
||||
* shall not disclose such Confidential Information and shall use
|
||||
* it only in accordance with the terms of the license agreement
|
||||
* you entered into with Sun.
|
||||
*/
|
||||
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
import javax.swing.*;
|
||||
|
||||
import javax.swing.event.*;
|
||||
import javax.swing.tree.*;
|
||||
import javax.swing.table.*;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Component;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This example shows how to create a simple JTreeTable component,
|
||||
* by using a JTree as a renderer (and editor) for the cells in a
|
||||
* particular column in the JTable.
|
||||
*
|
||||
* @version 1.2 10/27/98
|
||||
*
|
||||
* @author Philip Milne
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public class JTreeTable extends JTable {
|
||||
/** A subclass of JTree. */
|
||||
protected TreeTableCellRenderer tree;
|
||||
|
||||
public JTreeTable(TreeTableModel treeTableModel) {
|
||||
super();
|
||||
|
||||
// Create the tree. It will be used as a renderer and editor.
|
||||
tree = new TreeTableCellRenderer(treeTableModel);
|
||||
|
||||
// Install a tableModel representing the visible rows in the tree.
|
||||
super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
|
||||
|
||||
// Force the JTable and JTree to share their row selection models.
|
||||
ListToTreeSelectionModelWrapper selectionWrapper = new
|
||||
ListToTreeSelectionModelWrapper();
|
||||
tree.setSelectionModel(selectionWrapper);
|
||||
setSelectionModel(selectionWrapper.getListSelectionModel());
|
||||
|
||||
// Install the tree editor renderer and editor.
|
||||
setDefaultRenderer(TreeTableModel.class, tree);
|
||||
setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
|
||||
|
||||
// No grid.
|
||||
setShowGrid(false);
|
||||
|
||||
// No intercell spacing
|
||||
setIntercellSpacing(new Dimension(0, 0));
|
||||
|
||||
// And update the height of the trees row to match that of
|
||||
// the table.
|
||||
if (tree.getRowHeight() < 1) {
|
||||
// Metal looks better like this.
|
||||
setRowHeight(18);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to message super and forward the method to the tree.
|
||||
* Since the tree is not actually in the component hieachy it will
|
||||
* never receive this unless we forward it in this manner.
|
||||
*/
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
if(tree != null) {
|
||||
tree.updateUI();
|
||||
}
|
||||
// Use the tree's default foreground and background colors in the
|
||||
// table.
|
||||
LookAndFeel.installColorsAndFont(this, "Tree.background",
|
||||
"Tree.foreground", "Tree.font");
|
||||
}
|
||||
|
||||
/* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
|
||||
* paint the editor. The UI currently uses different techniques to
|
||||
* paint the renderers and editors and overriding setBounds() below
|
||||
* is not the right thing to do for an editor. Returning -1 for the
|
||||
* editing row in this case, ensures the editor is never painted.
|
||||
*/
|
||||
public int getEditingRow() {
|
||||
return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
|
||||
editingRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to pass the new rowHeight to the tree.
|
||||
*/
|
||||
public void setRowHeight(int rowHeight) {
|
||||
super.setRowHeight(rowHeight);
|
||||
if (tree != null && tree.getRowHeight() != rowHeight) {
|
||||
tree.setRowHeight(getRowHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tree that is being shared between the model.
|
||||
*/
|
||||
public JTree getTree() {
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* A TreeCellRenderer that displays a JTree.
|
||||
*/
|
||||
public class TreeTableCellRenderer extends JTree implements
|
||||
TableCellRenderer {
|
||||
/** Last table/tree row asked to renderer. */
|
||||
protected int visibleRow;
|
||||
|
||||
public TreeTableCellRenderer(TreeModel model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* updateUI is overridden to set the colors of the Tree's renderer
|
||||
* to match that of the table.
|
||||
*/
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
// Make the tree's cell renderer use the table's cell selection
|
||||
// colors.
|
||||
TreeCellRenderer tcr = getCellRenderer();
|
||||
if (tcr instanceof DefaultTreeCellRenderer) {
|
||||
DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
|
||||
// For 1.1 uncomment this, 1.2 has a bug that will cause an
|
||||
// exception to be thrown if the border selection color is
|
||||
// null.
|
||||
// dtcr.setBorderSelectionColor(null);
|
||||
dtcr.setTextSelectionColor(UIManager.getColor
|
||||
("Table.selectionForeground"));
|
||||
dtcr.setBackgroundSelectionColor(UIManager.getColor
|
||||
("Table.selectionBackground"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the row height of the tree, and forwards the row height to
|
||||
* the table.
|
||||
*/
|
||||
public void setRowHeight(int rowHeight) {
|
||||
if (rowHeight > 0) {
|
||||
super.setRowHeight(rowHeight);
|
||||
if (JTreeTable.this != null &&
|
||||
JTreeTable.this.getRowHeight() != rowHeight) {
|
||||
JTreeTable.this.setRowHeight(getRowHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is overridden to set the height to match that of the JTable.
|
||||
*/
|
||||
public void setBounds(int x, int y, int w, int h) {
|
||||
super.setBounds(x, 0, w, JTreeTable.this.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sublcassed to translate the graphics such that the last visible
|
||||
* row will be drawn at 0,0.
|
||||
*/
|
||||
public void paint(Graphics g) {
|
||||
g.translate(0, -visibleRow * getRowHeight());
|
||||
super.paint(g);
|
||||
}
|
||||
|
||||
/**
|
||||
* TreeCellRenderer method. Overridden to update the visible row.
|
||||
*/
|
||||
public Component getTableCellRendererComponent(JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
boolean hasFocus,
|
||||
int row, int column) {
|
||||
if(isSelected)
|
||||
setBackground(table.getSelectionBackground());
|
||||
else
|
||||
setBackground(table.getBackground());
|
||||
|
||||
visibleRow = row;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TreeTableCellEditor implementation. Component returned is the
|
||||
* JTree.
|
||||
*/
|
||||
public class TreeTableCellEditor extends AbstractCellEditor implements
|
||||
TableCellEditor {
|
||||
public Component getTableCellEditorComponent(JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
int r, int c) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to return false, and if the event is a mouse event
|
||||
* it is forwarded to the tree.<p>
|
||||
* The behavior for this is debatable, and should really be offered
|
||||
* as a property. By returning false, all keyboard actions are
|
||||
* implemented in terms of the table. By returning true, the
|
||||
* tree would get a chance to do something with the keyboard
|
||||
* events. For the most part this is ok. But for certain keys,
|
||||
* such as left/right, the tree will expand/collapse where as
|
||||
* the table focus should really move to a different column. Page
|
||||
* up/down should also be implemented in terms of the table.
|
||||
* By returning false this also has the added benefit that clicking
|
||||
* outside of the bounds of the tree node, but still in the tree
|
||||
* column will select the row, whereas if this returned true
|
||||
* that wouldn't be the case.
|
||||
* <p>By returning false we are also enforcing the policy that
|
||||
* the tree will never be editable (at least by a key sequence).
|
||||
*/
|
||||
public boolean isCellEditable(EventObject e) {
|
||||
if (e instanceof MouseEvent) {
|
||||
for (int counter = getColumnCount() - 1; counter >= 0;
|
||||
counter--) {
|
||||
if (getColumnClass(counter) == TreeTableModel.class) {
|
||||
MouseEvent me = (MouseEvent)e;
|
||||
MouseEvent newME = new MouseEvent(tree, me.getID(),
|
||||
me.getWhen(), me.getModifiers(),
|
||||
me.getX() - getCellRect(0, counter, true).x,
|
||||
me.getY(), me.getClickCount(),
|
||||
me.isPopupTrigger());
|
||||
tree.dispatchEvent(newME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
|
||||
* to listen for changes in the ListSelectionModel it maintains. Once
|
||||
* a change in the ListSelectionModel happens, the paths are updated
|
||||
* in the DefaultTreeSelectionModel.
|
||||
*/
|
||||
class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
|
||||
/** Set to true when we are updating the ListSelectionModel. */
|
||||
protected boolean updatingListSelectionModel;
|
||||
|
||||
public ListToTreeSelectionModelWrapper() {
|
||||
super();
|
||||
getListSelectionModel().addListSelectionListener
|
||||
(createListSelectionListener());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list selection model. ListToTreeSelectionModelWrapper
|
||||
* listens for changes to this model and updates the selected paths
|
||||
* accordingly.
|
||||
*/
|
||||
ListSelectionModel getListSelectionModel() {
|
||||
return listSelectionModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is overridden to set <code>updatingListSelectionModel</code>
|
||||
* and message super. This is the only place DefaultTreeSelectionModel
|
||||
* alters the ListSelectionModel.
|
||||
*/
|
||||
public void resetRowSelection() {
|
||||
if(!updatingListSelectionModel) {
|
||||
updatingListSelectionModel = true;
|
||||
try {
|
||||
super.resetRowSelection();
|
||||
}
|
||||
finally {
|
||||
updatingListSelectionModel = false;
|
||||
}
|
||||
}
|
||||
// Notice how we don't message super if
|
||||
// updatingListSelectionModel is true. If
|
||||
// updatingListSelectionModel is true, it implies the
|
||||
// ListSelectionModel has already been updated and the
|
||||
// paths are the only thing that needs to be updated.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns an instance of ListSelectionHandler.
|
||||
*/
|
||||
protected ListSelectionListener createListSelectionListener() {
|
||||
return new ListSelectionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* If <code>updatingListSelectionModel</code> is false, this will
|
||||
* reset the selected paths from the selected rows in the list
|
||||
* selection model.
|
||||
*/
|
||||
protected void updateSelectedPathsFromSelectedRows() {
|
||||
if(!updatingListSelectionModel) {
|
||||
updatingListSelectionModel = true;
|
||||
try {
|
||||
// This is way expensive, ListSelectionModel needs an
|
||||
// enumerator for iterating.
|
||||
int min = listSelectionModel.getMinSelectionIndex();
|
||||
int max = listSelectionModel.getMaxSelectionIndex();
|
||||
|
||||
clearSelection();
|
||||
if(min != -1 && max != -1) {
|
||||
for(int counter = min; counter <= max; counter++) {
|
||||
if(listSelectionModel.isSelectedIndex(counter)) {
|
||||
TreePath selPath = tree.getPathForRow
|
||||
(counter);
|
||||
|
||||
if(selPath != null) {
|
||||
addSelectionPath(selPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
updatingListSelectionModel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class responsible for calling updateSelectedPathsFromSelectedRows
|
||||
* when the selection of the list changse.
|
||||
*/
|
||||
class ListSelectionHandler implements ListSelectionListener {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
updateSelectedPathsFromSelectedRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3640
src/helma/scripting/rhino/debug/Main.java
Normal file
3640
src/helma/scripting/rhino/debug/Main.java
Normal file
File diff suppressed because it is too large
Load diff
43
src/helma/scripting/rhino/debug/ScopeProvider.java
Normal file
43
src/helma/scripting/rhino/debug/ScopeProvider.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino JavaScript Debugger code, released
|
||||
* November 21, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is See Beyond Corporation.
|
||||
|
||||
* Portions created by See Beyond are
|
||||
* Copyright (C) 2000 See Beyond Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Oliver
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
public interface ScopeProvider {
|
||||
public Scriptable getScope();
|
||||
};
|
71
src/helma/scripting/rhino/debug/TreeTableModel.java
Normal file
71
src/helma/scripting/rhino/debug/TreeTableModel.java
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* TreeTableModel.java
|
||||
*
|
||||
* Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
|
||||
*
|
||||
* This software is the confidential and proprietary information of Sun
|
||||
* Microsystems, Inc. ("Confidential Information"). You shall not
|
||||
* disclose such Confidential Information and shall use it only in
|
||||
* accordance with the terms of the license agreement you entered into
|
||||
* with Sun.
|
||||
*
|
||||
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
|
||||
* SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
|
||||
* SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
|
||||
* THIS SOFTWARE OR ITS DERIVATIVES.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
import javax.swing.tree.TreeModel;
|
||||
|
||||
|
||||
/**
|
||||
* TreeTableModel is the model used by a JTreeTable. It extends TreeModel
|
||||
* to add methods for getting inforamtion about the set of columns each
|
||||
* node in the TreeTableModel may have. Each column, like a column in
|
||||
* a TableModel, has a name and a type associated with it. Each node in
|
||||
* the TreeTableModel can return a value for each of the columns and
|
||||
* set that value if isCellEditable() returns true.
|
||||
*
|
||||
* @author Philip Milne
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public interface TreeTableModel extends TreeModel
|
||||
{
|
||||
/**
|
||||
* Returns the number ofs availible column.
|
||||
*/
|
||||
public int getColumnCount();
|
||||
|
||||
/**
|
||||
* Returns the name for column number <code>column</code>.
|
||||
*/
|
||||
public String getColumnName(int column);
|
||||
|
||||
/**
|
||||
* Returns the type for column number <code>column</code>.
|
||||
*/
|
||||
public Class getColumnClass(int column);
|
||||
|
||||
/**
|
||||
* Returns the value to be displayed for node <code>node</code>,
|
||||
* at column number <code>column</code>.
|
||||
*/
|
||||
public Object getValueAt(Object node, int column);
|
||||
|
||||
/**
|
||||
* Indicates whether the the value for node <code>node</code>,
|
||||
* at column number <code>column</code> is editable.
|
||||
*/
|
||||
public boolean isCellEditable(Object node, int column);
|
||||
|
||||
/**
|
||||
* Sets the value for node <code>node</code>,
|
||||
* at column number <code>column</code>.
|
||||
*/
|
||||
public void setValueAt(Object aValue, Object node, int column);
|
||||
}
|
128
src/helma/scripting/rhino/debug/TreeTableModelAdapter.java
Normal file
128
src/helma/scripting/rhino/debug/TreeTableModelAdapter.java
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* @(#)TreeTableModelAdapter.java 1.2 98/10/27
|
||||
*
|
||||
* Copyright 1997, 1998 by Sun Microsystems, Inc.,
|
||||
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is the confidential and proprietary information
|
||||
* of Sun Microsystems, Inc. ("Confidential Information"). You
|
||||
* shall not disclose such Confidential Information and shall use
|
||||
* it only in accordance with the terms of the license agreement
|
||||
* you entered into with Sun.
|
||||
*/
|
||||
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
import javax.swing.JTree;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import javax.swing.event.TreeModelEvent;
|
||||
import javax.swing.event.TreeModelListener;
|
||||
|
||||
/**
|
||||
* This is a wrapper class takes a TreeTableModel and implements
|
||||
* the table model interface. The implementation is trivial, with
|
||||
* all of the event dispatching support provided by the superclass:
|
||||
* the AbstractTableModel.
|
||||
*
|
||||
* @version 1.2 10/27/98
|
||||
*
|
||||
* @author Philip Milne
|
||||
* @author Scott Violet
|
||||
*/
|
||||
public class TreeTableModelAdapter extends AbstractTableModel
|
||||
{
|
||||
JTree tree;
|
||||
TreeTableModel treeTableModel;
|
||||
|
||||
public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) {
|
||||
this.tree = tree;
|
||||
this.treeTableModel = treeTableModel;
|
||||
|
||||
tree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
// Don't use fireTableRowsInserted() here; the selection model
|
||||
// would get updated twice.
|
||||
public void treeExpanded(TreeExpansionEvent event) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
public void treeCollapsed(TreeExpansionEvent event) {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
});
|
||||
|
||||
// Install a TreeModelListener that can update the table when
|
||||
// tree changes. We use delayedFireTableDataChanged as we can
|
||||
// not be guaranteed the tree will have finished processing
|
||||
// the event before us.
|
||||
treeTableModel.addTreeModelListener(new TreeModelListener() {
|
||||
public void treeNodesChanged(TreeModelEvent e) {
|
||||
delayedFireTableDataChanged();
|
||||
}
|
||||
|
||||
public void treeNodesInserted(TreeModelEvent e) {
|
||||
delayedFireTableDataChanged();
|
||||
}
|
||||
|
||||
public void treeNodesRemoved(TreeModelEvent e) {
|
||||
delayedFireTableDataChanged();
|
||||
}
|
||||
|
||||
public void treeStructureChanged(TreeModelEvent e) {
|
||||
delayedFireTableDataChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Wrappers, implementing TableModel interface.
|
||||
|
||||
public int getColumnCount() {
|
||||
return treeTableModel.getColumnCount();
|
||||
}
|
||||
|
||||
public String getColumnName(int column) {
|
||||
return treeTableModel.getColumnName(column);
|
||||
}
|
||||
|
||||
public Class getColumnClass(int column) {
|
||||
return treeTableModel.getColumnClass(column);
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return tree.getRowCount();
|
||||
}
|
||||
|
||||
protected Object nodeForRow(int row) {
|
||||
TreePath treePath = tree.getPathForRow(row);
|
||||
return treePath.getLastPathComponent();
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int column) {
|
||||
return treeTableModel.getValueAt(nodeForRow(row), column);
|
||||
}
|
||||
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return treeTableModel.isCellEditable(nodeForRow(row), column);
|
||||
}
|
||||
|
||||
public void setValueAt(Object value, int row, int column) {
|
||||
treeTableModel.setValueAt(value, nodeForRow(row), column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes fireTableDataChanged after all the pending events have been
|
||||
* processed. SwingUtilities.invokeLater is used to handle this.
|
||||
*/
|
||||
protected void delayedFireTableDataChanged() {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
fireTableDataChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
339
src/helma/scripting/rhino/debug/VariableModel.java
Normal file
339
src/helma/scripting/rhino/debug/VariableModel.java
Normal file
|
@ -0,0 +1,339 @@
|
|||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino JavaScript Debugger code, released
|
||||
* November 21, 2000.
|
||||
*
|
||||
* The Initial Developer of the Original Code is SeeBeyond Corporation.
|
||||
|
||||
* Portions created by SeeBeyond are
|
||||
* Copyright (C) 2000 SeeBeyond Technology Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Christopher Oliver
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package helma.scripting.rhino.debug;
|
||||
import org.mozilla.javascript.*;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class VariableModel extends AbstractTreeTableModel
|
||||
implements TreeTableModel {
|
||||
|
||||
// Names of the columns.
|
||||
|
||||
static protected String[] cNames = { " Name", " Value"};
|
||||
|
||||
// Types of the columns.
|
||||
|
||||
static protected Class[] cTypes = {TreeTableModel.class, String.class};
|
||||
|
||||
|
||||
public VariableModel(Scriptable scope) {
|
||||
super(scope == null ? null : new VariableNode(scope, "this"));
|
||||
}
|
||||
|
||||
//
|
||||
// Some convenience methods.
|
||||
//
|
||||
|
||||
protected Object getObject(Object node) {
|
||||
VariableNode varNode = ((VariableNode)node);
|
||||
if (varNode == null) return null;
|
||||
return varNode.getObject();
|
||||
}
|
||||
|
||||
protected Object[] getChildren(Object node) {
|
||||
VariableNode varNode = ((VariableNode)node);
|
||||
return varNode.getChildren();
|
||||
}
|
||||
|
||||
//
|
||||
// The TreeModel interface
|
||||
//
|
||||
|
||||
public int getChildCount(Object node) {
|
||||
Object[] children = getChildren(node);
|
||||
return (children == null) ? 0 : children.length;
|
||||
}
|
||||
|
||||
public Object getChild(Object node, int i) {
|
||||
return getChildren(node)[i];
|
||||
}
|
||||
|
||||
// The superclass's implementation would work, but this is more efficient.
|
||||
public boolean isLeaf(Object node) {
|
||||
if (node == null) return true;
|
||||
VariableNode varNode = (VariableNode)node;
|
||||
Object[] children = varNode.getChildren();
|
||||
if (children != null && children.length > 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isCellEditable(Object node, int column) {
|
||||
return column == 0;
|
||||
}
|
||||
|
||||
//
|
||||
// The TreeTableNode interface.
|
||||
//
|
||||
|
||||
public int getColumnCount() {
|
||||
return cNames.length;
|
||||
}
|
||||
|
||||
public String getColumnName(int column) {
|
||||
return cNames[column];
|
||||
}
|
||||
|
||||
public Class getColumnClass(int column) {
|
||||
return cTypes[column];
|
||||
}
|
||||
|
||||
public Object getValueAt(Object node, int column) {
|
||||
Context cx = Context.enter();
|
||||
try {
|
||||
Object value = getObject(node);
|
||||
switch (column) {
|
||||
case 0: // Name
|
||||
VariableNode varNode = (VariableNode)node;
|
||||
String name = "";
|
||||
if (varNode.name != null) {
|
||||
return name + varNode.name;
|
||||
}
|
||||
return name + "[" + varNode.index + "]";
|
||||
case 1: // Value
|
||||
if (value == Undefined.instance ||
|
||||
value == ScriptableObject.NOT_FOUND) {
|
||||
return "undefined";
|
||||
}
|
||||
if (value == null) {
|
||||
return "null";
|
||||
}
|
||||
if (value instanceof NativeCall) {
|
||||
return "[object Call]";
|
||||
}
|
||||
String result;
|
||||
try {
|
||||
result = Context.toString(value);
|
||||
} catch (RuntimeException exc) {
|
||||
result = exc.getMessage();
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
int len = result.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char ch = result.charAt(i);
|
||||
if (Character.isISOControl(ch)) {
|
||||
ch = ' ';
|
||||
}
|
||||
buf.append(ch);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
//exc.printStackTrace();
|
||||
} finally {
|
||||
cx.exit();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setScope(Scriptable scope) {
|
||||
VariableNode rootVar = (VariableNode)root;
|
||||
rootVar.scope = scope;
|
||||
fireTreeNodesChanged(this,
|
||||
new Object[]{root},
|
||||
null, new Object[]{root});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class VariableNode {
|
||||
Scriptable scope;
|
||||
String name;
|
||||
int index;
|
||||
|
||||
public VariableNode(Scriptable scope, String name) {
|
||||
this.scope = scope;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public VariableNode(Scriptable scope, int index) {
|
||||
this.scope = scope;
|
||||
this.name = null;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the the string to be used to display this leaf in the JTree.
|
||||
*/
|
||||
public String toString() {
|
||||
return (name != null ? name : "[" + index + "]");
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
try {
|
||||
if (scope == null) return null;
|
||||
if (name != null) {
|
||||
if (name.equals("this")) {
|
||||
return scope;
|
||||
}
|
||||
Object result = ScriptableObject.NOT_FOUND;
|
||||
if (name.equals("__proto__")) {
|
||||
result = scope.getPrototype();
|
||||
} else if (name.equals("__parent__")) {
|
||||
result = scope.getParentScope();
|
||||
} else {
|
||||
try {
|
||||
result = ScriptableObject.getProperty(scope, name);
|
||||
} catch (RuntimeException e) {
|
||||
result = e.getMessage();
|
||||
}
|
||||
}
|
||||
if (result == ScriptableObject.NOT_FOUND) {
|
||||
result = Undefined.instance;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Object result = ScriptableObject.getProperty(scope, index);
|
||||
if (result == ScriptableObject.NOT_FOUND) {
|
||||
result = Undefined.instance;
|
||||
}
|
||||
return result;
|
||||
} catch (Exception exc) {
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
|
||||
Object[] children;
|
||||
|
||||
static final Object[] empty = new Object[0];
|
||||
|
||||
protected Object[] getChildren() {
|
||||
if (children != null) return children;
|
||||
Context cx = Context.enter();
|
||||
try {
|
||||
Object value = getObject();
|
||||
if (value == null) return children = empty;
|
||||
if (value == ScriptableObject.NOT_FOUND ||
|
||||
value == Undefined.instance) {
|
||||
return children = empty;
|
||||
}
|
||||
if (value instanceof Scriptable) {
|
||||
Scriptable scrip = (Scriptable)value;
|
||||
Scriptable proto = scrip.getPrototype();
|
||||
Scriptable parent = scrip.getParentScope();
|
||||
if (scrip.has(0, scrip)) {
|
||||
int len = 0;
|
||||
try {
|
||||
Scriptable start = scrip;
|
||||
Scriptable obj = start;
|
||||
Object result = Undefined.instance;
|
||||
do {
|
||||
if (obj.has("length", start)) {
|
||||
result = obj.get("length", start);
|
||||
if (result != Scriptable.NOT_FOUND)
|
||||
break;
|
||||
}
|
||||
obj = obj.getPrototype();
|
||||
} while (obj != null);
|
||||
if (result instanceof Number) {
|
||||
len = ((Number)result).intValue();
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
}
|
||||
if (parent != null) {
|
||||
len++;
|
||||
}
|
||||
if (proto != null) {
|
||||
len++;
|
||||
}
|
||||
children = new VariableNode[len];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
if (parent != null) {
|
||||
children[i++] = new VariableNode(scrip, "__parent__");
|
||||
j++;
|
||||
}
|
||||
if (proto != null) {
|
||||
children[i++] = new VariableNode(scrip, "__proto__");
|
||||
j++;
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
children[i] = new VariableNode(scrip, i-j);
|
||||
}
|
||||
} else {
|
||||
int len = 0;
|
||||
Hashtable t = new Hashtable();
|
||||
Object[] ids;
|
||||
if (scrip instanceof ScriptableObject) {
|
||||
ids = ((ScriptableObject)scrip).getAllIds();
|
||||
} else {
|
||||
ids = scrip.getIds();
|
||||
}
|
||||
if (ids == null) ids = empty;
|
||||
if (proto != null) t.put("__proto__", "__proto__");
|
||||
if (parent != null) t.put("__parent__", "__parent__");
|
||||
if (ids.length > 0) {
|
||||
for (int j = 0; j < ids.length; j++) {
|
||||
t.put(ids[j], ids[j]);
|
||||
}
|
||||
}
|
||||
ids = new Object[t.size()];
|
||||
Enumeration e = t.keys();
|
||||
int j = 0;
|
||||
while (e.hasMoreElements()) {
|
||||
ids[j++] = e.nextElement().toString();
|
||||
}
|
||||
if (ids != null && ids.length > 0) {
|
||||
java.util.Arrays.sort(ids, new java.util.Comparator() {
|
||||
public int compare(Object l, Object r) {
|
||||
return l.toString().compareToIgnoreCase(r.toString());
|
||||
|
||||
}
|
||||
});
|
||||
len = ids.length;
|
||||
}
|
||||
children = new VariableNode[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
Object id = ids[i];
|
||||
children[i] = new
|
||||
VariableNode(scrip, id.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
} finally {
|
||||
cx.exit();
|
||||
}
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue