com.cladonia.xml.viewer.XmlElementNode.java Source code

Java tutorial

Introduction

Here is the source code for com.cladonia.xml.viewer.XmlElementNode.java

Source

/*
 * $Id: XmlElementNode.java,v 1.6 2004/09/09 15:53:48 knesbitt Exp $
 *
 * The contents of this file are subject to the Mozilla Public License 
 * Version 1.1 (the "License"); you may not use this file except in 
 * compliance with the License. You may obtain a copy of the License at 
 * http://www.mozilla.org/MPL/ 
 *
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the License.
 *
 * The Original Code is eXchaNGeR browser code. (org.xngr.browser.*)
 *
 * The Initial Developer of the Original Code is Cladonia Ltd.. Portions created 
 * by the Initial Developer are Copyright (C) 2002 the Initial Developer. 
 * All Rights Reserved. 
 *
 * Contributor(s): Dogsbay
 */
package com.cladonia.xml.viewer;

import java.awt.Color;
import java.awt.Font;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.swing.tree.DefaultMutableTreeNode;

import org.dom4j.Attribute;
import org.dom4j.CDATA;
import org.dom4j.Comment;
import org.dom4j.Element;
import org.dom4j.Entity;
import org.dom4j.Namespace;
import org.dom4j.Node;
import org.dom4j.ProcessingInstruction;
import org.dom4j.Text;

import com.cladonia.xml.XElement;
import com.cladonia.xngreditor.properties.TextPreferences;

/**
 * The node for the XML tree, containing an XML element.
 *
 * @version   $Revision: 1.6 $, $Date: 2004/09/09 15:53:48 $
 * @author Dogsbay
 */
public class XmlElementNode extends DefaultMutableTreeNode {
    private static final int MAX_LINE_LENGTH = 80;
    private XElement element = null;
    private static Viewer _viewer = null;
    private Line[] lines = null;
    private static final String XNGR_DUMMY_ROOT = "xngr_dummy_element";

    private boolean isEndTag = false;

    /**
     * Constructs the node for the XML element.
     *
     * @param element the XML element.
     */
    public XmlElementNode(Viewer viewer, XElement element) {
        this(viewer, element, false);
    }

    /**
     * Constructs the the XML element node.
     *
     * @param element the XML element.
     */
    public XmlElementNode(Viewer viewer, XElement element, boolean end) {
        this.element = element;
        _viewer = viewer;

        isEndTag = end;

        if (!isEndTag()) {
            if (!isMixed2(element) || !_viewer.showInline()) {
                for (int i = 0; i < element.nodeCount(); i++) {
                    Node node = element.node(i);

                    if (node instanceof XElement) {
                        add(new XmlElementNode(_viewer, (XElement) node));
                    } else if ((node instanceof Comment) && _viewer.showComments()) {
                        add(new XmlCommentNode(_viewer, (Comment) node));
                    } else if ((node instanceof ProcessingInstruction) && _viewer.showPI()) {
                        add(new XmlProcessingInstructionNode(_viewer, (ProcessingInstruction) node));
                    } else if ((node instanceof CDATA) && _viewer.showValues()) {
                        add(new XmlCDATANode(_viewer, (CDATA) node));
                    } else if ((node instanceof Text) && _viewer.showValues()) {
                        if (!isWhiteSpace(node)) {
                            if (!hasTextOnly((XElement) node.getParent())) {
                                add(new XmlTextNode(_viewer, (Text) node));
                            }
                        }
                    }
                }

                // check to see if we need to add end element
                if (!hasTextOnly(element) && element.hasContent() && !element.getName().equals(XNGR_DUMMY_ROOT)) {
                    add(new XmlElementNode(_viewer, element, true));
                }
            }
        }

        format();
    }

    /**
     * Constructs the the XML element node.
     *
     * @param the XML comment element.
     */
    public XmlElementNode(Viewer viewer) {
        _viewer = viewer;
    }

    public boolean isEndTag() {
        return isEndTag;
    }

    public void update() {
        for (int i = 0; i < getChildCount(); i++) {
            XmlElementNode node = (XmlElementNode) getChildAt(i);
            node.update();
        }

        format();
    }

