qdoc: Fixed bugs causing invalid DITA XML
authorMartin Smith <martin.smith@nokia.com>
Fri, 13 Apr 2012 10:55:56 +0000 (12:55 +0200)
committerQt by Nokia <qt-info@nokia.com>
Sat, 14 Apr 2012 17:46:00 +0000 (19:46 +0200)
Fixed a bug in qdoc that caused too many end elements to be generated.
Also fixed some doc errors that caused invalid DITA to be generated.

Task nr: QTBUG-25302

Change-Id: Ifbbf457d28c51c2691a252888447739da7713bc9
Reviewed-by: Martin Smith <martin.smith@nokia.com>
Reviewed-by: Casper van Donderen <casper.vandonderen@nokia.com>
src/corelib/tools/qregularexpression.cpp
src/tools/qdoc/ditaxmlgenerator.cpp
src/tools/qdoc/ditaxmlgenerator.h
src/tools/qdoc/doc/qdoc-manual.qdoc
src/tools/qdoc/node.cpp

index a65ac0c..393b2bb 100644 (file)
@@ -288,7 +288,7 @@ QT_BEGIN_NAMESPACE
     Partial matching is mainly useful in two scenarios: validating user input
     in real time and incremental/multi-segment matching.
 
-    \target
+    \target validating user input
     \section2 Validating user input
 
     Suppose that we would like the user to input a date in a specific
index 10641b0..1f986e3 100644 (file)
@@ -249,6 +249,14 @@ QString DitaXmlGenerator::ditaTags[] =
     ""
 };
 
