/***********************************************************************
*
* $CVSHeader$
*
* This file is part of WebScarab, an Open Web Application Security
* Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2004 Rogan Dawes
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Getting Source
* ==============
*
* Source for this application is maintained at Sourceforge.net, a
* repository for free software projects.
*
* For details, please see http://www.sourceforge.net/projects/owasp
*
*/
/*
* ObjectEditorPanel.java
*
* Created on 15 November 2003, 02:56
*/
package org.owasp.webscarab.ui.swing.editors;
import org.owasp.webscarab.util.swing.JTreeTable;
import org.owasp.webscarab.util.swing.treetable.DefaultTreeTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.JOptionPane;
import java.util.Map;
import java.util.Collection;
import java.util.List;
import java.util.Iterator;
import java.util.Date;
import java.text.DateFormat;
import javax.swing.CellEditor;
import java.awt.Component;
/** Provides a Swing Component that can be used to edit and modify a fairly
* arbitrary object structure. A Tree hierarchy is formed from Map and Collection
* classes. All of the java.lang types are supported, and many others as well.
* Fairly arbitrary classes can be instantiated (if they provide void constructors)
* however, the code will need to be modified to provide renderers and editors (or
* String-to-class convertors) in order to modify them successfully.
* @author rdawes
*/
public class ObjectPanel extends javax.swing.JPanel {
/**
*
*/
private static final long serialVersionUID = -1149080437965386611L;
private JTreeTable _tt;
private ObjectTreeTableModel _ottm;
private boolean _editable = false;
/** Creates new form ObjectPanel */
public ObjectPanel() {
initComponents();
setName("Object");
_ottm = new ObjectTreeTableModel();
_tt = new JTreeTable(_ottm) {
/**
*
*/
private static final long serialVersionUID = -6733180628013589307L;
public TableCellRenderer getCellRenderer(int row, int column) {
if (column == 2) {
Object o = ((ObjectTreeNode)getValueAt(row, 0)).getUserObject();
if (o != null) {
return getDefaultRenderer(o.getClass());
}
}
return super.getCellRenderer(row, column);
}
public TableCellEditor getCellEditor(int row, int column) {
if (column == 2) {
Object o = ((ObjectTreeNode)getValueAt(row, 0)).getUserObject();
if (o != null) {
return getDefaultEditor(o.getClass());
}
}
return super.getCellEditor(row, column);
}
};
_tt.setDefaultRenderer(Date.class, new DateRenderer());
ArrayRenderer ar = new ArrayRenderer();
_tt.setDefaultRenderer(byte[].class, ar);
_tt.setDefaultEditor(Date.class, new DateEditor());
_tt.setCellSelectionEnabled(true);
ttScrollPane.setViewportView(_tt);
setEditable(false);
}
/** Supplies the object to be edited
* @param object the object to be edited/displayed
*/
public void setObject(Object object) {
_ottm.setObject(object);
}
private void stopEditing() {
Component comp = _tt.getEditorComponent();
if (comp != null && comp instanceof CellEditor) {
((CellEditor) comp).stopCellEditing();
}
}
/** Returns the object that is currently being displayed
* @return The object
*/
public Object getObject() {
if (_editable) stopEditing();
return _ottm.getObject();
}
/** Allows one to specify whether the object may be edited or not.
* @param editable whether to allow editing
*/
public void setEditable(boolean editable) {
_editable = editable;
_ottm.setEditable(editable);
insertButton.setVisible(editable);
childButton.setVisible(editable);
deleteButton.setVisible(editable);
revalidate();
repaint();
}
public boolean isModified() {
if (_editable) stopEditing();
return _editable && _ottm.isModified();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents() {//GEN-BEGIN:initComponents
java.awt.GridBagConstraints gridBagConstraints;
ttScrollPane = new javax.swing.JScrollPane();
insertButton = new javax.swing.JButton();
childButton = new javax.swing.JButton();
deleteButton = new javax.swing.JButton();
setLayout(new java.awt.GridBagLayout());
ttScrollPane.setMinimumSize(new java.awt.Dimension(300, 200));
ttScrollPane.setPreferredSize(new java.awt.Dimension(300, 200));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridheight = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(ttScrollPane, gridBagConstraints);
insertButton.setText("Insert");
insertButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
insertButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
gridBagConstraints.weighty = 1.0;
add(insertButton, gridBagConstraints);
childButton.setText("New Child");
childButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
childButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
add(childButton, gridBagConstraints);
deleteButton.setText("Delete");
deleteButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deleteButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weighty = 1.0;
add(deleteButton, gridBagConstraints);
}//GEN-END:initComponents
private void childButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_childButtonActionPerformed
javax.swing.tree.TreePath path = _tt.getTree().getSelectionPath();
if (path == null) {
JOptionPane.showMessageDialog(null, "Please select a row", "No selection", JOptionPane.ERROR_MESSAGE);
return;
}
ObjectTreeNode selected = (ObjectTreeNode) path.getLastPathComponent();
Object userObject = selected.getUserObject();
if (userObject instanceof Map) {
Object key = JOptionPane.showInputDialog("Please input a key value");
if (key == null) return;
@SuppressWarnings("unchecked")
Map<Object, ?> map = (Map<Object, ?>) userObject;
if (map.containsKey(key)) {
JOptionPane.showMessageDialog(null, "The Map already contains " + key, "Key exists", JOptionPane.ERROR_MESSAGE);
return;
}
map.put(key, null);
Iterator<Object> it = map.keySet().iterator();
int position = 0;
while (it.hasNext() && it.next() != key) {
position++;
}
ObjectTreeNode newNode = new ObjectTreeNode(null);
newNode.setParentKey(key);
selected.insert(newNode, position);
_ottm.nodesWereInserted(selected, new int[] {position});
} else if (userObject instanceof List) {
List<?> list = (List<?>) userObject;
int position = list.size();
list.add(position, null);
ObjectTreeNode newNode = new ObjectTreeNode(null);
newNode.setParentKey(new Integer(position));
selected.insert(newNode, position);
_ottm.nodesWereInserted(selected, new int[] {position});
}
}//GEN-LAST:event_childButtonActionPerformed
private void insertButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_insertButtonActionPerformed
javax.swing.tree.TreePath path = _tt.getTree().getSelectionPath();
if (path == null) {
JOptionPane.showMessageDialog(null, "Please select a row", "No selection", JOptionPane.ERROR_MESSAGE);
return;
}
ObjectTreeNode selected = (ObjectTreeNode) path.getLastPathComponent();
ObjectTreeNode parent = (ObjectTreeNode) selected.getParent();
if (parent == null) {
JOptionPane.showMessageDialog(null, "It is not possible to insert a node at the root", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
Object parentObject = parent.getUserObject();
if (parentObject instanceof List) {
List<?> list = (List<?>) parentObject;
int position = ((Integer) selected.getParentKey()).intValue();
list.add(position, null);
ObjectTreeNode newNode = new ObjectTreeNode(null);
newNode.setParentKey(new Integer(position));
parent.insert(newNode, position);
_ottm.nodesWereInserted(parent, new int[] {position});
int[] changes = new int[parent.getChildCount() - (position+1)];
for (int i=position+1; i<parent.getChildCount(); i++) {
ObjectTreeNode sib = (ObjectTreeNode) parent.getChildAt(i);
sib.setParentKey(new Integer(i));
changes[i-(position+1)] = i;
}
_ottm.nodesChanged(parent, changes);
} else if (parentObject.getClass().isArray()) {
JOptionPane.showMessageDialog(null, "Don't know how to insert a node into an Array yet", "Error", JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(null, "It is only possible to insert a node into a List", "Error", JOptionPane.ERROR_MESSAGE);
}
}//GEN-LAST:event_insertButtonActionPerformed
private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed
javax.swing.tree.TreePath path = _tt.getTree().getSelectionPath();
if (path == null) {
JOptionPane.showMessageDialog(null, "Please select a row", "No selection", JOptionPane.ERROR_MESSAGE);
return;
}
ObjectTreeNode selected = (ObjectTreeNode) path.getLastPathComponent();
ObjectTreeNode parent = (ObjectTreeNode) selected.getParent();
if (parent == null) {
_ottm.setObject(null);
return;
}
Object parentObject = parent.getUserObject();
if (!(parentObject instanceof List || parentObject instanceof Map)) {
JOptionPane.showMessageDialog(null, "We can only delete children of java.util.List and java.util.Map", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
if (parentObject instanceof Map) {
Map<?, ?> map = (Map<?, ?>) parentObject;
Object key = selected.getParentKey();
int position = parent.getIndex(selected);
try {
map.remove(key);
} catch (UnsupportedOperationException uoe) {
JOptionPane.showMessageDialog(null, "Map returned an UnsupportedOperationException trying to remove " + key, "Error", JOptionPane.ERROR_MESSAGE);
return;
}
parent.remove(position);
_ottm.nodesWereRemoved(parent, new int[] {position}, new Object[] {selected});
} else if (parentObject instanceof List) {
List<?> list = (List<?>) parentObject;
int position = parent.getIndex(selected);
try {
list.remove(position);
} catch (UnsupportedOperationException uoe) {
JOptionPane.showMessageDialog(null, "List returned an UnsupportedOperationException trying to remove " + position, "Error", JOptionPane.ERROR_MESSAGE);
return;
}
parent.remove(position);
_ottm.nodesWereRemoved(parent, new int[] {position}, new Object[] {selected});
}
}//GEN-LAST:event_deleteButtonActionPerformed
public static void main(String[] args) {
java.util.ArrayList<Object> a = new java.util.ArrayList<Object>();
a.add(new String("the string"));
a.add(new Integer(123));
a.add(new Boolean(true));
Map<String, Object> m = new java.util.TreeMap<String, Object>();
m.put("a string", new String("value 1"));
m.put("a boolean", new Boolean(false));
m.put("a byte array", new byte[] {0x00, 0x01});
a.add(m);
a.add(new int[] { 1001, 1002, 1003 });
a.add(new java.util.ArrayList<Object>());
a.add(null);
java.util.Set<Object> s = new java.util.HashSet<Object>();
s.add(new Integer(7));
s.add(new Boolean(true));
s.add(new String("a new String"));
a.add(s);
a.add(new Date());
a.add(new byte[] { 0, 1, 2, 3 });
javax.swing.JFrame top = new javax.swing.JFrame("Object Panel");
top.getContentPane().setLayout(new java.awt.BorderLayout());
top.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
System.exit(0);
}
});
javax.swing.JButton button = new javax.swing.JButton("GET");
final ObjectPanel op = new ObjectPanel();
top.getContentPane().add(op);
top.getContentPane().add(button, java.awt.BorderLayout.SOUTH);
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
System.out.println(op.getObject());
}
});
top.setBounds(100,100,600,400);
top.setVisible(true);
try {
op.setEditable(false);
op.setObject(a);
// Thread.currentThread().sleep(3000);
op.setEditable(true);
} catch (Exception e) {
e.printStackTrace();
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton deleteButton;
private javax.swing.JScrollPane ttScrollPane;
private javax.swing.JButton childButton;
private javax.swing.JButton insertButton;
// End of variables declaration//GEN-END:variables
private class ObjectTreeTableModel extends DefaultTreeTableModel {
/**
*
*/
private static final long serialVersionUID = -310076954129946613L;
private boolean _modified = false;
private boolean _editable = false;
private String[] _columnNames = new String[] { "Key", "Class", "Value" };
public ObjectTreeTableModel() {
super(null, true);
}
public ObjectTreeTableModel(Object object) {
super(null, true); // we have to pass a parameter
setObject(object); // but we override it immediately!
}
public void setEditable(boolean editable) {
_editable = editable;
}
public void setObject(Object object) {
ObjectTreeNode root = createObjectTree(object);
setRoot(root);
nodeStructureChanged(root);
_modified = false; // after we fire, since we have not changed anything yet
}
public boolean isModified() {
return _modified;
}
public Object getObject() {
Object root = getRoot();
return root == null ? null : ((ObjectTreeNode)root).getUserObject();
}
/** Recursively creates ObjectTreeNodes with the UserObject set to
* the appropriate object in the tree hierarchy
*/
private ObjectTreeNode createObjectTree(Object object) {
ObjectTreeNode otn = new ObjectTreeNode(object);
if (object == null) {
return otn;
} else if (object instanceof Collection) {
Collection<?> collection = (Collection<?>) object;
Iterator<?> it = collection.iterator();
int count = 0;
while (it.hasNext()) {
ObjectTreeNode child = createObjectTree(it.next());
child.setParentKey(new Integer(count++));
otn.add(child);
}
} else if (object instanceof Map) {
Map<?, ?> map = (Map<?, ?>) object;
Iterator<?> it = map.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
ObjectTreeNode child = createObjectTree(map.get(key));
child.setParentKey(key);
otn.add(child);
}
} else if (object.getClass().isArray()) {
int length = java.lang.reflect.Array.getLength(object);
for (int i=0; i<length; i++) {
ObjectTreeNode child = new ObjectTreeNode(java.lang.reflect.Array.get(object, i));
child.setParentKey(new Integer(i));
otn.add(child);
}
}
return otn;
}
public int getColumnCount() {
return 3;
}
public String getColumnName(int column) {
return _columnNames[column];
}
public Object getValueAt(Object node, int column) {
ObjectTreeNode otn = (ObjectTreeNode) node;
Object object = otn.getUserObject();
ObjectTreeNode parent = (ObjectTreeNode) otn.getParent();
Object parentObject = null;
if (parent != null) {
parentObject = parent.getUserObject();
}
switch (column) {
case 0 : return node;
case 1 : if (object == null) {
return "void";
} else if (object.getClass().isArray()) {
return object.getClass().getComponentType() + "[]";
} else if (parentObject != null && parentObject.getClass().isArray()) {
return parentObject.getClass().getComponentType().getName();
} else {
return object.getClass().getName();
}
case 2 : return describe(object);
}
return null;
}
private Object describe(Object object) {
if (object == null) {
return "";
} else if (object instanceof Map) {
int size = ((Map<?, ?>)object).size();
return size + " item" + (size != 1 ? "s" : "");
} else if (object instanceof Collection) {
int size = ((Collection<?>)object).size();
return size + " item" + (size != 1 ? "s" : "");
} else if (object.getClass().isArray()) {
int size = java.lang.reflect.Array.getLength(object);
return size + " item" + (size != 1 ? "s" : "");
}
return object;
}
public boolean isCellEditable(Object node, int columnIndex) {
// the tree must be editable so it gets mouse events
// to expand and close nodes
if (columnIndex == 0) {
return true;
} else if (columnIndex == 1 && _editable) {
ObjectTreeNode parent = (ObjectTreeNode) ((ObjectTreeNode)node).getParent();
if (parent != null) {
Object parentObject = parent.getUserObject();
if (parentObject.getClass().isArray()) {
return false;
}
}
return true;
} else if (columnIndex == 2 && _editable) {
Object object = ((ObjectTreeNode)node).getUserObject();
if (object == null) {
return false;
} else if (object instanceof Collection || object instanceof Map || object.getClass().isArray()) {
return false;
} else {
ObjectTreeNode parent = (ObjectTreeNode) ((ObjectTreeNode)node).getParent();
if (parent != null) {
Object parentObject = parent.getUserObject();
if (parentObject instanceof List || parentObject instanceof Map || parentObject.getClass().isArray()) {
return true;
} else {
return false;
}
}
return true;
}
}
return false;
}
private Object newObjectOfClass(String theClass) {
try {
Class<?> aClass = Class.forName(theClass);
java.lang.reflect.Constructor<?>[] constructors = aClass.getConstructors();
if (constructors.length == 0) {
System.err.println(theClass + " has no constructors");
return null;
}
for (int i=0; i<constructors.length; i++) { // first look for void constructors
if (! java.lang.reflect.Modifier.isPublic(constructors[i].getModifiers())) {
continue;
}
Class<?>[] params = constructors[i].getParameterTypes();
if (params.length == 0) {
return constructors[i].newInstance(new Object[0]);
}
}
for (int i=0; i<constructors.length; i++) { // now look for single parameter constructors
if (! java.lang.reflect.Modifier.isPublic(constructors[i].getModifiers())) {
continue;
}
Class<?>[] params = constructors[i].getParameterTypes();
if (params.length == 1) {
if (params[0] == boolean.class) {
return constructors[i].newInstance(new Object[] {new Boolean(false)});
} else if (params[0] == String.class && Number.class.isAssignableFrom(aClass)) {
return constructors[i].newInstance(new Object[] {new String("0")});
} else if (params[0] == char.class) {
return constructors[i].newInstance(new Object[] {new Character('a')});
}
}
}
StringBuffer buff = new StringBuffer();
for (int i=0; i<constructors.length; i++) {
Class<?>[] params = constructors[i].getParameterTypes();
buff.append(java.lang.reflect.Modifier.toString(constructors[i].getModifiers()) + " " + theClass + "(" + params[0].getName());
for (int j=1; j<params.length; j++) {
buff.append(", " + params[j].getName());
}
buff.append(");\n");
}
System.err.println("Cannot instantiate a " + theClass);
System.err.println("Please special case this in newObjectOfClass() using one of the following constructors");
System.err.print(buff);
} catch (Exception e) {
System.err.println("Error instantiating the new object : " + e);
}
return null;
}
private Object convertValueToClass(Object value, Class<? extends Object> theClass) {
if (theClass == value.getClass()) { // The editor did any conversion for us
return value;
} else if (value instanceof String) {
String string = (String) value;
if (Number.class.isAssignableFrom(theClass)) {
try {
if (theClass == Byte.class) {
return new Byte(string);
} else if (value == Double.class) {
return new Double(string);
} else if (theClass == Float.class) {
return new Float(string);
} else if (theClass == Integer.class) {
return new Integer(string);
} else if (theClass == Long.class) {
return new Long(string);
} else if (theClass == Short.class) {
return new Short(string);
} else if (theClass == java.math.BigDecimal.class) {
return new java.math.BigDecimal(string);
} else if (theClass == java.math.BigInteger.class) {
return new java.math.BigInteger(string);
}
return null;
} catch (NumberFormatException nfe) {
System.err.println("Can't parse '" + string + "' as a " + theClass);
return null;
}
} else if (theClass == Boolean.class) {
return Boolean.valueOf(string);
} else if (theClass == Character.class) {
if (string.length()>0) {
return new Character(string.charAt(0));
} else {
return null;
}
} else if (theClass == Date.class) {
try {
return DateFormat.getDateTimeInstance().parse(string);
} catch (java.text.ParseException pe) {
System.err.println("Couldn't parse a date from '" + string + "' : " + pe);
return null;
}
}
}
System.err.println("Don't know how to convert a " + value.getClass().getName() + " to a " + theClass.getName());
System.err.println("Please update convertValueToClass() to support this if it is required");
return null;
}
public void setValueAt(Object aValue, Object node, int column) {
ObjectTreeNode child = (ObjectTreeNode) node;
Object childObject = child.getUserObject();
ObjectTreeNode parent = (ObjectTreeNode) child.getParent();
Object parentObject = null;
int childPosition = -1;
if (parent != null) {
parentObject = parent.getUserObject();
childPosition = parent.getIndex(child);
}
Object key = child.getParentKey();
if (parentObject != null && !(parentObject instanceof List || parentObject instanceof Map || parentObject.getClass().isArray())) {
System.err.println("I only know how to edit children of List or Map, not " + parentObject.getClass().getName());
return;
}
if (column == 0) {
System.err.println("Trying to edit the tree?!");
} else if (column == 1) {
String type = (String) aValue;
if ( (childObject == null && !type.equals("void")) ||
(childObject != null && !type.equals(childObject.getClass().getName())) ) {
if (type.equals("void")) {
childObject = null;
} else {
childObject = newObjectOfClass(type);
if (childObject == null) {
return;
}
}
} else { // we are not changing anything
return;
}
} else if (column == 2) {
if (childObject == null) { // this should not happen if isEditable is working
System.err.println("Please change the object type to a non-void class first!");
return;
}
childObject = convertValueToClass(aValue, childObject.getClass());
if (childObject == null) {
return;
}
} else {
throw new IndexOutOfBoundsException("Tried to edit column " + column);
}
child = createObjectTree(childObject);
child.setParentKey(key);
if (parent != null) { // we are not at the root
if (parentObject instanceof List) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>) parentObject;
list.set(childPosition, childObject);
} else if (parentObject instanceof Map) {
@SuppressWarnings("unchecked")
Map<Object, Object> map = (Map<Object, Object>) parentObject;
map.put(key, childObject);
} else if (parentObject.getClass().isArray()) {
java.lang.reflect.Array.set(parentObject, ((Integer) key).intValue(), childObject);
} else {
System.err.println("Shouldn't get here! ParentObject is a " + parentObject.getClass());
return;
}
_modified = true;
parent.remove(childPosition);
parent.insert(child, childPosition);
nodesChanged(parent, new int[] {childPosition});
} else {
_modified = true;
setRoot(child);
}
}
public void nodesWereInserted(TreeNode node, int[] childIndices) {
super.nodesWereInserted(node, childIndices);
_modified = true;
}
public void nodesWereRemoved(TreeNode node, int[] childIndices,
Object[] removedChildren) {
super.nodesWereRemoved(node, childIndices, removedChildren);
_modified = true;
}
public void nodesChanged(TreeNode node, int[] childIndices) {
super.nodesChanged(node, childIndices);
_modified = true;
}
public void nodeChanged(TreeNode node) {
super.nodeChanged(node);
_modified = true;
}
public void nodeStructureChanged(TreeNode node) {
super.nodeStructureChanged(node);
_modified = true;
}
}
private class ObjectTreeNode extends DefaultMutableTreeNode {
/**
*
*/
private static final long serialVersionUID = -3998840936827564434L;
private Object _key = null;
public ObjectTreeNode(Object object) {
super(object);
if (object instanceof Collection || object instanceof Map) {
setAllowsChildren(true);
} else if (object != null && object.getClass().isArray()) {
setAllowsChildren(true);
} else {
setAllowsChildren(false);
}
}
public void setParentKey(Object key) {
_key = key;
}
public Object getParentKey() {
return _key;
}
public String toString() {
// if we are the root, return "root", otherwise we return the key
return getParent() == null ? "root" : ( _key == null ? "null" : _key.toString() );
}
}
/** A simple CellRenderer to format a Date to include the time */
private class DateRenderer extends javax.swing.table.DefaultTableCellRenderer {
/**
*
*/
private static final long serialVersionUID = 7004833139749646236L;
private DateFormat _df;
public DateRenderer() { super(); }
public void setValue(Object value) {
if (_df == null) {
_df = DateFormat.getDateTimeInstance();
}
setText((value == null) ? "" : _df.format(value));
}
}
/** A simple CellEditor that parses java.util.Date objects */
private class DateEditor extends javax.swing.AbstractCellEditor implements javax.swing.table.TableCellEditor {
/**
*
*/
private static final long serialVersionUID = 1964260936777401751L;
private Object _value = null;
private javax.swing.JTextField _textField;
private DateFormat _df;
private int clickCountToStart = 2;
public DateEditor() {
_textField = new javax.swing.JTextField();
_df = DateFormat.getDateTimeInstance();
}
public boolean isCellEditable(java.util.EventObject anEvent) {
if (anEvent instanceof java.awt.event.MouseEvent) {
return ((java.awt.event.MouseEvent)anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
/** Returns the value contained in the editor.
* @return the value contained in the editor
*
*/
public Object getCellEditorValue() {
try {
return _df.parse(_textField.getText());
} catch (java.text.ParseException pe) {
System.err.println("Parse Error : " + pe);
return _value;
}
}
public java.awt.Component getTableCellEditorComponent(javax.swing.JTable table, Object value, boolean isSelected, int row, int column) {
_value = value;
_textField.setText(_df.format(value));
return _textField;
}
}
/** A simple CellRenderer to display the elements of an array */
private class ArrayRenderer extends javax.swing.table.DefaultTableCellRenderer {
/**
*
*/
private static final long serialVersionUID = -4882652613205132057L;
public ArrayRenderer() { super(); }
public void setValue(Object value) {
if (value.getClass().isArray()) {
StringBuffer buff = new StringBuffer();
buff.append("{");
int length = java.lang.reflect.Array.getLength(value);
if (length > 0) {
buff.append(java.lang.reflect.Array.get(value, 0));
}
for (int i=1; i<length; i++) {
buff.append(", ").append(java.lang.reflect.Array.get(value, i));
}
buff.append("}");
setText(buff.toString());
} else {
setText((value == null) ? "" : value.toString());
}
}
}
}