    /**
     * Returns the formatted lines for this element.
     *
     * @return the formatted Lines.
     */
    public Line[] getLines() {
        return lines;
    }

    /**
     * Returns the viewer.
     *
     * @return the viewer.
     */
    public Viewer getViewer() {
        return _viewer;
    }

    /**
     * Constructs the node for the XML element.
     *
     * @param element the XML element.
     */
    public XElement getElement() {
        return element;
    }

    private void format() {
        Vector lines = new Vector();
        Line current = new Line();
        lines.add(current);

        if (isEndTag()) {
            current = parseEndTag(lines, current, element);
        } else {
            current = parseElement(lines, current, element);
        }

        this.lines = new Line[lines.size()];

        for (int i = 0; i < lines.size(); i++) {
            this.lines[i] = (Line) lines.elementAt(i);
        }
    }

    protected Line parseElement(Vector lines, Line current, XElement elem) {

        if (isMixed2(element) && _viewer.showInline()) {
            current = parseMixedElement2(lines, current, elem);

            // decide if we need to display the end tag
            if (requiresEndTag(elem)) {
                current = parseEndTag(lines, current, elem);
            }
        } else {
            current = parseStartTag(lines, current, elem);

            if (_viewer.showValues()) {
                if (hasTextOnly(elem)) {
                    current = parseContent(lines, current, getContent(elem));
                    current = parseEndTag(lines, current, elem);
                }
            }
        }

        return current;
    }

    private String getContent(XElement elem) {
        Iterator iterator = elem.nodeIterator();
        StringBuffer buf = new StringBuffer();

        while (iterator.hasNext()) {
            Node node = (Node) iterator.next();
            if (node instanceof Text) {
                buf.append(node.asXML());
            }
        }

        return buf.toString().trim();
    }

    //    Elements parsed here can be both mixed and normal but then contained in a mixed element...
    protected Line parseMixedElement2(Vector lines, Line current, XElement elem) {

        current = parseStartTag(lines, current, elem);

        if (isMixed2(elem)) {

            int previousText = 0;

            for (int i = 0; i < elem.nodeCount(); i++) {
                Node node = elem.node(i);

                if (node instanceof XElement) {
                    previousText = 0;

                    current = parseMixedElement2(lines, current, (XElement) node);
                    XElement ele = (XElement) node;
                    if (isMixed2(ele)) {
                        if (requiresEndTag(ele)) {
                            current = parseEndTag(lines, current, (XElement) node);
                        }
                    }
                } else if ((node instanceof Text) || (node instanceof Entity)) {
                    if (_viewer.showValues() && !isWhiteSpace(node)) {
                        String text = node.getText().trim();

                        if (!"".equals(text)) {
                            if (previousText == 1) {
                                text = " " + text;
                            }
                            previousText = 1;
                        }

                        current = parseContent(lines, current, text);
                    }
                } else if ((node instanceof Comment) && _viewer.showComments()) {
                    previousText = 0;
                    current = parseComment(lines, current, (Comment) node);
                } else if ((node instanceof CDATA) && _viewer.showValues()) {
                    previousText = 0;
                    current = parseCDATA(lines, current, (CDATA) node);
                } else if ((node instanceof ProcessingInstruction) && _viewer.showPI()) {
                    previousText = 0;
                    current = parseProcessingInstruction(lines, current, (ProcessingInstruction) node);
                }
            }
        } else {
            List elements = (List) elem.elements();

            if (elements != null && elements.size() > 0) {
                Iterator iterator = elements.iterator();

                while (iterator.hasNext()) {
                    current = parseMixedElement2(lines, current, (XElement) iterator.next());
                }
                current = parseEndTag(lines, current, elem);
            } else if (elem.hasContent()) {
                if (_viewer.showValues()) {
                    current = parseContent(lines, current, elem.getText());
                    if (requiresEndTag(elem)) {
                        current = parseEndTag(lines, current, elem);
                    }
                }
            }
        }

        return current;
    }

