Source Code Cross Referenced for HTMLWriter.java in  » 6.0-JDK-Core » swing » javax » swing » text » html » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » swing » javax.swing.text.html 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1998-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025        package javax.swing.text.html;
0026
0027        import javax.swing.text.*;
0028        import java.io.Writer;
0029        import java.util.Stack;
0030        import java.util.Enumeration;
0031        import java.util.Vector;
0032        import java.io.IOException;
0033        import java.util.StringTokenizer;
0034        import java.util.NoSuchElementException;
0035        import java.net.URL;
0036
0037        /**
0038         * This is a writer for HTMLDocuments.
0039         *
0040         * @author  Sunita Mani
0041         * @version 1.26, 02/02/00
0042         */
0043
0044        public class HTMLWriter extends AbstractWriter {
0045            /*
0046             * Stores all elements for which end tags have to
0047             * be emitted.
0048             */
0049            private Stack blockElementStack = new Stack();
0050            private boolean inContent = false;
0051            private boolean inPre = false;
0052            /** When inPre is true, this will indicate the end offset of the pre
0053             * element. */
0054            private int preEndOffset;
0055            private boolean inTextArea = false;
0056            private boolean newlineOutputed = false;
0057            private boolean completeDoc;
0058
0059            /*
0060             * Stores all embedded tags. Embedded tags are tags that are
0061             * stored as attributes in other tags. Generally they're
0062             * character level attributes.  Examples include
0063             * <b>, <i>, <font>, and <a>. 
0064             */
0065            private Vector tags = new Vector(10);
0066
0067            /**
0068             * Values for the tags.
0069             */
0070            private Vector tagValues = new Vector(10);
0071
0072            /**
0073             * Used when writing out content.
0074             */
0075            private Segment segment;
0076
0077            /*
0078             * This is used in closeOutUnwantedEmbeddedTags.
0079             */
0080            private Vector tagsToRemove = new Vector(10);
0081
0082            /**
0083             * Set to true after the head has been output.
0084             */
0085            private boolean wroteHead;
0086
0087            /**
0088             * Set to true when entities (such as <) should be replaced.
0089             */
0090            private boolean replaceEntities;
0091
0092            /**
0093             * Temporary buffer.
0094             */
0095            private char[] tempChars;
0096
0097            /**
0098             * Creates a new HTMLWriter.
0099             *
0100             * @param w   a Writer
0101             * @param doc  an HTMLDocument
0102             *
0103             */
0104            public HTMLWriter(Writer w, HTMLDocument doc) {
0105                this (w, doc, 0, doc.getLength());
0106            }
0107
0108            /**
0109             * Creates a new HTMLWriter.
0110             *
0111             * @param w  a Writer
0112             * @param doc an HTMLDocument
0113             * @param pos the document location from which to fetch the content
0114             * @param len the amount to write out
0115             */
0116            public HTMLWriter(Writer w, HTMLDocument doc, int pos, int len) {
0117                super (w, doc, pos, len);
0118                completeDoc = (pos == 0 && len == doc.getLength());
0119                setLineLength(80);
0120            }
0121
0122            /**
0123             * Iterates over the 
0124             * Element tree and controls the writing out of
0125             * all the tags and its attributes.
0126             *
0127             * @exception IOException on any I/O error
0128             * @exception BadLocationException if pos represents an invalid
0129             *            location within the document.
0130             *
0131             */
0132            public void write() throws IOException, BadLocationException {
0133                ElementIterator it = getElementIterator();
0134                Element current = null;
0135                Element next = null;
0136
0137                wroteHead = false;
0138                setCurrentLineLength(0);
0139                replaceEntities = false;
0140                setCanWrapLines(false);
0141                if (segment == null) {
0142                    segment = new Segment();
0143                }
0144                inPre = false;
0145                boolean forcedBody = false;
0146                while ((next = it.next()) != null) {
0147                    if (!inRange(next)) {
0148                        if (completeDoc
0149                                && next.getAttributes().getAttribute(
0150                                        StyleConstants.NameAttribute) == HTML.Tag.BODY) {
0151                            forcedBody = true;
0152                        } else {
0153                            continue;
0154                        }
0155                    }
0156                    if (current != null) {
0157
0158                        /*
0159                          if next is child of current increment indent
0160                         */
0161
0162                        if (indentNeedsIncrementing(current, next)) {
0163                            incrIndent();
0164                        } else if (current.getParentElement() != next
0165                                .getParentElement()) {
0166                            /*
0167                               next and current are not siblings
0168                               so emit end tags for items on the stack until the
0169                               item on top of the stack, is the parent of the
0170                               next.
0171                             */
0172                            Element top = (Element) blockElementStack.peek();
0173                            while (top != next.getParentElement()) {
0174                                /*
0175                                   pop() will return top.
0176                                 */
0177                                blockElementStack.pop();
0178                                if (!synthesizedElement(top)) {
0179                                    AttributeSet attrs = top.getAttributes();
0180                                    if (!matchNameAttribute(attrs, HTML.Tag.PRE)
0181                                            && !isFormElementWithContent(attrs)) {
0182                                        decrIndent();
0183                                    }
0184                                    endTag(top);
0185                                }
0186                                top = (Element) blockElementStack.peek();
0187                            }
0188                        } else if (current.getParentElement() == next
0189                                .getParentElement()) {
0190                            /*
0191                               if next and current are siblings the indent level
0192                               is correct.  But, we need to make sure that if current is
0193                               on the stack, we pop it off, and put out its end tag.
0194                             */
0195                            Element top = (Element) blockElementStack.peek();
0196                            if (top == current) {
0197                                blockElementStack.pop();
0198                                endTag(top);
0199                            }
0200                        }
0201                    }
0202                    if (!next.isLeaf()
0203                            || isFormElementWithContent(next.getAttributes())) {
0204                        blockElementStack.push(next);
0205                        startTag(next);
0206                    } else {
0207                        emptyTag(next);
0208                    }
0209                    current = next;
0210                }
0211                /* Emit all remaining end tags */
0212
0213                /* A null parameter ensures that all embedded tags
0214                   currently in the tags vector have their
0215                   corresponding end tags written out.
0216                 */
0217                closeOutUnwantedEmbeddedTags(null);
0218
0219                if (forcedBody) {
0220                    blockElementStack.pop();
0221                    endTag(current);
0222                }
0223                while (!blockElementStack.empty()) {
0224                    current = (Element) blockElementStack.pop();
0225                    if (!synthesizedElement(current)) {
0226                        AttributeSet attrs = current.getAttributes();
0227                        if (!matchNameAttribute(attrs, HTML.Tag.PRE)
0228                                && !isFormElementWithContent(attrs)) {
0229                            decrIndent();
0230                        }
0231                        endTag(current);
0232                    }
0233                }
0234
0235                if (completeDoc) {
0236                    writeAdditionalComments();
0237                }
0238
0239                segment.array = null;
0240            }
0241
0242            /**
0243             * Writes out the attribute set.  Ignores all
0244             * attributes with a key of type HTML.Tag,
0245             * attributes with a key of type StyleConstants,
0246             * and attributes with a key of type
0247             * HTML.Attribute.ENDTAG.
0248             *
0249             * @param attr   an AttributeSet
0250             * @exception IOException on any I/O error
0251             *
0252             */
0253            protected void writeAttributes(AttributeSet attr)
0254                    throws IOException {
0255                // translate css attributes to html
0256                convAttr.removeAttributes(convAttr);
0257                convertToHTML32(attr, convAttr);
0258
0259                Enumeration names = convAttr.getAttributeNames();
0260                while (names.hasMoreElements()) {
0261                    Object name = names.nextElement();
0262                    if (name instanceof  HTML.Tag
0263                            || name instanceof  StyleConstants
0264                            || name == HTML.Attribute.ENDTAG) {
0265                        continue;
0266                    }
0267                    write(" " + name + "=\"" + convAttr.getAttribute(name)
0268                            + "\"");
0269                }
0270            }
0271
0272            /**
0273             * Writes out all empty elements (all tags that have no
0274             * corresponding end tag).
0275             *
0276             * @param elem   an Element
0277             * @exception IOException on any I/O error
0278             * @exception BadLocationException if pos represents an invalid
0279             *            location within the document.
0280             */
0281            protected void emptyTag(Element elem) throws BadLocationException,
0282                    IOException {
0283
0284                if (!inContent && !inPre) {
0285                    indentSmart();
0286                }
0287
0288                AttributeSet attr = elem.getAttributes();
0289                closeOutUnwantedEmbeddedTags(attr);
0290                writeEmbeddedTags(attr);
0291
0292                if (matchNameAttribute(attr, HTML.Tag.CONTENT)) {
0293                    inContent = true;
0294                    text(elem);
0295                } else if (matchNameAttribute(attr, HTML.Tag.COMMENT)) {
0296                    comment(elem);
0297                } else {
0298                    boolean isBlock = isBlockTag(elem.getAttributes());
0299                    if (inContent && isBlock) {
0300                        writeLineSeparator();
0301                        indentSmart();
0302                    }
0303
0304                    Object nameTag = (attr != null) ? attr
0305                            .getAttribute(StyleConstants.NameAttribute) : null;
0306                    Object endTag = (attr != null) ? attr
0307                            .getAttribute(HTML.Attribute.ENDTAG) : null;
0308
0309                    boolean outputEndTag = false;
0310                    // If an instance of an UNKNOWN Tag, or an instance of a 
0311                    // tag that is only visible during editing
0312                    //
0313                    if (nameTag != null && endTag != null
0314                            && (endTag instanceof  String)
0315                            && ((String) endTag).equals("true")) {
0316                        outputEndTag = true;
0317                    }
0318
0319                    if (completeDoc && matchNameAttribute(attr, HTML.Tag.HEAD)) {
0320                        if (outputEndTag) {
0321                            // Write out any styles.
0322                            writeStyles(((HTMLDocument) getDocument())
0323                                    .getStyleSheet());
0324                        }
0325                        wroteHead = true;
0326                    }
0327
0328                    write('<');
0329                    if (outputEndTag) {
0330                        write('/');
0331                    }
0332                    write(elem.getName());
0333                    writeAttributes(attr);
0334                    write('>');
0335                    if (matchNameAttribute(attr, HTML.Tag.TITLE)
0336                            && !outputEndTag) {
0337                        Document doc = elem.getDocument();
0338                        String title = (String) doc
0339                                .getProperty(Document.TitleProperty);
0340                        write(title);
0341                    } else if (!inContent || isBlock) {
0342                        writeLineSeparator();
0343                        if (isBlock && inContent) {
0344                            indentSmart();
0345                        }
0346                    }
0347                }
0348            }
0349
0350            /**
0351             * Determines if the HTML.Tag associated with the
0352             * element is a block tag.
0353             *
0354             * @param attr  an AttributeSet
0355             * @return  true if tag is block tag, false otherwise.
0356             */
0357            protected boolean isBlockTag(AttributeSet attr) {
0358                Object o = attr.getAttribute(StyleConstants.NameAttribute);
0359                if (o instanceof  HTML.Tag) {
0360                    HTML.Tag name = (HTML.Tag) o;
0361                    return name.isBlock();
0362                }
0363                return false;
0364            }
0365
0366            /**
0367             * Writes out a start tag for the element.
0368             * Ignores all synthesized elements.
0369             *
0370             * @param elem   an Element
0371             * @exception IOException on any I/O error
0372             */
0373            protected void startTag(Element elem) throws IOException,
0374                    BadLocationException {
0375
0376                if (synthesizedElement(elem)) {
0377                    return;
0378                }
0379
0380                // Determine the name, as an HTML.Tag.
0381                AttributeSet attr = elem.getAttributes();
0382                Object nameAttribute = attr
0383                        .getAttribute(StyleConstants.NameAttribute);
0384                HTML.Tag name;
0385                if (nameAttribute instanceof  HTML.Tag) {
0386                    name = (HTML.Tag) nameAttribute;
0387                } else {
0388                    name = null;
0389                }
0390
0391                if (name == HTML.Tag.PRE) {
0392                    inPre = true;
0393                    preEndOffset = elem.getEndOffset();
0394                }
0395
0396                // write out end tags for item on stack
0397                closeOutUnwantedEmbeddedTags(attr);
0398
0399                if (inContent) {
0400                    writeLineSeparator();
0401                    inContent = false;
0402                    newlineOutputed = false;
0403                }
0404
0405                if (completeDoc && name == HTML.Tag.BODY && !wroteHead) {
0406                    // If the head has not been output, output it and the styles.
0407                    wroteHead = true;
0408                    indentSmart();
0409                    write("<head>");
0410                    writeLineSeparator();
0411                    incrIndent();
0412                    writeStyles(((HTMLDocument) getDocument()).getStyleSheet());
0413                    decrIndent();
0414                    writeLineSeparator();
0415                    indentSmart();
0416                    write("</head>");
0417                    writeLineSeparator();
0418                }
0419
0420                indentSmart();
0421                write('<');
0422                write(elem.getName());
0423                writeAttributes(attr);
0424                write('>');
0425                if (name != HTML.Tag.PRE) {
0426                    writeLineSeparator();
0427                }
0428
0429                if (name == HTML.Tag.TEXTAREA) {
0430                    textAreaContent(elem.getAttributes());
0431                } else if (name == HTML.Tag.SELECT) {
0432                    selectContent(elem.getAttributes());
0433                } else if (completeDoc && name == HTML.Tag.BODY) {
0434                    // Write out the maps, which is not stored as Elements in
0435                    // the Document.
0436                    writeMaps(((HTMLDocument) getDocument()).getMaps());
0437                } else if (name == HTML.Tag.HEAD) {
0438                    HTMLDocument document = (HTMLDocument) getDocument();
0439                    wroteHead = true;
0440                    incrIndent();
0441                    writeStyles(document.getStyleSheet());
0442                    if (document.hasBaseTag()) {
0443                        indentSmart();
0444                        write("<base href=\"" + document.getBase() + "\">");
0445                        writeLineSeparator();
0446                    }
0447                    decrIndent();
0448                }
0449
0450            }
0451
0452            /**
0453             * Writes out text that is contained in a TEXTAREA form
0454             * element.
0455             *
0456             * @param attr  an AttributeSet
0457             * @exception IOException on any I/O error
0458             * @exception BadLocationException if pos represents an invalid
0459             *            location within the document.
0460             */
0461            protected void textAreaContent(AttributeSet attr)
0462                    throws BadLocationException, IOException {
0463                Document doc = (Document) attr
0464                        .getAttribute(StyleConstants.ModelAttribute);
0465                if (doc != null && doc.getLength() > 0) {
0466                    if (segment == null) {
0467                        segment = new Segment();
0468                    }
0469                    doc.getText(0, doc.getLength(), segment);
0470                    if (segment.count > 0) {
0471                        inTextArea = true;
0472                        incrIndent();
0473                        indentSmart();
0474                        setCanWrapLines(true);
0475                        replaceEntities = true;
0476                        write(segment.array, segment.offset, segment.count);
0477                        replaceEntities = false;
0478                        setCanWrapLines(false);
0479                        writeLineSeparator();
0480                        inTextArea = false;
0481                        decrIndent();
0482                    }
0483                }
0484            }
0485
0486            /**
0487             * Writes out text.  If a range is specified when the constructor
0488             * is invoked, then only the appropriate range of text is written
0489             * out.
0490             *
0491             * @param elem   an Element
0492             * @exception IOException on any I/O error
0493             * @exception BadLocationException if pos represents an invalid
0494             *            location within the document.
0495             */
0496            protected void text(Element elem) throws BadLocationException,
0497                    IOException {
0498                int start = Math.max(getStartOffset(), elem.getStartOffset());
0499                int end = Math.min(getEndOffset(), elem.getEndOffset());
0500                if (start < end) {
0501                    if (segment == null) {
0502                        segment = new Segment();
0503                    }
0504                    getDocument().getText(start, end - start, segment);
0505                    newlineOutputed = false;
0506                    if (segment.count > 0) {
0507                        if (segment.array[segment.offset + segment.count - 1] == '\n') {
0508                            newlineOutputed = true;
0509                        }
0510                        if (inPre && end == preEndOffset) {
0511                            if (segment.count > 1) {
0512                                segment.count--;
0513                            } else {
0514                                return;
0515                            }
0516                        }
0517                        replaceEntities = true;
0518                        setCanWrapLines(!inPre);
0519                        write(segment.array, segment.offset, segment.count);
0520                        setCanWrapLines(false);
0521                        replaceEntities = false;
0522                    }
0523                }
0524            }
0525
0526            /**
0527             * Writes out the content of the SELECT form element.
0528             * 
0529             * @param attr the AttributeSet associated with the form element
0530             * @exception IOException on any I/O error
0531             */
0532            protected void selectContent(AttributeSet attr) throws IOException {
0533                Object model = attr.getAttribute(StyleConstants.ModelAttribute);
0534                incrIndent();
0535                if (model instanceof  OptionListModel) {
0536                    OptionListModel listModel = (OptionListModel) model;
0537                    int size = listModel.getSize();
0538                    for (int i = 0; i < size; i++) {
0539                        Option option = (Option) listModel.getElementAt(i);
0540                        writeOption(option);
0541                    }
0542                } else if (model instanceof  OptionComboBoxModel) {
0543                    OptionComboBoxModel comboBoxModel = (OptionComboBoxModel) model;
0544                    int size = comboBoxModel.getSize();
0545                    for (int i = 0; i < size; i++) {
0546                        Option option = (Option) comboBoxModel.getElementAt(i);
0547                        writeOption(option);
0548                    }
0549                }
0550                decrIndent();
0551            }
0552
0553            /**
0554             * Writes out the content of the Option form element.
0555             * @param option  an Option
0556             * @exception IOException on any I/O error
0557             * 
0558             */
0559            protected void writeOption(Option option) throws IOException {
0560
0561                indentSmart();
0562                write('<');
0563                write("option");
0564                // PENDING: should this be changed to check for null first?
0565                Object value = option.getAttributes().getAttribute(
0566                        HTML.Attribute.VALUE);
0567                if (value != null) {
0568                    write(" value=" + value);
0569                }
0570                if (option.isSelected()) {
0571                    write(" selected");
0572                }
0573                write('>');
0574                if (option.getLabel() != null) {
0575                    write(option.getLabel());
0576                }
0577                writeLineSeparator();
0578            }
0579
0580            /**
0581             * Writes out an end tag for the element.
0582             *
0583             * @param elem    an Element
0584             * @exception IOException on any I/O error
0585             */
0586            protected void endTag(Element elem) throws IOException {
0587                if (synthesizedElement(elem)) {
0588                    return;
0589                }
0590
0591                // write out end tags for item on stack
0592                closeOutUnwantedEmbeddedTags(elem.getAttributes());
0593                if (inContent) {
0594                    if (!newlineOutputed && !inPre) {
0595                        writeLineSeparator();
0596                    }
0597                    newlineOutputed = false;
0598                    inContent = false;
0599                }
0600                if (!inPre) {
0601                    indentSmart();
0602                }
0603                if (matchNameAttribute(elem.getAttributes(), HTML.Tag.PRE)) {
0604                    inPre = false;
0605                }
0606                write('<');
0607                write('/');
0608                write(elem.getName());
0609                write('>');
0610                writeLineSeparator();
0611            }
0612
0613            /**
0614             * Writes out comments.
0615             *
0616             * @param elem    an Element
0617             * @exception IOException on any I/O error
0618             * @exception BadLocationException if pos represents an invalid
0619             *            location within the document.
0620             */
0621            protected void comment(Element elem) throws BadLocationException,
0622                    IOException {
0623                AttributeSet as = elem.getAttributes();
0624                if (matchNameAttribute(as, HTML.Tag.COMMENT)) {
0625                    Object comment = as.getAttribute(HTML.Attribute.COMMENT);
0626                    if (comment instanceof  String) {
0627                        writeComment((String) comment);
0628                    } else {
0629                        writeComment(null);
0630                    }
0631                }
0632            }
0633
0634            /**
0635             * Writes out comment string.
0636             *
0637             * @param string   the comment
0638             * @exception IOException on any I/O error
0639             * @exception BadLocationException if pos represents an invalid
0640             *            location within the document.
0641             */
0642            void writeComment(String string) throws IOException {
0643                write("<!--");
0644                if (string != null) {
0645                    write(string);
0646                }
0647                write("-->");
0648                writeLineSeparator();
0649                indentSmart();
0650            }
0651
0652            /**
0653             * Writes out any additional comments (comments outside of the body)
0654             * stored under the property HTMLDocument.AdditionalComments.
0655             */
0656            void writeAdditionalComments() throws IOException {
0657                Object comments = getDocument().getProperty(
0658                        HTMLDocument.AdditionalComments);
0659
0660                if (comments instanceof  Vector) {
0661                    Vector v = (Vector) comments;
0662                    for (int counter = 0, maxCounter = v.size(); counter < maxCounter; counter++) {
0663                        writeComment(v.elementAt(counter).toString());
0664                    }
0665                }
0666            }
0667
0668            /**
0669             * Returns true if the element is a
0670             * synthesized element.  Currently we are only testing
0671             * for the p-implied tag.
0672             */
0673            protected boolean synthesizedElement(Element elem) {
0674                if (matchNameAttribute(elem.getAttributes(), HTML.Tag.IMPLIED)) {
0675                    return true;
0676                }
0677                return false;
0678            }
0679
0680            /**
0681             * Returns true if the StyleConstants.NameAttribute is
0682             * equal to the tag that is passed in as a parameter.
0683             */
0684            protected boolean matchNameAttribute(AttributeSet attr, HTML.Tag tag) {
0685                Object o = attr.getAttribute(StyleConstants.NameAttribute);
0686                if (o instanceof  HTML.Tag) {
0687                    HTML.Tag name = (HTML.Tag) o;
0688                    if (name == tag) {
0689                        return true;
0690                    }
0691                }
0692                return false;
0693            }
0694
0695            /**
0696             * Searches for embedded tags in the AttributeSet
0697             * and writes them out.  It also stores these tags in a vector
0698             * so that when appropriate the corresponding end tags can be
0699             * written out.
0700             *
0701             * @exception IOException on any I/O error
0702             */
0703            protected void writeEmbeddedTags(AttributeSet attr)
0704                    throws IOException {
0705
0706                // translate css attributes to html
0707                attr = convertToHTML(attr, oConvAttr);
0708
0709                Enumeration names = attr.getAttributeNames();
0710                while (names.hasMoreElements()) {
0711                    Object name = names.nextElement();
0712                    if (name instanceof  HTML.Tag) {
0713                        HTML.Tag tag = (HTML.Tag) name;
0714                        if (tag == HTML.Tag.FORM || tags.contains(tag)) {
0715                            continue;
0716                        }
0717                        write('<');
0718                        write(tag.toString());
0719                        Object o = attr.getAttribute(tag);
0720                        if (o != null && o instanceof  AttributeSet) {
0721                            writeAttributes((AttributeSet) o);
0722                        }
0723                        write('>');
0724                        tags.addElement(tag);
0725                        tagValues.addElement(o);
0726                    }
0727                }
0728            }
0729
0730            /**
0731             * Searches the attribute set for a tag, both of which
0732             * are passed in as a parameter.  Returns true if no match is found
0733             * and false otherwise.
0734             */
0735            private boolean noMatchForTagInAttributes(AttributeSet attr,
0736                    HTML.Tag t, Object tagValue) {
0737                if (attr != null && attr.isDefined(t)) {
0738                    Object newValue = attr.getAttribute(t);
0739
0740                    if ((tagValue == null) ? (newValue == null)
0741                            : (newValue != null && tagValue.equals(newValue))) {
0742                        return false;
0743                    }
0744                }
0745                return true;
0746            }
0747
0748            /**
0749             * Searches the attribute set and for each tag
0750             * that is stored in the tag vector.  If the tag isnt found,
0751             * then the tag is removed from the vector and a corresponding
0752             * end tag is written out.
0753             *
0754             * @exception IOException on any I/O error
0755             */
0756            protected void closeOutUnwantedEmbeddedTags(AttributeSet attr)
0757                    throws IOException {
0758
0759                tagsToRemove.removeAllElements();
0760
0761                // translate css attributes to html
0762                attr = convertToHTML(attr, null);
0763
0764                HTML.Tag t;
0765                Object tValue;
0766                int firstIndex = -1;
0767                int size = tags.size();
0768                // First, find all the tags that need to be removed.
0769                for (int i = size - 1; i >= 0; i--) {
0770                    t = (HTML.Tag) tags.elementAt(i);
0771                    tValue = tagValues.elementAt(i);
0772                    if ((attr == null)
0773                            || noMatchForTagInAttributes(attr, t, tValue)) {
0774                        firstIndex = i;
0775                        tagsToRemove.addElement(t);
0776                    }
0777                }
0778                if (firstIndex != -1) {
0779                    // Then close them out.
0780                    boolean removeAll = ((size - firstIndex) == tagsToRemove
0781                            .size());
0782                    for (int i = size - 1; i >= firstIndex; i--) {
0783                        t = (HTML.Tag) tags.elementAt(i);
0784                        if (removeAll || tagsToRemove.contains(t)) {
0785                            tags.removeElementAt(i);
0786                            tagValues.removeElementAt(i);
0787                        }
0788                        write('<');
0789                        write('/');
0790                        write(t.toString());
0791                        write('>');
0792                    }
0793                    // Have to output any tags after firstIndex that still remaing,
0794                    // as we closed them out, but they should remain open.
0795                    size = tags.size();
0796                    for (int i = firstIndex; i < size; i++) {
0797                        t = (HTML.Tag) tags.elementAt(i);
0798                        write('<');
0799                        write(t.toString());
0800                        Object o = tagValues.elementAt(i);
0801                        if (o != null && o instanceof  AttributeSet) {
0802                            writeAttributes((AttributeSet) o);
0803                        }
0804                        write('>');
0805                    }
0806                }
0807            }
0808
0809            /**
0810             * Determines if the element associated with the attributeset
0811             * is a TEXTAREA or SELECT.  If true, returns true else
0812             * false
0813             */
0814            private boolean isFormElementWithContent(AttributeSet attr) {
0815                if (matchNameAttribute(attr, HTML.Tag.TEXTAREA)
0816                        || matchNameAttribute(attr, HTML.Tag.SELECT)) {
0817                    return true;
0818                }
0819                return false;
0820            }
0821
0822            /**
0823             * Determines whether a the indentation needs to be
0824             * incremented.  Basically, if next is a child of current, and
0825             * next is NOT a synthesized element, the indent level will be
0826             * incremented.  If there is a parent-child relationship and "next"
0827             * is a synthesized element, then its children must be indented.
0828             * This state is maintained by the indentNext boolean.
0829             *
0830             * @return boolean that's true if indent level
0831             *         needs incrementing.
0832             */
0833            private boolean indentNext = false;
0834
0835            private boolean indentNeedsIncrementing(Element current,
0836                    Element next) {
0837                if ((next.getParentElement() == current) && !inPre) {
0838                    if (indentNext) {
0839                        indentNext = false;
0840                        return true;
0841                    } else if (synthesizedElement(next)) {
0842                        indentNext = true;
0843                    } else if (!synthesizedElement(current)) {
0844                        return true;
0845                    }
0846                }
0847                return false;
0848            }
0849
0850            /**
0851             * Outputs the maps as elements. Maps are not stored as elements in
0852             * the document, and as such this is used to output them.
0853             */
0854            void writeMaps(Enumeration maps) throws IOException {
0855                if (maps != null) {
0856                    while (maps.hasMoreElements()) {
0857                        Map map = (Map) maps.nextElement();
0858                        String name = map.getName();
0859
0860                        incrIndent();
0861                        indentSmart();
0862                        write("<map");
0863                        if (name != null) {
0864                            write(" name=\"");
0865                            write(name);
0866                            write("\">");
0867                        } else {
0868                            write('>');
0869                        }
0870                        writeLineSeparator();
0871                        incrIndent();
0872
0873                        // Output the areas
0874                        AttributeSet[] areas = map.getAreas();
0875                        if (areas != null) {
0876                            for (int counter = 0, maxCounter = areas.length; counter < maxCounter; counter++) {
0877                                indentSmart();
0878                                write("<area");
0879                                writeAttributes(areas[counter]);
0880                                write("></area>");
0881                                writeLineSeparator();
0882                            }
0883                        }
0884                        decrIndent();
0885                        indentSmart();
0886                        write("</map>");
0887                        writeLineSeparator();
0888                        decrIndent();
0889                    }
0890                }
0891            }
0892
0893            /**
0894             * Outputs the styles as a single element. Styles are not stored as
0895             * elements, but part of the document. For the time being styles are
0896             * written out as a comment, inside a style tag.
0897             */
0898            void writeStyles(StyleSheet sheet) throws IOException {
0899                if (sheet != null) {
0900                    Enumeration styles = sheet.getStyleNames();
0901                    if (styles != null) {
0902                        boolean outputStyle = false;
0903                        while (styles.hasMoreElements()) {
0904                            String name = (String) styles.nextElement();
0905                            // Don't write out the default style.
0906                            if (!StyleContext.DEFAULT_STYLE.equals(name)
0907                                    && writeStyle(name, sheet.getStyle(name),
0908                                            outputStyle)) {
0909                                outputStyle = true;
0910                            }
0911                        }
0912                        if (outputStyle) {
0913                            writeStyleEndTag();
0914                        }
0915                    }
0916                }
0917            }
0918
0919            /**
0920             * Outputs the named style. <code>outputStyle</code> indicates
0921             * whether or not a style has been output yet. This will return
0922             * true if a style is written.
0923             */
0924            boolean writeStyle(String name, Style style, boolean outputStyle)
0925                    throws IOException {
0926                boolean didOutputStyle = false;
0927                Enumeration attributes = style.getAttributeNames();
0928                if (attributes != null) {
0929                    while (attributes.hasMoreElements()) {
0930                        Object attribute = attributes.nextElement();
0931                        if (attribute instanceof  CSS.Attribute) {
0932                            String value = style.getAttribute(attribute)
0933                                    .toString();
0934                            if (value != null) {
0935                                if (!outputStyle) {
0936                                    writeStyleStartTag();
0937                                    outputStyle = true;
0938                                }
0939                                if (!didOutputStyle) {
0940                                    didOutputStyle = true;
0941                                    indentSmart();
0942                                    write(name);
0943                                    write(" {");
0944                                } else {
0945                                    write(";");
0946                                }
0947                                write(' ');
0948                                write(attribute.toString());
0949                                write(": ");
0950                                write(value);
0951                            }
0952                        }
0953                    }
0954                }
0955                if (didOutputStyle) {
0956                    write(" }");
0957                    writeLineSeparator();
0958                }
0959                return didOutputStyle;
0960            }
0961
0962            void writeStyleStartTag() throws IOException {
0963                indentSmart();
0964                write("<style type=\"text/css\">");
0965                incrIndent();
0966                writeLineSeparator();
0967                indentSmart();
0968                write("<!--");
0969                incrIndent();
0970                writeLineSeparator();
0971            }
0972
0973            void writeStyleEndTag() throws IOException {
0974                decrIndent();
0975                indentSmart();
0976                write("-->");
0977                writeLineSeparator();
0978                decrIndent();
0979                indentSmart();
0980                write("</style>");
0981                writeLineSeparator();
0982                indentSmart();
0983            }
0984
0985            // --- conversion support ---------------------------
0986
0987            /**
0988             * Convert the give set of attributes to be html for
0989             * the purpose of writing them out.  Any keys that
0990             * have been converted will not appear in the resultant
0991             * set.  Any keys not converted will appear in the 
0992             * resultant set the same as the received set.<p>
0993             * This will put the converted values into <code>to</code>, unless
0994             * it is null in which case a temporary AttributeSet will be returned.
0995             */
0996            AttributeSet convertToHTML(AttributeSet from, MutableAttributeSet to) {
0997                if (to == null) {
0998                    to = convAttr;
0999                }
1000                to.removeAttributes(to);
1001                if (writeCSS) {
1002                    convertToHTML40(from, to);
1003                } else {
1004                    convertToHTML32(from, to);
1005                }
1006                return to;
1007            }
1008
1009            /**
1010             * If true, the writer will emit CSS attributes in preference
1011             * to HTML tags/attributes (i.e. It will emit an HTML 4.0
1012             * style).
1013             */
1014            private boolean writeCSS = false;
1015
1016            /**
1017             * Buffer for the purpose of attribute conversion
1018             */
1019            private MutableAttributeSet convAttr = new SimpleAttributeSet();
1020
1021            /**
1022             * Buffer for the purpose of attribute conversion. This can be
1023             * used if convAttr is being used.
1024             */
1025            private MutableAttributeSet oConvAttr = new SimpleAttributeSet();
1026
1027            /**
1028             * Create an older style of HTML attributes.  This will 
1029             * convert character level attributes that have a StyleConstants
1030             * mapping over to an HTML tag/attribute.  Other CSS attributes
1031             * will be placed in an HTML style attribute.
1032             */
1033            private static void convertToHTML32(AttributeSet from,
1034                    MutableAttributeSet to) {
1035                if (from == null) {
1036                    return;
1037                }
1038                Enumeration keys = from.getAttributeNames();
1039                String value = "";
1040                while (keys.hasMoreElements()) {
1041                    Object key = keys.nextElement();
1042                    if (key instanceof  CSS.Attribute) {
1043                        if ((key == CSS.Attribute.FONT_FAMILY)
1044                                || (key == CSS.Attribute.FONT_SIZE)
1045                                || (key == CSS.Attribute.COLOR)) {
1046
1047                            createFontAttribute((CSS.Attribute) key, from, to);
1048                        } else if (key == CSS.Attribute.FONT_WEIGHT) {
1049                            // add a bold tag is weight is bold
1050                            CSS.FontWeight weightValue = (CSS.FontWeight) from
1051                                    .getAttribute(CSS.Attribute.FONT_WEIGHT);
1052                            if ((weightValue != null)
1053                                    && (weightValue.getValue() > 400)) {
1054                                addAttribute(to, HTML.Tag.B,
1055                                        SimpleAttributeSet.EMPTY);
1056                            }
1057                        } else if (key == CSS.Attribute.FONT_STYLE) {
1058                            String s = from.getAttribute(key).toString();
1059                            if (s.indexOf("italic") >= 0) {
1060                                addAttribute(to, HTML.Tag.I,
1061                                        SimpleAttributeSet.EMPTY);
1062                            }
1063                        } else if (key == CSS.Attribute.TEXT_DECORATION) {
1064                            String decor = from.getAttribute(key).toString();
1065                            if (decor.indexOf("underline") >= 0) {
1066                                addAttribute(to, HTML.Tag.U,
1067                                        SimpleAttributeSet.EMPTY);
1068                            }
1069                            if (decor.indexOf("line-through") >= 0) {
1070                                addAttribute(to, HTML.Tag.STRIKE,
1071                                        SimpleAttributeSet.EMPTY);
1072                            }
1073                        } else if (key == CSS.Attribute.VERTICAL_ALIGN) {
1074                            String vAlign = from.getAttribute(key).toString();
1075                            if (vAlign.indexOf("sup") >= 0) {
1076                                addAttribute(to, HTML.Tag.SUP,
1077                                        SimpleAttributeSet.EMPTY);
1078                            }
1079                            if (vAlign.indexOf("sub") >= 0) {
1080                                addAttribute(to, HTML.Tag.SUB,
1081                                        SimpleAttributeSet.EMPTY);
1082                            }
1083                        } else if (key == CSS.Attribute.TEXT_ALIGN) {
1084                            addAttribute(to, HTML.Attribute.ALIGN, from
1085                                    .getAttribute(key).toString());
1086                        } else {
1087                            // default is to store in a HTML style attribute
1088                            if (value.length() > 0) {
1089                                value = value + "; ";
1090                            }
1091                            value = value + key + ": " + from.getAttribute(key);
1092                        }
1093                    } else {
1094                        Object attr = from.getAttribute(key);
1095                        if (attr instanceof  AttributeSet) {
1096                            attr = ((AttributeSet) attr).copyAttributes();
1097                        }
1098                        addAttribute(to, key, attr);
1099                    }
1100                }
1101                if (value.length() > 0) {
1102                    to.addAttribute(HTML.Attribute.STYLE, value);
1103                }
1104            }
1105
1106            /**
1107             * Add an attribute only if it doesn't exist so that we don't
1108             * loose information replacing it with SimpleAttributeSet.EMPTY
1109             */
1110            private static void addAttribute(MutableAttributeSet to,
1111                    Object key, Object value) {
1112                Object attr = to.getAttribute(key);
1113                if (attr == null || attr == SimpleAttributeSet.EMPTY) {
1114                    to.addAttribute(key, value);
1115                } else {
1116                    if (attr instanceof  MutableAttributeSet
1117                            && value instanceof  AttributeSet) {
1118                        ((MutableAttributeSet) attr)
1119                                .addAttributes((AttributeSet) value);
1120                    }
1121                }
1122            }
1123
1124            /**
1125             * Create/update an HTML &lt;font&gt; tag attribute.  The
1126             * value of the attribute should be a MutableAttributeSet so
1127             * that the attributes can be updated as they are discovered.
1128             */
1129            private static void createFontAttribute(CSS.Attribute a,
1130                    AttributeSet from, MutableAttributeSet to) {
1131                MutableAttributeSet fontAttr = (MutableAttributeSet) to
1132                        .getAttribute(HTML.Tag.FONT);
1133                if (fontAttr == null) {
1134                    fontAttr = new SimpleAttributeSet();
1135                    to.addAttribute(HTML.Tag.FONT, fontAttr);
1136                }
1137                // edit the parameters to the font tag
1138                String htmlValue = from.getAttribute(a).toString();
1139                if (a == CSS.Attribute.FONT_FAMILY) {
1140                    fontAttr.addAttribute(HTML.Attribute.FACE, htmlValue);
1141                } else if (a == CSS.Attribute.FONT_SIZE) {
1142                    fontAttr.addAttribute(HTML.Attribute.SIZE, htmlValue);
1143                } else if (a == CSS.Attribute.COLOR) {
1144                    fontAttr.addAttribute(HTML.Attribute.COLOR, htmlValue);
1145                }
1146            }
1147
1148            /**
1149             * Copies the given AttributeSet to a new set, converting
1150             * any CSS attributes found to arguments of an HTML style
1151             * attribute.
1152             */
1153            private static void convertToHTML40(AttributeSet from,
1154                    MutableAttributeSet to) {
1155                Enumeration keys = from.getAttributeNames();
1156                String value = "";
1157                while (keys.hasMoreElements()) {
1158                    Object key = keys.nextElement();
1159                    if (key instanceof  CSS.Attribute) {
1160                        value = value + " " + key + "="
1161                                + from.getAttribute(key) + ";";
1162                    } else {
1163                        to.addAttribute(key, from.getAttribute(key));
1164                    }
1165                }
1166                if (value.length() > 0) {
1167                    to.addAttribute(HTML.Attribute.STYLE, value);
1168                }
1169            }
1170
1171            //
1172            // Overrides the writing methods to only break a string when
1173            // canBreakString is true.
1174            // In a future release it is likely AbstractWriter will get this
1175            // functionality.
1176            //
1177
1178            /**
1179             * Writes the line separator. This is overriden to make sure we don't
1180             * replace the newline content in case it is outside normal ascii.
1181             * @since 1.3
1182             */
1183            protected void writeLineSeparator() throws IOException {
1184                boolean oldReplace = replaceEntities;
1185                replaceEntities = false;
1186                super .writeLineSeparator();
1187                replaceEntities = oldReplace;
1188                indented = false;
1189            }
1190
1191            /**
1192             * This method is overriden to map any character entities, such as
1193             * &lt; to &amp;lt;. <code>super.output</code> will be invoked to
1194             * write the content.
1195             * @since 1.3
1196             */
1197            protected void output(char[] chars, int start, int length)
1198                    throws IOException {
1199                if (!replaceEntities) {
1200                    super .output(chars, start, length);
1201                    return;
1202                }
1203                int last = start;
1204                length += start;
1205                for (int counter = start; counter < length; counter++) {
1206                    // This will change, we need better support character level
1207                    // entities.
1208                    switch (chars[counter]) {
1209                    // Character level entities.
1210                    case '<':
1211                        if (counter > last) {
1212                            super .output(chars, last, counter - last);
1213                        }
1214                        last = counter + 1;
1215                        output("&lt;");
1216                        break;
1217                    case '>':
1218                        if (counter > last) {
1219                            super .output(chars, last, counter - last);
1220                        }
1221                        last = counter + 1;
1222                        output("&gt;");
1223                        break;
1224                    case '&':
1225                        if (counter > last) {
1226                            super .output(chars, last, counter - last);
1227                        }
1228                        last = counter + 1;
1229                        output("&amp;");
1230                        break;
1231                    case '"':
1232                        if (counter > last) {
1233                            super .output(chars, last, counter - last);
1234                        }
1235                        last = counter + 1;
1236                        output("&quot;");
1237                        break;
1238                    // Special characters
1239                    case '\n':
1240                    case '\t':
1241                    case '\r':
1242                        break;
1243                    default:
1244                        if (chars[counter] < ' ' || chars[counter] > 127) {
1245                            if (counter > last) {
1246                                super .output(chars, last, counter - last);
1247                            }
1248                            last = counter + 1;
1249                            // If the character is outside of ascii, write the
1250                            // numeric value.
1251                            output("&#");
1252                            output(String.valueOf((int) chars[counter]));
1253                            output(";");
1254                        }
1255                        break;
1256                    }
1257                }
1258                if (last < length) {
1259                    super .output(chars, last, length - last);
1260                }
1261            }
1262
1263            /**
1264             * This directly invokes super's <code>output</code> after converting
1265             * <code>string</code> to a char[].
1266             */
1267            private void output(String string) throws IOException {
1268                int length = string.length();
1269                if (tempChars == null || tempChars.length < length) {
1270                    tempChars = new char[length];
1271                }
1272                string.getChars(0, length, tempChars, 0);
1273                super .output(tempChars, 0, length);
1274            }
1275
1276            private boolean indented = false;
1277
1278            /**
1279             * Writes indent only once per line.
1280             */
1281            private void indentSmart() throws IOException {
1282                if (!indented) {
1283                    indent();
1284                    indented = true;
1285                }
1286            }
1287        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.