Initial Commit
[packages] / xemacs-packages / jde / java / src / jde / debugger / command / LVTreeNode.java
1 package jde.debugger.gui;
2
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;
11
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;
24
25
26
27
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>
32  *
33  * This class implements MutableTreeNode mainly because the
34  * DefaultTreeModel requires it.  Most of the methods in that
35  * interface simply throw exceptions.
36  *
37  * @author <a href="mailto:udalrich@carolingia.org">Troy Daniels</a>
38  * @since 2.3.2
39  * @version $Revision: 1.2 $
40  */
41 abstract class LVTreeNode implements MutableTreeNode, Protocol {
42
43   /** LVTreeNode constructor for subclasses.
44    * @param localVar A reference to a local variable.
45    * @param val The value of localVar.
46    */
47   protected LVTreeNode(String name,
48                        String typeName,
49                        Value val,
50                        DefaultTreeModel model) {
51     m_name = name;
52     m_typeName = typeName;
53     m_model = model;
54     setValue(val, false);
55   }
56
57
58   /** Create a new LVTreeNode object.  Based on the arguments,
59    * Different classes will be returned, customized to actual
60    *  values.
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.
66    */
67   public static MutableTreeNode makeTreeNode(String name,
68                                              String typeName,
69                                              Value val,
70                                              DefaultTreeModel model)
71     throws JDEException
72   {
73     if (val instanceof PrimitiveValue)
74       return new PrimitiveTreeNode(name, typeName, val, model);
75     else if ((val instanceof ObjectReference) ||
76              (val == null))
77       return new ReferenceTreeNode(name, typeName, val, model);
78     else
79       throw new JDEException("Unknown variable type " + val);
80   }
81
82   /** Create a new LVTreeNode object.  Based on the arguments,
83    * different classes will be returned, customized to actual
84    *  values.
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.
89    */
90   public static MutableTreeNode makeTreeNode(LocalVariable localVar,
91                                              Value val,
92                                              DefaultTreeModel model)
93     throws JDEException
94   {
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.
98
99     return makeTreeNode(localVar.name(),
100                         localVar.typeName(),
101                         val,
102                         model);
103   }
104
105   /** Create a new LVTreeNode object.  Based on the arguments,
106    * different classes will be returned, customized to actual
107    *  values.
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.
111    */
112   public static MutableTreeNode makeTreeNode(Field field,
113                                              Value val,
114                                              DefaultTreeModel model)
115     throws JDEException
116   {
117     return makeTreeNode(field.name(),
118                         field.typeName(),
119                         val,
120                         model);
121   }
122
123   // Implementation of javax.swing.tree.TreeNode
124
125   /** Get the parent of this node */
126   public TreeNode getParent() {
127     return m_parent;
128   }
129
130   /** Set the parent of this node */
131   public void setParent(MutableTreeNode parent) {
132     m_parent = parent;
133   }
134
135
136   /**
137    * Describe <code>remove</code> method here.
138    *
139    * @param n an <code>int</code> value
140    */
141   public void remove(int n) {
142     throw new IllegalArgumentException("Attempt to remove a node " +
143                                        "from the local variables tree");
144   }
145
146   /**
147    * Describe <code>remove</code> method here.
148    *
149    * @param mutableTreeNode a <code>MutableTreeNode</code> value
150    */
151   public void remove(MutableTreeNode mutableTreeNode) {
152     throw new IllegalArgumentException("Attempt to remove a node " +
153                                        "from the local variables tree");
154   }
155
156   /**
157    * Describe <code>insert</code> method here.
158    *
159    * @param mutableTreeNode a <code>MutableTreeNode</code> value
160    * @param n an <code>int</code> value
161    */
162   public void insert(MutableTreeNode mutableTreeNode, int n) {
163     throw new IllegalArgumentException("Attempt to insert a node " +
164                                        "from the local variables tree");
165   }
166
167
168   /**
169    * Describe <code>setUserObject</code> method here.
170    *
171    * @param object an <code>Object</code> value
172    */
173   public void setUserObject(Object object) {
174
175   }
176
177
178
179   /**
180    * Describe <code>removeFromParent</code> method here.
181    *
182    */
183   public void removeFromParent() {
184     throw new IllegalArgumentException("Attempt to remove a node from its parent " +
185                                        "in the local variables tree");
186   }
187
188   /** Get the name of the variable */
189   String getName() {
190     return m_name;
191   }
192
193   /** Get the name of the type of the variable */
194   String getTypeName() {
195     return m_typeName;
196   }
197
198   /** Set the value of the object.
199    * @param val The new value
200    */
201   public void setValue(Value val) {
202     setValue(val, true);
203   }
204
205   /** Set the value of the object.<p>
206    *
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.
210    *
211    * @param val The new value
212    * @param notify Should we notify the tree model
213    */
214   private void setValue(Value val, boolean notify) {
215     int oldNumChildren = getChildCount();
216
217     // Store the value and the type of the value
218     if (val != null)
219       m_type = val.type();
220     else
221       m_type = null;
222
223     valueChanged(val);
224
225     // Tell the TreeModel that we changed.
226     if (notify)
227       handleChildChange(oldNumChildren);
228   }
229
230   /** Called when the value has changed.  Default implementation does nothing.
231    * @param oldValue The old value
232    * @param newValue THe new value
233    */
234   abstract void valueChanged(Value newValue);
235
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() + ")");
250     } else {
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() + ")");
258     }
259   }
260
261   /** Get the string to display the value of the variable */
262   abstract String getValue();
263
264   /** Get the TreeModel for this Node */
265   protected DefaultTreeModel getModel() {
266     return m_model;
267   }
268
269   public final String toString() {
270       return getClass().getName() + "[" + paramString() + "]";
271   }
272
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;
279   }
280
281   protected final String m_name;
282   protected final String m_typeName;
283   protected Type m_type;
284
285   private DefaultTreeModel m_model;
286   private TreeNode m_parent;
287 }