    // Elements parsed here can be both mixed and normal but then contained in a mixed element...
    protected Line parseMixedElement(Vector lines, Line current, XElement elem) {

        current = parseStartTag(lines, current, elem);

        if (_viewer.showValues()) {
            if (isMixed(elem)) {
                for (int i = 0; i < elem.nodeCount(); i++) {
                    Node node = elem.node(i);

                    if (node instanceof XElement) {
                        current = parseMixedElement(lines, current, (XElement) node);
                    } else if ((node instanceof Text) || (node instanceof Entity)) {
                        String text = node.getText();
                        current = parseContent(lines, current, text);
                    } else if ((node instanceof Comment) && _viewer.showComments()) {
                        current = parseComment(lines, current, (Comment) node);
                    }
                }
            } else {
                List elements = (List) elem.elements();

                if (elements != null && elements.size() > 0) {
                    Iterator iterator = elements.iterator();

                    while (iterator.hasNext()) {
                        current = parseMixedElement(lines, current, (XElement) iterator.next());
                    }

                    current = parseEndTag(lines, current, elem);
                } else if (elem.hasContent()) {
                    current = parseContent(lines, current, elem.getText());
                    current = parseEndTag(lines, current, elem);
                }
            }
        }

        return current;
    }

    protected Line parseComment(Vector lines, Line current, Comment comment) {
        StyledElement styledElement = new StyledElement();
        styledElement.addString(COMMENT_START);

        current.addStyledElement(styledElement);
        current = parseCommentContent(lines, current, comment.getText());

        styledElement = new StyledElement();
        styledElement.addString(COMMENT_END);
        current.addStyledElement(styledElement);

        return current;
    }

    protected Line parseProcessingInstruction(Vector lines, Line current, ProcessingInstruction pi) {
        StyledElement styledElement = new StyledElement();
        styledElement.addString(PI_START);

        current.addStyledElement(styledElement);
        current = parseProcessingInstructionContent(lines, current, pi);

        styledElement = new StyledElement();
        styledElement.addString(PI_END);
        current.addStyledElement(styledElement);

        return current;
    }

    protected Line parseCDATA(Vector lines, Line current, CDATA cdata) {
        StyledElement styledElement = new StyledElement();
        styledElement.addString(new CDATA_SECTION(cdata.asXML()));
        current.addStyledElement(styledElement);
        return current;
    }

    protected Line parseTextNode(Vector lines, Line current, Text textNode) {
        current = parseContent(lines, current, textNode.asXML().trim());
        return current;
    }

