/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*
ditaxmlgenerator.cpp
*/
#include
#include
#include
#include
#include
#include "codemarker.h"
#include "codeparser.h"
#include "ditaxmlgenerator.h"
#include "node.h"
#include "quoter.h"
#include "separator.h"
#include "tree.h"
#include
#include "qdocdatabase.h"
QT_BEGIN_NAMESPACE
#define COMMAND_VERSION Doc::alias("version")
int DitaXmlGenerator::id = 0;
/*
The strings in this array must appear in the same order as
the values in enum DitaXmlGenerator::DitaTag.
*/
QString DitaXmlGenerator::ditaTags[] =
{
"",
"alt",
"apiData",
"apiDef",
"apiDefItem",
"apiDesc",
"apiDetail",
"apiItemName",
"APIMap",
"apiName",
"apiRef",
"apiRelation",
"audience",
"author",
"b",
"body",
"bodydiv",
"brand",
"category",
"codeblock",
"colspec",
"comment",
"component",
"copyrholder",
"copyright",
"copyryear",
"created",
"critdates",
"cxxAPIMap",
"cxxClass",
"cxxClassAbstract",
"cxxClassAccessSpecifier",
"cxxClassAPIItemLocation",
"cxxClassBaseClass",
"cxxClassDeclarationFile",
"cxxClassDeclarationFileLine",
"cxxClassDeclarationFileLineStart",
"cxxClassDeclarationFileLineEnd",
"cxxClassDefinition",
"cxxClassDerivation",
"cxxClassDerivationAccessSpecifier",
"cxxClassDerivations",
"cxxClassDetail",
"cxxClassNested",
"cxxClassNestedClass",
"cxxClassNestedDetail",
"cxxDefine",
"cxxDefineAccessSpecifier",
"cxxDefineAPIItemLocation",
"cxxDefineDeclarationFile",
"cxxDefineDeclarationFileLine",
"cxxDefineDefinition",
"cxxDefineDetail",
"cxxDefineNameLookup",
"cxxDefineParameter",
"cxxDefineParameterDeclarationName",
"cxxDefineParameters",
"cxxDefinePrototype",
"cxxDefineReimplemented",
"cxxEnumeration",
"cxxEnumerationAccessSpecifier",
"cxxEnumerationAPIItemLocation",
"cxxEnumerationDeclarationFile",
"cxxEnumerationDeclarationFileLine",
"cxxEnumerationDeclarationFileLineStart",
"cxxEnumerationDeclarationFileLineEnd",
"cxxEnumerationDefinition",
"cxxEnumerationDetail",
"cxxEnumerationNameLookup",
"cxxEnumerationPrototype",
"cxxEnumerationScopedName",
"cxxEnumerator",
"cxxEnumeratorInitialiser",
"cxxEnumeratorNameLookup",
"cxxEnumeratorPrototype",
"cxxEnumerators",
"cxxEnumeratorScopedName",
"cxxFunction",
"cxxFunctionAccessSpecifier",
"cxxFunctionAPIItemLocation",
"cxxFunctionConst",
"cxxFunctionConstructor",
"cxxFunctionDeclarationFile",
"cxxFunctionDeclarationFileLine",
"cxxFunctionDeclaredType",
"cxxFunctionDefinition",
"cxxFunctionDestructor",
"cxxFunctionDetail",
"cxxFunctionNameLookup",
"cxxFunctionParameter",
"cxxFunctionParameterDeclarationName",
"cxxFunctionParameterDeclaredType",
"cxxFunctionParameterDefaultValue",
"cxxFunctionParameters",
"cxxFunctionPrototype",
"cxxFunctionPureVirtual",
"cxxFunctionReimplemented",
"cxxFunctionScopedName",
"cxxFunctionStorageClassSpecifierStatic",
"cxxFunctionVirtual",
"cxxTypedef",
"cxxTypedefAccessSpecifier",
"cxxTypedefAPIItemLocation",
"cxxTypedefDeclarationFile",
"cxxTypedefDeclarationFileLine",
"cxxTypedefDefinition",
"cxxTypedefDetail",
"cxxTypedefNameLookup",
"cxxTypedefScopedName",
"cxxVariable",
"cxxVariableAccessSpecifier",
"cxxVariableAPIItemLocation",
"cxxVariableDeclarationFile",
"cxxVariableDeclarationFileLine",
"cxxVariableDeclaredType",
"cxxVariableDefinition",
"cxxVariableDetail",
"cxxVariableNameLookup",
"cxxVariablePrototype",
"cxxVariableReimplemented",
"cxxVariableScopedName",
"cxxVariableStorageClassSpecifierStatic",
"data",
"data-about",
"dd",
"dl",
"dlentry",
"dt",
"entry",
"fig",
"i",
"image",
"keyword",
"keywords",
"li",
"link",
"linktext",
"lq",
"map",
"mapref",
"metadata",
"note",
"ol",
"othermeta",
"p",
"parameter",
"permissions",
"ph",
"platform",
"pre",
"prodinfo",
"prodname",
"prolog",
"publisher",
"qmlAttached",
"qmlDetail",
"qmlImportModule",
"qmlInheritedBy",
"qmlInherits",
"qmlInstantiates",
"qmlMethod",
"qmlMethodDef",
"qmlMethodDetail",
"qmlName",
"qmlProperty",
"qmlPropertyDef",
"qmlPropertyDetail",
"qmlPropertyGroup",
"qmlPropertyGroupDef",
"qmlPropertyGroupDetail",
"qmlQualifier",
"qmlSignal",
"qmlSignalDef",
"qmlSignalDetail",
"qmlSignalHandler",
"qmlSignalHandlerDef",
"qmlSignalHandlerDetail",
"qmlSignature",
"qmlSince",
"qmlType",
"qmlTypeDef",
"qmlTypeDetail",
"related-links",
"resourceid",
"revised",
"row",
"section",
"sectiondiv",
"shortdesc",
"simpletable",
"source",
"stentry",
"sthead",
"strow",
"sub",
"sup",
"table",
"tbody",
"tgroup",
"thead",
"title",
"tm",
"topic",
"topicmeta",
"topicref",
"tt",
"u",
"uicontrol",
"ul",
"unknown",
"vrm",
"vrmlist",
"xref",
""
};
/*!
Composes a string to be used as an href attribute in DITA
XML. It is composed of the file name and the UUID separated
by a '#'. If this node is a class node, the file name is
taken from this node; if this node is a function node, the
file name is taken from the parent node of this node.
*/
QString DitaXmlGenerator::ditaXmlHref(Node* n)
{
QString href;
if ((n->type() == Node::Function) ||
(n->type() == Node::Property) ||
(n->type() == Node::Variable)) {
href = fileBase(n->parent());
}
else {
href = fileBase(n);
}
if (!href.endsWith(".xml") && !href.endsWith(".dita"))
href += ".dita";
return href + QLatin1Char('#') + n->guid();
}
void DitaXmlGenerator::debugPara(const QString& t)
{
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass",t);
xmlWriter().writeCharacters(t);
writeEndTag(); //
}
static bool showBrokenLinks = false;
/*!
Quick, dirty, and very ugly. Unescape \a text
so QXmlStreamWriter::writeCharacters() can put
the escapes back in again!
*/
void DitaXmlGenerator::writeCharacters(const QString& text)
{
QString t = text;
t = t.replace("<","<");
t = t.replace(">",">");
t = t.replace("&","&");
t = t.replace(""","\"");
xmlWriter().writeCharacters(t);
}
/*!
Appends an element to the current XML stream
with the \a href attribute and the \a text.
*/
void DitaXmlGenerator::addLink(const QString& href,
const QStringRef& text,
DitaTag t)
{
if (!href.isEmpty()) {
writeStartTag(t);
// formathtml
writeHrefAttribute(href);
writeCharacters(text.toString());
writeEndTag(); //
}
else {
writeCharacters(text.toString());
}
}
/*!
Push \a t onto the dita tag stack and write the appropriate
start tag to the DITA XML file.
*/
void DitaXmlGenerator::writeStartTag(DitaTag t)
{
xmlWriter().writeStartElement(ditaTags[t]);
tagStack.push(t);
}
/*!
Pop the current DITA tag off the stack, and write the
appropriate end tag to the DITA XML file. If \a t is
not \e DT_NONE (default), then \a t contains the enum
value of the tag that should be on top of the stack.
If the stack is empty, no end tag is written and false
is returned. Otherwise, an end tag is written and true
is returned.
*/
bool DitaXmlGenerator::writeEndTag(DitaTag t)
{
if (tagStack.isEmpty())
return false;
DitaTag top = tagStack.pop();
if (t > DT_NONE && top != t)
qDebug() << "Expected:" << t << "ACTUAL:" << top;
xmlWriter().writeEndElement();
return true;
}
/*!
Return the current DITA element tag, the one
on top of the stack.
*/
DitaXmlGenerator::DitaTag DitaXmlGenerator::currentTag()
{
return tagStack.top();
}
/*!
Write the start \a tag. if \a title is not empty, generate
a GUID from it and write the GUID as the value of the \e{id}
attribute.
Then if \a outputclass is not empty, write it as the value
of the \a outputclass attribute.
Fiunally, set the section nesting level to 1 and return 1.
*/
int DitaXmlGenerator::enterDesc(DitaTag tag, const QString& outputclass, const QString& title)
{
writeStartTag(tag);
if (!title.isEmpty()) {
writeGuidAttribute(title);
//Are there cases where the spectitle is required?
//xmlWriter().writeAttribute("spectitle",title);
}
if (!outputclass.isEmpty())
xmlWriter().writeAttribute("outputclass",outputclass);
sectionNestingLevel = 1;
return sectionNestingLevel;
}
/*!
If the section nesting level is 0, output a \c{}
element with an \e id attribute generated from \a title and
an \e outputclass attribute set to \a outputclass.
If \a title is null, no \e id attribute is output.
If \a outputclass is empty, no \e outputclass attribute
is output.
Finally, increment the section nesting level and return
the new value.
*/
int DitaXmlGenerator::enterSection(const QString& outputclass, const QString& title)
{
if (sectionNestingLevel == 0) {
writeStartTag(DT_section);
if (!title.isEmpty())
writeGuidAttribute(title);
if (!outputclass.isEmpty())
xmlWriter().writeAttribute("outputclass",outputclass);
}
else if (!title.isEmpty()) {
writeStartTag(DT_p);
writeGuidAttribute(title);
if (!outputclass.isEmpty())
xmlWriter().writeAttribute("outputclass",outputclass);
writeCharacters(title);
writeEndTag(); //
}
return ++sectionNestingLevel;
}
/*!
If the section nesting level is greater than 0, decrement
it. If it becomes 0, output a \c {}. Return the
decremented section nesting level.
*/
int DitaXmlGenerator::leaveSection()
{
if (sectionNestingLevel > 0) {
--sectionNestingLevel;
if (sectionNestingLevel == 0)
writeEndTag(); // or
}
return sectionNestingLevel;
}
/*!
Constructs the DITA XML output generator.
*/
DitaXmlGenerator::DitaXmlGenerator()
: inDetailedDescription(false),
inLegaleseText(false),
inObsoleteLink(false),
inTableBody(false),
noLinks(false),
obsoleteLinks(false),
divNestingLevel(0),
sectionNestingLevel(0),
tableColumnCount(0),
funcLeftParen("\\S(\\()"),
nodeTypeMaps(Node::LastType,0),
nodeSubtypeMaps(Node::LastSubtype,0),
pageTypeMaps(Node::OnBeyondZebra,0)
{
}
/*!
Destroys the DITA XML output generator.
*/
DitaXmlGenerator::~DitaXmlGenerator()
{
GuidMaps::iterator i = guidMaps.begin();
while (i != guidMaps.end()) {
delete i.value();
++i;
}
}
/*!
Initializes the DITA XML output generator's data structures
from the configuration class \a config.
*/
void DitaXmlGenerator::initializeGenerator(const Config &config)
{
Generator::initializeGenerator(config);
obsoleteLinks = config.getBool(CONFIG_OBSOLETELINKS);
setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");
style = config.getString(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_STYLE);
postHeader = config.getString(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_POSTHEADER);
postPostHeader = config.getString(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_POSTPOSTHEADER);
footer = config.getString(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_FOOTER);
address = config.getString(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_ADDRESS);
pleaseGenerateMacRef = config.getBool(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_GENERATEMACREFS);
project = config.getString(CONFIG_PROJECT);
projectDescription = config.getString(CONFIG_DESCRIPTION);
if (projectDescription.isEmpty() && !project.isEmpty())
projectDescription = project + " Reference Documentation";
projectUrl = config.getString(CONFIG_URL);
tagFile_ = config.getString(CONFIG_TAGFILE);
#ifndef QT_NO_TEXTCODEC
outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
if (outputEncoding.isEmpty())
outputEncoding = QLatin1String("ISO-8859-1");
outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
#endif
naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE);
if (naturalLanguage.isEmpty())
naturalLanguage = QLatin1String("en");
config.subVarsAndValues("dita.metadata.default",metadataDefaults);
QSet editionNames = config.subVars(CONFIG_EDITION);
QSet::ConstIterator edition = editionNames.constBegin();
while (edition != editionNames.constEnd()) {
QString editionName = *edition;
QStringList editionModules = config.getStringList(CONFIG_EDITION +
Config::dot +
editionName +
Config::dot +
"modules");
QStringList editionGroups = config.getStringList(CONFIG_EDITION +
Config::dot +
editionName +
Config::dot +
"groups");
if (!editionModules.isEmpty())
editionModuleMap[editionName] = editionModules;
if (!editionGroups.isEmpty())
editionGroupMap[editionName] = editionGroups;
++edition;
}
stylesheets = config.getStringList(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_STYLESHEETS);
customHeadElements = config.getStringList(DitaXmlGenerator::format() +
Config::dot +
DITAXMLGENERATOR_CUSTOMHEADELEMENTS);
version = config.getString(CONFIG_VERSION);
vrm = version.split(QLatin1Char('.'));
}
/*!
Gracefully terminates the DITA XML output generator.
*/
void DitaXmlGenerator::terminateGenerator()
{
Generator::terminateGenerator();
}
/*!
Returns "DITAXML".
*/
QString DitaXmlGenerator::format()
{
return "DITAXML";
}
/*!
Calls lookupGuid() to get a GUID for \a text, then writes
it to the XML stream as an "id" attribute, and returns it.
*/
QString DitaXmlGenerator::writeGuidAttribute(QString text)
{
QString guid = lookupGuid(outFileName(),text);
xmlWriter().writeAttribute("id",guid);
return guid;
}
/*!
Write's the GUID for the \a node to the current XML stream
as an "id" attribute. If the \a node doesn't yet have a GUID,
one is generated.
*/
void DitaXmlGenerator::writeGuidAttribute(Node* node)
{
xmlWriter().writeAttribute("id",node->guid());
}
/*!
Looks up \a text in the GUID map. If it finds \a text,
it returns the associated GUID. Otherwise it inserts
\a text into the map with a new GUID, and it returns
the new GUID.
*/
QString DitaXmlGenerator::lookupGuid(QString text)
{
QMap::const_iterator i = name2guidMap.constFind(text);
if (i != name2guidMap.constEnd())
return i.value();
QString guid = Node::cleanId(text);
name2guidMap.insert(text,guid);
return guid;
}
/*!
First, look up the GUID map for \a fileName. If there isn't
a GUID map for \a fileName, create one and insert it into
the map of GUID maps. Then look up \a text in that GUID map.
If \a text is found, return the associated GUID. Otherwise,
insert \a text into the GUID map with a new GUID, and return
the new GUID.
*/
QString DitaXmlGenerator::lookupGuid(const QString& fileName, const QString& text)
{
GuidMap* gm = lookupGuidMap(fileName);
GuidMap::const_iterator i = gm->constFind(text);
if (i != gm->constEnd())
return i.value();
QString guid = Node::cleanId(text);
gm->insert(text,guid);
return guid;
}
/*!
Looks up \a fileName in the map of GUID maps. If it finds
\a fileName, it returns a pointer to the associated GUID
map. Otherwise it creates a new GUID map and inserts it
into the map of GUID maps with \a fileName as its key.
*/
GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
{
GuidMaps::const_iterator i = guidMaps.constFind(fileName);
if (i != guidMaps.constEnd())
return i.value();
GuidMap* gm = new GuidMap;
guidMaps.insert(fileName,gm);
return gm;
}
/*!
Traverses the current tree generating all the DITA XML documentation.
*/
void DitaXmlGenerator::generateDocs()
{
if (!runPrepareOnly()) {
Generator::generateDocs();
generateCollisionPages();
}
if (!runGenerateOnly()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
projectUrl,
projectDescription,
this,
true);
}
if (!runPrepareOnly()) {
writeDitaMap();
/*
Generate the XML tag file, if it was requested.
*/
qdb_->generateTagFile(tagFile_, this);
}
}
static int countTableColumns(const Atom* t)
{
int result = 0;
if (t->type() == Atom::TableHeaderLeft) {
while (t->type() == Atom::TableHeaderLeft) {
int count = 0;
t = t->next();
while (t->type() != Atom::TableHeaderRight) {
if (t->type() == Atom::TableItemLeft) {
for (int i=0; icount(); ++i) {
QString attr = t->string(i);
if (!attr.contains('=')) {
QStringList spans = attr.split(QLatin1Char(','));
if (spans.size() == 2) {
count += spans[0].toInt();
}
else {
++count;
}
}
}
}
t = t->next();
}
if (count > result)
result = count;
t = t->next();
}
}
else if (t->type() == Atom::TableRowLeft) {
while (t->type() != Atom::TableRowRight) {
if (t->type() == Atom::TableItemLeft) {
for (int i=0; icount(); ++i) {
QString attr = t->string(i);
if (!attr.contains('=')) {
QStringList spans = attr.split(QLatin1Char(','));
if (spans.size() == 2) {
result += spans[0].toInt();
}
else {
++result;
}
}
}
}
t = t->next();
}
}
return result;
}
/*!
Generate html from an instance of Atom.
*/
int DitaXmlGenerator::generateAtom(const Atom *atom,
const Node *relative,
CodeMarker *marker)
{
int skipAhead = 0;
QString hx, str;
static bool in_para = false;
QString guid, hc, attr;
switch (atom->type()) {
case Atom::AbstractLeft:
break;
case Atom::AbstractRight:
break;
case Atom::AutoLink:
if (!noLinks && !inLink_ && !inContents_ && !inSectionHeading_) {
const Node* node = 0;
QString link = getLink(atom, relative, &node);
if (!link.isEmpty()) {
beginLink(link);
generateLink(atom, marker);
endLink();
}
else {
writeCharacters(protectEnc(atom->string()));
}
}
else {
writeCharacters(protectEnc(atom->string()));
}
break;
case Atom::BaseName:
break;
case Atom::BriefLeft:
{
Node::Type t = relative->type();
if (inSection()) {
in_para = true;
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","brief");
}
else {
noLinks = true;
writeStartTag(DT_shortdesc);
}
if (t == Node::Property || t == Node::Variable) {
xmlWriter().writeCharacters("This ");
if (relative->type() == Node::Property)
xmlWriter().writeCharacters("property");
else if (relative->type() == Node::Variable)
xmlWriter().writeCharacters("variable");
xmlWriter().writeCharacters(" holds ");
}
if (noLinks) {
atom = atom->next();
while (atom != 0 && atom->type() != Atom::BriefRight) {
if (atom->type() == Atom::String ||
atom->type() == Atom::AutoLink)
str += atom->string();
skipAhead++;
atom = atom->next();
}
if (t == Node::Property || t == Node::Variable)
str[0] = str[0].toLower();
if (str.endsWith(QLatin1Char('.')))
str.truncate(str.length() - 1);
writeCharacters(str + QLatin1Char('.'));
}
}
break;
case Atom::BriefRight:
writeEndTag(); // or
if (in_para)
in_para = false;
noLinks = false;
break;
case Atom::C:
writeStartTag(DT_tt);
if (inLink_) {
writeCharacters(protectEnc(plainCode(atom->string())));
}
else {
writeText(atom->string(), relative);
}
writeEndTag(); // see writeStartElement() above
break;
case Atom::Code:
{
writeStartTag(DT_codeblock);
xmlWriter().writeAttribute("outputclass","cpp");
writeCharacters("\n");
writeText(trimmedTrailing(atom->string()), relative);
writeEndTag(); //
}
break;
case Atom::Qml:
writeStartTag(DT_codeblock);
xmlWriter().writeAttribute("outputclass","qml");
writeCharacters("\n");
writeText(trimmedTrailing(atom->string()), relative);
writeEndTag(); //
break;
case Atom::CodeNew:
writeStartTag(DT_p);
xmlWriter().writeCharacters("you can rewrite it as");
writeEndTag(); //
writeStartTag(DT_codeblock);
writeCharacters("\n");
writeText(trimmedTrailing(atom->string()), relative);
writeEndTag(); //
break;
case Atom::CodeOld:
writeStartTag(DT_p);
xmlWriter().writeCharacters("For example, if you have code like");
writeEndTag(); //
// fallthrough
case Atom::CodeBad:
writeStartTag(DT_codeblock);
writeCharacters("\n");
writeCharacters(trimmedTrailing(plainCode(atom->string())));
writeEndTag(); //
break;
case Atom::DivLeft:
{
bool inStartElement = false;
attr = atom->string();
DitaTag t = currentTag();
if ((t == DT_section) || (t == DT_sectiondiv)) {
writeStartTag(DT_sectiondiv);
divNestingLevel++;
inStartElement = true;
}
else if ((t == DT_body) || (t == DT_bodydiv)) {
writeStartTag(DT_bodydiv);
divNestingLevel++;
inStartElement = true;
}
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;
index = attr.indexOf('"',from);
if (index > from) {
if (!values.isEmpty())
values.append(' ');
values += attr.mid(from,index-from);
from = index+1;
}
}
}
attr = values;
}
}
if (inStartElement)
xmlWriter().writeAttribute("outputclass", attr);
}
break;
case Atom::DivRight:
if ((currentTag() == DT_sectiondiv) || (currentTag() == DT_bodydiv)) {
writeEndTag(); // , , or
if (divNestingLevel > 0)
--divNestingLevel;
}
break;
case Atom::FootnoteLeft:
// ### For now
if (in_para) {
writeEndTag(); //
in_para = false;
}
xmlWriter().writeCharacters("");
break;
case Atom::FormatElse:
case Atom::FormatEndif:
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(); //
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;
index = attr.indexOf('"',from);
if (index > from) {
if (!values.isEmpty())
values.append(' ');
values += attr.mid(from,index-from);
from = index+1;
}
}
}
attr = values;
}
}
xmlWriter().writeAttribute("outputclass", attr);
}
}
break;
case Atom::FormattingRight:
if (atom->string() == ATOM_FORMATTING_LINK) {
endLink();
}
else {
writeEndTag(); // ?
}
break;
case Atom::AnnotatedList:
{
GroupNode* gn = qdb_->getGroup(atom->string());
if (gn)
generateAnnotatedList(relative, marker, gn->members());
}
break;
case Atom::GeneratedList:
if (atom->string() == "annotatedclasses") {
generateAnnotatedList(relative, marker, qdb_->getCppClasses());
}
else if (atom->string() == "classes") {
generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral("Q"));
}
else if (atom->string() == "qmlclasses") {
generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral(""));
}
else if (atom->string().contains("classesbymodule")) {
QString arg = atom->string().trimmed();
QString moduleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
QDocDatabase* qdb = QDocDatabase::qdocDB();
ModuleNode* mn = qdb->findModule(moduleName);
if (mn) {
NodeMap m;
mn->getMemberClasses(m);
if (!m.isEmpty()) {
generateAnnotatedList(relative, marker, m);
}
}
}
else if (atom->string() == "classhierarchy") {
generateClassHierarchy(relative, qdb_->getCppClasses());
}
else if (atom->string() == "compatclasses") {
// "compatclasses" is no longer used. Delete this at some point.
// mws 03/10/2013
generateCompactList(Generic, relative, qdb_->getCompatibilityClasses(), false, QStringLiteral("Q"));
}
else if (atom->string() == "obsoleteclasses") {
generateCompactList(Generic, relative, qdb_->getObsoleteClasses(), false, QStringLiteral("Q"));
}
else if (atom->string() == "obsoleteqmltypes") {
generateCompactList(Generic, relative, qdb_->getObsoleteQmlTypes(), false, QStringLiteral(""));
}
else if (atom->string() == "obsoletecppmembers") {
generateCompactList(Obsolete, relative, qdb_->getClassesWithObsoleteMembers(), false, QStringLiteral("Q"));
}
else if (atom->string() == "obsoleteqmlmembers") {
generateCompactList(Obsolete, relative, qdb_->getQmlTypesWithObsoleteMembers(), false, QStringLiteral(""));
}
else if (atom->string() == "functionindex") {
generateFunctionIndex(relative);
}
else if (atom->string() == "legalese") {
generateLegaleseList(relative, marker);
}
else if (atom->string() == "mainclasses") {
// "mainclasses" is no longer used. Delete this at some point.
// mws 03/10/2013
generateCompactList(Generic, relative, qdb_->getMainClasses(), true, QStringLiteral("Q"));
}
else if (atom->string() == "services") {
// "services" is no longer used. Delete this at some point.
// mws 03/10/2013
generateCompactList(Generic, relative, qdb_->getServiceClasses(), false, QStringLiteral("Q"));
}
else if (atom->string() == "overviews") {
generateOverviewList(relative);
}
else if (atom->string() == "namespaces") {
generateAnnotatedList(relative, marker, qdb_->getNamespaces());
}
else if (atom->string() == "related") {
if (relative && relative->isCollectionNode()) {
const CollectionNode* cn = static_cast(relative);
if (cn)
generateAnnotatedList(cn, marker, cn->members());
}
}
break;
case Atom::SinceList:
{
const NodeMultiMap& nsmap = qdb_->getSinceMap(atom->string());
const NodeMap& ncmap = qdb_->getClassMap(atom->string());
const NodeMap& nqcmap = qdb_->getQmlTypeMap(atom->string());
if (!nsmap.isEmpty()) {
QList sections;
QList::ConstIterator s;
for (int i=0; itype()) {
case Node::QmlType:
sections[QmlClass].appendMember((Node*)node);
break;
case Node::Namespace:
sections[Namespace].appendMember((Node*)node);
break;
case Node::Class:
sections[Class].appendMember((Node*)node);
break;
case Node::Enum:
sections[Enum].appendMember((Node*)node);
break;
case Node::Typedef:
sections[Typedef].appendMember((Node*)node);
break;
case Node::Function: {
const FunctionNode* fn = static_cast(node);
if (fn->isMacro())
sections[Macro].appendMember((Node*)node);
else {
Node* p = fn->parent();
if (p) {
if (p->type() == Node::Class)
sections[MemberFunction].appendMember((Node*)node);
else if (p->type() == Node::Namespace) {
if (p->name().isEmpty())
sections[GlobalFunction].appendMember((Node*)node);
else
sections[NamespaceFunction].appendMember((Node*)node);
}
else
sections[GlobalFunction].appendMember((Node*)node);
}
else
sections[GlobalFunction].appendMember((Node*)node);
}
break;
}
case Node::Property:
sections[Property].appendMember((Node*)node);
break;
case Node::Variable:
sections[Variable].appendMember((Node*)node);
break;
case Node::QmlProperty:
sections[QmlProperty].appendMember((Node*)node);
break;
case Node::QmlSignal:
sections[QmlSignal].appendMember((Node*)node);
break;
case Node::QmlSignalHandler:
sections[QmlSignalHandler].appendMember((Node*)node);
break;
case Node::QmlMethod:
sections[QmlMethod].appendMember((Node*)node);
break;
default:
break;
}
++n;
}
writeStartTag(DT_ul);
s = sections.constBegin();
while (s != sections.constEnd()) {
if (!(*s).members.isEmpty()) {
QString li = outFileName() + QLatin1Char('#') + Doc::canonicalTitle((*s).name);
writeXrefListItem(li, (*s).name);
}
++s;
}
writeEndTag(); //
int idx = 0;
s = sections.constBegin();
while (s != sections.constEnd()) {
if (!(*s).members.isEmpty()) {
writeStartTag(DT_p);
writeGuidAttribute(Doc::canonicalTitle((*s).name));
xmlWriter().writeAttribute("outputclass","h3");
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
if (idx == Class)
generateCompactList(Generic, 0, ncmap, false, QString("Q"));
else if (idx == QmlClass)
generateCompactList(Generic, 0, nqcmap, false, QString("Q"));
else if (idx == MemberFunction) {
ParentMaps parentmaps;
ParentMaps::iterator pmap;
NodeList::const_iterator i = s->members.constBegin();
while (i != s->members.constEnd()) {
Node* p = (*i)->parent();
pmap = parentmaps.find(p);
if (pmap == parentmaps.end())
pmap = parentmaps.insert(p,NodeMultiMap());
pmap->insert((*i)->name(),(*i));
++i;
}
pmap = parentmaps.begin();
while (pmap != parentmaps.end()) {
NodeList nlist = pmap->values();
writeStartTag(DT_p);
xmlWriter().writeCharacters("Class ");
writeStartTag(DT_xref);
// formathtml
xmlWriter().writeAttribute("href",linkForNode(pmap.key(), 0));
QStringList pieces = pmap.key()->fullName().split("::");
writeCharacters(protectEnc(pieces.last()));
writeEndTag(); //
xmlWriter().writeCharacters(":");
writeEndTag(); //
generateSection(nlist, 0, marker, CodeMarker::Summary);
++pmap;
}
}
else {
generateSection(s->members, 0, marker, CodeMarker::Summary);
}
}
++idx;
++s;
}
}
}
break;
case Atom::BR:
// DITA XML can't do
break;
case Atom::HR: //
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","horizontal-rule");
writeEndTag(); //
break;
case Atom::Image:
case Atom::InlineImage:
{
QString fileName = imageFileName(relative, atom->string());
QString text;
if (atom->next() != 0)
text = atom->next()->string();
if (fileName.isEmpty()) {
relative->location().warning(tr("Missing image: %1").arg(protectEnc(atom->string())));
QString images = "images";
if (!atom->string().isEmpty() && atom->string()[0] != '/')
images.append(QLatin1Char('/'));
fileName = images + atom->string();
}
if (relative && relative->isExample()) {
const ExampleNode* cen = static_cast(relative);
if (cen->imageFileName().isEmpty()) {
ExampleNode* en = const_cast(cen);
en->setImageFileName(fileName);
}
}
if (currentTag() != DT_xref && atom->type() != Atom::InlineImage)
writeStartTag(DT_fig);
writeStartTag(DT_image);
writeHrefAttribute(protectEnc(fileName));
if (atom->type() == Atom::Image) {
xmlWriter().writeAttribute("placement","break");
xmlWriter().writeAttribute("align","center");
}
if (!text.isEmpty()) {
writeStartTag(DT_alt);
writeCharacters(protectEnc(text));
writeEndTag(); //
}
writeEndTag(); //
if (currentTag() != DT_xref && atom->type() != Atom::InlineImage)
writeEndTag(); //
}
break;
case Atom::ImageText:
// nothing
break;
case Atom::ImportantLeft:
writeStartTag(DT_note);
xmlWriter().writeAttribute("type","important");
break;
case Atom::ImportantRight:
writeEndTag(); //
break;
case Atom::NoteLeft:
writeStartTag(DT_note);
xmlWriter().writeAttribute("type","note");
break;
case Atom::NoteRight:
writeEndTag(); //
break;
case Atom::LegaleseLeft:
inLegaleseText = true;
break;
case Atom::LegaleseRight:
inLegaleseText = false;
break;
case Atom::LineBreak:
//xmlWriter().writeEmptyElement("br");
break;
case Atom::Link:
{
const Node *node = 0;
QString myLink = getLink(atom, relative, &node);
//if (myLink.isEmpty())
//myLink = getCollisionLink(atom);
if (myLink.isEmpty() && !noLinkErrors())
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;
}
break;
case Atom::LinkNode:
{
const Node* node = CodeMarker::nodeForString(atom->string());
beginLink(linkForNode(node, relative));
skipAhead = 1;
}
break;
case Atom::ListLeft:
if (in_para) {
writeEndTag(); //
in_para = false;
}
if (atom->string() == ATOM_LIST_BULLET) {
writeStartTag(DT_ul);
}
else if (atom->string() == ATOM_LIST_TAG) {
writeStartTag(DT_dl);
}
else if (atom->string() == ATOM_LIST_VALUE) {
threeColumnEnumValueTable_ = isThreeColumnEnumValueTable(atom);
if (threeColumnEnumValueTable_) {
writeStartTag(DT_simpletable);
xmlWriter().writeAttribute("outputclass","valuelist");
writeStartTag(DT_sthead);
writeStartTag(DT_stentry);
xmlWriter().writeCharacters("Constant");
writeEndTag(); //
writeStartTag(DT_stentry);
xmlWriter().writeCharacters("Value");
writeEndTag(); //
writeStartTag(DT_stentry);
xmlWriter().writeCharacters("Description");
writeEndTag(); //
writeEndTag(); //
}
else {
writeStartTag(DT_simpletable);
xmlWriter().writeAttribute("outputclass","valuelist");
writeStartTag(DT_sthead);
writeStartTag(DT_stentry);
xmlWriter().writeCharacters("Constant");
writeEndTag(); //
writeStartTag(DT_stentry);
xmlWriter().writeCharacters("Value");
writeEndTag(); //
writeEndTag(); //
}
}
else {
writeStartTag(DT_ol);
if (atom->string() == ATOM_LIST_UPPERALPHA)
xmlWriter().writeAttribute("outputclass","upperalpha");
else if (atom->string() == ATOM_LIST_LOWERALPHA)
xmlWriter().writeAttribute("outputclass","loweralpha");
else if (atom->string() == ATOM_LIST_UPPERROMAN)
xmlWriter().writeAttribute("outputclass","upperroman");
else if (atom->string() == ATOM_LIST_LOWERROMAN)
xmlWriter().writeAttribute("outputclass","lowerroman");
else // (atom->string() == ATOM_LIST_NUMERIC)
xmlWriter().writeAttribute("outputclass","numeric");
if (atom->next() != 0 && atom->next()->string().toInt() != 1) {
/*
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 only used in the
qdoc manual.
*/
//xmlWriter().writeAttribute("start",atom->next()->string());
}
}
break;
case Atom::ListItemNumber:
// nothing
break;
case Atom::ListTagLeft:
if (atom->string() == ATOM_LIST_TAG) {
writeStartTag(DT_dt);
}
else { // (atom->string() == ATOM_LIST_VALUE)
writeStartTag(DT_strow);
writeStartTag(DT_stentry);
writeStartTag(DT_tt);
writeCharacters(protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),
relative))));
writeEndTag(); //
writeEndTag(); //
writeStartTag(DT_stentry);
QString itemValue;
if (relative->type() == Node::Enum) {
const EnumNode *enume = static_cast(relative);
itemValue = enume->itemValue(atom->next()->string());
}
if (itemValue.isEmpty())
xmlWriter().writeCharacters("?");
else {
writeStartTag(DT_tt);
writeCharacters(protectEnc(itemValue));
writeEndTag(); //
}
skipAhead = 1;
}
break;
case Atom::ListTagRight:
if (atom->string() == ATOM_LIST_TAG)
writeEndTag(); //
break;
case Atom::ListItemLeft:
if (atom->string() == ATOM_LIST_TAG) {
writeStartTag(DT_dd);
}
else if (atom->string() == ATOM_LIST_VALUE) {
if (threeColumnEnumValueTable_) {
writeEndTag(); //
writeStartTag(DT_stentry);
}
}
else {
writeStartTag(DT_li);
}
if (matchAhead(atom, Atom::ParaLeft))
skipAhead = 1;
break;
case Atom::ListItemRight:
if (atom->string() == ATOM_LIST_TAG) {
writeEndTag(); //
}
else if (atom->string() == ATOM_LIST_VALUE) {
writeEndTag(); //
writeEndTag(); //
}
else {
writeEndTag(); //
}
break;
case Atom::ListRight:
if (atom->string() == ATOM_LIST_BULLET) {
writeEndTag(); //
}
else if (atom->string() == ATOM_LIST_TAG) {
writeEndTag(); //
}
else if (atom->string() == ATOM_LIST_VALUE) {
writeEndTag(); //
}
else {
writeEndTag(); //
}
break;
case Atom::Nop:
// nothing
break;
case Atom::ParaLeft:
writeStartTag(DT_p);
if (inLegaleseText)
xmlWriter().writeAttribute("outputclass","legalese");
in_para = true;
break;
case Atom::ParaRight:
endLink();
if (in_para) {
writeEndTag(); //
in_para = false;
}
break;
case Atom::QuotationLeft:
writeStartTag(DT_lq);
break;
case Atom::QuotationRight:
writeEndTag(); //
break;
case Atom::RawString:
if (atom->string() == " ")
break;
if (atom->string().startsWith(QLatin1Char('&')))
writeCharacters(atom->string());
else if (atom->string() == "*") {
writeStartTag(DT_sup);
writeCharacters("*");
writeEndTag(); //
}
else if (atom->string() == "®") {
writeStartTag(DT_tm);
xmlWriter().writeAttribute("tmtype","reg");
writeEndTag(); //
}
else {
writeStartTag(DT_pre);
xmlWriter().writeAttribute("outputclass","raw-html");
writeCharacters(atom->string());
writeEndTag(); //
}
break;
case Atom::SectionLeft:
enterSection("details",QString());
break;
case Atom::SectionRight:
leaveSection();
break;
case Atom::SectionHeadingLeft:
{
writeStartTag(DT_p);
QString id = Text::sectionHeading(atom).toString();
id = stripMarkup(id);
id = Doc::canonicalTitle(id);
writeGuidAttribute(id);
hx = QLatin1Char('h') + QString::number(atom->string().toInt() + hOffset(relative));
xmlWriter().writeAttribute("outputclass",hx);
inSectionHeading_ = true;
}
break;
case Atom::SectionHeadingRight:
writeEndTag(); // (see case Atom::SectionHeadingLeft)
inSectionHeading_ = false;
break;
case Atom::SidebarLeft:
// nothing
break;
case Atom::SidebarRight:
// nothing
break;
case Atom::String:
if (inLink_ && !inContents_ && !inSectionHeading_) {
generateLink(atom, marker);
}
else {
writeCharacters(atom->string());
}
break;
case Atom::TableLeft:
{
QString attr;
if ((atom->count() > 0) && (atom->string(0) == "borderless"))
attr = "borderless";
else if ((atom->count() > 1) && (atom->string(1) == "borderless"))
attr = "borderless";
if (in_para) {
writeEndTag(); //
in_para = false;
}
writeStartTag(DT_table);
if (!attr.isEmpty())
xmlWriter().writeAttribute("outputclass",attr);
numTableRows_ = 0;
if (tableColumnCount != 0) {
qDebug() << "ERROR: Nested tables!";
tableColumnCount = 0;
}
tableColumnCount = countTableColumns(atom->next());
writeStartTag(DT_tgroup);
xmlWriter().writeAttribute("cols",QString::number(tableColumnCount));
for (int i = 0; i < tableColumnCount; i++) {
writeStartTag(DT_colspec);
xmlWriter().writeAttribute("colname", QStringLiteral("col%1").arg(i));
xmlWriter().writeAttribute("colnum", QString::number(i));
xmlWriter().writeAttribute("colwidth", QStringLiteral("1*"));
writeEndTag(); // DT_colspec
}
inTableHeader_ = false;
inTableBody = false;
}
break;
case Atom::TableRight:
writeEndTag(); //
writeEndTag(); //
writeEndTag(); //
inTableHeader_ = false;
inTableBody = false;
tableColumnCount = 0;
currentColumn = 0;
break;
case Atom::TableHeaderLeft:
if (inTableBody) {
writeEndTag(); //
writeEndTag(); //
writeEndTag(); //
inTableHeader_ = false;
inTableBody = false;
tableColumnCount = 0;
writeStartTag(DT_table);
numTableRows_ = 0;
tableColumnCount = countTableColumns(atom);
writeStartTag(DT_tgroup);
xmlWriter().writeAttribute("cols",QString::number(tableColumnCount));
}
currentColumn = 0;
writeStartTag(DT_thead);
xmlWriter().writeAttribute("valign","top");
writeStartTag(DT_row);
xmlWriter().writeAttribute("valign","top");
inTableHeader_ = true;
inTableBody = false;
break;
case Atom::TableHeaderRight:
writeEndTag(); //
if (matchAhead(atom, Atom::TableHeaderLeft)) {
skipAhead = 1;
writeStartTag(DT_row);
xmlWriter().writeAttribute("valign","top");
}
else {
writeEndTag(); //
inTableHeader_ = false;
inTableBody = true;
writeStartTag(DT_tbody);
}
break;
case Atom::TableRowLeft:
if (!inTableHeader_ && !inTableBody) {
inTableBody = true;
writeStartTag(DT_tbody);
}
currentColumn = 0;
writeStartTag(DT_row);
attr = atom->string();
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;
index = attr.indexOf('"',from);
if (index > from) {
if (!values.isEmpty())
values.append(' ');
values += attr.mid(from,index-from);
from = index+1;
}
}
}
attr = values;
}
xmlWriter().writeAttribute("outputclass", attr);
}
xmlWriter().writeAttribute("valign","top");
break;
case Atom::TableRowRight:
writeEndTag(); //
break;
case Atom::TableItemLeft:
{
QString values;
writeStartTag(DT_entry);
for (int i=0; icount(); ++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;
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) {
xmlWriter().writeAttribute("namest",QStringLiteral("col%1").arg(currentColumn));
xmlWriter().writeAttribute("nameend",QStringLiteral("col%1")
.arg(currentColumn + (spans[0].toInt() - 1)));
}
if (spans[1].toInt()>1)
xmlWriter().writeAttribute("morerows",spans[1].simplified());
currentColumn += spans[0].toInt();
}
}
}
if (!values.isEmpty())
xmlWriter().writeAttribute("outputclass",values);
if (matchAhead(atom, Atom::ParaLeft))
skipAhead = 1;
}
break;
case Atom::TableItemRight:
if (inTableHeader_) {
writeEndTag(); //
}
else {
writeEndTag(); //
}
if (matchAhead(atom, Atom::ParaLeft))
skipAhead = 1;
break;
case Atom::TableOfContents:
{
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 = qdb_->findNodeForTarget(path, relative);
if (!node)
relative->doc().location().warning(tr("Cannot link to '%1'").arg(path));
}
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) {
writeEndTag(); //
in_para = false;
}
writeStartTag(DT_p);
writeGuidAttribute(Doc::canonicalTitle(atom->string()));
xmlWriter().writeAttribute("outputclass","target");
//xmlWriter().writeCharacters(protectEnc(atom->string()));
writeEndTag(); //
break;
case Atom::UnhandledFormat:
writeStartTag(DT_b);
xmlWriter().writeAttribute("outputclass","error");
xmlWriter().writeCharacters("");
writeEndTag(); //
break;
case Atom::UnknownCommand:
writeStartTag(DT_b);
xmlWriter().writeAttribute("outputclass","error unknown-command");
writeCharacters(protectEnc(atom->string()));
writeEndTag(); //
break;
case Atom::QmlText:
case Atom::EndQmlText:
// don't do anything with these. They are just tags.
break;
default:
// unknownAtom(atom);
break;
}
return skipAhead;
}
/*!
Generate a element (and all the stuff inside it)
for the C++ class represented by \a innerNode. \a marker is
for marking up the code. I don't know what that means exactly.
*/
void
DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
QList::ConstIterator s;
QString title;
QString rawTitle;
QString fullTitle;
if (inner->type() == Node::Namespace) {
const NamespaceNode* nsn = const_cast(static_cast(inner));
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
title = rawTitle + " Namespace";
/*
Note: Because the C++ specialization we are using
has no element, we are using the
element with an outputclass attribute
set to "namespace" .
*/
generateHeader(inner, fullTitle);
generateBrief(inner, marker); //
writeProlog(inner);
writeStartTag(DT_cxxClassDetail);
writeStartTag(DT_cxxClassDefinition);
writeLocation(nsn);
writeEndTag(); //
enterDesc(DT_apiDesc,QString(),title);
generateStatus(nsn, marker);
generateThreadSafeness(nsn, marker);
generateSince(nsn, marker);
enterSection(QString(), QString());
generateBody(nsn, marker);
generateAlsoList(nsn, marker);
leaveSection();
leaveSection(); //
bool needOtherSection = false;
QList summarySections;
summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
if (!summarySections.isEmpty()) {
enterSection("redundant",QString());
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
if (!s->inherited.isEmpty())
needOtherSection = true;
}
else {
QString attr;
if (!s->members.isEmpty()) {
writeStartTag(DT_p);
attr = cleanRef((*s).name).toLower() + " h2";
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
generateSection(s->members, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
if (!s->reimpMembers.isEmpty()) {
QString name = QString("Reimplemented ") + (*s).name;
attr = cleanRef(name).toLower() + " h2";
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc(name));
writeEndTag(); //
generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
}
++s;
}
if (needOtherSection) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner);
++s;
}
}
leaveSection();
}
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.constBegin();
while (s != detailSections.constEnd()) {
if ((*s).name == "Classes") {
writeNestedClasses((*s),nsn);
break;
}
++s;
}
s = detailSections.constBegin();
while (s != detailSections.constEnd()) {
if ((*s).name == "Function Documentation") {
writeFunctions((*s),nsn,marker);
}
else if ((*s).name == "Type Documentation") {
writeEnumerations((*s),marker);
writeTypedefs((*s),marker);
}
else if ((*s).name == "Namespaces") {
qDebug() << "Nested namespaces" << outFileName();
}
else if ((*s).name == "Macro Documentation") {
//writeMacros((*s),marker);
}
++s;
}
generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); //
}
else if (inner->type() == Node::Class) {
const ClassNode* cn = const_cast(static_cast(inner));
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
title = rawTitle + " Class";
generateHeader(inner, fullTitle);
generateBrief(inner, marker); //
writeProlog(inner);
writeStartTag(DT_cxxClassDetail);
writeStartTag(DT_cxxClassDefinition);
writeStartTag(DT_cxxClassAccessSpecifier);
xmlWriter().writeAttribute("value",inner->accessString());
writeEndTag(); //
if (cn->isAbstract()) {
writeStartTag(DT_cxxClassAbstract);
xmlWriter().writeAttribute("name","abstract");
xmlWriter().writeAttribute("value","abstract");
writeEndTag(); //
}
writeDerivations(cn); //
// not included:
writeLocation(cn);
writeEndTag(); //
enterDesc(DT_apiDesc,QString(),title);
generateStatus(cn, marker);
generateInherits(cn, marker);
generateInheritedBy(cn, marker);
generateThreadSafeness(cn, marker);
generateSince(cn, marker);
enterSection(QString(), QString());
generateBody(cn, marker);
generateAlsoList(cn, marker);
leaveSection();
leaveSection(); //
bool needOtherSection = false;
QList summarySections;
summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
if (!summarySections.isEmpty()) {
enterSection("redundant",QString());
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
if (!s->inherited.isEmpty())
needOtherSection = true;
}
else {
QString attr;
if (!s->members.isEmpty()) {
writeStartTag(DT_p);
attr = cleanRef((*s).name).toLower() + " h2";
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
generateSection(s->members, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
if (!s->reimpMembers.isEmpty()) {
QString name = QString("Reimplemented ") + (*s).name;
attr = cleanRef(name).toLower() + " h2";
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc(name));
writeEndTag(); //
generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
}
++s;
}
if (needOtherSection) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner);
++s;
}
}
leaveSection();
}
// not included: or
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.constBegin();
while (s != detailSections.constEnd()) {
if ((*s).name == "Member Function Documentation") {
writeFunctions((*s),cn,marker);
}
else if ((*s).name == "Member Type Documentation") {
writeEnumerations((*s),marker);
writeTypedefs((*s),marker);
}
else if ((*s).name == "Member Variable Documentation") {
writeDataMembers((*s),marker);
}
else if ((*s).name == "Property Documentation") {
writeProperties((*s),marker);
}
else if ((*s).name == "Macro Documentation") {
//writeMacros((*s),marker);
}
else if ((*s).name == "Related Non-Members") {
QString attribute("related-non-member");
writeFunctions((*s),cn,marker,attribute);
}
++s;
}
generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); //
}
else if (inner->isHeaderFile()) {
const DocNode* dn = const_cast(static_cast(inner));
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
title = rawTitle;
/*
Note: Because the C++ specialization we are using
has no element, we are using the
element with an outputclass attribute
set to "headerfile" .
*/
generateHeader(inner, fullTitle);
generateBrief(inner, marker); //
writeProlog(inner);
writeStartTag(DT_cxxClassDetail);
enterDesc(DT_apiDesc,QString(),title);
generateStatus(dn, marker);
generateThreadSafeness(dn, marker);
generateSince(dn, marker);
generateSince(dn, marker);
enterSection(QString(), QString());
generateBody(dn, marker);
generateAlsoList(dn, marker);
leaveSection();
leaveSection(); //
bool needOtherSection = false;
QList summarySections;
summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
if (!summarySections.isEmpty()) {
enterSection("redundant",QString());
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
if (!s->inherited.isEmpty())
needOtherSection = true;
}
else {
QString attr;
if (!s->members.isEmpty()) {
writeStartTag(DT_p);
attr = cleanRef((*s).name).toLower() + " h2";
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
generateSection(s->members, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
if (!s->reimpMembers.isEmpty()) {
QString name = QString("Reimplemented ") + (*s).name;
attr = cleanRef(name).toLower() + " h2";
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc(name));
writeEndTag(); //
generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
generateSectionInheritedList(*s, inner);
}
}
++s;
}
if (needOtherSection) {
enterSection("additional-inherited-members redundant",QString());
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.constBegin();
while (s != summarySections.constEnd()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner);
++s;
}
}
leaveSection();
}
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.constBegin();
while (s != detailSections.constEnd()) {
if ((*s).name == "Classes") {
writeNestedClasses((*s),dn);
break;
}
++s;
}
s = detailSections.constBegin();
while (s != detailSections.constEnd()) {
if ((*s).name == "Function Documentation") {
writeFunctions((*s),dn,marker);
}
else if ((*s).name == "Type Documentation") {
writeEnumerations((*s),marker);
writeTypedefs((*s),marker);
}
else if ((*s).name == "Namespaces") {
qDebug() << "Nested namespaces" << outFileName();
}
else if ((*s).name == "Macro Documentation") {
//writeMacros((*s),marker);
}
++s;
}
generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); //
}
else if (inner->isQmlType()) {
QmlClassNode* qcn = const_cast(static_cast(inner));
ClassNode* cn = qcn->classNode();
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
title = rawTitle + " Type";
Node::clearPropertyGroupCount();
generateHeader(inner, fullTitle);
generateBrief(inner, marker); //
writeProlog(inner);
writeStartTag(DT_qmlTypeDetail);
generateQmlModuleDef(qcn);
generateQmlInherits(qcn,marker);
generateQmlInheritedBy(qcn, marker);
generateQmlInstantiates(qcn,marker);
generateQmlSince(qcn);
enterDesc(DT_apiDesc,QString(),title);
enterSection(QString(), QString());
generateBody(qcn, marker);
if (cn) {
generateQmlText(cn->doc().body(), cn, marker, qcn->name());
generateAlsoList(cn, marker);
}
leaveSection();
leaveSection(); //
writeEndTag(); //
QList members = marker->qmlSections(qcn,CodeMarker::Detailed);
if (!members.isEmpty()) {
s = members.constBegin();
while (s != members.constEnd()) {
if (!s->members.isEmpty()) {
NodeList::ConstIterator m = (*s).members.constBegin();
while (m != (*s).members.constEnd()) {
generateDetailedQmlMember(*m, qcn, marker);
++m;
}
}
++s;
}
}
writeEndTag(); //
}
}
/*!
Generate the DITA page for a qdoc file that doesn't map
to an underlying c++ file.
*/
void DitaXmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
{
QList sections;
QList::const_iterator s;
QString fullTitle = "QML Basic Type: " + qbtn->fullTitle();
generateHeader(qbtn, fullTitle);
generateBrief(qbtn, marker); //
writeProlog(qbtn);
writeStartTag(DT_body);
enterSection(QString(), QString());
if (!qbtn->doc().isEmpty()) {
generateBody(qbtn, marker);
generateAlsoList(qbtn, marker);
}
leaveSection(); //
if (!writeEndTag()) { //