KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > core > TemplateElement


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.core;
54
55 import java.util.*;
56 import java.io.IOException JavaDoc;
57 import javax.swing.tree.TreeNode JavaDoc;
58 import freemarker.template.*;
59 import freemarker.template.utility.Collections12;
60
61 /**
62  * Objects that represent elements in the compiled
63  * tree representation of the template necessarily
64  * descend from this abstract class.
65  */

66 abstract public class TemplateElement extends TemplateObject implements TreeNode JavaDoc {
67
68     TemplateElement parent;
69
70 // Only one of nestedBlock and nestedElements can be non-null.
71

72     TemplateElement nestedBlock;
73
74     List nestedElements;
75
76     /**
77      * Processes the contents of this <tt>TemplateElement</tt> and
78      * outputs the resulting text
79      *
80      * @param env The runtime environment
81      */

82     abstract void accept(Environment env) throws TemplateException, IOException JavaDoc;
83
84     abstract public String JavaDoc getDescription();
85     
86 // Methods to implement TemplateNodeModel
87

88     public TemplateNodeModel getParentNode() {
89 // return parent;
90
return null;
91     }
92     
93     public String JavaDoc getNodeNamespace() {
94         return null;
95     }
96     
97     public String JavaDoc getNodeType() {
98         return "element";
99     }
100     
101     public TemplateSequenceModel getChildNodes() {
102         if (nestedElements != null) {
103             return new SimpleSequence(nestedElements);
104         }
105         SimpleSequence result = null;
106         if (nestedBlock != null) {
107             result.add(nestedBlock);
108         }
109         return result;
110     }
111     
112     public String JavaDoc getNodeName() {
113         String JavaDoc classname = this.getClass().getName();
114         int shortNameOffset = classname.lastIndexOf('.')+1;
115         return classname.substring(shortNameOffset);
116     }
117     
118 // Methods so that we can implement the Swing TreeNode API.
119

120     public boolean isLeaf() {
121         return nestedBlock == null
122                && (nestedElements == null || nestedElements.isEmpty());
123     }
124
125     public boolean getAllowsChildren() {
126         return !isLeaf();
127     }
128
129     public int getIndex(TreeNode JavaDoc node) {
130         if (nestedBlock instanceof MixedContent) {
131             return nestedBlock.getIndex(node);
132         }
133         if (nestedBlock != null) {
134             if (node == nestedBlock) {
135                 return 0;
136             }
137         }
138         else if (nestedElements != null) {
139             return nestedElements.indexOf(node);
140         }
141         return -1;
142     }
143
144     public int getChildCount() {
145         if (nestedBlock instanceof MixedContent) {
146             return nestedBlock.getChildCount();
147         }
148         if (nestedBlock != null) {
149             return 1;
150         }
151         else if (nestedElements != null) {
152             return nestedElements.size();
153         }
154         return 0;
155     }
156
157     public Enumeration children() {
158         if (nestedBlock instanceof MixedContent) {
159             return nestedBlock.children();
160         }
161         if (nestedBlock != null) {
162             return Collections.enumeration(Collections12.singletonList(nestedBlock));
163         }
164         else if (nestedElements != null) {
165             return Collections.enumeration(nestedElements);
166         }
167         return Collections.enumeration(Collections.EMPTY_LIST);
168     }
169
170     public TreeNode JavaDoc getChildAt(int index) {
171         if (nestedBlock instanceof MixedContent) {
172             return nestedBlock.getChildAt(index);
173         }
174         if (nestedBlock != null) {
175             if (index == 0) {
176                 return nestedBlock;
177             }
178             throw new ArrayIndexOutOfBoundsException JavaDoc("invalid index");
179         }
180         else if (nestedElements != null) {
181             return(TreeNode JavaDoc) nestedElements.get(index);
182         }
183         throw new ArrayIndexOutOfBoundsException JavaDoc("element has no children");
184     }
185
186     public void setChildAt(int index, TemplateElement element) {
187         if(nestedBlock instanceof MixedContent) {
188             nestedBlock.setChildAt(index, element);
189         }
190         else if(nestedBlock != null) {
191             if(index == 0) {
192                 nestedBlock = element;
193                 element.parent = this;
194             }
195             else {
196                 throw new IndexOutOfBoundsException JavaDoc("invalid index");
197             }
198         }
199         else if(nestedElements != null) {
200             nestedElements.set(index, element);
201             element.parent = this;
202         }
203         else {
204             throw new IndexOutOfBoundsException JavaDoc("element has no children");
205         }
206     }
207     
208     public TreeNode JavaDoc getParent() {
209         return parent;
210     }
211
212     // Walk the tree and set the parent field in all the nested elements recursively.
213

214     void setParentRecursively(TemplateElement parent) {
215         this.parent = parent;
216         int nestedSize = nestedElements == null ? 0 : nestedElements.size();
217         for (int i = 0; i < nestedSize; i++) {
218             ((TemplateElement) nestedElements.get(i)).setParentRecursively(this);
219         }
220         if (nestedBlock != null) {
221             nestedBlock.setParentRecursively(this);
222         }
223     }
224
225     /**
226      * We walk the tree and do some cleanup
227      * @param stripWhitespace whether to clean up superfluous whitespace
228      */

229     TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException {
230         if (nestedElements != null) {
231             for (int i = 0; i < nestedElements.size(); i++) {
232                 TemplateElement te = (TemplateElement) nestedElements.get(i);
233                 te = te.postParseCleanup(stripWhitespace);
234                 nestedElements.set(i, te);
235                 te.parent = this;
236             }
237             if (stripWhitespace) {
238                 for (Iterator it = nestedElements.iterator(); it.hasNext();) {
239                     TemplateElement te = (TemplateElement) it.next();
240                     if (te.isIgnorable()) {
241                         it.remove();
242                     }
243                 }
244             }
245             if (nestedElements instanceof ArrayList) {
246                 ((ArrayList) nestedElements).trimToSize();
247             }
248         }
249         if (nestedBlock != null) {
250             nestedBlock = nestedBlock.postParseCleanup(stripWhitespace);
251             if (nestedBlock.isIgnorable()) {
252                 nestedBlock = null;
253             } else {
254                 nestedBlock.parent = this;
255             }
256         }
257         return this;
258     }
259
260     boolean isIgnorable() {
261         return false;
262     }
263
264 // The following methods exist to support some fancier tree-walking
265
// and were introduced to support the whitespace cleanup feature in 2.2
266

267     TemplateElement prevTerminalNode() {
268         TemplateElement prev = previousSibling();
269         if (prev != null) {
270             return prev.getLastLeaf();
271         }
272         else if (parent != null) {
273             return parent.prevTerminalNode();
274         }
275         return null;
276     }
277
278     TemplateElement nextTerminalNode() {
279         TemplateElement next = nextSibling();
280         if (next != null) {
281             return next.getFirstLeaf();
282         }
283         else if (parent != null) {
284             return parent.nextTerminalNode();
285         }
286         return null;
287     }
288
289
290
291     TemplateElement previousSibling() {
292         if (parent == null) {
293             return null;
294         }
295         List siblings = parent.nestedElements;
296         if (siblings == null) {
297             return null;
298         }
299         for (int i = siblings.size() - 1; i>=0; i--) {
300             if (siblings.get(i) == this) {
301                 return(i >0) ? (TemplateElement) siblings.get(i-1) : null;
302             }
303         }
304         return null;
305     }
306
307     TemplateElement nextSibling() {
308         if (parent == null) {
309             return null;
310         }
311         List siblings = parent.nestedElements;
312         if (siblings == null) {
313             return null;
314         }
315         for (int i = 0; i < siblings.size(); i++) {
316             if (siblings.get(i) == this) {
317                 return (i+1) < siblings.size() ? (TemplateElement) siblings.get(i+1) : null;
318             }
319         }
320         return null;
321     }
322
323     private TemplateElement getFirstChild() {
324         if (nestedBlock != null) {
325             return nestedBlock;
326         }
327         if (nestedElements != null && nestedElements.size() >0) {
328             return(TemplateElement) nestedElements.get(0);
329         }
330         return null;
331     }
332
333     private TemplateElement getLastChild() {
334         if (nestedBlock != null) {
335             return nestedBlock;
336         }
337         if (nestedElements != null && nestedElements.size() >0) {
338             return(TemplateElement) nestedElements.get(nestedElements.size() -1);
339         }
340         return null;
341     }
342
343
344     private TemplateElement getFirstLeaf() {
345         TemplateElement te = this;
346         while (!te.isLeaf() && !(te instanceof Macro) && !(te instanceof BlockAssignment)) {
347              // A macro or macro invocation is treated as a leaf here for special reasons
348
te = te.getFirstChild();
349         }
350         return te;
351     }
352
353     private TemplateElement getLastLeaf() {
354         TemplateElement te = this;
355         while (!te.isLeaf() && !(te instanceof Macro) && !(te instanceof BlockAssignment)) {
356             // A macro or macro invocation is treated as a leaf here for special reasons
357
te = te.getLastChild();
358         }
359         return te;
360     }
361
362     /**
363      * determines whether this element's presence on a line
364      * indicates that we should not strip opening whitespace
365      * in the post-parse whitespace gobbling step.
366      */

367     boolean heedsOpeningWhitespace() {
368         return false;
369     }
370
371     /**
372      * determines whether this element's presence on a line
373      * indicates that we should not strip trailing whitespace
374      * in the post-parse whitespace gobbling step.
375      */

376     boolean heedsTrailingWhitespace() {
377         return false;
378     }
379 }
380
Popular Tags