    // Create a styled version of the start-tag.
    protected Line parseStartTag(Vector lines, Line current, XElement elem) {
        StyledElement styledElement = new StyledElement();
        styledElement.addString(OPEN_BRACKET);

        if (_viewer.showNamespaces()) {
            String prefix = elem.getNamespacePrefix();

            if (prefix != null && prefix.length() > 0) {
                styledElement.addString(new ElementPrefix(prefix));
                styledElement.addString(ELEMENT_COLON);
            }
        }

        styledElement.addString(new ElementName(elem.getName()));
        current.addStyledElement(styledElement);

        if (_viewer.showNamespaces()) {
            Namespace ns = elem.getNamespace();

            if (ns != null) {
                XElement parent = (XElement) elem.getParent();

                if (parent != null) {
                    Namespace prev = parent.getNamespaceForPrefix(ns.getPrefix());

                    if (prev == null || !ns.equals(prev)) {
                        StyledElement sns = formatNamespace(ns);

                        if (sns != null) {
                            if (current.length() + sns.length() + 1 > MAX_LINE_LENGTH) {
                                current = new Line();
                                lines.add(current);
                                current.addStyledString(TAB);
                            } else {
                                current.addStyledString(SPACE);
                            }

                            current.addStyledElement(sns);
                        }
                    }
                } else {
                    StyledElement sns = formatNamespace(ns);

                    if (sns != null) {
                        if (current.length() + sns.length() + 1 > MAX_LINE_LENGTH) {
                            current = new Line();
                            lines.add(current);
                            current.addStyledString(TAB);
                        } else {
                            current.addStyledString(SPACE);
                        }

                        current.addStyledElement(sns);
                    }
                }
            }

            List namespaces = elem.additionalNamespaces();

            if (namespaces != null && namespaces.size() > 0) {
                Iterator iterator = namespaces.iterator();

                for (int i = 0; i < namespaces.size(); i++) {
                    StyledElement sns = formatNamespace((Namespace) iterator.next());

                    if (sns != null) {
                        if (current.length() + sns.length() + 1 > MAX_LINE_LENGTH) {
                            current = new Line();
                            lines.add(current);
                            current.addStyledString(TAB);
                        } else {
                            current.addStyledString(SPACE);
                        }

                        current.addStyledElement(sns);
                    }
                }
            }
        }

        if (_viewer.showAttributes()) {
            List attributes = elem.attributes();

            if (attributes != null && attributes.size() > 0) {
                Iterator iterator = attributes.iterator();

                for (int i = 0; i < attributes.size(); i++) {
                    StyledElement sa = formatAttribute((Attribute) iterator.next());

                    if (current.length() + sa.length() + 1 > MAX_LINE_LENGTH) {
                        current = new Line();
                        lines.add(current);
                        current.addStyledString(TAB);
                    } else {
                        current.addStyledString(SPACE);
                    }

                    current.addStyledElement(sa);
                }
            }
        }

        if (!elem.hasContent()) {
            current.addStyledString(SLASH);
        } else if (hasTextOnly(elem) && !_viewer.showValues()) {
            current.addStyledString(SLASH);
        } else if (!requiresEndTag(elem) && _viewer.showInline()) {
            current.addStyledString(SLASH);
        }

        //      else if (_viewer.showInline())
        //      {
        //         if (!_viewer.showValues())
        //         {
        //            if ( hasTextOrCDATAOnly(elem))
        //            {
        //               current.addStyledString( SLASH);
        //            }
        //            else if (hasComment(elem) && !_viewer.showComments() && !hasProcessingInstruction(elem) 
        //                  && !hasEntity(elem))
        //            {
        //               current.addStyledString( SLASH);
        //            }
        //            else if (hasProcessingInstruction(elem) && !_viewer.showPI() && !hasComment(elem) 
        //                  && !hasEntity(elem))
        //            {
        //               current.addStyledString( SLASH);
        //            }
        //            else if (hasComment(elem) && hasProcessingInstruction(elem) && !_viewer.showComments() 
        //                  && !hasProcessingInstruction(elem) && !hasEntity(elem))
        //            {
        //               current.addStyledString( SLASH);
        //            }
        //         }
        //         else
        //         {
        //            if (!hasTextOrCDATA(elem))
        //            {
        //               if (hasComment(elem) && !_viewer.showComments() && !hasProcessingInstruction(elem) 
        //                     && !hasEntity(elem))
        //               {
        //                  current.addStyledString( SLASH);
        //               }
        //               else if (hasProcessingInstruction(elem) && !_viewer.showPI() && !hasComment(elem) 
        //                     && !hasEntity(elem))
        //               {
        //                  current.addStyledString( SLASH);
        //               }
        //               else if (hasComment(elem) && hasProcessingInstruction(elem) && !_viewer.showComments() 
        //                     && !hasProcessingInstruction(elem) && !hasEntity(elem))
        //               {
        //                  current.addStyledString( SLASH);
        //               }
        //            }
        //         }
        //      }

        current.addStyledString(CLOSE_BRACKET);

        return current;
    }

    private boolean requiresEndTag(XElement elem) {
        if (elem.hasChildElements()) {
            return true;
        }

        if (!_viewer.showValues()) {
            if (hasTextOrCDATAOnly(elem)) {
                return false;
            } else if (hasComment(elem) && !_viewer.showComments() && !hasProcessingInstruction(elem)
                    && !hasEntity(elem)) {
                return false;
            } else if (hasProcessingInstruction(elem) && !_viewer.showPI() && !hasComment(elem)
                    && !hasEntity(elem)) {
                return false;
            } else if (hasComment(elem) && hasProcessingInstruction(elem) && !_viewer.showComments()
                    && !_viewer.showPI() && !hasEntity(elem)) {
                return false;
            }
        } else {
            if (!hasTextOrCDATA(elem)) {
                if (hasComment(elem) && !_viewer.showComments() && !hasProcessingInstruction(elem)
                        && !hasEntity(elem)) {
                    return false;
                } else if (hasProcessingInstruction(elem) && !_viewer.showPI() && !hasComment(elem)
                        && !hasEntity(elem)) {
                    return false;
                } else if (hasComment(elem) && hasProcessingInstruction(elem) && !_viewer.showComments()
                        && !_viewer.showPI() && !hasEntity(elem)) {
                    return false;
                }
            }
        }

        return true;
    }

