1 /*
2 * Copyright 2009 - 2010 JEuclid, http://jeuclid.sf.net
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* $Id $ */
18
19 package net.sourceforge.jeuclid.biparser;
20
21 import org.w3c.dom.Node;
22
23 /**
24 * this class is used to store typical information about a xml-node.
25 *
26 * @version $Revision: 0b66106c7ff7 $
27 *
28 */
29 public abstract class AbstractBiNode implements IBiNode {
30
31 /** previous node, null if node is root. */
32 private IBiNode previous;
33
34 /** sibling node, can be null. */
35 private IBiNode sibling;
36
37 /** reference to node in DOM-tree. */
38 private Node node;
39
40 /** length of node in characters. */
41 private int length;
42
43 /**
44 * get previous node, null if node is root.
45 *
46 * @return previous
47 */
48 public final IBiNode getPrevious() {
49 return this.previous;
50 }
51
52 /**
53 * set previous for this node.
54 *
55 * @param prev
56 * previous node for this node
57 */
58 public final void setPrevious(final IBiNode prev) {
59 this.previous = prev;
60 }
61
62 /**
63 * get parent node for this node.
64 *
65 * @return parent
66 */
67 public final BiNode getParent() {
68 // check if previous isn't a "real parent"
69 if (this.previous != null && this.previous.getSibling() == this) {
70 return this.previous.getParent();
71 } else {
72 // previous is "real parent" or null
73 return (BiNode) this.previous;
74 }
75 }
76
77 /**
78 * get sibling node, can be null.
79 *
80 * @return sibling
81 */
82 public final IBiNode getSibling() {
83 return this.sibling;
84 }
85
86 /**
87 * set sibling for this node and set previous of sibling to this.
88 *
89 * @param sibl
90 * new sibling for this node
91 */
92 public final void setSibling(final IBiNode sibl) {
93 if (sibl != null) {
94 sibl.setPrevious(this);
95 }
96
97 this.sibling = sibl;
98 }
99
100 /**
101 * add sibling to a node, not possible at a textnode. if node already has a
102 * sibling, forward to sibling.
103 *
104 * @param sibl
105 * new sibling for this node
106 */
107 public final void addSibling(final IBiNode sibl) {
108 if (this.sibling == null) {
109 // 2nd child
110 this.setSibling(sibl);
111 } else {
112 // forward(3rd - nth child)
113 this.sibling.addSibling(sibl);
114 }
115 }
116
117 /**
118 * get reference to node in DOM-tree.
119 *
120 * @return node in DOM-tree
121 */
122 public final Node getNode() {
123 return this.node;
124 }
125
126 /**
127 * set reference to node in DOM-tree.
128 *
129 * @param n
130 * reference in DOM-tree
131 */
132 public final void setNode(final Node n) {
133 this.node = n;
134 }
135
136 /**
137 * get length of node (number of characters).
138 *
139 * @return length of node
140 */
141 public final int getLength() {
142 return this.length;
143 }
144
145 /**
146 * set length of node.
147 *
148 * @param len
149 * to set
150 */
151 public final void setLength(final int len) {
152 this.length = len;
153 }
154
155 /**
156 * change length of node and recursive of all parents.
157 *
158 * @param change
159 * changevalue (can be positive or negative)
160 */
161 public final void changeLengthRec(final int change) {
162 if (change == 0) {
163 return;
164 }
165
166 this.length += change;
167
168 if (this.getParent() != null) {
169 this.getParent().changeLengthRec(change);
170 }
171 }
172
173 /**
174 * helper method to insert or remove characters.
175 *
176 * @param insert
177 * if true call insert-method else remove-method
178 * @param biTree
179 * reference to BiTree to which this node contains
180 * @param offset
181 * position to insert/remove characters
182 * @param len
183 * number of characters to insert/remove
184 * @param totalOffset
185 * offset of node to begin of text
186 * @throws ReparseException
187 * if a reparse at upper level is needed
188 * @throws NonIncrementalElementException
189 * if the subtree contains an element which cannot be
190 * incrementally updated.
191 */
192 public void forwardToSibling(final boolean insert, final BiTree biTree,
193 final int offset, final int len, final int totalOffset)
194 throws ReparseException, NonIncrementalElementException {
195
196 if (this.getSibling() == null) {
197 // reparsing
198 throw new ReparseException();
199 } else {
200 if (insert) {
201 this.getSibling().insert(biTree, offset, len, totalOffset);
202 } else {
203 this.getSibling().remove(biTree, offset, len, totalOffset);
204 }
205 }
206 }
207
208 /**
209 * search a DOM node in this node. if nodes are equal return offset to begin
210 * of inputtext, else null
211 *
212 * @param n
213 * DOM node to search for
214 * @param totalOffset
215 * offset of node to begin of inputtext
216 * @return position of node in inputtext
217 */
218 public TextPosition searchNode(final Node n, final int totalOffset) {
219 if (this.node != null && this.node.equals(n)) {
220 return new TextPosition(totalOffset, this.length);
221 }
222
223 return null;
224 }
225
226 /**
227 * helper method for outputting the length of node.
228 *
229 * @return formatted output of length
230 */
231 public String formatLength() {
232 int i;
233 final int max = 3;
234 final StringBuffer sb = new StringBuffer();
235
236 for (i = 1; i <= max && 1 > this.getLength() / Math.pow(10, max - i); i++) {
237
238 if (i == 1 && this.getLength() == 0) {
239 continue;
240 }
241 sb.append(' ');
242 }
243
244 sb.append(this.length);
245
246 return sb.toString();
247 }
248 }