KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > jdom > DOMNode


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.jdom;
12
13 import java.util.Enumeration JavaDoc;
14
15 import org.eclipse.jdt.core.jdom.*;
16 import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
17 import org.eclipse.jdt.internal.core.util.Messages;
18
19 /**
20  * DOMNode provides an implementation for <code>IDOMNode</code>.
21  *
22  * <p>A node represents a document fragment. When a node is created, its
23  * contents are located in a contiguous range of a shared document. A shared
24  * document is a char array, and is shared in the sense that the contents of other
25  * document fragments may also be contained in the array.
26  *
27  * <p>A node maintains indicies of relevant portions of its contents
28  * in the shared document. Thus the original document and indicies create a
29  * form from which to generate the contents of the document fragment. As attributes
30  * of a node are changed, the node attempts to maintain the original formatting
31  * by only replacing relevant portions of the shared document with the value
32  * of new attributes (that is, filling in the form with replacement values).
33  *
34  * <p>When a node is first created, it is considered unfragmented. When any
35  * attribute of the node is altered, the node is then considered fragmented
36  * from that point on. A node is also considered fragmented if any of its
37  * descendants are fragmented. When a node is unfragmented, the contents of the
38  * node can be efficiently generated from the original shared document. When
39  * a node is fragmented, the contents of the node must be created using the
40  * original document and indicies as a form, filling in replacement values
41  * as required.
42  *
43  * <p>Generally, a node's contents consists of complete lines in a shared document.
44  * The contents of the node are normalized on creation to include any whitespace
45  * preceding the node on the line where the node begins, and to include and trailing
46  * whitespace up to the line where the next node begins. Any trailing // comments
47  * that begin on the line where the current node ends, are considered part of that
48  * node.
49  *
50  * @see IDOMNode
51  * @deprecated The JDOM was made obsolete by the addition in 2.0 of the more
52  * powerful, fine-grained DOM/AST API found in the
53  * org.eclipse.jdt.core.dom package.
54  */

