/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia 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.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*
ditaxmlgenerator.cpp
*/
#include "codemarker.h"
#include "codeparser.h"
#include "ditaxmlgenerator.h"
#include "node.h"
#include "quoter.h"
#include "separator.h"
#include "tree.h"
#include
#include
#include
#include
#include
#include
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",
"apiDesc",
"APIMap",
"apiName",
"apiRelation",
"audience",
"author",
"b",
"body",
"bodydiv",
"brand",
"category",
"codeblock",
"comment",
"component",
"copyrholder",
"copyright",
"copyryear",
"created",
"critdates",
"cxxAPIMap",
"cxxClass",
"cxxClassAbstract",
"cxxClassAccessSpecifier",
"cxxClassAPIItemLocation",
"cxxClassBaseClass",
"cxxClassDeclarationFile",
"cxxClassDeclarationFileLine",
"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",
"cxxEnumerationDefinition",
"cxxEnumerationDefinitionFile",
"cxxEnumerationDefinitionFileLineStart",
"cxxEnumerationDefinitionFileLineEnd",
"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",
"metadata",
"ol",
"othermeta",
"p",
"parameter",
"permissions",
"ph",
"platform",
"pre",
"prodinfo",
"prodname",
"prolog",
"publisher",
"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",
"ul",
"unknown",
"vrm",
"vrmlist",
"xref",
""
};
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
xmlWriter().writeAttribute("href", 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.
*/
void DitaXmlGenerator::writeEndTag(DitaTag t)
{
DitaTag top = tagStack.pop();
if (t > DT_NONE && top != t)
qDebug() << "Expected:" << t << "ACTUAL:" << top;
xmlWriter().writeEndElement();
}
/*!
Return the current DITA element tag, the one
on top of the stack.
*/
DitaXmlGenerator::DitaTag DitaXmlGenerator::currentTag()
{
return tagStack.top();
}
/*!
Write the start tag \c{}. if \a title is not
empty, generate a GUID from it and write the GUID as the
value of the \e{id} attribute. Then write \a title as
the value of the \e {spectitle} 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::enterApiDesc(const QString& outputclass, const QString& title)
{
writeStartTag(DT_apiDesc);
if (!title.isEmpty()) {
writeGuidAttribute(title);
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;
}
/*!
The default constructor.
*/
DitaXmlGenerator::DitaXmlGenerator()
: inContents(false),
inDetailedDescription(false),
inLegaleseText(false),
inLink(false),
inObsoleteLink(false),
inSectionHeading(false),
inTableHeader(false),
inTableBody(false),
noLinks(false),
obsoleteLinks(false),
offlineDocs(true),
threeColumnEnumValueTable(true),
codeIndent(0),
numTableRows(0),
divNestingLevel(0),
sectionNestingLevel(0),
tableColumnCount(0),
funcLeftParen("\\S(\\()"),
myTree(0)
{
// nothing yet.
}
/*!
The destructor has nothing to do.
*/
DitaXmlGenerator::~DitaXmlGenerator()
{
GuidMaps::iterator i = guidMaps.begin();
while (i != guidMaps.end()) {
delete i.value();
++i;
}
}
/*!
A lot of internal structures are initialized.
*/
void DitaXmlGenerator::initializeGenerator(const Config &config)
{
Generator::initializeGenerator(config);
obsoleteLinks = config.getBool(QLatin1String(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);
outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
if (outputEncoding.isEmpty())
outputEncoding = QLatin1String("ISO-8859-1");
outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
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.begin();
while (edition != editionNames.end()) {
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);
codeIndent = config.getInt(CONFIG_CODEINDENT);
version = config.getString(CONFIG_VERSION);
vrm = version.split(".");
}
/*!
All this does is call the same function in the base class.
*/
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.find(text);
if (i != name2guidMap.end())
return i.value();
QString t = QUuid::createUuid().toString();
QString guid = "id-" + t.mid(1,t.length()-2);
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->find(text);
if (i != gm->end())
return i.value();
QString t = QUuid::createUuid().toString();
QString guid = "id-" + t.mid(1,t.length()-2);
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.find(fileName);
if (i != guidMaps.end())
return i.value();
GuidMap* gm = new GuidMap;
guidMaps.insert(fileName,gm);
return gm;
}
/*!
This is where the DITA XML files are written.
\note The file generation is done in the base class,
PageGenerator::generateTree().
*/
void DitaXmlGenerator::generateTree(const Tree *tree)
{
myTree = tree;
nonCompatClasses.clear();
mainClasses.clear();
compatClasses.clear();
obsoleteClasses.clear();
moduleClassMap.clear();
moduleNamespaceMap.clear();
funcIndex.clear();
legaleseTexts.clear();
serviceClasses.clear();
qmlClasses.clear();
findAllClasses(tree->root());
findAllFunctions(tree->root());
findAllLegaleseTexts(tree->root());
findAllNamespaces(tree->root());
findAllSince(tree->root());
PageGenerator::generateTree(tree);
writeDitaMap();
}
void DitaXmlGenerator::startText(const Node* /* relative */,
CodeMarker* /* marker */)
{
inLink = false;
inContents = false;
inSectionHeading = false;
inTableHeader = false;
numTableRows = 0;
threeColumnEnumValueTable = true;
link.clear();
sectionNumber.clear();
}
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)
++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)
++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, marker, &node);
if (!link.isEmpty()) {
beginLink(link);
generateLink(atom, relative, marker);
endLink();
}
else {
writeCharacters(protectEnc(atom->string()));
}
}
else {
writeCharacters(protectEnc(atom->string()));
}
break;
case Atom::BaseName:
break;
case Atom::BriefLeft:
//if (relative->type() == Node::Fake) {
//skipAhead = skipAtoms(atom, Atom::BriefRight);
//break;
//}
if (inSection()) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","brief");
}
else {
noLinks = true;
writeStartTag(DT_shortdesc);
}
if (relative->type() == Node::Property ||
relative->type() == 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();
}
str[0] = str[0].toLower();
if (str.right(1) == ".")
str.truncate(str.length() - 1);
writeCharacters(str + ".");
}
break;
case Atom::BriefRight:
// if (relative->type() != Node::Fake)
writeEndTag(); // or
noLinks = false;
break;
case Atom::C:
writeStartTag(DT_tt);
if (inLink) {
writeCharacters(protectEnc(plainCode(atom->string())));
}
else {
writeText(atom->string(), marker, relative);
}
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(); //
}
break;
case Atom::Qml:
writeStartTag(DT_codeblock);
xmlWriter().writeAttribute("outputclass","qml");
writeText(trimmedTrailing(atom->string()), marker, relative);
writeEndTag(); //
break;
case Atom::CodeNew:
writeStartTag(DT_p);
xmlWriter().writeCharacters("you can rewrite it as");
writeEndTag(); //
writeStartTag(DT_codeblock);
writeText(trimmedTrailing(atom->string()), marker, 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(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_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:
{
QList values = myTree->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);
}
break;
case Atom::GeneratedList:
if (atom->string() == "annotatedclasses") {
generateAnnotatedList(relative, marker, nonCompatClasses);
}
else if (atom->string() == "classes") {
generateCompactList(relative, marker, nonCompatClasses, true);
}
else if (atom->string() == "qmlclasses") {
generateCompactList(relative, marker, qmlClasses, true);
}
else if (atom->string().contains("classesbymodule")) {
QString arg = atom->string().trimmed();
QString moduleName = atom->string().mid(atom->string().indexOf(
"classesbymodule") + 15).trimmed();
if (moduleClassMap.contains(moduleName))
generateAnnotatedList(relative, marker, moduleClassMap[moduleName]);
}
else if (atom->string().contains("classesbyedition")) {
QString arg = atom->string().trimmed();
QString editionName = atom->string().mid(atom->string().indexOf(
"classesbyedition") + 16).trimmed();
if (editionModuleMap.contains(editionName)) {
// Add all classes in the modules listed for that edition.
NodeMap editionClasses;
foreach (const QString &moduleName, editionModuleMap[editionName]) {
if (moduleClassMap.contains(moduleName))
editionClasses.unite(moduleClassMap[moduleName]);
}
// Add additional groups and remove groups of classes that
// should be excluded from the edition.
QMultiMap groups = myTree->groups();
foreach (const QString &groupName, editionGroupMap[editionName]) {
QList groupClasses;
if (groupName.startsWith("-")) {
groupClasses = groups.values(groupName.mid(1));
foreach (const Node *node, groupClasses)
editionClasses.remove(node->name());
}
else {
groupClasses = groups.values(groupName);
foreach (const Node *node, groupClasses)
editionClasses.insert(node->name(), node);
}
}
generateAnnotatedList(relative, marker, editionClasses);
}
}
else if (atom->string() == "classhierarchy") {
generateClassHierarchy(relative, marker, nonCompatClasses);
}
else if (atom->string() == "compatclasses") {
generateCompactList(relative, marker, compatClasses, false);
}
else if (atom->string() == "obsoleteclasses") {
generateCompactList(relative, marker, obsoleteClasses, false);
}
else if (atom->string() == "functionindex") {
generateFunctionIndex(relative, marker);
}
else if (atom->string() == "legalese") {
generateLegaleseList(relative, marker);
}
else if (atom->string() == "mainclasses") {
generateCompactList(relative, marker, mainClasses, true);
}
else if (atom->string() == "services") {
generateCompactList(relative, marker, serviceClasses, false);
}
else if (atom->string() == "overviews") {
generateOverviewList(relative, marker);
}
else if (atom->string() == "namespaces") {
generateAnnotatedList(relative, marker, namespaceIndex);
}
else if (atom->string() == "related") {
const FakeNode *fake = static_cast(relative);
if (fake && !fake->groupMembers().isEmpty()) {
NodeMap groupMembersMap;
foreach (const Node *node, fake->groupMembers()) {
if (node->type() == Node::Fake)
groupMembersMap[fullName(node, relative, marker)] = node;
}
generateAnnotatedList(fake, marker, groupMembersMap);
}
}
break;
case Atom::SinceList:
{
NewSinceMaps::const_iterator nsmap;
nsmap = newSinceMaps.find(atom->string());
NewClassMaps::const_iterator ncmap;
ncmap = newClassMaps.find(atom->string());
NewClassMaps::const_iterator nqcmap;
nqcmap = newQmlClassMaps.find(atom->string());
if ((nsmap != newSinceMaps.constEnd()) && !nsmap.value().isEmpty()) {
QList sections;
QList::ConstIterator s;
for (int i=0; itype()) {
case Node::Fake:
if (node->subType() == Node::QmlClass) {
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::QmlMethod:
sections[QmlMethod].appendMember((Node*)node);
break;
default:
break;
}
++n;
}
/*
First generate the table of contents.
*/
writeStartTag(DT_ul);
s = sections.constBegin();
while (s != sections.constEnd()) {
if (!(*s).members.isEmpty()) {
QString li = outFileName() + "#" + 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(0, marker, ncmap.value(), false, QString("Q"));
else if (idx == QmlClass)
generateCompactList(0, marker, nqcmap.value(), 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 = fullName(pmap.key(), 0, marker).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::Image:
case Atom::InlineImage:
{
QString fileName = imageFileName(relative, atom->string());
QString text;
if (atom->next() != 0)
text = atom->next()->string();
if (fileName.isEmpty()) {
/*
Don't bother outputting an error message.
Just output the href as if the image is in
the images directory...
*/
if (atom->string()[0] == '/')
fileName = QLatin1String("images") + atom->string();
else
fileName = QLatin1String("images/") + atom->string();
}
if (currentTag() != DT_xref)
writeStartTag(DT_fig);
writeStartTag(DT_image);
xmlWriter().writeAttribute("href",protectEnc(fileName));
if (atom->type() == Atom::InlineImage)
xmlWriter().writeAttribute("placement","inline");
else {
xmlWriter().writeAttribute("placement","break");
xmlWriter().writeAttribute("align","center");
}
if (!text.isEmpty()) {
writeStartTag(DT_alt);
writeCharacters(protectEnc(text));
writeEndTag(); //
}
writeEndTag(); //
if (currentTag() != DT_xref)
writeEndTag(); //
}
break;
case Atom::ImageText:
// nothing
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, marker, &node);
if (myLink.isEmpty()) {
relative->doc().location().warning(tr("Can't link to '%1' in %2")
.arg(atom->string())
.arg(marker->plainFullName(relative)));
}
else if (!inSectionHeading) {
beginLink(myLink);
}
#if 0
else {
//xmlWriter().writeCharacters(atom->string());
//qDebug() << "MYLINK:" << myLink << outFileName() << atom->string();
}
#endif
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) {
// I don't think this attribute is supported.
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("&"))
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:
#if 0
if (inApiDesc) {
writeEndTag(); //
inApiDesc = false;
}
#endif
enterSection("details",QString());
//writeGuidAttribute(Doc::canonicalTitle(Text::sectionHeading(atom).toString()));
break;
case Atom::SectionRight:
leaveSection();
break;
case Atom::SectionHeadingLeft:
writeStartTag(DT_p);
writeGuidAttribute(Doc::canonicalTitle(Text::sectionHeading(atom).toString()));
hx = "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, relative, marker);
}
else {
writeCharacters(atom->string());
}
break;
case Atom::TableLeft:
{
if (in_para) {
writeEndTag(); //
in_para = false;
}
writeStartTag(DT_table);
numTableRows = 0;
if (tableColumnCount != 0) {
qDebug() << "ERROR: Nested tables!";
tableColumnCount = 0;
}
tableColumnCount = countTableColumns(atom->next());
writeStartTag(DT_tgroup);
xmlWriter().writeAttribute("cols",QString::number(tableColumnCount));
inTableHeader = false;
inTableBody = false;
}
break;
case Atom::TableRight:
writeEndTag(); //
writeEndTag(); //
writeEndTag(); //
inTableHeader = false;
inTableBody = false;
tableColumnCount = 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));
}
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);
}
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(",");
if (spans.size() == 2) {
if ((spans[0].toInt()>1) || (spans[1].toInt()>1)) {
values += "span(" + spans[0] + "," + spans[1] + ")";
}
}
}
}
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(",");
QString columnText = params.at(0);
QStringList pieces = columnText.split(" ", 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);
}
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(const 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 = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
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(); //
enterApiDesc(QString(),title);
Text brief = nsn->doc().briefText(); // zzz
if (!brief.isEmpty()) {
writeStartTag(DT_p);
generateText(brief, nsn, marker);
writeEndTag(); //
}
generateIncludes(nsn, marker);
generateStatus(nsn, marker);
generateThreadSafeness(nsn, marker);
generateSince(nsn, marker);
enterSection("h2","Detailed Description");
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.begin();
while (s != summarySections.end()) {
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, marker);
}
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, marker);
}
}
++s;
}
if (needOtherSection) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.begin();
while (s != summarySections.end()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner, marker);
++s;
}
}
leaveSection();
}
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.begin();
while (s != detailSections.end()) {
if ((*s).name == "Classes") {
writeNestedClasses((*s),nsn);
break;
}
++s;
}
s = detailSections.begin();
while (s != detailSections.end()) {
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 = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
title = rawTitle + " Class Reference";
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, marker); //
// not included:
writeLocation(cn);
writeEndTag(); //
enterApiDesc(QString(),title);
Text brief = cn->doc().briefText(); // zzz
if (!brief.isEmpty()) {
writeStartTag(DT_p);
generateText(brief, cn, marker);
writeEndTag(); //
}
generateIncludes(cn, marker);
generateStatus(cn, marker);
generateInherits(cn, marker);
generateInheritedBy(cn, marker);
generateThreadSafeness(cn, marker);
generateSince(cn, marker);
enterSection("h2","Detailed Description");
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.begin();
while (s != summarySections.end()) {
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, marker);
}
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, marker);
}
}
++s;
}
if (needOtherSection) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.begin();
while (s != summarySections.end()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner, marker);
++s;
}
}
leaveSection();
}
// not included: or
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.begin();
while (s != detailSections.end()) {
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);
}
++s;
}
generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); //
}
else if ((inner->type() == Node::Fake) && (inner->subType() == Node::HeaderFile)) {
const FakeNode* fn = const_cast(static_cast(inner));
rawTitle = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
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);
enterApiDesc(QString(),title);
Text brief = fn->doc().briefText(); // zzz
if (!brief.isEmpty()) {
writeStartTag(DT_p);
generateText(brief, fn, marker);
writeEndTag(); //
}
generateIncludes(fn, marker);
generateStatus(fn, marker);
generateThreadSafeness(fn, marker);
generateSince(fn, marker);
generateSince(fn, marker);
enterSection("h2","Detailed Description");
generateBody(fn, marker);
generateAlsoList(fn, marker);
leaveSection();
leaveSection(); //
bool needOtherSection = false;
QList summarySections;
summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
if (!summarySections.isEmpty()) {
enterSection("redundant",QString());
s = summarySections.begin();
while (s != summarySections.end()) {
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, marker);
}
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, marker);
}
}
++s;
}
if (needOtherSection) {
enterSection("additional-inherited-members redundant",QString());
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
xmlWriter().writeCharacters("Additional Inherited Members");
writeEndTag(); //
s = summarySections.begin();
while (s != summarySections.end()) {
if (s->members.isEmpty())
generateSectionInheritedList(*s, inner, marker);
++s;
}
}
leaveSection();
}
writeEndTag(); //
// not included:
// not included:
QList detailSections;
detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
s = detailSections.begin();
while (s != detailSections.end()) {
if ((*s).name == "Classes") {
writeNestedClasses((*s),fn);
break;
}
++s;
}
s = detailSections.begin();
while (s != detailSections.end()) {
if ((*s).name == "Function Documentation") {
writeFunctions((*s),fn,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::Fake) && (inner->subType() == Node::QmlClass)) {
const QmlClassNode* qcn = const_cast(static_cast(inner));
const ClassNode* cn = qcn->classNode();
rawTitle = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
title = rawTitle + " Element Reference";
//QString fullTitle = fake->fullTitle();
//QString htmlTitle = fullTitle;
generateHeader(inner, fullTitle);
generateBrief(inner, marker); //
writeProlog(inner);
writeStartTag(DT_cxxClassDetail);
enterApiDesc(QString(),title);
Text brief = qcn->doc().briefText(); // zzz
if (!brief.isEmpty()) {
writeStartTag(DT_p);
generateText(brief, qcn, marker);
writeEndTag(); //
}
generateQmlInstantiates(qcn, marker);
generateQmlInherits(qcn, marker);
generateQmlInheritedBy(qcn, marker);
generateSince(qcn, marker);
enterSection("h2","Detailed Description");
generateBody(qcn, marker);
if (cn) {
generateQmlText(cn->doc().body(), cn, marker, qcn->name());
generateAlsoList(cn, marker);
}
leaveSection();
leaveSection(); //
QList summarySections;
summarySections = marker->qmlSections(qcn,CodeMarker::Summary,0);
if (!summarySections.isEmpty()) {
enterSection("redundant",QString());
s = summarySections.begin();
while (s != summarySections.end()) {
QString attr;
if (!s->members.isEmpty()) {
writeStartTag(DT_p);
attr = cleanRef((*s).name).toLower() + " h2";
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
generateQmlSummary(*s,qcn,marker);
//generateSection(s->members, inner, marker, CodeMarker::Summary);
//generateSectionInheritedList(*s, inner, marker);
}
++s;
}
leaveSection();
}
QList detailSections;
detailSections = marker->qmlSections(qcn,CodeMarker::Detailed,0);
if (!detailSections.isEmpty()) {
enterSection("details",QString());
s = detailSections.begin();
while (s != detailSections.end()) {
if (!s->members.isEmpty()) {
QString attr;
writeStartTag(DT_p);
attr = cleanRef((*s).name).toLower() + " h2";
xmlWriter().writeAttribute("outputclass",attr);
writeCharacters(protectEnc((*s).name));
writeEndTag(); //
NodeList::ConstIterator m = (*s).members.begin();
while (m != (*s).members.end()) {
generateDetailedQmlMember(*m, qcn, marker);
++m;
}
}
++s;
}
leaveSection();
}
writeEndTag(); //
writeEndTag(); //
}
}
/*!
Write a list item for a \a link with the given \a text.
*/
void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& text)
{
writeStartTag(DT_li);
writeStartTag(DT_xref);
// formathtml
xmlWriter().writeAttribute("href",link);
writeCharacters(text);
writeEndTag(); //
writeEndTag(); //
}
/*!
Generate the html page for a qdoc file that doesn't map
to an underlying c++ file.
*/
void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker)
{
QList sections;
QList::const_iterator s;
QString fullTitle = fake->fullTitle();
if (fake->subType() == Node::QmlBasicType) {
fullTitle = "QML Basic Type: " + fullTitle;
}
generateHeader(fake, fullTitle);
generateBrief(fake, marker); //
writeProlog(fake);
writeStartTag(DT_body);
enterSection(QString(),QString());
if (fake->subType() == Node::Module) {
generateStatus(fake, marker);
if (moduleNamespaceMap.contains(fake->name())) {
enterSection("h2","Namespaces");
generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]);
leaveSection();
}
if (moduleClassMap.contains(fake->name())) {
enterSection("h2","Classes");
generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);
leaveSection();
}
}
if (fake->doc().isEmpty()) {
if (fake->subType() == Node::File) {
Text text;
Quoter quoter;
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass", "small-subtitle");
text << fake->subTitle();
generateText(text, fake, marker);
writeEndTag(); //
Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
QString code = quoter.quoteTo(fake->location(), "", "");
text.clear();
text << Atom(Atom::Code, code);
generateText(text, fake, marker);
}
}
else {
if (fake->subType() == Node::Module) {
enterSection("h2","Detailed Description");
generateBody(fake, marker);
leaveSection();
}
else
generateBody(fake, marker);
generateAlsoList(fake, marker);
if (!fake->groupMembers().isEmpty()) {
NodeMap groupMembersMap;
foreach (const Node *node, fake->groupMembers()) {
if (node->type() == Node::Class || node->type() == Node::Namespace)
groupMembersMap[node->name()] = node;
}
generateAnnotatedList(fake, marker, groupMembersMap);
}
}
leaveSection(); //
writeEndTag(); //