|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
ElementTreePanel.java | 14.3% | 25.4% | 29.2% | 22.6% |
|
1 |
/*
|
|
2 |
* @(#)ElementTreePanel.java 1.9 99/04/23
|
|
3 |
*
|
|
4 |
* Copyright (c) 1998, 1999 by Sun Microsystems, Inc. All Rights Reserved.
|
|
5 |
*
|
|
6 |
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
|
|
7 |
* modify and redistribute this software in source and binary code form,
|
|
8 |
* provided that i) this copyright notice and license appear on all copies of
|
|
9 |
* the software; and ii) Licensee does not utilize the software in a manner
|
|
10 |
* which is disparaging to Sun.
|
|
11 |
*
|
|
12 |
* This software is provided "AS IS," without a warranty of any kind. ALL
|
|
13 |
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
|
|
14 |
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
|
15 |
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
|
|
16 |
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
|
17 |
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
|
|
18 |
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
|
|
19 |
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
|
|
20 |
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
|
|
21 |
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
|
|
22 |
* POSSIBILITY OF SUCH DAMAGES.
|
|
23 |
*
|
|
24 |
* This software is not designed or intended for use in on-line control of
|
|
25 |
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
|
|
26 |
* the design, construction, operation or maintenance of any nuclear
|
|
27 |
* facility. Licensee represents and warrants that it will not use or
|
|
28 |
* redistribute the Software for such purposes.
|
|
29 |
*/
|
|
30 |
|
|
31 |
import javax.swing.*;
|
|
32 |
import javax.swing.event.*;
|
|
33 |
import javax.swing.text.*;
|
|
34 |
import javax.swing.tree.*;
|
|
35 |
import javax.swing.undo.*;
|
|
36 |
import java.awt.*;
|
|
37 |
import java.beans.*;
|
|
38 |
import java.util.*;
|
|
39 |
|
|
40 |
/**
|
|
41 |
* Displays a tree showing all the elements in a text Document. Selecting
|
|
42 |
* a node will result in reseting the selection of the JTextComponent.
|
|
43 |
* This also becomes a CaretListener to know when the selection has changed
|
|
44 |
* in the text to update the selected item in the tree.
|
|
45 |
*
|
|
46 |
* @author Scott Violet
|
|
47 |
* @version 1.9 04/23/99
|
|
48 |
*/
|
|
49 |
public class ElementTreePanel extends JPanel implements CaretListener, DocumentListener, PropertyChangeListener, TreeSelectionListener { |
|
50 |
/** Tree showing the documents element structure. */
|
|
51 |
protected JTree tree;
|
|
52 |
/** Text component showing elemenst for. */
|
|
53 |
protected JTextComponent editor;
|
|
54 |
/** Model for the tree. */
|
|
55 |
protected ElementTreeModel treeModel;
|
|
56 |
/** Set to true when updatin the selection. */
|
|
57 |
protected boolean updatingSelection; |
|
58 |
|
|
59 | 2 |
public ElementTreePanel(JTextComponent editor) {
|
60 | 2 |
this.editor = editor;
|
61 |
|
|
62 | 2 |
Document document = editor.getDocument(); |
63 |
|
|
64 |
// Create the tree.
|
|
65 | 2 |
treeModel = new ElementTreeModel(document);
|
66 | 2 |
tree = new JTree(treeModel) {
|
67 | 22 |
public String convertValueToText(Object value, boolean selected, |
68 |
boolean expanded, boolean leaf, |
|
69 |
int row, boolean hasFocus) { |
|
70 |
// Should only happen for the root
|
|
71 | 22 |
if(!(value instanceof Element)) |
72 | 4 |
return value.toString();
|
73 |
|
|
74 | 18 |
Element e = (Element)value; |
75 | 18 |
AttributeSet as = e.getAttributes().copyAttributes(); |
76 | 18 |
String asString; |
77 |
|
|
78 | 18 |
if(as != null) { |
79 | 18 |
StringBuffer retBuffer = new StringBuffer("["); |
80 | 18 |
Enumeration names = as.getAttributeNames(); |
81 |
|
|
82 | 18 |
while(names.hasMoreElements()) {
|
83 | 9 |
Object nextName = names.nextElement(); |
84 |
|
|
85 | 9 |
if(nextName != StyleConstants.ResolveAttribute) {
|
86 | 9 |
retBuffer.append(" ");
|
87 | 9 |
retBuffer.append(nextName); |
88 | 9 |
retBuffer.append("=");
|
89 | 9 |
retBuffer.append(as.getAttribute(nextName)); |
90 |
} |
|
91 |
} |
|
92 | 18 |
retBuffer.append(" ]");
|
93 | 18 |
asString = retBuffer.toString(); |
94 |
} |
|
95 |
else
|
|
96 | 0 |
asString = "[ ]";
|
97 |
|
|
98 | 18 |
if(e.isLeaf())
|
99 | 0 |
return e.getName() + " [" + e.getStartOffset() + |
100 |
", " + e.getEndOffset() +"] Attributes: " + asString; |
|
101 | 18 |
return e.getName() + " [" + e.getStartOffset() + |
102 |
", " + e.getEndOffset() + "] Attributes: " + |
|
103 |
asString; |
|
104 |
} |
|
105 |
}; |
|
106 | 2 |
tree.addTreeSelectionListener(this);
|
107 |
// Don't show the root, it is fake.
|
|
108 | 2 |
tree.setRootVisible(false);
|
109 |
// Since the display value of every node after the insertion point
|
|
110 |
// changes every time the text changes and we don't generate a change
|
|
111 |
// event for all those nodes the display value can become off.
|
|
112 |
// This can be seen as '...' instead of the complete string value.
|
|
113 |
// This is a temporary workaround, increase the needed size by 15,
|
|
114 |
// hoping that will be enough.
|
|
115 | 2 |
tree.setCellRenderer(new DefaultTreeCellRenderer() {
|
116 | 8 |
public Dimension getPreferredSize() {
|
117 | 8 |
Dimension retValue = super.getPreferredSize();
|
118 | 8 |
if(retValue != null) |
119 | 8 |
retValue.width += 15; |
120 | 8 |
return retValue;
|
121 |
} |
|
122 |
}); |
|
123 |
// become a listener on the document to update the tree.
|
|
124 | 2 |
document.addDocumentListener(this);
|
125 |
|
|
126 |
// become a PropertyChangeListener to know when the Document has
|
|
127 |
// changed.
|
|
128 | 2 |
editor.addPropertyChangeListener(this);
|
129 |
|
|
130 |
// Become a CaretListener
|
|
131 | 2 |
editor.addCaretListener(this);
|
132 |
|
|
133 |
// configure the panel and frame containing it.
|
|
134 | 2 |
setLayout(new BorderLayout());
|
135 | 2 |
add(new JScrollPane(tree), BorderLayout.CENTER);
|
136 |
|
|
137 |
// Add a label above tree to describe what is being shown
|
|
138 | 2 |
JLabel label = new JLabel("Elements that make up the current document", SwingConstants.CENTER); |
139 |
|
|
140 | 2 |
label.setFont(new Font("Dialog", Font.BOLD, 14)); |
141 | 2 |
add(label, BorderLayout.NORTH); |
142 |
|
|
143 | 2 |
setPreferredSize(new Dimension(400, 400));
|
144 |
} |
|
145 |
|
|
146 |
/**
|
|
147 |
* Resets the JTextComponent to <code>editor</code>. This will update
|
|
148 |
* the tree accordingly.
|
|
149 |
*/
|
|
150 | 0 |
public void setEditor(JTextComponent editor) { |
151 | 0 |
if (this.editor == editor) { |
152 | 0 |
return;
|
153 |
} |
|
154 |
|
|
155 | 0 |
if (this.editor != null) { |
156 | 0 |
Document oldDoc = this.editor.getDocument();
|
157 |
|
|
158 | 0 |
oldDoc.removeDocumentListener(this);
|
159 | 0 |
this.editor.removePropertyChangeListener(this); |
160 | 0 |
this.editor.removeCaretListener(this); |
161 |
} |
|
162 | 0 |
this.editor = editor;
|
163 | 0 |
if (editor == null) { |
164 | 0 |
treeModel = null;
|
165 | 0 |
tree.setModel(null);
|
166 |
} |
|
167 |
else {
|
|
168 | 0 |
Document newDoc = editor.getDocument(); |
169 |
|
|
170 | 0 |
newDoc.addDocumentListener(this);
|
171 | 0 |
editor.addPropertyChangeListener(this);
|
172 | 0 |
editor.addCaretListener(this);
|
173 | 0 |
treeModel = new ElementTreeModel(newDoc);
|
174 | 0 |
tree.setModel(treeModel); |
175 |
} |
|
176 |
} |
|
177 |
|
|
178 |
// PropertyChangeListener
|
|
179 |
|
|
180 |
/**
|
|
181 |
* Invoked when a property changes. We are only interested in when the
|
|
182 |
* Document changes to reset the DocumentListener.
|
|
183 |
*/
|
|
184 | 0 |
public void propertyChange(PropertyChangeEvent e) { |
185 | 0 |
if (e.getSource() == getEditor() &&
|
186 |
e.getPropertyName().equals("document")) {
|
|
187 | 0 |
JTextComponent editor = getEditor(); |
188 | 0 |
Document oldDoc = (Document)e.getOldValue(); |
189 | 0 |
Document newDoc = (Document)e.getNewValue(); |
190 |
|
|
191 |
// Reset the DocumentListener
|
|
192 | 0 |
oldDoc.removeDocumentListener(this);
|
193 | 0 |
newDoc.addDocumentListener(this);
|
194 |
|
|
195 |
// Recreate the TreeModel.
|
|
196 | 0 |
treeModel = new ElementTreeModel(newDoc);
|
197 | 0 |
tree.setModel(treeModel); |
198 |
} |
|
199 |
} |
|
200 |
|
|
201 |
|
|
202 |
// DocumentListener
|
|
203 |
|
|
204 |
/**
|
|
205 |
* Gives notification that there was an insert into the document. The
|
|
206 |
* given range bounds the freshly inserted region.
|
|
207 |
*
|
|
208 |
* @param e the document event
|
|
209 |
*/
|
|
210 | 0 |
public void insertUpdate(DocumentEvent e) { |
211 | 0 |
updateTree(e); |
212 |
} |
|
213 |
|
|
214 |
/**
|
|
215 |
* Gives notification that a portion of the document has been
|
|
216 |
* removed. The range is given in terms of what the view last
|
|
217 |
* saw (that is, before updating sticky positions).
|
|
218 |
*
|
|
219 |
* @param e the document event
|
|
220 |
*/
|
|
221 | 0 |
public void removeUpdate(DocumentEvent e) { |
222 | 0 |
updateTree(e); |
223 |
} |
|
224 |
|
|
225 |
/**
|
|
226 |
* Gives notification that an attribute or set of attributes changed.
|
|
227 |
*
|
|
228 |
* @param e the document event
|
|
229 |
*/
|
|
230 | 0 |
public void changedUpdate(DocumentEvent e) { |
231 | 0 |
updateTree(e); |
232 |
} |
|
233 |
|
|
234 |
// CaretListener
|
|
235 |
|
|
236 |
/**
|
|
237 |
* Messaged when the selection in the editor has changed. Will update
|
|
238 |
* the selection in the tree.
|
|
239 |
*/
|
|
240 | 0 |
public void caretUpdate(CaretEvent e) { |
241 | 0 |
if(!updatingSelection) {
|
242 | 0 |
JTextComponent editor = getEditor(); |
243 | 0 |
int selBegin = Math.min(e.getDot(), e.getMark());
|
244 | 0 |
int end = Math.max(e.getDot(), e.getMark());
|
245 | 0 |
Vector paths = new Vector();
|
246 | 0 |
TreeModel model = getTreeModel(); |
247 | 0 |
Object root = model.getRoot(); |
248 | 0 |
int rootCount = model.getChildCount(root);
|
249 |
|
|
250 |
// Build an array of all the paths to all the character elements
|
|
251 |
// in the selection.
|
|
252 | 0 |
for(int counter = 0; counter < rootCount; counter++) { |
253 | 0 |
int start = selBegin;
|
254 |
|
|
255 | 0 |
while(start <= end) {
|
256 | 0 |
TreePath path = getPathForIndex(start, root, |
257 |
(Element)model.getChild(root, counter)); |
|
258 | 0 |
Element charElement = (Element)path. |
259 |
getLastPathComponent(); |
|
260 |
|
|
261 | 0 |
paths.addElement(path); |
262 | 0 |
if(start >= charElement.getEndOffset())
|
263 | 0 |
start++; |
264 |
else
|
|
265 | 0 |
start = charElement.getEndOffset(); |
266 |
} |
|
267 |
} |
|
268 |
|
|
269 |
// If a path was found, select it (them).
|
|
270 | 0 |
int numPaths = paths.size();
|
271 |
|
|
272 | 0 |
if(numPaths > 0) {
|
273 | 0 |
TreePath[] pathArray = new TreePath[numPaths];
|
274 |
|
|
275 | 0 |
paths.copyInto(pathArray); |
276 | 0 |
updatingSelection = true;
|
277 | 0 |
try {
|
278 | 0 |
getTree().setSelectionPaths(pathArray); |
279 | 0 |
getTree().scrollPathToVisible(pathArray[0]); |
280 |
} |
|
281 |
finally {
|
|
282 | 0 |
updatingSelection = false;
|
283 |
} |
|
284 |
} |
|
285 |
} |
|
286 |
} |
|
287 |
|
|
288 |
// TreeSelectionListener
|
|
289 |
|
|
290 |
/**
|
|
291 |
* Called whenever the value of the selection changes.
|
|
292 |
* @param e the event that characterizes the change.
|
|
293 |
*/
|
|
294 | 0 |
public void valueChanged(TreeSelectionEvent e) { |
295 | 0 |
JTree tree = getTree(); |
296 |
|
|
297 | 0 |
if(!updatingSelection && tree.getSelectionCount() == 1) {
|
298 | 0 |
TreePath selPath = tree.getSelectionPath(); |
299 | 0 |
Object lastPathComponent = selPath.getLastPathComponent(); |
300 |
|
|
301 | 0 |
if(!(lastPathComponent instanceof DefaultMutableTreeNode)) { |
302 | 0 |
Element selElement = (Element)lastPathComponent; |
303 |
|
|
304 | 0 |
updatingSelection = true;
|
305 | 0 |
try {
|
306 | 0 |
getEditor().select(selElement.getStartOffset(), |
307 |
selElement.getEndOffset()); |
|
308 |
} |
|
309 |
finally {
|
|
310 | 0 |
updatingSelection = false;
|
311 |
} |
|
312 |
} |
|
313 |
} |
|
314 |
} |
|
315 |
|
|
316 |
// Local methods
|
|
317 |
|
|
318 |
/**
|
|
319 |
* @return tree showing elements.
|
|
320 |
*/
|
|
321 | 0 |
protected JTree getTree() {
|
322 | 0 |
return tree;
|
323 |
} |
|
324 |
|
|
325 |
/**
|
|
326 |
* @return JTextComponent showing elements for.
|
|
327 |
*/
|
|
328 | 0 |
protected JTextComponent getEditor() {
|
329 | 0 |
return editor;
|
330 |
} |
|
331 |
|
|
332 |
/**
|
|
333 |
* @return TreeModel implementation used to represent the elements.
|
|
334 |
*/
|
|
335 | 0 |
public DefaultTreeModel getTreeModel() {
|
336 | 0 |
return treeModel;
|
337 |
} |
|
338 |
|
|
339 |
/**
|
|
340 |
* Updates the tree based on the event type. This will invoke either
|
|
341 |
* updateTree with the root element, or handleChange.
|
|
342 |
*/
|
|
343 | 0 |
protected void updateTree(DocumentEvent event) { |
344 | 0 |
updatingSelection = true;
|
345 | 0 |
try {
|
346 | 0 |
TreeModel model = getTreeModel(); |
347 | 0 |
Object root = model.getRoot(); |
348 |
|
|
349 | 0 |
for(int counter = model.getChildCount(root) - 1; counter >= 0; |
350 |
counter--) { |
|
351 | 0 |
updateTree(event, (Element)model.getChild(root, counter)); |
352 |
} |
|
353 |
} |
|
354 |
finally {
|
|
355 | 0 |
updatingSelection = false;
|
356 |
} |
|
357 |
} |
|
358 |
|
|
359 |
/**
|
|
360 |
* Creates TreeModelEvents based on the DocumentEvent and messages
|
|
361 |
* the treemodel. This recursively invokes this method with children
|
|
362 |
* elements.
|
|
363 |
* @param event indicates what elements in the tree hierarchy have
|
|
364 |
* changed.
|
|
365 |
* @param element Current element to check for changes against.
|
|
366 |
*/
|
|
367 | 0 |
protected void updateTree(DocumentEvent event, Element element) { |
368 | 0 |
DocumentEvent.ElementChange ec = event.getChange(element); |
369 |
|
|
370 | 0 |
if (ec != null) { |
371 | 0 |
Element[] removed = ec.getChildrenRemoved(); |
372 | 0 |
Element[] added = ec.getChildrenAdded(); |
373 | 0 |
int startIndex = ec.getIndex();
|
374 |
|
|
375 |
// Check for removed.
|
|
376 | 0 |
if(removed != null && removed.length > 0) { |
377 | 0 |
int[] indices = new int[removed.length]; |
378 |
|
|
379 | 0 |
for(int counter = 0; counter < removed.length; counter++) { |
380 | 0 |
indices[counter] = startIndex + counter; |
381 |
} |
|
382 | 0 |
getTreeModel().nodesWereRemoved((TreeNode)element, indices, |
383 |
removed); |
|
384 |
} |
|
385 |
// check for added
|
|
386 | 0 |
if(added != null && added.length > 0) { |
387 | 0 |
int[] indices = new int[added.length]; |
388 |
|
|
389 | 0 |
for(int counter = 0; counter < added.length; counter++) { |
390 | 0 |
indices[counter] = startIndex + counter; |
391 |
} |
|
392 | 0 |
getTreeModel().nodesWereInserted((TreeNode)element, indices); |
393 |
} |
|
394 |
} |
|
395 | 0 |
if(!element.isLeaf()) {
|
396 | 0 |
int startIndex = element.getElementIndex
|
397 |
(event.getOffset()); |
|
398 | 0 |
int elementCount = element.getElementCount();
|
399 | 0 |
int endIndex = Math.min(elementCount - 1,
|
400 |
element.getElementIndex |
|
401 |
(event.getOffset() + event.getLength())); |
|
402 |
|
|
403 | 0 |
if(startIndex > 0 && startIndex < elementCount &&
|
404 |
element.getElement(startIndex).getStartOffset() == |
|
405 |
event.getOffset()) { |
|
406 |
// Force checking the previous element.
|
|
407 | 0 |
startIndex--; |
408 |
} |
|
409 | 0 |
if(startIndex != -1 && endIndex != -1) {
|
410 | 0 |
for(int counter = startIndex; counter <= endIndex; counter++) { |
411 | 0 |
updateTree(event, element.getElement(counter)); |
412 |
} |
|
413 |
} |
|
414 |
} |
|
415 |
else {
|
|
416 |
// Element is a leaf, assume it changed
|
|
417 | 0 |
getTreeModel().nodeChanged((TreeNode)element); |
418 |
} |
|
419 |
} |
|
420 |
|
|
421 |
/**
|
|
422 |
* Returns a TreePath to the element at <code>position</code>.
|
|
423 |
*/
|
|
424 | 0 |
protected TreePath getPathForIndex(int position, Object root, |
425 |
Element rootElement) { |
|
426 | 0 |
TreePath path = new TreePath(root);
|
427 | 0 |
Element child = rootElement.getElement |
428 |
(rootElement.getElementIndex(position)); |
|
429 |
|
|
430 | 0 |
path = path.pathByAddingChild(rootElement); |
431 | 0 |
path = path.pathByAddingChild(child); |
432 | 0 |
while(!child.isLeaf()) {
|
433 | 0 |
child = child.getElement(child.getElementIndex(position)); |
434 | 0 |
path = path.pathByAddingChild(child); |
435 |
} |
|
436 | 0 |
return path;
|
437 |
} |
|
438 |
|
|
439 |
|
|
440 |
/**
|
|
441 |
* ElementTreeModel is an implementation of TreeModel to handle displaying
|
|
442 |
* the Elements from a Document. AbstractDocument.AbstractElement is
|
|
443 |
* the default implementation used by the swing text package to implement
|
|
444 |
* Element, and it implements TreeNode. This makes it trivial to create
|
|
445 |
* a DefaultTreeModel rooted at a particular Element from the Document.
|
|
446 |
* Unfortunately each Document can have more than one root Element.
|
|
447 |
* Implying that to display all the root elements as a child of another
|
|
448 |
* root a fake node has be created. This class creates a fake node as
|
|
449 |
* the root with the children being the root elements of the Document
|
|
450 |
* (getRootElements).
|
|
451 |
* <p>This subclasses DefaultTreeModel. The majority of the TreeModel
|
|
452 |
* methods have been subclassed, primarily to special case the root.
|
|
453 |
*/
|
|
454 |
public static class ElementTreeModel extends DefaultTreeModel { |
|
455 |
protected Element[] rootElements;
|
|
456 |
|
|
457 | 2 |
public ElementTreeModel(Document document) {
|
458 | 2 |
super(new DefaultMutableTreeNode("root"), false); |
459 | 2 |
rootElements = document.getRootElements(); |
460 |
} |
|
461 |
|
|
462 |
/**
|
|
463 |
* Returns the child of <I>parent</I> at index <I>index</I> in
|
|
464 |
* the parent's child array. <I>parent</I> must be a node
|
|
465 |
* previously obtained from this data source. This should
|
|
466 |
* not return null if <i>index</i> is a valid index for
|
|
467 |
* <i>parent</i> (that is <i>index</i> >= 0 && <i>index</i>
|
|
468 |
* < getChildCount(<i>parent</i>)).
|
|
469 |
*
|
|
470 |
* @param parent a node in the tree, obtained from this data source
|
|
471 |
* @return the child of <I>parent</I> at index <I>index</I>
|
|
472 |
*/
|
|
473 | 4 |
public Object getChild(Object parent, int index) { |
474 | 4 |
if(parent == root)
|
475 | 4 |
return rootElements[index];
|
476 | 0 |
return super.getChild(parent, index); |
477 |
} |
|
478 |
|
|
479 |
|
|
480 |
/**
|
|
481 |
* Returns the number of children of <I>parent</I>. Returns 0
|
|
482 |
* if the node is a leaf or if it has no children.
|
|
483 |
* <I>parent</I> must be a node previously obtained from this
|
|
484 |
* data source.
|
|
485 |
*
|
|
486 |
* @param parent a node in the tree, obtained from this data source
|
|
487 |
* @return the number of children of the node <I>parent</I>
|
|
488 |
*/
|
|
489 | 2 |
public int getChildCount(Object parent) { |
490 | 2 |
if(parent == root)
|
491 | 2 |
return rootElements.length;
|
492 | 0 |
return super.getChildCount(parent); |
493 |
} |
|
494 |
|
|
495 |
|
|
496 |
/**
|
|
497 |
* Returns true if <I>node</I> is a leaf. It is possible for
|
|
498 |
* this method to return false even if <I>node</I> has no
|
|
499 |
* children. A directory in a filesystem, for example, may
|
|
500 |
* contain no files; the node representing the directory is
|
|
501 |
* not a leaf, but it also has no children.
|
|
502 |
*
|
|
503 |
* @param node a node in the tree, obtained from this data source
|
|
504 |
* @return true if <I>node</I> is a leaf
|
|
505 |
*/
|
|
506 | 30 |
public boolean isLeaf(Object node) { |
507 | 30 |
if(node == root)
|
508 | 12 |
return false; |
509 | 18 |
return super.isLeaf(node); |
510 |
} |
|
511 |
|
|
512 |
/**
|
|
513 |
* Returns the index of child in parent.
|
|
514 |
*/
|
|
515 | 0 |
public int getIndexOfChild(Object parent, Object child) { |
516 | 0 |
if(parent == root) {
|
517 | 0 |
for(int counter = rootElements.length - 1; counter >= 0; |
518 |
counter--) { |
|
519 | 0 |
if(rootElements[counter] == child)
|
520 | 0 |
return counter;
|
521 |
} |
|
522 | 0 |
return -1;
|
523 |
} |
|
524 | 0 |
return super.getIndexOfChild(parent, child); |
525 |
} |
|
526 |
|
|
527 |
/**
|
|
528 |
* Invoke this method after you've changed how node is to be
|
|
529 |
* represented in the tree.
|
|
530 |
*/
|
|
531 | 0 |
public void nodeChanged(TreeNode node) { |
532 | 0 |
if(listenerList != null && node != null) { |
533 | 0 |
TreeNode parent = node.getParent(); |
534 |
|
|
535 | 0 |
if(parent == null && node != root) { |
536 | 0 |
parent = root; |
537 |
} |
|
538 | 0 |
if(parent != null) { |
539 | 0 |
int anIndex = getIndexOfChild(parent, node);
|
540 |
|
|
541 | 0 |
if(anIndex != -1) {
|
542 | 0 |
int[] cIndexs = new int[1]; |
543 |
|
|
544 | 0 |
cIndexs[0] = anIndex; |
545 | 0 |
nodesChanged(parent, cIndexs); |
546 |
} |
|
547 |
} |
|
548 |
} |
|
549 |
} |
|
550 |
|
|
551 |
/**
|
|
552 |
* Returns the path to a particluar node. This is recursive.
|
|
553 |
*/
|
|
554 | 0 |
protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) { |
555 | 0 |
TreeNode[] retNodes; |
556 |
|
|
557 |
/* Check for null, in case someone passed in a null node, or
|
|
558 |
they passed in an element that isn't rooted at root. */
|
|
559 | 0 |
if(aNode == null) { |
560 | 0 |
if(depth == 0)
|
561 | 0 |
return null; |
562 |
else
|
|
563 | 0 |
retNodes = new TreeNode[depth];
|
564 |
} |
|
565 |
else {
|
|
566 | 0 |
depth++; |
567 | 0 |
if(aNode == root)
|
568 | 0 |
retNodes = new TreeNode[depth];
|
569 |
else {
|
|
570 | 0 |
TreeNode parent = aNode.getParent(); |
571 |
|
|
572 | 0 |
if(parent == null) |
573 | 0 |
parent = root; |
574 | 0 |
retNodes = getPathToRoot(parent, depth); |
575 |
} |
|
576 | 0 |
retNodes[retNodes.length - depth] = aNode; |
577 |
} |
|
578 | 0 |
return retNodes;
|
579 |
} |
|
580 |
} |
|
581 |
|
|
582 | 0 |
public void finalize() { |
583 |
//System.out.println("ElementTreePanel finalize");
|
|
584 |
} |
|
585 |
} |
|
586 |
|
|