    // Create a styled version of the element content.
    protected Line parseContent(Vector lines, Line current, String text) {

        if ((current.length() + 1 >= MAX_LINE_LENGTH) && (text.length() > 0)) {
            current = new Line();
            lines.add(current);
            current.addStyledString(TAB);
        }

        if (text.length() > 0) {
            boolean parsed = false;

            while (!parsed) {
                int length = MAX_LINE_LENGTH - (current.length() + 1);

                if (length > text.length()) {
                    int index = 0;

                    if (text.indexOf("\n") != -1) {
                        index = text.indexOf("\n");
                    } else if (text.indexOf("\r") != -1) {
                        index = text.indexOf("\r");
                    } else {
                        index = text.length();
                    }

                    if (index != 0) {
                        String string = text.substring(0, index);
                        current.addStyledString(new ElementValue(string));
                    }

                    if (index == text.length()) {
                        parsed = true;
                    } else {
                        text = text.substring(index + 1, text.length());
                    }
                } else {
                    int index = 0;
                    String sub = text.substring(0, length);

                    if (sub.indexOf("\n") != -1) {
                        index = sub.indexOf("\n");
                    } else if (sub.indexOf("\r") != -1) {
                        index = sub.indexOf("\r");
                    } else if (sub.lastIndexOf(" ") != -1) {
                        index = sub.lastIndexOf(" ");
                    }

                    if (index != 0) {
                        String string = sub.substring(0, index);
                        current.addStyledString(new ElementValue(string));

                        text = text.substring(index + 1, text.length());
                    } else { // Text is too long without any whitespaces...
                        int nlindex = text.indexOf("\n");
                        int rindex = text.indexOf("\r");
                        int spindex = sub.indexOf(" ");

                        if (nlindex == -1) {
                            nlindex = Integer.MAX_VALUE;
                        }
                        if (rindex == -1) {
                            rindex = Integer.MAX_VALUE;
                        }
                        if (spindex == -1) {
                            spindex = Integer.MAX_VALUE;
                        }

                        index = Math.min(nlindex, rindex);
                        index = Math.min(index, spindex);
                        index = Math.min(index, text.length());

                        String string = text.substring(0, index);
                        current.addStyledString(new ElementValue(string));

                        if (index == text.length()) {
                            parsed = true;
                        } else {
                            text = text.substring(index + 1, text.length());
                        }
                    }
                }

                if (!parsed) {
                    current = new Line();
                    lines.add(current);
                    current.addStyledString(TAB);
                }
            }
        }

        return current;
    }

    protected Line parseProcessingInstructionContent(Vector lines, Line current, ProcessingInstruction pi) {
        String target = pi.getTarget();

        if ((current.length() + 1 >= MAX_LINE_LENGTH) && (target.length() > 0)) {
            current = new Line();
            lines.add(current);
            current.addStyledString(TAB);
        }

        if (target.length() > 0) {
            // get the PI Target
            current.addStyledString(new PI_Target(target));
        }

        String text = pi.getText();
        if (text.length() > 0) {
            // get the PI text
            current.addStyledString(SPACE);
            current.addStyledString(new PI_Text(text));
        }

        return current;
    }

