1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.xml.dom;
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.DOMException;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Node;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.w3c.dom.Text;
22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Provides a straightforward implementation of the corresponding W3C DOM
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * interface. The class is used internally only, thus only notable members that
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * are not in the original interface are documented (the W3C docs are quite
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * extensive). Hope that's ok.
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * <p>
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Some of the fields may have package visibility, so other classes belonging to
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the DOM implementation can easily access them while maintaining the DOM tree
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * structure.
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class TextImpl extends CharacterDataImpl implements Text {
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
35bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    public TextImpl(DocumentImpl document, String data) {
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(document, data);
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getNodeName() {
41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return "#text";
42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public short getNodeType() {
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return Node.TEXT_NODE;
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
49bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    public final Text splitText(int offset) throws DOMException {
508b2f7a2b953a0ae4f01f7632fab2f29fe4d14a64Jesse Wilson        Text newText = document.createTextNode(
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                substringData(offset, getLength() - offset));
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        deleteData(0, offset);
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Node refNode = getNextSibling();
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (refNode == null) {
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            getParentNode().appendChild(newText);
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            getParentNode().insertBefore(newText, refNode);
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
64bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    public final boolean isElementContentWhitespace() {
65bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // Undefined because we don't validate. Whether whitespace characters
66bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // constitute "element content whitespace" is defined by the containing
67bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // element's declaration (DTD) and we don't parse that.
68bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // TODO: wire this up when we support document validation
69bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        return false;
70320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
72bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    public final String getWholeText() {
73bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // TODO: support entity references. This code should expand through
74bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // the child elements of entity references.
75bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        //     http://code.google.com/p/android/issues/detail?id=6807
76bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
77bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        StringBuilder result = new StringBuilder();
78bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        for (TextImpl n = firstTextNodeInCurrentRun(); n != null; n = n.nextTextNode()) {
79bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            n.appendDataTo(result);
80bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        }
81bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        return result.toString();
82320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
83320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
84bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    public final Text replaceWholeText(String content) throws DOMException {
85bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // TODO: support entity references. This code should expand and replace
86bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // the child elements of entity references.
87bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        //     http://code.google.com/p/android/issues/detail?id=6807
88bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
89bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        Node parent = getParentNode();
90bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        Text result = null;
91bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
92bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        // delete all nodes in the current run of text...
93bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        for (TextImpl n = firstTextNodeInCurrentRun(); n != null; ) {
94bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
95bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            // ...except the current node if we have content for it
96bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            if (n == this && content != null && content.length() > 0) {
97bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                setData(content);
98bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                result = this;
99bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                n = n.nextTextNode();
100bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
101bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            } else {
102bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                Node toRemove = n; // because removeChild() detaches siblings
103bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                n = n.nextTextNode();
104bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                parent.removeChild(toRemove);
105bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            }
106bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        }
107bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
108bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        return result;
109bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    }
110bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
111bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    /**
112bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     * Returns the first text or CDATA node in the current sequence of text and
113bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     * CDATA nodes.
114bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     */
115bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    private TextImpl firstTextNodeInCurrentRun() {
116bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        TextImpl firstTextInCurrentRun = this;
117bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        for (Node p = getPreviousSibling(); p != null; p = p.getPreviousSibling()) {
118bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            short nodeType = p.getNodeType();
119bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            if (nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE) {
120bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                firstTextInCurrentRun = (TextImpl) p;
121bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            } else {
122bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                break;
123bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            }
124bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        }
125bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        return firstTextInCurrentRun;
126bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    }
127bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
128bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    /**
129bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     * Returns the next sibling node if it exists and it is text or CDATA.
130bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     * Otherwise returns null.
131bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson     */
132bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson    private TextImpl nextTextNode() {
133bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        Node nextSibling = getNextSibling();
134bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        if (nextSibling == null) {
135bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson            return null;
136bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        }
137bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson
138bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        short nodeType = nextSibling.getNodeType();
139bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson        return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE
140bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                ? (TextImpl) nextSibling
141bda224da00c0372a7752b1304aeda98e2930c4afJesse Wilson                : null;
142320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
1438092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
1448092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    /**
1458092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * Tries to remove this node using itself and the previous node as context.
1468092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * If this node's text is empty, this node is removed and null is returned.
1478092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * If the previous node exists and is a text node, this node's text will be
1488092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * appended to that node's text and this node will be removed.
1498092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     *
1508092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * <p>Although this method alters the structure of the DOM tree, it does
1518092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * not alter the document's semantics.
1528092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     *
1538092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     * @return the node holding this node's text and the end of the operation.
1548092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     *     Can be null if this node contained the empty string.
1558092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson     */
1568092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    public final TextImpl minimize() {
1578092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        if (getLength() == 0) {
1588092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            parent.removeChild(this);
1598092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            return null;
1608092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
1618092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
1628092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        Node previous = getPreviousSibling();
1638092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        if (previous == null || previous.getNodeType() != Node.TEXT_NODE) {
1648092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson            return this;
1658092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        }
1668092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson
1678092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        TextImpl previousText = (TextImpl) previous;
1688092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        previousText.buffer.append(buffer);
1698092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        parent.removeChild(this);
1708092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson        return previousText;
1718092253eb6a1cff91f0e4953f1387165169157b5Jesse Wilson    }
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
173