55 public abstract class DOMNode implements IDOMNode {
56
57     /**
58      * The first child of this node - <code>null</code>
59      * when this node has no children. (Children of a node
60      * are implemented as a doubly linked list).
61      */

62     protected DOMNode fFirstChild= null;
63
64     /**
65      * The last child of this node - <code>null</code>
66      * when this node has no children. Used for efficient
67      * access to the last child when adding new children
68      * at the end of the linked list of children.
69      */

70     protected DOMNode fLastChild= null;
71
72     /**
73      * The sibling node following this node - <code>null</code>
74      * for the last node in the sibling list.
75      */

76     protected DOMNode fNextNode= null;
77
78     /**
79      * The parent of this node. A <code>null</code>
80      * parent indicates that this node is a root
81      * node of a document fragment.
82      */

83     protected DOMNode fParent= null;
84
85     /**
86      * The sibling node preceding this node - <code>null</code>
87      * for the first node in the sibling list.
88      */

89     protected DOMNode fPreviousNode= null;
90
91     /**
92      * True when this node has attributes that have
93      * been altered from their original state in the
94      * shared document, or when the attributes of a
95      * descendant have been altered. False when the
96      * contents of this node and all descendants are
97      * consistent with the content of the shared
98      * document.
99      */

100     protected boolean fIsFragmented= false;
101
102     /**
103      * The name of this node. For efficiency, the
104      * name of a node is duplicated in this variable
105      * on creation, rather than always having to fetch
106      * the name from the shared document.
107      */

108     protected String JavaDoc fName= null;
109
110     /**
111      * The original inclusive indicies of this node's name in
112      * the shared document. Values of -1 indiciate the name
113      * does not exist in the document.
114      */

115     protected int[] fNameRange;
116
117     /**
118      * The shared document that the contents for this node
119      * are contained in. Attribute indicies are positions
120      * in this character array.
121      */

122     protected char[] fDocument= null;
123
124     /**
125      * The original entire inclusive range of this node's contents
126      * within its document. Values of -1 indicate the contents
127      * of this node do not exist in the document.
128      */

129     protected int[] fSourceRange;
130
131     /**
132      * The current state of bit masks defined by this node.
133      * Initially all bit flags are turned off. All bit masks
134      * are defined by this class to avoid overlap, although
135      * bit masks are node type specific.
136      *
137      * @see #setMask
138      * @see #getMask
139      */

140     protected int fStateMask= 0;
141
142     /**
143      * This position is the position of the end of the last line separator before the closing brace starting
144      * position of the receiver.
145      */

146     protected int fInsertionPosition;
147
148     /**
149      * A bit mask indicating this field has an initializer
150      * expression
151      */

152     protected static final int MASK_FIELD_HAS_INITIALIZER= 0x00000001;
153     
154     /**
155      * A bit mask indicating this field is a secondary variable
156      * declarator for a previous field declaration.
157      */

158     protected static final int MASK_FIELD_IS_VARIABLE_DECLARATOR= 0x00000002;
159
160     /**
161      * A bit mask indicating this field's type has been
162      * altered from its original contents in the document.
163      */

164     protected static final int MASK_FIELD_TYPE_ALTERED= 0x00000004;
165
166     /**
167      * A bit mask indicating this node's name has been
168      * altered from its original contents in the document.
169      */

170     protected static final int MASK_NAME_ALTERED= 0x00000008;
171
172     /**
173      * A bit mask indicating this node currently has a
174      * body.
175      */

176     protected static final int MASK_HAS_BODY= 0x00000010;
177     
178     /**
179      * A bit mask indicating this node currently has a
180      * preceding comment.
181      */

182     protected static final int MASK_HAS_COMMENT= 0x00000020;
183
184     /**
185      * A bit mask indicating this method is a constructor.
186      */

187     protected static final int MASK_IS_CONSTRUCTOR= 0x00000040;
188
189     /**
190      * A bit mask indicating this type is a class.
191      */

192     protected static final int MASK_TYPE_IS_CLASS= 0x00000080;
193
194     /**
195      * A bit mask indicating this type has a superclass
196      * (requires or has an 'extends' clause).
197      */

198     protected static final int MASK_TYPE_HAS_SUPERCLASS= 0x00000100;
199
200     /**
201      * A bit mask indicating this type implements
202      * or extends some interfaces
203      */

204     protected static final int MASK_TYPE_HAS_INTERFACES= 0x00000200;
205
206     /**
207      * A bit mask indicating this return type of this method has
208      * been altered from the original contents.
209      */

210     protected static final int MASK_RETURN_TYPE_ALTERED= 0x00000400;
211
212     /**
213      * A bit mask indicating this node has detailed source indexes
214      */

215     protected static final int MASK_DETAILED_SOURCE_INDEXES = 0x00000800;
216
217 /**
218  * Creates a new empty document fragment.
219  */

220 DOMNode() {
221     fName= null;
222     fDocument= null;
223     fSourceRange= new int[]{-1, -1};
224     fNameRange= new int[]{-1, -1};
225     fragment();
226 }
227 /**
228  * Creates a new document fragment on the given range of the document.
229  *
230  * @param document - the document containing this node's original contents
231  * @param sourceRange - a two element array of integers describing the
232  * entire inclusive source range of this node within its document.
233  * Contents start on and include the character at the first position.
234  * Contents end on and include the character at the last position.
235  * An array of -1's indicates this node's contents do not exist
236  * in the document.
237  * @param name - the identifier portion of the name of this node, or
238  * <code>null</code> if this node does not have a name
239  * @param nameRange - a two element array of integers describing the
240  * entire inclusive source range of this node's name within its document,
241  * including any array qualifiers that might immediately follow the name
242  * or -1's if this node does not have a name.
243  */

244 DOMNode(char[] document, int[] sourceRange, String JavaDoc name, int[] nameRange) {
245     super();
246     fDocument= document;
247     fSourceRange= sourceRange;
248     fName= name;
249     fNameRange= nameRange;
250
251 }
252 /**
253  * Adds the given un-parented node (document fragment) as the last child of
254  * this node.
255  *
256  * <p>When a child is added, this node must be considered fragmented such that
257  * the contents of this node are properly generated.
258  *
259  * @see IDOMNode#addChild(IDOMNode)
260  */

261 public void addChild(IDOMNode child) throws IllegalArgumentException JavaDoc, DOMException {
262     basicAddChild(child);
263     
264     // if the node is a constructor, it must also be fragmented to update the constructor's name
265
if (child.getNodeType() == IDOMNode.METHOD && ((IDOMMethod)child).isConstructor()) {
266         ((DOMNode)child).fragment();
267     } else {
268         fragment();
269     }
270 }
271 /**
272  * Appends the current contents of this document fragment
273  * to the given <code>CharArrayBuffer</code>.
274  *
275  * <p>If this node is fragmented, contents must be generated by
276  * using the original document and indicies as a form for the current
277  * attribute values of this node. If this node not fragmented, the
278  * contents can be obtained from the document.
279  *
280  */

281 protected void appendContents(CharArrayBuffer buffer) {
282     if (isFragmented()) {
283         appendFragmentedContents(buffer);
284     } else {
285         buffer.append(fDocument, fSourceRange[0], fSourceRange[1] + 1 - fSourceRange[0]);
286     }
287 }
288 /**
289  * Appends the contents of all children of this node to the
290  * given <code>CharArrayBuffer</code>.
291  *
292  * <p>This algorithm used minimizes String generation by merging
293  * adjacent unfragmented children into one substring operation.
294  *
295  */

296 protected void appendContentsOfChildren(CharArrayBuffer buffer) {
297     DOMNode child= fFirstChild;
298     DOMNode sibling;
299     
300     int start= 0, end= 0;
301     if (child != null) {
302         start= child.getStartPosition();
303         end= child.getEndPosition();
304     }
305     while (child != null) {
306         sibling= child.fNextNode;
307         if (sibling != null) {
308             if (sibling.isContentMergableWith(child)) {
309                 end= sibling.getEndPosition();
310             } else {
311                 if (child.isFragmented()) {
312                     child.appendContents(buffer);
313                 } else {
314                     buffer.append(child.getDocument(), start, end + 1 - start);
315                 }
316                 start= sibling.getStartPosition();
317                 end= sibling.getEndPosition();
318             }
319         } else {
320             if (child.isFragmented()) {
321                 child.appendContents(buffer);
322             } else {
323                 buffer.append(child.getDocument(), start, end + 1 - start);
324             }
325         }
326         child= sibling;
327     }
328 }
329 /**
330  * Appends the contents of this node to the given <code>CharArrayBufer</code>, using
331  * the original document and indicies as a form for the current attribute
332  * values of this node.
333  */

334 protected abstract void appendFragmentedContents(CharArrayBuffer buffer);
335 /**
336  * Adds the given un-parented node (document fragment) as the last child of
337  * this node without setting this node's 'fragmented' flag. This
338  * method is only used by the <code>DOMBuilder</code> when creating a new DOM such
339  * that a new DOM is unfragmented.
340  */

341 void basicAddChild(IDOMNode child) throws IllegalArgumentException JavaDoc, DOMException {
342     // verify child may be added
343
if (!canHaveChildren()) {
344         throw new DOMException(Messages.dom_unableAddChild);
345     }
346     if (child == null) {
347         throw new IllegalArgumentException JavaDoc(Messages.dom_addNullChild);
348     }
349     if (!isAllowableChild(child)) {
350         throw new DOMException(Messages.dom_addIncompatibleChild);
351     }
352     if (child.getParent() != null) {
353         throw new DOMException(Messages.dom_addChildWithParent);
354     }
355     /* NOTE: To test if the child is an ancestor of this node, we
356      * need only test if the root of this node is the child (the child
357      * is already a root since we have just guarenteed it has no parent).
358      */

359     if (child == getRoot()) {
360         throw new DOMException(Messages.dom_addAncestorAsChild);
361     }
362
363     DOMNode node= (DOMNode)child;
364     
365     // if the child is not already part of this document, localize its contents
366
// before adding it to the tree
367
if (node.getDocument() != getDocument()) {
368         node.localizeContents();
369     }
370     
371     // add the child last
372
if (fFirstChild == null) {
373         // this is the first and only child
374
fFirstChild= node;
375     } else {
376         fLastChild.fNextNode= node;
377         node.fPreviousNode= fLastChild;
378     }
379     fLastChild= node;
380     node.fParent= this;
381 }
382 /**
383  * Generates detailed source indexes for this node if possible.
384  *
385  * @exception DOMException if unable to generate detailed source indexes
386  * for this node
387  */

388 protected void becomeDetailed() throws DOMException {
389     if (!isDetailed()) {
390         DOMNode detailed= getDetailedNode();
391         if (detailed == null) {
392             throw new DOMException(Messages.dom_cannotDetail);
393         }
394         if (detailed != this) {
395             shareContents(detailed);
396         }
397     }
398 }
399 /**
400  * Returns true if this node is allowed to have children, otherwise false.
401  *
402  * <p>Default implementation of <code>IDOMNode</code> interface method returns false; this
403  * method must be overridden by subclasses that implement nodes that allow
404  * children.
405  *
406  * @see IDOMNode#canHaveChildren()
407  */

408 public boolean canHaveChildren() {
409     return false;
410 }
411 /**
412  * @see IDOMNode#clone()
413  */

414 public Object JavaDoc clone() {
415
416     // create a new buffer with all my contents and children contents
417
int length= 0;
418     char[] buffer= null;
419     int offset= fSourceRange[0];
420     
421     if (offset >= 0) {
422         length= fSourceRange[1] - offset + 1;
423         buffer= new char[length];
424         System.arraycopy(fDocument, offset, buffer, 0, length);
425     }
426     DOMNode clone= newDOMNode();
427     clone.shareContents(this);
428     clone.fDocument = buffer;
429
430     if (offset > 0) {
431         clone.offset(0 - offset);
432     }
433
434     // clone my children
435
if (canHaveChildren()) {
436         Enumeration JavaDoc children= getChildren();
437         while (children.hasMoreElements()) {
438             DOMNode child= (DOMNode)children.nextElement();
439             if (child.fDocument == fDocument) {
440                 DOMNode childClone= child.cloneSharingDocument(buffer, offset);
441                 clone.basicAddChild(childClone);
442             } else {
443                 DOMNode childClone= (DOMNode)child.clone();
444                 clone.addChild(childClone);
445             }
446             
447         }
448     }
449     
450     return clone;
451 }
452 private DOMNode cloneSharingDocument(char[] document, int rootOffset) {
453
454     DOMNode clone = newDOMNode();
455     clone.shareContents(this);
456     clone.fDocument = document;
457     if (rootOffset > 0) {
458         clone.offset(0 - rootOffset);
459     }
460     
461     if (canHaveChildren()) {
462         Enumeration JavaDoc children = getChildren();
463         while (children.hasMoreElements()) {
464             DOMNode child = (DOMNode) children.nextElement();
465             if (child.fDocument == fDocument) {
466                 DOMNode childClone= child.cloneSharingDocument(document, rootOffset);
467                 clone.basicAddChild(childClone);
468             } else {
469                 DOMNode childClone= (DOMNode)child.clone();
470                 clone.addChild(childClone);
471             }
472         }
473     }
474     return clone;
475 }
476 /**
477  * Sets this node's fragmented flag and all ancestor fragmented flags
478  * to <code>true<code>. This happens when an attribute of this node or a descendant
479  * node has been altered. When a node is fragmented, its contents must
480  * be generated from its attributes and original "form" rather than
481  * from the original contents in the document.
482  */

483 protected void fragment() {
484     if (!isFragmented()) {
485         fIsFragmented= true;
486         if (fParent != null) {
487             fParent.fragment();
488         }
489     }
490 }
491 /**
492  * @see IDOMNode#getCharacters()
493  */

494 public char[] getCharacters() {
495     CharArrayBuffer buffer= new CharArrayBuffer();
496     appendContents(buffer);
497     return buffer.getContents();
498 }
499 /**
500  * @see IDOMNode#getChild(String)
501  */

502 public IDOMNode getChild(String JavaDoc name) {
503     DOMNode child = fFirstChild;
504     while (child != null) {
505         String JavaDoc n = child.getName();
506         if (name == null) {
507             if (n == null) {
508                 return child;
509             }
510         } else {
511             if (name.equals(n)) {
512                 return child;
513             }
514         }
515         child = child.fNextNode;
516     }
517     return null;
518 }
519 /**
520  * @see IDOMNode#getChildren()
521  */

522 public Enumeration JavaDoc getChildren() {
523     return new SiblingEnumeration(fFirstChild);
524 }
525 /**
526  * Returns the current contents of this document fragment,
527  * or <code>null</code> if this node has no contents.
528  *
529  * <p>If this node is fragmented, contents must be generated by
530  * using the original document and indicies as a form for the current
531  * attribute values of this node. If this node not fragmented, the
532  * contents can be obtained from the document.
533  *
534  * @see IDOMNode#getContents()
535  */

536 public String JavaDoc getContents() {
537     CharArrayBuffer buffer= new CharArrayBuffer();
538     appendContents(buffer);
539     return buffer.toString();
540 }
541 /**
542  * Returns a new document fragment representing this node with
543  * detailed source indexes. Subclasses that provide a detailed
544  * implementation must override this method.
545  */

546 protected DOMNode getDetailedNode() {
547     return this;
548 }
549 /**
550  * Returns the document containing this node's original contents.
551  * The document may be shared by other nodes.
552  */

553 protected char[] getDocument() {
554     return fDocument;
555 }
556 /**
557  * Returns the original position of the last character of this
558  * node's contents in its document.
559  */

560 public int getEndPosition() {
561     return fSourceRange[1];
562 }
563 /**
564  * Returns a factory with which to create new document fragments.
565  */

566 protected IDOMFactory getFactory() {
567     return new DOMFactory();
568 }
569 /**
570  * @see IDOMNode#getFirstChild()
571  */

572 public IDOMNode getFirstChild() {
573     return fFirstChild;
574 }
575 /**
576  * Returns the position at which the first child of this node should be inserted.
577  */

578 public int getInsertionPosition() {
579     return fInsertionPosition;
580 }
581 /**
582  * Returns <code>true</code> if the given mask of this node's state flag
583  * is turned on, otherwise <code>false</code>.
584  */

585 protected boolean getMask(int mask) {
586     return (fStateMask & mask) > 0;
587 }
588 /**
589  * @see IDOMNode#getName()
590  */

591 public String JavaDoc getName() {
592     return fName;
593 }
594 /**
595  * Returns the source code to be used for this node's name.
596  */

597 protected char[] getNameContents() {
598     if (isNameAltered()) {
599         return fName.toCharArray();
600     } else {
601         if (fName == null || fNameRange[0] < 0) {
602             return null;
603         } else {
604             int length = fNameRange[1] + 1 - fNameRange[0];
605             char[] result = new char[length];
606             System.arraycopy(fDocument, fNameRange[0], result, 0, length);
607             return result;
608         }
609     }
610 }
611 /**
612  * @see IDOMNode#getNextNode()
613  */

614 public IDOMNode getNextNode() {
615     return fNextNode;
616 }
617 /**
618  * @see IDOMNode#getParent()
619  */

620 public IDOMNode getParent() {
621     return fParent;
622 }
623 /**
624  * Answers a source position which corresponds to the end of the parent
625  * element's declaration.
626  */

627 protected int getParentEndDeclaration() {
628     IDOMNode parent = getParent();
629     if (parent == null) {
630         return 0;
631     } else {
632         if (parent instanceof IDOMCompilationUnit) {
633             return 0;
634         } else {
635             return ((DOMType)parent).getOpenBodyEnd();
636         }
637     }
638 }
639 /**
640  * @see IDOMNode#getPreviousNode()
641  */

642 public IDOMNode getPreviousNode() {
643     return fPreviousNode;
644 }
645 /**
646  * Returns the root node of this document fragment.
647  */

648 protected IDOMNode getRoot() {
649     if (fParent == null) {
650         return this;
651     } else {
652         return fParent.getRoot();
653     }
654 }
655 /**
656  * Returns the original position of the first character of this
657  * node's contents in its document.
658  */

659 public int getStartPosition() {
660     return fSourceRange[0];
661 }
662 /**
663  * @see IDOMNode#insertSibling(IDOMNode)
664  */

665 public void insertSibling(IDOMNode sibling) throws IllegalArgumentException JavaDoc, DOMException {
666     // verify sibling may be added
667
if (sibling == null) {
668         throw new IllegalArgumentException JavaDoc(Messages.dom_addNullSibling);
669     }
670     if (fParent == null) {
671         throw new DOMException(Messages.dom_addSiblingBeforeRoot);
672     }
673     if (!fParent.isAllowableChild(sibling)) {
674         throw new DOMException(Messages.dom_addIncompatibleSibling);
675     }
676     if (sibling.getParent() != null) {
677         throw new DOMException(Messages.dom_addSiblingWithParent);
678     }
679     /* NOTE: To test if the sibling is an ancestor of this node, we
680      * need only test if the root of this node is the child (the sibling
681      * is already a root since we have just guaranteed it has no parent).
682      */

683     if (sibling == getRoot()) {
684         throw new DOMException(Messages.dom_addAncestorAsSibling);
685     }
686
687     DOMNode node= (DOMNode)sibling;
688     
689     // if the sibling is not already part of this document, localize its contents
690
// before inserting it into the tree
691
if (node.getDocument() != getDocument()) {
692         node.localizeContents();
693     }
694
695     // insert the node
696
if (fPreviousNode == null) {
697         fParent.fFirstChild= node;
698     } else {
699         fPreviousNode.fNextNode= node;
700     }
701     node.fParent= fParent;
702     node.fPreviousNode= fPreviousNode;
703     node.fNextNode= this;
704     fPreviousNode= node;
705
706     // if the node is a constructor, it must also be fragmented to update the constructor's name
707
if (node.getNodeType() == IDOMNode.METHOD && ((IDOMMethod)node).isConstructor()) {
708         node.fragment();
709     } else {
710         fParent.fragment();
711     }
712 }
713 /**
714  * @see IDOMNode
715  */

716 public boolean isAllowableChild(IDOMNode node) {
717     return false;
718 }
719 /**
720  * Returns <code>true</code> if the contents of this node are from the same document as
721  * the given node, the contents of this node immediately follow the contents
722  * of the given node, and neither this node or the given node are fragmented -
723  * otherwise <code>false</code>.
724  */

725 protected boolean isContentMergableWith(DOMNode node) {
726     return !node.isFragmented() && !isFragmented() && node.getDocument() == getDocument() &&
727         node.getEndPosition() + 1 == getStartPosition();
728 }
729 /**
730  * Returns <code>true</code> if this node has detailed source index information,
731  * or <code>false</code> if this node has limited source index information. To
732  * perform some manipulations, detailed indexes are required.
733  */

734 protected boolean isDetailed() {
735     return getMask(MASK_DETAILED_SOURCE_INDEXES);
736 }
737 /**
738  * Returns <code>true</code> if this node's or a descendant node's contents
739  * have been altered since this node was created. This indicates
740  * that the contents of this node are no longer consistent with
741  * the contents of this node's document.
742  */

743 protected boolean isFragmented() {
744     return fIsFragmented;
745 }
746 /**
747  * Returns <code>true</code> if this noed's name has been altered
748  * from the original document contents.
749  */

750 protected boolean isNameAltered() {
751     return getMask(MASK_NAME_ALTERED);
752 }
753 /**
754  * @see IDOMNode#isSignatureEqual(IDOMNode)
755  *
756  * <p>By default, the signatures of two nodes are equal if their
757  * type and names are equal. Node types that have other requirements
758  * for equality must override this method.
759  */

760 public boolean isSignatureEqual(IDOMNode node) {
761     return getNodeType() == node.getNodeType() && getName().equals(node.getName());
762 }
763 /**
764  * Localizes the contents of this node and all descendant nodes,
765  * such that this node is no longer dependent on its original
766  * document in order to generate its contents. This node and all
767  * descendant nodes become unfragmented and share a new
768  * document.
769  */

770 protected void localizeContents() {
771
772     DOMNode clone= (DOMNode)clone();
773     shareContents(clone);
774
775 }
776 /**
777  * Returns a new empty <code>DOMNode</code> for this instance.
778  */

779 protected abstract DOMNode newDOMNode();
780 /**
781  * Normalizes this <code>DOMNode</code>'s source positions to include whitespace preceeding
782  * the node on the line on which the node starts, and all whitespace after the node up to
783  * the next node's start
784  */

785 void normalize(ILineStartFinder finder) {
786     if (getPreviousNode() == null)
787         normalizeStartPosition(getParentEndDeclaration(), finder);
788
789     // Set the children's position
790
if (canHaveChildren()) {
791         Enumeration JavaDoc children = getChildren();
792         while(children.hasMoreElements())
793             ((DOMNode)children.nextElement()).normalize(finder);
794     }
795
796     normalizeEndPosition(finder, (DOMNode)getNextNode());
797 }
798 /**
799  * Normalizes this <code>DOMNode</code>'s end position.
800  */

801 void normalizeEndPosition(ILineStartFinder finder, DOMNode next) {
802     if (next == null) {
803         // this node's end position includes all of the characters up
804
// to the end of the enclosing node
805
DOMNode parent = (DOMNode) getParent();
806         if (parent == null || parent instanceof DOMCompilationUnit) {
807             setSourceRangeEnd(fDocument.length - 1);
808         } else {
809             // parent is a type
810
int temp = ((DOMType)parent).getCloseBodyPosition() - 1;
811             setSourceRangeEnd(temp);
812             fInsertionPosition = Math.max(finder.getLineStart(temp + 1), getEndPosition());
813         }
814     } else {
815         // this node's end position is just before the start of the next node
816
int temp = next.getStartPosition() - 1;
817         fInsertionPosition = Math.max(finder.getLineStart(temp + 1), getEndPosition());
818         next.normalizeStartPosition(getEndPosition(), finder);
819         setSourceRangeEnd(next.getStartPosition() - 1);
820     }
821 }
822 /**
823  * Normalizes this <code>DOMNode</code>'s start position.
824  */

825 void normalizeStartPosition(int previousEnd, ILineStartFinder finder) {
826     int nodeStart = getStartPosition();
827     int lineStart = finder.getLineStart(nodeStart);
828     if (nodeStart > lineStart && (lineStart > previousEnd || (previousEnd == 0 && lineStart == 0)))
829         setStartPosition(lineStart);
830 }
831 /**
832  * Offsets all the source indexes in this node by the given amount.
833  */

834 protected void offset(int offset) {
835     offsetRange(fNameRange, offset);
836     offsetRange(fSourceRange, offset);
837 }
838 /**
839  * Offsets the source range by the given amount
840  */

841 protected void offsetRange(int[] range, int offset) {
842     for (int i= 0; i < range.length; i++) {
843         range[i]+=offset;
844         if (range[i] < 0) {
845             range[i]= -1;
846         }
847     }
848 }
849 /**
850  * Returns a copy of the given range.
851  */

852 protected int[] rangeCopy(int[] range) {
853     int[] copy= new int[range.length];
854     for (int i= 0; i < range.length; i++) {
855         copy[i]= range[i];
856     }
857     return copy;
858 }
859 /**
860  * Separates this node from its parent and siblings, maintaining any ties that
861  * this node has to the underlying document fragment.
862  *
863  * <p>When a child is removed, its parent is fragmented such that it properly
864  * generates its contents.
865  *
866  * @see IDOMNode#remove()
867  */

868 public void remove() {
869
870     if (fParent != null) {
871         fParent.fragment();
872     }
873     
874     // link siblings
875
if (fNextNode != null) {
876         fNextNode.fPreviousNode= fPreviousNode;
877     }
878     if (fPreviousNode != null) {
879         fPreviousNode.fNextNode= fNextNode;
880     }
881     // fix parent's pointers
882
if (fParent != null) {
883         if (fParent.fFirstChild == this) {
884             fParent.fFirstChild= fNextNode;
885         }
886         if (fParent.fLastChild == this) {
887             fParent.fLastChild= fPreviousNode;
888         }
889     }
890     // remove myself
891
fParent= null;
892     fNextNode= null;
893     fPreviousNode= null;
894 }
895 /**
896  * Sets the specified mask of this node's state mask on or off
897  * based on the boolean value - true -> on, false -> off.
898  */

899 protected void setMask(int mask, boolean on) {
900     if (on) {
901         fStateMask |= mask;
902     } else {
903         fStateMask &= ~mask;
904     }
905 }
906 /**
907  * @see IDOMNode#setName
908  */

909 public void setName(String JavaDoc name) {
910     fName= name;
911     setNameAltered(true);
912     fragment();
913 }
914 /**
915  * Sets the state of this node as having
916  * its name attribute altered from the original
917  * document contents.
918  */

919 protected void setNameAltered(boolean altered) {
920     setMask(MASK_NAME_ALTERED, altered);
921 }
922 /**
923  * Sets the original position of the last character of this node's contents
924  * in its document. This method is only used during DOM creation while
925  * normalizing the source range of each node.
926  */

927 protected void setSourceRangeEnd(int end) {
928     fSourceRange[1]= end;
929 }
930 /**
931  * Sets the original position of the first character of this node's contents
932  * in its document. This method is only used during DOM creation while
933  * normalizing the source range of each node.
934  */

935 protected void setStartPosition(int start) {
936     fSourceRange[0]= start;
937 }
938 /**
939  * Sets the contents of this node and descendant nodes to be the
940  * (identical) contents of the given node and its descendants. This
941  * does not effect this node's parent and sibling configuration,
942  * only the contents of this node. This is used only to localize
943  * the contents of this node.
944  */

945 protected void shareContents(DOMNode node) {
946     fDocument= node.fDocument;
947     fIsFragmented= node.fIsFragmented;
948     fName= node.fName;
949     fNameRange= rangeCopy(node.fNameRange);
950     fSourceRange= rangeCopy(node.fSourceRange);
951     fStateMask= node.fStateMask;
952
953     
954     if (canHaveChildren()) {
955         Enumeration JavaDoc myChildren= getChildren();
956         Enumeration JavaDoc otherChildren= node.getChildren();
957         DOMNode myChild, otherChild;
958         while (myChildren.hasMoreElements()) {
959             myChild= (DOMNode)myChildren.nextElement();
960             otherChild= (DOMNode)otherChildren.nextElement();
961             myChild.shareContents(otherChild);
962         }
963     }
964 }
965 /**
966  * Returns a <code>String</code> representing this node - for Debug purposes only.
967  */

968 public abstract String JavaDoc toString();
969 }
970
Popular Tags