KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lobobrowser > html > domimpl > NodeImpl


1 /*
2     GNU LESSER GENERAL PUBLIC LICENSE
3     Copyright (C) 2006 The Lobo Project
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19     Contact info: xamjadmin@users.sourceforge.net
20 */

21 /*
22  * Created on Sep 3, 2005
23  */

24 package org.lobobrowser.html.domimpl;
25
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.*;
29 import java.util.logging.*;
30
31 import org.lobobrowser.html.*;
32 import org.lobobrowser.html.style.*;
33 import org.lobobrowser.js.*;
34 import org.lobobrowser.util.*;
35 import org.w3c.dom.*;
36
37 public abstract class NodeImpl extends AbstractScriptableDelegate implements Node, ModelNode {
38     private static final NodeImpl[] EMPTY_ARRAY = new NodeImpl[0];
39     private static final RenderState INVALID_RENDER_STATE = new StyleSheetRenderState(null, null);
40     protected static final Logger logger = Logger.getLogger(NodeImpl.class.getName());
41     protected UINode uiNode;
42     protected ArrayList nodeList;
43     protected volatile Document document;
44     
45     /**
46      * A tree lock is less deadlock-prone than
47      * a node-level lock. This is assigned in
48      * setOwnerDocument.
49      */

50     protected volatile Object JavaDoc treeLock = this;
51     
52     public NodeImpl() {
53         super();
54     }
55
56     public void setUINode(UINode uiNode) {
57         // Called in GUI thread always.
58
this.uiNode = uiNode;
59     }
60     
61     public UINode getUINode() {
62         // Called in GUI thread always.
63
return this.uiNode;
64     }
65     
66     /**
67      * Tries to get a UINode associated with the current node.
68      * Failing that, it tries ancestors recursively.
69      */

70     public UINode findUINode() {
71         // Called in GUI thread always.
72
UINode uiNode = this.uiNode;
73         if(uiNode != null) {
74             return uiNode;
75         }
76         NodeImpl parentNode = (NodeImpl) this.getParentNode();
77         return parentNode == null ? null : parentNode.findUINode();
78     }
79         
80 // protected final Object getTreeLock() {
81
// //TODO: Is this necessary? Why not use a lock per node?
82
// Object doc = this.document;
83
// return doc == null ? this : doc;
84
// }
85
//
86
public Node appendChild(Node newChild)
87             throws DOMException {
88         synchronized(this.treeLock) {
89             ArrayList nl = this.nodeList;
90             if(nl == null) {
91                 nl = new ArrayList(3);
92                 this.nodeList = nl;
93             }
94             nl.add(newChild);
95             if(newChild instanceof NodeImpl) {
96                 ((NodeImpl) newChild).setParentImpl(this);
97             }
98         }
99                 
100         if(!this.notificationsSuspended) {
101             this.informInvalid();
102         }
103         return newChild;
104     }
105     
106     protected void removeAllChildren() {
107         synchronized(this.treeLock) {
108             this.removeAllChildrenImpl();
109         }
110     }
111
112     protected void removeAllChildrenImpl() {
113         synchronized(this.treeLock) {
114             ArrayList nl = this.nodeList;
115             if(nl != null) {
116                 nl.clear();
117                 //this.nodeList = null;
118
}
119         }
120         if(!this.notificationsSuspended) {
121             this.informInvalid();
122         }
123     }
124
125     protected NodeList getNodeList(NodeFilter filter) {
126         Collection collection = new ArrayList();
127         synchronized(this.treeLock) {
128             this.appendChildrenToCollectionImpl(filter, collection);
129         }
130         return new NodeListImpl(collection);
131     }
132
133     public NodeImpl[] getChildrenArray() {
134         ArrayList nl = this.nodeList;
135         synchronized(this.treeLock) {
136             return nl == null ? null : (NodeImpl[]) nl.toArray(NodeImpl.EMPTY_ARRAY);
137         }
138     }
139     
140     int getChildCount() {
141         ArrayList nl = this.nodeList;
142         synchronized(this.treeLock) {
143             return nl == null ? 0 : nl.size();
144         }
145     }
146     
147     private ChildHTMLCollection childrenCollection;
148     public ChildHTMLCollection getChildren() {
149         // Method required by JavaScript
150
synchronized(this) {
151             ChildHTMLCollection collection = this.childrenCollection;
152             if(collection == null) {
153                 collection = new ChildHTMLCollection(this);
154                 this.childrenCollection = collection;
155             }
156             return collection;
157         }
158     }
159     
160     /**
161      * Gets descendent nodes that match according to
162      * the filter, but it does not nest into matching nodes.
163      */

164     public ArrayList getDescendents(NodeFilter filter) {
165         ArrayList al = new ArrayList();
166         synchronized(this.treeLock) {
167             this.extractDescendentsArrayImpl(filter, al);
168         }
169         return al;
170     }
171     
172     /**
173      * Extracts all descendents that match the filter, except those
174      * descendents of nodes that match the filter.
175      * @param filter
176      * @param al
177      */

178     private void extractDescendentsArrayImpl(NodeFilter filter, ArrayList al) {
179         ArrayList nl = this.nodeList;
180         if(nl != null) {
181             Iterator i = nl.iterator();
182             while(i.hasNext()) {
183                 NodeImpl n = (NodeImpl) i.next();
184                 if(filter.accept(n)) {
185                     al.add(n);
186                 }
187                 else if(n.getNodeType() == Node.ELEMENT_NODE) {
188                     n.extractDescendentsArrayImpl(filter, al);
189                 }
190             }
191         }
192     }
193
194     private void appendChildrenToCollectionImpl(NodeFilter filter, Collection collection) {
195         ArrayList nl = this.nodeList;
196         if(nl != null) {
197             Iterator i = nl.iterator();
198             while(i.hasNext()) {
199                 NodeImpl node = (NodeImpl) i.next();
200                 if(filter.accept(node)) {
201                     collection.add(node);
202                 }
203                 node.appendChildrenToCollectionImpl(filter, collection);
204             }
205         }
206     }
207
208     /**
209      * Should create a node with some cloned properties, like the node name,
210      * but not attributes or children.
211      */

212     protected abstract Node createSimilarNode();
213     
214     public Node cloneNode(boolean deep) {
215         try {
216             Node newNode = this.createSimilarNode();
217             NodeList children = this.getChildNodes();
218             int length = children.getLength();
219             for(int i = 0; i < length; i++) {
220                 Node child = (Node) children.item(i);
221                 Node newChild = deep ? child.cloneNode(deep) : child;
222                 newNode.appendChild(newChild);
223             }
224             if(newNode instanceof Element) {
225                 Element elem = (Element) newNode;
226                 NamedNodeMap nnmap = this.getAttributes();
227                 if(nnmap != null) {
228                     int nnlength = nnmap.getLength();
229                     for(int i = 0; i < nnlength; i++) {
230                         Attr attr = (Attr) nnmap.item(i);
231                         elem.setAttributeNode((Attr) attr.cloneNode(true));
232                     }
233                 }
234             }
235             return newNode;
236         } catch(Exception JavaDoc err) {
237             throw new IllegalStateException JavaDoc(err.getMessage());
238         }
239     }
240
241     private int getNodeIndex() {
242         NodeImpl parent = (NodeImpl) this.getParentNode();
243         return parent == null ? -1 : parent.getChildIndex(this);
244     }
245     
246     int getChildIndex(Node child) {
247         synchronized(this.treeLock) {
248             ArrayList nl = this.nodeList;
249             return nl == null ? -1 : nl.indexOf(child);
250         }
251     }
252
253     Node getChildAtIndex(int index) {
254         synchronized(this.treeLock) {
255             ArrayList nl = this.nodeList;
256             try {
257                 return nl == null ? null : (Node) nl.get(index);
258             } catch(IndexOutOfBoundsException JavaDoc iob) {
259                 this.warn("getChildAtIndex(): Bad index=" + index + " for node=" + this + ".");
260                 return null;
261             }
262         }
263     }
264     
265     private boolean isAncestorOf(Node other) {
266         NodeImpl parent = (NodeImpl) other.getParentNode();
267         if(parent == this) {
268             return true;
269         }
270         else if(parent == null) {
271             return false;
272         }
273         else {
274             return this.isAncestorOf(parent);
275         }
276     }
277     
278     public short compareDocumentPosition(Node other)
279             throws DOMException {
280         Node parent = this.getParentNode();
281         if(!(other instanceof NodeImpl)) {
282             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Unknwon node implementation");
283         }
284         if(parent != null && parent == other.getParentNode()) {
285             int thisIndex = this.getNodeIndex();
286             int otherIndex = ((NodeImpl) other).getNodeIndex();
287             if(thisIndex == -1 || otherIndex == -1) {
288                 return Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
289             }
290             if(thisIndex < otherIndex) {
291                 return Node.DOCUMENT_POSITION_FOLLOWING;
292             }
293             else {
294                 return Node.DOCUMENT_POSITION_PRECEDING;
295             }
296         }
297         else if(this.isAncestorOf(other)) {
298             return Node.DOCUMENT_POSITION_CONTAINED_BY;
299         }
300         else if(((NodeImpl) other).isAncestorOf(this)) {
301             return Node.DOCUMENT_POSITION_CONTAINS;
302         }
303         else {
304             return Node.DOCUMENT_POSITION_DISCONNECTED;
305         }
306     }
307
308     public NamedNodeMap getAttributes() {
309         return null;
310     }
311     
312     public Document getOwnerDocument() {
313         return this.document;
314     }
315
316     void setOwnerDocument(Document value) {
317         this.document = value;
318         this.treeLock = value == null ? this : (Object JavaDoc) value;
319     }
320     
321     void setOwnerDocument(Document value, boolean deep) {
322         this.document = value;
323         this.treeLock = value == null ? this : (Object JavaDoc) value;
324         if(deep) {
325             synchronized(this.treeLock) {
326                 ArrayList nl = this.nodeList;
327                 if(nl != null) {
328                     Iterator i = nl.iterator();
329                     while(i.hasNext()) {
330                         NodeImpl child = (NodeImpl) i.next();
331                         child.setOwnerDocument(value, deep);
332                     }
333                 }
334             }
335         }
336     }
337     
338     void visitImpl(NodeVisitor visitor) {
339         try {
340             visitor.visit(this);
341         } catch(SkipVisitorException sve) {
342             return;
343         } catch(StopVisitorException sve) {
344             throw sve;
345         }
346         ArrayList nl = this.nodeList;
347         if(nl != null) {
348             Iterator i = nl.iterator();
349             while(i.hasNext()) {
350                 NodeImpl child = (NodeImpl) i.next();
351                 try {
352                     // Call with child's synchronization
353
child.visit(visitor);
354                 } catch(StopVisitorException sve) {
355                     throw sve;
356                 }
357             }
358         }
359     }
360     
361     void visit(NodeVisitor visitor) {
362         synchronized(this.treeLock) {
363             this.visitImpl(visitor);
364         }
365     }
366     
367     public Node insertBefore(Node newChild, Node refChild)
368             throws DOMException {
369         synchronized(this.treeLock) {
370             ArrayList nl = this.nodeList;
371             int idx = nl == null ? -1 : nl.indexOf(refChild);
372             if(idx == -1) {
373                 throw new DOMException(DOMException.NOT_FOUND_ERR, "refChild not found");
374             }
375             nl.add(idx, newChild);
376             if(newChild instanceof NodeImpl) {
377                 ((NodeImpl) newChild).setParentImpl(this);
378             }
379         }
380         if(!this.notificationsSuspended) {
381             this.informInvalid();
382         }
383         return newChild;
384     }
385
386     protected Node insertAt(Node newChild, int idx)
387     throws DOMException {
388         synchronized(this.treeLock) {
389             ArrayList nl = this.nodeList;
390             if(nl == null) {
391                 nl = new ArrayList();
392                 this.nodeList = nl;
393             }
394             nl.add(idx, newChild);
395             if(newChild instanceof NodeImpl) {
396                 ((NodeImpl) newChild).setParentImpl(this);
397             }
398         }
399         if(!this.notificationsSuspended) {
400             this.informInvalid();
401         }
402         return newChild;
403     }
404
405     public Node replaceChild(Node newChild, Node oldChild)
406             throws DOMException {
407         synchronized(this.treeLock) {
408             ArrayList nl = this.nodeList;
409             int idx = nl == null ? -1 : nl.indexOf(oldChild);
410             if(idx == -1) {
411                 throw new DOMException(DOMException.NOT_FOUND_ERR, "oldChild not found");
412             }
413             nl.set(idx, newChild);
414         }
415         if(!this.notificationsSuspended) {
416             this.informInvalid();
417         }
418         return newChild;
419     }
420
421     public Node removeChild(Node oldChild)
422             throws DOMException {
423         synchronized(this.treeLock) {
424             ArrayList nl = this.nodeList;
425             if(nl == null || !nl.remove(oldChild)) {
426                 throw new DOMException(DOMException.NOT_FOUND_ERR, "oldChild not found");
427             }
428         }
429         if(!this.notificationsSuspended) {
430             this.informInvalid();
431         }
432         return oldChild;
433     }
434
435     public Node removeChildAt(int index)
436     throws DOMException {
437         try {
438             synchronized(this.treeLock) {
439                 ArrayList nl = this.nodeList;
440                 if(nl == null) {
441                     throw new DOMException(DOMException.INDEX_SIZE_ERR, "Empty list of children");
442                 }
443                 Node n = (Node) nl.remove(index);
444                 if (n == null) {
445                     throw new DOMException(DOMException.INDEX_SIZE_ERR, "No node with that index");
446                 }
447                 return n;
448             }
449         } finally {
450             if(!this.notificationsSuspended) {
451                 this.informInvalid();
452             }
453         }
454     }
455
456     public boolean hasChildNodes() {
457         synchronized(this.treeLock) {
458             ArrayList nl = this.nodeList;
459             return nl != null && !nl.isEmpty();
460         }
461     }
462
463     public String JavaDoc getBaseURI() {
464         Document document = this.document;
465         return document == null ? null : document.getBaseURI();
466     }
467
468     public NodeList getChildNodes() {
469         synchronized(this.treeLock) {
470             ArrayList nl = this.nodeList;
471             return new NodeListImpl(nl == null ? Collections.EMPTY_LIST : nl);
472         }
473     }
474
475     public Node getFirstChild() {
476         synchronized(this.treeLock) {
477             ArrayList nl = this.nodeList;
478             try {
479                 return nl == null ? null : (Node) nl.get(0);
480             } catch(IndexOutOfBoundsException JavaDoc iob) {
481                 return null;
482             }
483         }
484     }
485
486     public Node getLastChild() {
487         synchronized(this.treeLock) {
488             ArrayList nl = this.nodeList;
489             try {
490                 return nl == null ? null : (Node) nl.get(nl.size() - 1);
491             } catch(IndexOutOfBoundsException JavaDoc iob) {
492                 return null;
493             }
494         }
495     }
496
497     private Node getPreviousTo(Node node) {
498         synchronized(this.treeLock) {
499             ArrayList nl = this.nodeList;
500             int idx = nl == null ? -1 : nl.indexOf(node);
501             if(idx == -1) {
502                 throw new DOMException(DOMException.NOT_FOUND_ERR, "node not found");
503             }
504             try {
505                 return (Node) nl.get(idx-1);
506             } catch(IndexOutOfBoundsException JavaDoc iob) {
507                 return null;
508             }
509         }
510     }
511     
512     private Node getNextTo(Node node) {
513         synchronized(this.treeLock) {
514             ArrayList nl = this.nodeList;
515             int idx = nl == null ? -1 : nl.indexOf(node);
516             if(idx == -1) {
517                 throw new DOMException(DOMException.NOT_FOUND_ERR, "node not found");
518             }
519             try {
520                 return (Node) nl.get(idx+1);
521             } catch(IndexOutOfBoundsException JavaDoc iob) {
522                 return null;
523             }
524         }
525     }
526
527     public Node getPreviousSibling() {
528         NodeImpl parent = (NodeImpl) this.getParentNode();
529         return parent == null ? null : parent.getPreviousTo(this);
530     }
531
532     public Node getNextSibling() {
533         NodeImpl parent = (NodeImpl) this.getParentNode();
534         return parent == null ? null : parent.getNextTo(this);
535     }
536
537     public Object JavaDoc getFeature(String JavaDoc feature, String JavaDoc version) {
538         //TODO What should this do?
539
return null;
540     }
541
542     private Map userData;
543     //TODO: Inform handlers on cloning, etc.
544
private List userDataHandlers;
545     protected volatile boolean notificationsSuspended = false;
546     
547     public Object JavaDoc setUserData(String JavaDoc key, Object JavaDoc data,
548             UserDataHandler handler) {
549         if(org.lobobrowser.html.parser.HtmlParser.MODIFYING_KEY.equals(key)) {
550             boolean ns = (Boolean.TRUE == data);
551             this.notificationsSuspended = ns;
552             if(!ns) {
553                 this.informNodeLoaded();
554             }
555         }
556         synchronized(this) {
557             if(handler != null) {
558                 if(this.userDataHandlers == null) {
559                     this.userDataHandlers = new LinkedList();
560                 }
561                 this.userDataHandlers.add(handler);
562             }
563             Map userData = this.userData;
564             if(userData == null) {
565                 userData = new HashMap();
566                 this.userData = userData;
567             }
568             return userData.put(key, data);
569         }
570     }
571
572     public Object JavaDoc getUserData(String JavaDoc key) {
573         synchronized(this) {
574             Map ud = this.userData;
575             return ud == null ? null : ud.get(key);
576         }
577     }
578
579     public abstract String JavaDoc getLocalName();
580
581     public boolean hasAttributes() {
582         return false;
583     }
584
585     public String JavaDoc getNamespaceURI() {
586         return null;
587     }
588
589     public abstract String JavaDoc getNodeName();
590
591     public abstract String JavaDoc getNodeValue() throws DOMException;
592
593     private volatile String JavaDoc prefix;
594     
595     public String JavaDoc getPrefix() {
596         return this.prefix;
597     }
598
599     public void setPrefix(String JavaDoc prefix) throws DOMException {
600         this.prefix = prefix;
601     }
602
603     public abstract void setNodeValue(String JavaDoc nodeValue) throws DOMException;
604
605     public abstract short getNodeType();
606
607     /**
608      * Gets the text content of this node
609      * and its descendents.
610      */

611     public String JavaDoc getTextContent() throws DOMException {
612         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
613         synchronized(this.treeLock) {
614             ArrayList nl = this.nodeList;
615             if(nl != null) {
616                 Iterator i = nl.iterator();
617                 while(i.hasNext()) {
618                     Node node = (Node) i.next();
619                     short type = node.getNodeType();
620                     switch(type) {
621                     case Node.CDATA_SECTION_NODE:
622                     case Node.TEXT_NODE:
623                     case Node.ELEMENT_NODE:
624                         String JavaDoc textContent = node.getTextContent();
625                         if(textContent != null) {
626                             sb.append(textContent);
627                         }
628                         break;
629                     default:
630                         break;
631                     }
632                 }
633             }
634         }
635         return sb.toString();
636     }
637
638     public void setTextContent(String JavaDoc textContent) throws DOMException {
639         synchronized(this.treeLock) {
640             this.removeChildrenImpl(new TextFilter());
641             if(textContent != null && !"".equals(textContent)) {
642                 TextImpl t = new TextImpl(textContent);
643                 t.setOwnerDocument(this.document);
644                 t.setParentImpl(this);
645                 ArrayList nl = this.nodeList;
646                 if(nl == null) {
647                     nl = new ArrayList();
648                     this.nodeList = nl;
649                 }
650                 nl.add(t);
651             }
652         }
653         if(!this.notificationsSuspended) {
654             this.informInvalid();
655         }
656     }
657     
658     protected void removeChildren(NodeFilter filter) {
659         synchronized(this.treeLock) {
660             this.removeChildrenImpl(filter);
661         }
662         if(!this.notificationsSuspended) {
663             this.informInvalid();
664         }
665     }
666     
667     protected void removeChildrenImpl(NodeFilter filter) {
668         ArrayList nl = this.nodeList;
669         if(nl != null) {
670             int len = nl.size();
671             for(int i = len; --i >= 0;) {
672                 Node node = (Node) nl.get(i);
673                 if(filter.accept(node)) {
674                     nl.remove(i);
675                 }
676             }
677         }
678     }
679     
680     public Node insertAfter(Node newChild, Node refChild) {
681         synchronized(this.treeLock) {
682             ArrayList nl = this.nodeList;
683             int idx = nl == null ? -1 : nl.indexOf(refChild);
684             if(idx == -1) {
685                 throw new DOMException(DOMException.NOT_FOUND_ERR, "refChild not found");
686             }
687             nl.add(idx+1, newChild);
688             if(newChild instanceof NodeImpl) {
689                 ((NodeImpl) newChild).setParentImpl(this);
690             }
691         }
692         if(!this.notificationsSuspended) {
693             this.informInvalid();
694         }
695         return newChild;
696     }
697
698     public Text replaceAdjacentTextNodes(Text node, String JavaDoc textContent) {
699         try {
700             synchronized(this.treeLock) {
701                 ArrayList nl = this.nodeList;
702                 if(nl == null) {
703                     throw new DOMException(DOMException.NOT_FOUND_ERR, "Node not a child");
704                 }
705                 int idx = nl.indexOf(node);
706                 if(idx == -1) {
707                     throw new DOMException(DOMException.NOT_FOUND_ERR, "Node not a child");
708                 }
709                 int firstIdx = idx;
710                 List toDelete = new LinkedList();
711                 for(int adjIdx = idx; --adjIdx >= 0;) {
712                     Object JavaDoc child = this.nodeList.get(adjIdx);
713                     if(child instanceof Text) {
714                         firstIdx = adjIdx;
715                         toDelete.add(child);
716                     }
717                 }
718                 int length = this.nodeList.size();
719                 for(int adjIdx = idx; ++adjIdx < length;) {
720                     Object JavaDoc child = this.nodeList.get(adjIdx);
721                     if(child instanceof Text) {
722                         toDelete.add(child);
723                     }
724                 }
725                 this.nodeList.removeAll(toDelete);
726                 TextImpl textNode = new TextImpl(textContent);
727                 textNode.setOwnerDocument(this.document);
728                 textNode.setParentImpl(this);
729                 this.nodeList.add(firstIdx, textNode);
730                 return textNode;
731             }
732         } finally {
733             if(!this.notificationsSuspended) {
734                 this.informInvalid();
735             }
736         }
737     }
738
739     public Text replaceAdjacentTextNodes(Text node) {
740         try {
741             synchronized(this.treeLock) {
742                 ArrayList nl = this.nodeList;
743                 if(nl == null) {
744                     throw new DOMException(DOMException.NOT_FOUND_ERR, "Node not a child");
745                 }
746                 int idx = nl.indexOf(node);
747                 if(idx == -1) {
748                     throw new DOMException(DOMException.NOT_FOUND_ERR, "Node not a child");
749                 }
750                 StringBuffer JavaDoc textBuffer = new StringBuffer JavaDoc();
751                 int firstIdx = idx;
752                 List toDelete = new LinkedList();
753                 for(int adjIdx = idx; --adjIdx >= 0;) {
754                     Object JavaDoc child = this.nodeList.get(adjIdx);
755                     if(child instanceof Text) {
756                         firstIdx = adjIdx;
757                         toDelete.add(child);
758                         textBuffer.append(((Text) child).getNodeValue());
759                     }
760                 }
761                 int length = this.nodeList.size();
762                 for(int adjIdx = idx; ++adjIdx < length;) {
763                     Object JavaDoc child = this.nodeList.get(adjIdx);
764                     if(child instanceof Text) {
765                         toDelete.add(child);
766                         textBuffer.append(((Text) child).getNodeValue());
767                     }
768                 }
769                 this.nodeList.removeAll(toDelete);
770                 TextImpl textNode = new TextImpl(textBuffer.toString());
771                 textNode.setOwnerDocument(this.document);
772                 textNode.setParentImpl(this);
773                 this.nodeList.add(firstIdx, textNode);
774                 return textNode;
775             }
776         } finally {
777             if(!this.notificationsSuspended) {
778                 this.informInvalid();
779             }
780         }
781     }
782         
783     protected volatile Node parentNode;
784     
785     public Node getParentNode() {
786         // Should it be synchronized? Could have side-effects.
787
return this.parentNode;
788     }
789     
790     public boolean isSameNode(Node other) {
791         return this == other;
792     }
793
794     public boolean isSupported(String JavaDoc feature, String JavaDoc version) {
795         return ("HTML".equals(feature) && version.compareTo("4.01") <= 0);
796     }
797
798     public String JavaDoc lookupNamespaceURI(String JavaDoc prefix) {
799         return null;
800     }
801
802     public boolean equalAttributes(Node arg) {
803         return false;
804     }
805     
806     public boolean isEqualNode(Node arg) {
807         return arg instanceof NodeImpl &&
808             this.getNodeType() == arg.getNodeType() &&
809             Objects.equals(this.getNodeName(), arg.getNodeName()) &&
810             Objects.equals(this.getNodeValue(), arg.getNodeValue()) &&
811             Objects.equals(this.getLocalName(), arg.getLocalName()) &&
812             Objects.equals(this.nodeList, ((NodeImpl) arg).nodeList) &&
813             this.equalAttributes(arg);
814     }
815
816     public boolean isDefaultNamespace(String JavaDoc namespaceURI) {
817         return namespaceURI == null;
818     }
819
820     public String JavaDoc lookupPrefix(String JavaDoc namespaceURI) {
821         return null;
822     }
823
824     public void normalize() {
825         synchronized(this.treeLock) {
826             ArrayList nl = this.nodeList;
827             if(nl != null) {
828                 Iterator i = nl.iterator();
829                 List textNodes = new LinkedList();
830                 boolean prevText = false;
831                 while(i.hasNext()) {
832                     Node child = (Node) i.next();
833                     if(child.getNodeType() == Node.TEXT_NODE) {
834                         if(!prevText) {
835                             prevText = true;
836                             textNodes.add(child);
837                         }
838                     }
839                     else {
840                         prevText = false;
841                     }
842                 }
843                 i = textNodes.iterator();
844                 while(i.hasNext()) {
845                     Text text = (Text) i.next();
846                     this.replaceAdjacentTextNodes(text);
847                 }
848             }
849         }
850         if(!this.notificationsSuspended) {
851             this.informInvalid();
852         }
853     }
854     
855     public String JavaDoc toString() {
856         return this.getNodeName();
857     }
858     
859     public UserAgentContext getUserAgentContext() {
860         Object JavaDoc doc = this.document;
861         if(doc instanceof HTMLDocumentImpl) {
862             return ((HTMLDocumentImpl) doc).getUserAgentContext();
863         }
864         else {
865             return null;
866         }
867     }
868     
869     public HtmlRendererContext getHtmlRendererContext() {
870         Object JavaDoc doc = this.document;
871         if(doc instanceof HTMLDocumentImpl) {
872             return ((HTMLDocumentImpl) doc).getHtmlRendererContext();
873         }
874         else {
875             return null;
876         }
877     }
878
879     final void setParentImpl(Node parent) {
880         // Call holding treeLock.
881
this.parentNode = parent;
882     }
883     
884     //----- ModelNode implementation
885

886     /* (non-Javadoc)
887      * @see org.xamjwg.html.renderer.RenderableContext#getAlignmentX()
888      */

889     public float getAlignmentX() {
890         //TODO: Removable method?
891
return 0.5f;
892     }
893
894     /* (non-Javadoc)
895      * @see org.xamjwg.html.renderer.RenderableContext#getAlignmentY()
896      */

897     public float getAlignmentY() {
898         return 0.5f;
899     }
900
901     /* (non-Javadoc)
902      * @see org.xamjwg.html.renderer.RenderableContext#getFullURL(java.lang.String)
903      */

904     public URL JavaDoc getFullURL(String JavaDoc spec) throws MalformedURLException JavaDoc {
905         Object JavaDoc doc = this.document;
906         if(doc instanceof HTMLDocumentImpl) {
907             return ((HTMLDocumentImpl) doc).getFullURL(spec);
908         }
909         else {
910             return new java.net.URL JavaDoc(spec);
911         }
912     }
913     
914     public URL JavaDoc getDocumentURL() {
915         Object JavaDoc doc = this.document;
916         if(doc instanceof HTMLDocumentImpl) {
917             return ((HTMLDocumentImpl) doc).getDocumentURL();
918         }
919         else {
920             return null;
921         }
922     }
923     
924     /* (non-Javadoc)
925      * @see org.xamjwg.html.renderer.RenderableContext#getDocumentItem(java.lang.String)
926      */

927     public Object JavaDoc getDocumentItem(String JavaDoc name) {
928         org.w3c.dom.Document JavaDoc document = this.document;
929         return document == null ? null : document.getUserData(name);
930     }
931     
932     /* (non-Javadoc)
933      * @see org.xamjwg.html.renderer.RenderableContext#setDocumentItem(java.lang.String, java.lang.Object)
934      */

935     public void setDocumentItem(String JavaDoc name, Object JavaDoc value) {
936         org.w3c.dom.Document JavaDoc document = this.document;
937         if(document == null) {
938             return;
939         }
940         document.setUserData(name, value, null);
941     }
942
943     /* (non-Javadoc)
944      * @see org.xamjwg.html.renderer.RenderableContext#isEqualOrDescendentOf(org.xamjwg.html.renderer.RenderableContext)
945      */

946     public final boolean isEqualOrDescendentOf(ModelNode otherContext) {
947         if(otherContext == this) {
948             return true;
949         }
950         Object JavaDoc parent = this.getParentNode();
951         if(parent instanceof HTMLElementImpl) {
952             return ((HTMLElementImpl) parent).isEqualOrDescendentOf(otherContext);
953         }
954         else {
955             return false;
956         }
957     }
958     
959     public final ModelNode getParentModelNode() {
960         return (ModelNode) this.parentNode;
961     }
962
963     public void warn(String JavaDoc message, Throwable JavaDoc err) {
964         logger.log(Level.WARNING, message, err);
965     }
966     
967     public void warn(String JavaDoc message) {
968         logger.log(Level.WARNING, message);
969     }
970
971     public void informSizeInvalid() {
972         HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
973         if(doc != null) {
974             doc.sizeInvalidated(this);
975         }
976     }
977     
978     public void informLookInvalid() {
979         this.forgetRenderState();
980         HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
981         if(doc != null) {
982             doc.lookInvalidated(this);
983         }
984     }
985     
986     public void informPositionInvalid() {
987         HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
988         if(doc != null) {
989             doc.positionInParentInvalidated(this);
990         }
991     }
992     
993     public void informInvalid() {
994         // This is called when an attribute or child changes.
995
this.forgetRenderState();
996         HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
997         if(doc != null) {
998             doc.invalidated(this);
999         }
1000    }
1001    
1002    protected void informNodeLoaded() {
1003        // This is called when an attribute or child changes.
1004
this.forgetRenderState();
1005        HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
1006        if(doc != null) {
1007            doc.nodeLoaded(this);
1008        }
1009    }
1010
1011    protected void informExternalScriptLoading() {
1012        // This is called when an attribute or child changes.
1013
this.forgetRenderState();
1014        HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
1015        if(doc != null) {
1016            doc.externalScriptLoading(this);
1017        }
1018    }
1019
1020    public void informLayoutInvalid() {
1021        // This is called by the style properties object.
1022
this.forgetRenderState();
1023        HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document;
1024        if(doc != null) {
1025            doc.invalidated(this);
1026        }
1027    }
1028
1029    private RenderState renderState = INVALID_RENDER_STATE;
1030    
1031    public RenderState getRenderState() {
1032        // Generally called from the GUI thread, except for
1033
// offset properties.
1034
RenderState rs;
1035        synchronized(this.treeLock) {
1036            rs = this.renderState;
1037            if(rs != INVALID_RENDER_STATE) {
1038                return rs;
1039            }
1040            Object JavaDoc parent = this.parentNode;
1041            if(parent != null || this instanceof Document) {
1042                RenderState prs = this.getParentRenderState(parent);
1043                rs = this.createRenderState(prs);
1044                this.renderState = rs;
1045                return rs;
1046            }
1047            else {
1048                // Return null without caching.
1049
// Scenario is possible due to Javascript.
1050
return null;
1051            }
1052        }
1053    }
1054
1055    protected final RenderState getParentRenderState(Object JavaDoc parent) {
1056        if(parent instanceof NodeImpl) {
1057            return ((NodeImpl) parent).getRenderState();
1058        }
1059        else {
1060            return null;
1061        }
1062    }
1063    
1064    protected RenderState createRenderState(RenderState prevRenderState) {
1065        return prevRenderState;
1066    }
1067    
1068    protected void forgetRenderState() {
1069        synchronized(this.treeLock) {
1070            if(this.renderState != INVALID_RENDER_STATE) {
1071                this.renderState = INVALID_RENDER_STATE;
1072                // Note that getRenderState() "validates"
1073
// ancestor states as well.
1074
java.util.ArrayList JavaDoc nl = this.nodeList;
1075                if(nl != null) {
1076                    Iterator i = nl.iterator();
1077                    while(i.hasNext()) {
1078                        ((NodeImpl) i.next()).forgetRenderState();
1079                    }
1080                }
1081            }
1082        }
1083    }
1084
1085}
1086
Popular Tags