1 package jde.debugger.gui;
3 import java.util.Arrays;
4 import java.util.Collections;
5 import java.util.Enumeration;
6 import javax.swing.SwingUtilities;
7 import javax.swing.tree.DefaultMutableTreeNode;
8 import javax.swing.tree.DefaultTreeModel;
9 import javax.swing.tree.MutableTreeNode;
10 import javax.swing.tree.TreeNode;
12 import com.sun.jdi.ArrayReference;
13 import com.sun.jdi.ClassNotLoadedException;
14 import com.sun.jdi.Field;
15 import com.sun.jdi.LocalVariable;
16 import com.sun.jdi.ObjectCollectedException;
17 import com.sun.jdi.ObjectReference;
18 import com.sun.jdi.PrimitiveValue;
19 import com.sun.jdi.Type;
20 import com.sun.jdi.Value;
21 import jde.debugger.JDE;
22 import jde.debugger.JDEException;
23 import jde.debugger.Protocol;
28 /** A TreeNode for displaying local variables. This class has no
29 * public constructors. Instead, it uses a factory method { @link
30 * #makeTreeNode } to create objects. This will probably return a
31 * subclass based on the type of variable we are displaying.<p>
33 * This class implements MutableTreeNode mainly because the
34 * DefaultTreeModel requires it. Most of the methods in that
35 * interface simply throw exceptions.
37 * @author <a href="mailto:udalrich@carolingia.org">Troy Daniels</a>
39 * @version $Revision: 1.2 $
41 abstract class LVTreeNode implements MutableTreeNode, Protocol {
43 /** LVTreeNode constructor for subclasses.
44 * @param localVar A reference to a local variable.
45 * @param val The value of localVar.
47 protected LVTreeNode(String name,
50 DefaultTreeModel model) {
52 m_typeName = typeName;
58 /** Create a new LVTreeNode object. Based on the arguments,
59 * Different classes will be returned, customized to actual
61 * @param name The name of the variable
62 * @param type The Type of the variable
63 * @param val The value of the variable.
64 * @param model The tree model.
65 * @return A TreeNode for use in a JTree.
67 public static MutableTreeNode makeTreeNode(String name,
70 DefaultTreeModel model)
73 if (val instanceof PrimitiveValue)
74 return new PrimitiveTreeNode(name, typeName, val, model);
75 else if ((val instanceof ObjectReference) ||
77 return new ReferenceTreeNode(name, typeName, val, model);
79 throw new JDEException("Unknown variable type " + val);
82 /** Create a new LVTreeNode object. Based on the arguments,
83 * different classes will be returned, customized to actual
85 * @param localVar A reference to a local variable.
86 * @param val The value of localVar.
87 * @param model The tree model.
88 * @return A TreeNode for use in a JTree.
90 public static MutableTreeNode makeTreeNode(LocalVariable localVar,
92 DefaultTreeModel model)
95 // it appears that: localVar.type() returns a ClassType about the
96 // class, ObjectReference.referenceType returns the type of the
97 // value, which is what we want to use.
99 return makeTreeNode(localVar.name(),
105 /** Create a new LVTreeNode object. Based on the arguments,
106 * different classes will be returned, customized to actual
108 * @param field A field within an object
109 * @param val The value of the field.
110 * @return A TreeNode for use in a JTree.
112 public static MutableTreeNode makeTreeNode(Field field,
114 DefaultTreeModel model)
117 return makeTreeNode(field.name(),
123 // Implementation of javax.swing.tree.TreeNode
125 /** Get the parent of this node */
126 public TreeNode getParent() {
130 /** Set the parent of this node */
131 public void setParent(MutableTreeNode parent) {
137 * Describe <code>remove</code> method here.
139 * @param n an <code>int</code> value
141 public void remove(int n) {
142 throw new IllegalArgumentException("Attempt to remove a node " +
143 "from the local variables tree");
147 * Describe <code>remove</code> method here.
149 * @param mutableTreeNode a <code>MutableTreeNode</code> value
151 public void remove(MutableTreeNode mutableTreeNode) {
152 throw new IllegalArgumentException("Attempt to remove a node " +
153 "from the local variables tree");
157 * Describe <code>insert</code> method here.
159 * @param mutableTreeNode a <code>MutableTreeNode</code> value
160 * @param n an <code>int</code> value
162 public void insert(MutableTreeNode mutableTreeNode, int n) {
163 throw new IllegalArgumentException("Attempt to insert a node " +
164 "from the local variables tree");
169 * Describe <code>setUserObject</code> method here.
171 * @param object an <code>Object</code> value
173 public void setUserObject(Object object) {
180 * Describe <code>removeFromParent</code> method here.
183 public void removeFromParent() {
184 throw new IllegalArgumentException("Attempt to remove a node from its parent " +
185 "in the local variables tree");
188 /** Get the name of the variable */
193 /** Get the name of the type of the variable */
194 String getTypeName() {
198 /** Set the value of the object.
199 * @param val The new value
201 public void setValue(Value val) {
205 /** Set the value of the object.<p>
207 * In the constructor, we don't want to notify the model, since that
208 * can cause an infinite loop if the object refers to itself. Also,
209 * notification is intended for changes to existing nodes.
211 * @param val The new value
212 * @param notify Should we notify the tree model
214 private void setValue(Value val, boolean notify) {
215 int oldNumChildren = getChildCount();
217 // Store the value and the type of the value
225 // Tell the TreeModel that we changed.
227 handleChildChange(oldNumChildren);
230 /** Called when the value has changed. Default implementation does nothing.
231 * @param oldValue The old value
232 * @param newValue THe new value
234 abstract void valueChanged(Value newValue);
236 private void handleChildChange(int oldNumChildren) {
237 int numChildren = getChildCount();
238 JDE.debug(GUI, "handleChildChange: old=" + oldNumChildren +
239 ",new=" + numChildren + ",name=" + getName());
240 if (numChildren == oldNumChildren) {
241 m_model.nodeChanged(this);
242 JDE.debug(GUI, "nodeChanged(" + getName() + ")");
243 } else if (numChildren > oldNumChildren) {
244 // } else if (numChildren > oldNumChildren) {
245 int added[] = new int[numChildren - oldNumChildren];
246 for (int index = 0; index < added.length; ++index)
247 added[index] = oldNumChildren + index;
248 m_model.nodesWereInserted(this, added);
249 JDE.debug(GUI, "nodesWereInserted(" + getName() + ")");
251 m_model.nodeStructureChanged(this);
252 // m_model.nodeChanged(this);
253 // int removed[] = new int[oldNumChildren - numChildren];
254 // for (int index = 0; index < removed.length; ++index)
255 // removed[index] = numChildren + index;
256 // m_model.nodesWereRemoved(this, removed);
257 JDE.debug(GUI, "nodeStructureChanged(" + getName() + ")");
261 /** Get the string to display the value of the variable */
262 abstract String getValue();
264 /** Get the TreeModel for this Node */
265 protected DefaultTreeModel getModel() {
269 public final String toString() {
270 return getClass().getName() + "[" + paramString() + "]";
273 protected String paramString() {
274 return "m_name=" + m_name + "," +
275 "m_typeName=" + m_typeName + "," +
276 "m_type=" + m_type + "," +
277 "m_model=" + m_model + "," +
278 "m_parent=" + m_parent;
281 protected final String m_name;
282 protected final String m_typeName;
283 protected Type m_type;
285 private DefaultTreeModel m_model;
286 private TreeNode m_parent;