/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $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;
QString DitaXmlGenerator::sinceTitles[] =
{
" New Namespaces",
" New Classes",
" New Member Functions",
" New Functions in Namespaces",
" New Global Functions",
" New Macros",
" New Enum Types",
" New Typedefs",
" New Properties",
" New Variables",
" New QML Elements",
" New Qml Properties",
" New Qml Signals",
" New Qml Methods",
""
};
/*
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",
"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)
{
if (!href.isEmpty()) {
writeStartTag(DT_xref);
// 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);
QString chars = trimmedTrailing(atom->string());
writeText(chars, marker, relative);
writeEndTag(); //
}
break;
case Atom::Qml:
writeStartTag(DT_codeblock);
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:
{
attr = atom->string();
DitaTag t = currentTag();
if ((t == DT_section) || (t == DT_sectiondiv)) {
writeStartTag(DT_sectiondiv);
divNestingLevel++;
}
else if ((t == DT_body) || (t == DT_bodydiv)) {
writeStartTag(DT_bodydiv);
divNestingLevel++;
}
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::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...
*/
fileName = QLatin1String("images/") + protectEnc(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:
{
#if 0
qDebug() << "GUID LINK:" << atom->string() << outFileName();
#endif
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(protectEnc(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::SectioningUnit sectioningUnit = 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);
sectioningUnit = (Doc::SectioningUnit)params.at(1).toInt();
}
if (node)
generateTableOfContents(node,
marker,
sectioningUnit,
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,marker);
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);
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,marker);
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);
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,marker);
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);
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,marker);
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());
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, marker);
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(); //