+void DitaXmlGenerator::debugPara(const QString& t)
+{
+    writeStartTag(DT_p);
+    xmlWriter().writeAttribute("outputclass",t);
+    xmlWriter().writeCharacters(t);
+    writeEndTag(); // </p>
+}
+
 static bool showBrokenLinks = false;
 
 /*!
@@ -693,6 +701,13 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
     static bool in_para = false;
     QString guid, hc, attr;
 
+#if 0
+    // Leave this here for debugging.
+    if (outFileName() == "modules.dita") {
+        QString comment = "ATOM:" + atom->typeString();
+        xmlWriter().writeComment(comment);
+    }
+#endif
     switch (atom->type()) {
     case Atom::AbstractLeft:
         break;
@@ -721,6 +736,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
         {
             Node::Type t = relative->type();
             if (inSection()) {
+                in_para = true;
                 writeStartTag(DT_p);
                 xmlWriter().writeAttribute("outputclass","brief");
             }
@@ -756,6 +772,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
     case Atom::BriefRight:
         //        if (relative->type() != Node::Fake)
         writeEndTag(); // </shortdesc> or </p>
+        if (in_para)
+            in_para = false;
         noLinks = false;
         break;
     case Atom::C:
@@ -769,13 +787,13 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
         writeEndTag(); // see writeStartElement() above
         break;
     case Atom::Code:
-    {
-        writeStartTag(DT_codeblock);
-        xmlWriter().writeAttribute("outputclass","cpp");
-        QString chars = trimmedTrailing(atom->string());
-        writeText(chars, marker, relative);
-        writeEndTag(); // </codeblock>
-    }
+        {
+            writeStartTag(DT_codeblock);
+            xmlWriter().writeAttribute("outputclass","cpp");
+            QString chars = trimmedTrailing(atom->string());
+            writeText(chars, marker, relative);
+            writeEndTag(); // </codeblock>
+        }
         break;
     case Atom::Qml:
         writeStartTag(DT_codeblock);
@@ -866,71 +884,71 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
     case Atom::FormatIf:
         break;
     case Atom::FormattingLeft:
-    {
-        DitaTag t = DT_LAST;
-        if (atom->string() == ATOM_FORMATTING_BOLD)
-            t = DT_b;
-        else if (atom->string() == ATOM_FORMATTING_PARAMETER)
-            t = DT_i;
-        else if (atom->string() == ATOM_FORMATTING_ITALIC)
-            t = DT_i;
-        else if (atom->string() == ATOM_FORMATTING_TELETYPE)
-            t = DT_tt;
-        else if (atom->string().startsWith("span ")) {
-            t = DT_keyword;
-        }
-        else if (atom->string() == ATOM_FORMATTING_UICONTROL)
-            t = DT_uicontrol;
-        else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
-            t = DT_u;
-        else if (atom->string() == ATOM_FORMATTING_INDEX)
-            t = DT_comment;
-        else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
-            t = DT_sub;
-        else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
-            t = DT_sup;
-        else
-            qDebug() << "DT_LAST";
-        writeStartTag(t);
-        if (atom->string() == ATOM_FORMATTING_PARAMETER) {
-            if (atom->next() != 0 && atom->next()->type() == Atom::String) {
-                QRegExp subscriptRegExp("([a-z]+)_([0-9n])");
-                if (subscriptRegExp.exactMatch(atom->next()->string())) {
-                    xmlWriter().writeCharacters(subscriptRegExp.cap(1));
-                    writeStartTag(DT_sub);
-                    xmlWriter().writeCharacters(subscriptRegExp.cap(2));
-                    writeEndTag(); // </sub>
-                    skipAhead = 1;
+        {
+            DitaTag t = DT_LAST;
+            if (atom->string() == ATOM_FORMATTING_BOLD)
+                t = DT_b;
+            else if (atom->string() == ATOM_FORMATTING_PARAMETER)
+                t = DT_i;
+            else if (atom->string() == ATOM_FORMATTING_ITALIC)
+                t = DT_i;
+            else if (atom->string() == ATOM_FORMATTING_TELETYPE)
+                t = DT_tt;
+            else if (atom->string().startsWith("span ")) {
+                t = DT_keyword;
+            }
+            else if (atom->string() == ATOM_FORMATTING_UICONTROL)
+                t = DT_uicontrol;
+            else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
+                t = DT_u;
+            else if (atom->string() == ATOM_FORMATTING_INDEX)
+                t = DT_comment;
+            else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
+                t = DT_sub;
+            else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
+                t = DT_sup;
+            else
+                qDebug() << "DT_LAST";
+            writeStartTag(t);
+            if (atom->string() == ATOM_FORMATTING_PARAMETER) {
+                if (atom->next() != 0 && atom->next()->type() == Atom::String) {
+                    QRegExp subscriptRegExp("([a-z]+)_([0-9n])");
+                    if (subscriptRegExp.exactMatch(atom->next()->string())) {
+                        xmlWriter().writeCharacters(subscriptRegExp.cap(1));
+                        writeStartTag(DT_sub);
+                        xmlWriter().writeCharacters(subscriptRegExp.cap(2));
+                        writeEndTag(); // </sub>
+                        skipAhead = 1;
+                    }
                 }
             }
-        }
-        else if (t == DT_keyword) {
-            QString attr = atom->string().mid(5);
-            if (!attr.isEmpty()) {
-                if (attr.contains('=')) {
-                    int index = 0;
-                    int from = 0;
-                    QString values;
-                    while (index >= 0) {
-                        index = attr.indexOf('"',from);
-                        if (index >= 0) {
-                            ++index;
-                            from = index;
+            else if (t == DT_keyword) {
+                QString attr = atom->string().mid(5);
+                if (!attr.isEmpty()) {
+                    if (attr.contains('=')) {
+                        int index = 0;
+                        int from = 0;
+                        QString values;
+                        while (index >= 0) {
                             index = attr.indexOf('"',from);
-                            if (index > from) {
-                                if (!values.isEmpty())
-                                    values.append(' ');
-                                values += attr.mid(from,index-from);
-                                from = index+1;
+                            if (index >= 0) {
+                                ++index;
+                                from = index;
+                                index = attr.indexOf('"',from);
+                                if (index > from) {
+                                    if (!values.isEmpty())
+                                        values.append(' ');
+                                    values += attr.mid(from,index-from);
+                                    from = index+1;
+                                }
                             }
                         }
+                        attr = values;
                     }
-                    attr = values;
                 }
+                xmlWriter().writeAttribute("outputclass", attr);
             }
-            xmlWriter().writeAttribute("outputclass", attr);
         }
-    }
         break;
     case Atom::FormattingRight:
         if (atom->string() == ATOM_FORMATTING_LINK) {
@@ -941,17 +959,17 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
         }
         break;
     case Atom::AnnotatedList:
-    {
-        QList<Node*> values = tree_->groups().values(atom->string());
-        NodeMap nodeMap;
-        for (int i = 0; i < values.size(); ++i) {
-            const Node* n = values.at(i);
-            if ((n->status() != Node::Internal) && (n->access() != Node::Private)) {
-                nodeMap.insert(n->nameForLists(),n);
+        {
+            QList<Node*> values = tree_->groups().values(atom->string());
+            NodeMap nodeMap;
+            for (int i = 0; i < values.size(); ++i) {
+                const Node* n = values.at(i);
+                if ((n->status() != Node::Internal) && (n->access() != Node::Private)) {
+                    nodeMap.insert(n->nameForLists(),n);
+                }
             }
+            generateAnnotatedList(relative, marker, nodeMap);
         }
-        generateAnnotatedList(relative, marker, nodeMap);
-    }
         break;
     case Atom::GeneratedList:
         if (atom->string() == "annotatedclasses") {
@@ -1270,34 +1288,34 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
         //xmlWriter().writeEmptyElement("br");
         break;
     case Atom::Link:
-    {
-        const Node *node = 0;
-        QString myLink = getLink(atom, relative, marker, &node);
-        if (myLink.isEmpty()) {
-            myLink = getCollisionLink(atom);
-        }
-        if (myLink.isEmpty()) {
-            relative->doc().location().warning(tr("Can't link to '%1'")
-                                               .arg(atom->string()));
-        }
-        else if (!inSectionHeading) {
-            beginLink(myLink);
+        {
+            const Node *node = 0;
+            QString myLink = getLink(atom, relative, marker, &node);
+            if (myLink.isEmpty()) {
+                myLink = getCollisionLink(atom);
+            }
+            if (myLink.isEmpty()) {
+                relative->doc().location().warning(tr("Can't link to '%1'")
+                                                   .arg(atom->string()));
+            }
+            else if (!inSectionHeading) {
+                beginLink(myLink);
+            }
+            skipAhead = 1;
         }
-        skipAhead = 1;
-    }
         break;
     case Atom::GuidLink:
-    {
-        beginLink(atom->string());
-        skipAhead = 1;
-    }
+        {
+            beginLink(atom->string());
+            skipAhead = 1;
+        }
         break;
     case Atom::LinkNode:
-    {
-        const Node* node = CodeMarker::nodeForString(atom->string());
-        beginLink(linkForNode(node, relative));
-        skipAhead = 1;
-    }
+        {
+            const Node* node = CodeMarker::nodeForString(atom->string());
+            beginLink(linkForNode(node, relative));
+            skipAhead = 1;
+        }
         break;
     case Atom::ListLeft:
         if (in_para) {
@@ -1353,8 +1371,13 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
             else // (atom->string() == ATOM_LIST_NUMERIC)
                 xmlWriter().writeAttribute("outputclass","numeric");
             if (atom->next() != 0 && atom->next()->string().toInt() != 1) {
-                // I don't think this attribute is supported.
-                xmlWriter().writeAttribute("start",atom->next()->string());
+                /*
+                  This attribute is not supported in DITA, and at the
+                  moment, including it is causing a validation error
+                  wherever it is used. I think it is onlym used in the
+                  qdoc manual.
+                 */
+                //xmlWriter().writeAttribute("start",atom->next()->string());
             }
         }
         break;