    protected Line parseCommentContent(Vector lines, Line current, String text) {

        if ((current.length() + 1 >= MAX_LINE_LENGTH) && (text.length() > 0)) {
            current = new Line();
            lines.add(current);
            current.addStyledString(TAB);
        }

        if (text.length() > 0) {
            boolean parsed = false;

            while (!parsed) {
                int length = MAX_LINE_LENGTH - (current.length() + 1);

                if (length > text.length()) {
                    int index = 0;

                    if (text.indexOf("\n") != -1) {
                        index = text.indexOf("\n");
                    } else if (text.indexOf("\r") != -1) {
                        index = text.indexOf("\r");
                    } else {
                        index = text.length();
                    }

                    if (index != 0) {
                        String string = text.substring(0, index);
                        current.addStyledString(new CommentText(string));
                    }

                    if (index == text.length()) {
                        parsed = true;
                    } else {
                        text = text.substring(index + 1, text.length());
                    }
                } else {
                    int index = 0;
                    String sub = text.substring(0, length);

                    if (sub.indexOf("\n") != -1) {
                        index = sub.indexOf("\n");
                    } else if (sub.indexOf("\r") != -1) {
                        index = sub.indexOf("\r");
                    } else if (sub.lastIndexOf(" ") != -1) {
                        index = sub.lastIndexOf(" ");
                    }

                    if (index != 0) {
                        String string = sub.substring(0, index);
                        current.addStyledString(new CommentText(string));

                        text = text.substring(index + 1, text.length());
                    } else { // Text is too long without any whitespaces...
                        int nlindex = text.indexOf("\n");
                        int rindex = text.indexOf("\r");
                        int spindex = sub.indexOf(" ");

                        if (nlindex == -1) {
                            nlindex = Integer.MAX_VALUE;
                        }
                        if (rindex == -1) {
                            rindex = Integer.MAX_VALUE;
                        }
                        if (spindex == -1) {
                            spindex = Integer.MAX_VALUE;
                        }

                        index = Math.min(nlindex, rindex);
                        index = Math.min(index, spindex);
                        index = Math.min(index, text.length());

                        String string = text.substring(0, index);
                        current.addStyledString(new CommentText(string));

                        if (index == text.length()) {
                            parsed = true;
                        } else {
                            text = text.substring(index + 1, text.length());
                        }
                    }
                }

                if (!parsed) {
                    current = new Line();
                    lines.add(current);
                    current.addStyledString(TAB);
                }
            }
        }

        return current;
    }

    // Create a styled version of the end-tag.
    protected Line parseEndTag(Vector lines, Line current, Element elem) {

        StyledElement styledEnd = new StyledElement();
        styledEnd.addString(OPEN_BRACKET);
        styledEnd.addString(SLASH);

        if (_viewer.showNamespaces()) {
            String prefix = elem.getNamespacePrefix();

            if (prefix != null && prefix.length() > 0) {
                styledEnd.addString(new ElementPrefix(prefix));
                styledEnd.addString(ELEMENT_COLON);
            }
        }

        styledEnd.addString(new ElementName(elem.getName()));
        styledEnd.addString(CLOSE_BRACKET);
        current.addStyledElement(styledEnd);

        return current;
    }

    private StyledElement formatAttribute(Attribute a) {
        StyledElement styledAttribute = new StyledElement();

        String name = a.getName();
        String value = a.getValue();

        if (_viewer.showNamespaces()) {
            String prefix = a.getNamespacePrefix();

            if (prefix != null && prefix.length() > 0) {
                styledAttribute.addString(new AttributePrefix(prefix));
                styledAttribute.addString(ATTRIBUTE_COLON);
            }
        }

        styledAttribute.addString(new AttributeName(name));
        styledAttribute.addString(ATTRIBUTE_ASIGN);

        styledAttribute.addString(new AttributeValue(value));

        return styledAttribute;
    }

    private StyledElement formatNamespace(Namespace n) {
        StyledElement styledNamespace = null;

        String prefix = n.getPrefix();
        String value = n.getText();

        if (value != null && value.length() > 0) {
            styledNamespace = new StyledElement();
            styledNamespace.addString(NAMESPACE_NAME);

            if (prefix != null && prefix.length() > 0) {
                styledNamespace.addString(NAMESPACE_COLON);
                styledNamespace.addString(new NamespacePrefix(prefix));
            }

            styledNamespace.addString(NAMESPACE_ASIGN);
            styledNamespace.addString(new NamespaceURI(value));
        }

        return styledNamespace;
    }

    public class StyledElement {
        private Vector strings = null;

        public StyledElement() {
            strings = new Vector();
        }

        public void addString(StyledString string) {
            strings.addElement(string);
        }

        public int length() {
            int result = 0;

            for (int i = 0; i < strings.size(); i++) {
                result += ((StyledString) strings.elementAt(i)).getText().length();
            }

            return result;
        }

