Initial Commit
[packages] / xemacs-packages / jde / java / src / jde / debugger / command / ReferenceTreeNode.java
1 package jde.debugger.gui;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.Enumeration;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.TreeSet;
12 import javax.swing.tree.DefaultMutableTreeNode;
13 import javax.swing.tree.DefaultTreeModel;
14 import javax.swing.tree.MutableTreeNode;
15 import javax.swing.tree.TreeNode;
16
17 import com.sun.jdi.ArrayReference;
18 import com.sun.jdi.ClassNotLoadedException;
19 import com.sun.jdi.Field;
20 import com.sun.jdi.ObjectCollectedException;
21 import com.sun.jdi.ObjectReference;
22 import com.sun.jdi.ReferenceType;
23 import com.sun.jdi.StringReference;
24 import com.sun.jdi.Value;
25 import jde.debugger.JDE;
26 import jde.debugger.JDEException;
27 import jde.debugger.Protocol;
28
29
30
31
32
33
34
35 /** A TreeNode for object references.
36  * @author <a href="mailto:udalrich@carolingia.org">Troy Daniels</a>
37  * @since 2.3.2
38  * @version $Revision: 1.2 $
39  */
40 class ReferenceTreeNode extends LVTreeNode implements Protocol {
41   /**  Constructor
42    * @param name The name of the variable
43    * @param type The Type of the variable
44    * @param val The value of the variable.
45    * @param model The tree model
46    */
47   protected ReferenceTreeNode(String name,
48                               String typeName,
49                               Value val,
50                               DefaultTreeModel model) throws JDEException {
51     super(name, typeName, val, model);
52     if (!((m_type instanceof ReferenceType) ||
53           (val == null)))
54       throw new JDEException("ReferenceTreeNode received non-object reference Type " +
55                              m_type.name());
56     if ((null != val) &&
57         !(val instanceof ObjectReference)) {
58       JDE.debug(GUI, "Incorrect Value type in ReferenceTreeNode constructor");
59       JDE.debug(GUI, "val=" + val);
60       JDE.debug(GUI, "val.type()=" + val.type());
61       throw new JDEException("ReferenceTreeNode received non-object reference value " +
62                              val.type().name());
63     }
64   }
65
66   /** Called when the value has changed.  Updates the object which
67    * actually implements the public methods.
68    * @param oldValue The old value
69    * @param newValue THe new value
70    */
71   protected void valueChanged(Value newValue) {
72     // Create the new model for displaying the value
73     if (null == newValue)
74       m_model = new NullModel();
75     else if (newValue instanceof ArrayReference)
76       m_model = new ArrayModel((ArrayReference) newValue, getModel());
77     else
78       m_model = new ObjectModel((ObjectReference) newValue, getModel());
79
80     // If we have children, update the values in them and resize the
81     // array
82     if (getAllowsChildren()) {
83       if (null == m_children)
84         m_children = new MutableTreeNode[m_model.getChildCount()];
85       else {
86         // Ensure that the child array is the correct size
87         if (m_children.length != m_model.getChildCount()) {
88           MutableTreeNode[] newChildren = new MutableTreeNode[m_model.getChildCount()];
89           System.arraycopy(m_children, 0,
90                            newChildren, 0,
91                            Math.min(m_children.length,
92                                     newChildren.length));
93           m_children = newChildren;
94         }
95       }
96     } else
97       m_children = null;
98
99     m_model.updateChildren(m_children);
100   }
101
102
103   /** Get the number of children.
104    * @return The number of fields that we should be displaying.
105    */
106   public int getChildCount() {
107     if (null == m_children)
108       return 0;
109     else
110       return m_children.length;
111   }
112
113   /** Returns if the node allows children
114    * @return true if the value is not null. */
115   public boolean getAllowsChildren() {
116     return m_model.getAllowsChildren();
117   }
118
119
120   /** Get a string to represent the value of the variable */
121   String getValue() {
122     return m_model.getValue();
123   }
124
125
126
127
128   /**
129    * Returns the index of node in the receivers children.
130    *
131    * @param treeNode a <code>TreeNode</code> value
132    * @return the index of node in the receivers children.  Returns -1
133    * if <code>treeNode</code> is not a child of this node.
134    */
135   public int getIndex(TreeNode treeNode) {
136     for (int index = 0; index < m_children.length; ++index)
137       if (m_children[index] == treeNode)
138         return index;
139     return -1;
140   }
141
142   /**
143    * Returns the children of the reciever as an Enumeration.
144    *
145    * @return the children of the reciever as an Enumeration.
146    */
147   public Enumeration children() {
148     return Collections.enumeration(Arrays.asList(m_children));
149   }
150
151   /**
152    * Returns the child TreeNode at index childIndex.  The child is
153    * created if it doesn't exist.
154    *
155    * @param childIndex the index of the child
156    * @return the child TreeNode at index childIndex.
157    */
158   public TreeNode getChildAt(int childIndex) {
159     try {
160       if (null == m_children[childIndex]) {
161         m_children[childIndex] = m_model.createChildAt(childIndex);
162         m_children[childIndex].setParent(this);
163       }
164     } catch (JDEException exc) {
165       m_children[childIndex] =
166         new DefaultMutableTreeNode("Error displaying data: " + exc.getMessage());
167     }
168     return m_children[childIndex];
169   }
170
171   /**
172    * Returns true if the receiver is a leaf.
173    *
174    * @return true if the receiver is a leaf.
175    */
176   public boolean isLeaf() {
177     return (null == m_children) ||
178       (m_children.length == 0);
179   }
180
181
182
183   /**
184    * Returns the child TreeNode at index childIndex.  The child is
185    * <b>not</b> created if it doesn't exist.
186    *
187    * @param childIndex the index of the child
188    * @return the child TreeNode at index childIndex or null if there
189    * is no child at that index yet, or the child is not an LVTreeNode.
190    */
191   protected LVTreeNode getExistingChildAt(int childIndex) {
192     if ((null == m_children[childIndex]) ||
193         (!(m_children[childIndex] instanceof LVTreeNode)))
194       return null;
195     return (LVTreeNode) m_children[childIndex];
196   }
197
198   /** Get the current length of the children array. For use when updating values. */
199   protected int getExistingChildLength() {
200     return m_children.length;
201   }
202
203   protected String paramString() {
204     return super.paramString() +
205       ",m_model=" + m_model +
206       ",m_children=" + m_children +
207       ((null == m_children)? "": ("[" + m_children.length + "]"));
208   }
209
210   private ReferenceModel m_model;
211   private MutableTreeNode[] m_children;
212 }