@@ -1629,47 +1652,48 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
         writeEndTag(); // </row>
         break;
     case Atom::TableItemLeft:
-    {
-        QString values;
-        writeStartTag(DT_entry);
-        for (int i=0; i<atom->count(); ++i) {
-            attr = atom->string(i);
-            if (attr.contains('=')) {
-                int index = 0;
-                int from = 0;
-                while (index >= 0) {
-                    index = attr.indexOf('"',from);
-                    if (index >= 0) {
-                        ++index;
-                        from = index;
+        {
+            QString values;
+            writeStartTag(DT_entry);
+            for (int i=0; i<atom->count(); ++i) {
+                attr = atom->string(i);
+                if (attr.contains('=')) {
+                    int index = 0;
+                    int from = 0;
+                    while (index >= 0) {
                         index = attr.indexOf('"',from);
-                        if (index > from) {
-                            if (!values.isEmpty())
-                                values.append(' ');
-                            values += attr.mid(from,index-from);
-                            from = index+1;
+                        if (index >= 0) {
+                            ++index;
+                            from = index;
+                            index = attr.indexOf('"',from);
+                            if (index > from) {
+                                if (!values.isEmpty())
+                                    values.append(' ');
+                                values += attr.mid(from,index-from);
+                                from = index+1;
+                            }
                         }
                     }
                 }
-            }
-            else {
-                QStringList spans = attr.split(QLatin1Char(','));
-                if (spans.size() == 2) {
-                    if ((spans[0].toInt()>1) || (spans[1].toInt()>1)) {
-                        values += "span(" + spans[0] + QLatin1Char(',') + spans[1] + QLatin1Char(')');
+                else {
+                    QStringList spans = attr.split(QLatin1Char(','));
+                    if (spans.size() == 2) {
+                        if ((spans[0].toInt()>1) || (spans[1].toInt()>1)) {
+                            values += "span(" + spans[0] + QLatin1Char(',') + spans[1] + QLatin1Char(')');
+                        }
                     }
                 }
             }
+            if (!values.isEmpty())
+                xmlWriter().writeAttribute("outputclass",values);
+            if (matchAhead(atom, Atom::ParaLeft))
+                skipAhead = 1;
         }
-        if (!values.isEmpty())
-            xmlWriter().writeAttribute("outputclass",values);
-        if (matchAhead(atom, Atom::ParaLeft))
-            skipAhead = 1;
-    }
         break;
     case Atom::TableItemRight:
-        if (inTableHeader)
+        if (inTableHeader) {
             writeEndTag(); // </entry>
+        }
         else {
             writeEndTag(); // </entry>
         }
@@ -1677,33 +1701,33 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
             skipAhead = 1;
         break;
     case Atom::TableOfContents:
-    {
-        int numColumns = 1;
-        const Node* node = relative;
+        {
+            int numColumns = 1;
+            const Node* node = relative;
 
-        Doc::Sections sectionUnit = Doc::Section4;
-        QStringList params = atom->string().split(QLatin1Char(','));
-        QString columnText = params.at(0);
-        QStringList pieces = columnText.split(QLatin1Char(' '), QString::SkipEmptyParts);
-        if (pieces.size() >= 2) {
-            columnText = pieces.at(0);
-            pieces.pop_front();
-            QString path = pieces.join(" ").trimmed();
-            node = findNodeForTarget(path, relative, marker, atom);
-        }
+            Doc::Sections sectionUnit = Doc::Section4;
+            QStringList params = atom->string().split(QLatin1Char(','));
+            QString columnText = params.at(0);
+            QStringList pieces = columnText.split(QLatin1Char(' '), QString::SkipEmptyParts);
+            if (pieces.size() >= 2) {
+                columnText = pieces.at(0);
+                pieces.pop_front();
+                QString path = pieces.join(" ").trimmed();
+                node = findNodeForTarget(path, relative, marker, atom);
+            }
 
-        if (params.size() == 2) {
-            numColumns = qMax(columnText.toInt(), numColumns);
-            sectionUnit = (Doc::Sections)params.at(1).toInt();
-        }
+            if (params.size() == 2) {
+                numColumns = qMax(columnText.toInt(), numColumns);
+                sectionUnit = (Doc::Sections)params.at(1).toInt();
+            }
 
-        if (node)
-            generateTableOfContents(node,
-                                    marker,
-                                    sectionUnit,
-                                    numColumns,
-                                    relative);
-    }
+            if (node)
+                generateTableOfContents(node,
+                                        marker,
+                                        sectionUnit,
+                                        numColumns,
+                                        relative);
+        }
         break;
     case Atom::Target:
         if (in_para) {
@@ -2278,7 +2302,7 @@ void DitaXmlGenerator::generateFakeNode(FakeNode* fake, CodeMarker* marker)
     writeProlog(fake);
 
     writeStartTag(DT_body);
-    enterSection(QString(),QString());
+    enterSection("","");
     if (fake->subType() == Node::Module) {
         generateStatus(fake, marker);
         if (moduleNamespaceMap.contains(fake->name())) {
@@ -6412,7 +6436,7 @@ void DitaXmlGenerator::generateCollisionPages()
         generateHeader(ncn, ditaTitle);
         writeProlog(ncn);
         writeStartTag(DT_body);
-        enterSection(QString(),QString());
+        enterSection("","");
 
         NodeMap nm;
         for (int i=0; i<collisions.size(); ++i) {
index 6eea6dc..6ce42fc 100644 (file)
@@ -457,6 +457,7 @@ private:
     void writeDitaRefs(const DitaRefList& ditarefs);
     void writeTopicrefs(NodeMultiMap* nmm, const QString& navtitle);
     bool isDuplicate(NodeMultiMap* nmm, const QString& key, Node* node);
+    void debugPara(const QString& t);
 
 private:
     /*
index 2914749..fa3301e 100644 (file)
            * /
            \endcode
 
+    \note This doesn't work in DITA XML, so don't use it because it
+    produces a DITA XML file that doesn't validate. There probably is
+    a way to do this in DITA, so if we figure it out, we will put it
+    in. But this capability is not used anywhere other than right
+    here, so it probably isn't important. For now, if you use this
+    option, qdoc will ignore it and produce a list without it.
+
     QDoc renders this as:
 
            \list G
index 1ee4719..24c0006 100644 (file)
@@ -2280,7 +2280,7 @@ bool QmlPropertyNode::isWritable(Tree* tree)
         return pn->isWritable();
     }
     else {
-        location().warning(tr("Can't detect if QML property %1 isread-only; writable assumed.").arg(name()));
+        location().warning(tr("Can't detect if QML property %1 is read-only; writable assumed.").arg(name()));
         return true;
     }
 }