        public Vector getStrings() {
            return strings;
        }
    }

    public class Line {
        private Vector strings = null;

        public Line() {
            strings = new Vector();
        }

        public void addStyledString(StyledString string) {
            strings.add(string);
        }

        public void addStyledElement(StyledElement element) {
            Vector strings = element.getStrings();

            for (int i = 0; i < strings.size(); i++) {
                addStyledString((StyledString) strings.elementAt(i));
            }
        }

        public StyledString[] getStyledStrings() {
            StyledString[] ss = new StyledString[strings.size()];

            for (int i = 0; i < strings.size(); i++) {
                ss[i] = (StyledString) strings.elementAt(i);
            }

            return ss;
        }

        public int length() {
            int result = 0;

            for (int i = 0; i < strings.size(); i++) {
                result += ((StyledString) strings.elementAt(i)).getText().length();
            }

            return result;
        }

        public String getText() {
            String result = "";

            for (int i = 0; i < strings.size(); i++) {
                result += ((StyledString) strings.elementAt(i)).getText();
            }

            return result;
        }
    }

    // solves a problem in the Element that hasMixedContent returns true when the content 
    // has comment information.
    private static boolean isMixed(XElement element) {
        if (element.hasMixedContent()) {
            boolean elementFound = false;
            boolean textFound = false;

            for (int i = 0; i < element.nodeCount(); i++) {
                Node node = element.node(i);

                if (node instanceof XElement) {
                    elementFound = true;
                } else if ((node instanceof Text) || (node instanceof CDATA) || (node instanceof Entity)) {
                    if (!isWhiteSpace(node)) {
                        textFound = true;
                    }
                }

                if (textFound && elementFound) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Checks to see if the element has a combination of text and one of the other type nodes
     *
     * @param element the XML element.
     */
    private static boolean isMixed2(XElement element) {
        if (element.hasMixedContent()) {
            boolean elementFound = false;
            boolean otherFound = false;
            boolean textFound = false;

            for (int i = 0; i < element.nodeCount(); i++) {
                Node node = element.node(i);

                if ((node instanceof XElement) || (node instanceof CDATA) || (node instanceof Entity)
                        || (node instanceof Comment) || (node instanceof ProcessingInstruction)) {
                    otherFound = true;
                } else if ((node instanceof Text) || (node instanceof CDATA) || (node instanceof Entity)
                        || (node instanceof Comment) || (node instanceof ProcessingInstruction)) {
                    if (!isWhiteSpace(node)) {
                        textFound = true;
                    }
                }

                if (textFound && otherFound) {
                    return true;
                }
            }
        }

        return false;
    }

    // has text only, ie no other type node and not only whitespace
    private static boolean hasTextOnly(XElement element) {
        boolean textFound = false;

        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if ((node instanceof XElement) || (node instanceof CDATA) || (node instanceof Entity)
                    || (node instanceof Comment) || (node instanceof ProcessingInstruction)) {
                return false;
            } else if (node instanceof Text) {
                if (!isWhiteSpace(node)) {
                    textFound = true;
                }
            }
        }

        return textFound;
    }

    //    has text and\or cdata only, ie no other type node and not only whitespace
    private static boolean hasTextOrCDATAOnly(XElement element) {
        boolean textCDATAFound = false;

        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if ((node instanceof XElement) || (node instanceof Entity) || (node instanceof Comment)
                    || (node instanceof ProcessingInstruction)) {
                return false;
            } else if (node instanceof CDATA) {
                textCDATAFound = true;
            } else if (node instanceof Text) {
                if (!isWhiteSpace(node)) {
                    textCDATAFound = true;
                }
            }
        }

        return textCDATAFound;
    }

    //    has text and\or cdata 
    private static boolean hasTextOrCDATA(XElement element) {
        boolean textCDATAFound = false;

        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if (node instanceof CDATA) {
                textCDATAFound = true;
            } else if (node instanceof Text) {
                if (!isWhiteSpace(node)) {
                    textCDATAFound = true;
                }
            }
        }

        return textCDATAFound;
    }

