qdoc: Fixed bugs causing invalid DITA XML

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>
bb10
Martin Smith 2012-04-13 12:55:56 +02:00 committed by Qt by Nokia
parent eb52d31ddf
commit aabd54b8bb
5 changed files with 190 additions and 158 deletions

View 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

View 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);
{
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;
}
if (myLink.isEmpty()) {
relative->doc().location().warning(tr("Can't link to '%1'")
.arg(atom->string()));
}
else if (!inSectionHeading) {
beginLink(myLink);
}
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 (node)
generateTableOfContents(node,
marker,
sectionUnit,
numColumns,
relative);
}
if (params.size() == 2) {
numColumns = qMax(columnText.toInt(), numColumns);
sectionUnit = (Doc::Sections)params.at(1).toInt();
}
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) {

View 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:
/*

View File

@ -2973,6 +2973,13 @@
* /
\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

View 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;
}
}