    // returns true if the element contains a comment, 
    private static boolean hasComment(XElement element) {
        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if (node instanceof Comment) {
                return true;
            }
        }

        return false;
    }

    //returns true if the element contains a PI
    private static boolean hasProcessingInstruction(XElement element) {
        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if (node instanceof ProcessingInstruction) {
                return true;
            }
        }

        return false;
    }

    //   returns true if the element contains a PI
    private static boolean hasEntity(XElement element) {
        for (int i = 0; i < element.nodeCount(); i++) {
            Node node = element.node(i);

            if (node instanceof Entity) {
                return true;
            }
        }

        return false;
    }

    private static boolean isWhiteSpace(Node node) {
        return node.getText().trim().length() == 0;
    }

    private static final StyledString COMMENT_START = new ControlString("<!--");
    private static final StyledString COMMENT_END = new ControlString("-->");
    private static final StyledString PI_START = new ControlString("<?");
    private static final StyledString PI_END = new ControlString("?>");
    private static final StyledString SPACE = new ControlString(" ");
    private static final StyledString TAB = new ControlString("  ");
    private static final StyledString SLASH = new ControlString("/");
    private static final StyledString ATTRIBUTE_ASIGN = new ControlString("=");
    private static final StyledString ATTRIBUTE_COLON = new ControlString(":");
    private static final StyledString NAMESPACE_ASIGN = new ControlString("=");
    private static final StyledString NAMESPACE_COLON = new ControlString(":");
    private static final StyledString NAMESPACE_NAME = new NamespaceName();
    private static final StyledString ELEMENT_COLON = new ControlString(":");

    private static final StyledString OPEN_BRACKET = new ControlString("<");
    private static final StyledString CLOSE_BRACKET = new ControlString(">");

    public class CommentText extends StyledString {
        public CommentText(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.COMMENT).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.COMMENT).getFont();
        }
    }

    public class PI_Target extends StyledString {
        public PI_Target(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.PI_TARGET).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.PI_TARGET).getFont();
        }
    }

    public class PI_Text extends StyledString {
        public PI_Text(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.PI_NAME).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.PI_NAME).getFont();
        }
    }

    public class CDATA_SECTION extends StyledString {
        public CDATA_SECTION(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.CDATA).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.CDATA).getFont();
        }
    }

    public class ElementValue extends StyledString {
        public ElementValue(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_VALUE).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_VALUE).getFont();
        }
    }

    public class AttributeValue extends StyledString {
        public AttributeValue(String text) {
            super("\"" + text + "\"");
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_VALUE).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_VALUE).getFont();
        }
    }

    public class AttributePrefix extends StyledString {
        public AttributePrefix(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_PREFIX).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_PREFIX).getFont();
        }
    }

    public class AttributeName extends StyledString {
        public AttributeName(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_NAME).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ATTRIBUTE_NAME).getFont();
        }
    }

    public class NamespaceURI extends StyledString {
        public NamespaceURI(String text) {
            super("\"" + text + "\"");
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_VALUE).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_VALUE).getFont();
        }
    }

    public static class NamespaceName extends StyledString {
        public NamespaceName() {
            super("xmlns");
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_NAME).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_NAME).getFont();
        }
    }

    public static class ControlString extends StyledString {
        public ControlString(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.SPECIAL).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.SPECIAL).getFont();
        }
    }

    public class NamespacePrefix extends StyledString {
        public NamespacePrefix(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_PREFIX).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.NAMESPACE_PREFIX).getFont();
        }
    }

    public class ElementName extends StyledString {
        public ElementName(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_NAME).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_NAME).getFont();
        }
    }

    public class ElementPrefix extends StyledString {
        public ElementPrefix(String text) {
            super(text);
        }

        public Color getColor() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_PREFIX).getColor();
        }

        public Font getFont() {
            return TextPreferences.getFontType(TextPreferences.ELEMENT_PREFIX).getFont();
        }
    }

    public void cleanup() {
        Enumeration list = children();

        while (list.hasMoreElements()) {
            ((XmlElementNode) list.nextElement()).cleanup();
        }

        finalize();
    }

    protected void finalize() {
        element = null;
        _viewer = null;
        lines = null;
    }

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
}