/**************************************************************************** ** ** Copyright (C) 2010 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 "separator.h" #include "tree.h" #include #include #include #include #include #include QT_BEGIN_NAMESPACE #define COMMAND_VERSION Doc::alias("version") int DitaXmlGenerator::id = 0; #define cxxapi_d_xref Doc::alias("cxxapi-d-xref") #define cxxclass Doc::alias("cxxclass") #define cxxdefine Doc::alias("cxxdefine") #define cxxenumeration Doc::alias("cxxenumeration") #define cxxfile Doc::alias("cxxfile") #define cxxfunction Doc::alias("cxxfunction") #define cxxstruct Doc::alias("cxxstruct") #define cxxtypedef Doc::alias("cxxtypedef") #define cxxunion Doc::alias("cxxunion") #define cxxvariable Doc::alias("cxxvariable") #define CXXAPIMAP Doc::alias("cxxAPIMap") #define CXXCLASSREF Doc::alias("cxxClassRef") #define CXXDEFINEREF Doc::alias("cxxDefineRef") #define CXXENUMERATIONREF Doc::alias("cxxEnumerationRef") #define CXXFILEREF Doc::alias("cxxFileRef") #define CXXFUNCTIONREF Doc::alias("cxxFunctionRef") #define CXXSTRUCTREF Doc::alias("cxxStructRef") #define CXXTYPDEFREF Doc::alias("cxxTypedefRef") #define CXXUNIONREF Doc::alias("cxxUnionRef") #define CXXVARIABLEREF Doc::alias("cxxVariableRef") #define CXXCLASS Doc::alias("cxxClass") #define CXXCLASSABSTRACT Doc::alias("cxxClassAbstract") #define CXXCLASSACCESSSPECIFIER Doc::alias("cxxClassAccessSpecifier") #define CXXCLASSAPIITEMLOCATION Doc::alias("cxxClassAPIItemLocation") #define CXXCLASSBASECLASS Doc::alias("cxxClassBaseClass") #define CXXCLASSBASECLASSSTRUCT Doc::alias("cxxClassBaseStruct") #define CXXCLASSBASEUNION Doc::alias("cxxClassBaseUnion") #define CXXCLASSDECLARATIONFILE Doc::alias("cxxClassDeclarationFile") #define CXXCLASSDECLARATIONFILELINE Doc::alias("cxxClassDeclarationFileLine") #define CXXCLASSDEFINITION Doc::alias("cxxClassDefinition") #define CXXCLASSDEFINITIONFILE Doc::alias("cxxClassDefinitionFile") #define CXXCLASSDEFINITIONFILEEND Doc::alias("cxxClassDefinitionFileLineEnd") #define CXXCLASSDEFINITIONFILESTART Doc::alias("cxxClassDefinitionFileLineStart") #define CXXCLASSDERIVATION Doc::alias("cxxClassDerivation") #define CXXCLASSDERIVATIONACCESSSPECIFIER Doc::alias("cxxClassDerivationAccessSpecifier") #define CXXCLASSDERIVATIONS Doc::alias("cxxClassDerivations") #define CXXCLASSDERIVATIONVIRTUAL Doc::alias("cxxClassDerivationVirtual") #define CXXCLASSDETAIL Doc::alias("cxxClassDetail") #define CXXCLASSENUMERATIONINHERITED Doc::alias("cxxClassEnumerationInherited") #define CXXCLASSENUMERATORINHERITED Doc::alias("cxxClassEnumeratorInherited") #define CXXCLASSFUNCTIONINHERITED Doc::alias("cxxClassFunctionInherited") #define CXXCLASSINHERITS Doc::alias("cxxClassInherits") #define CXXCLASSINHERITSDETAIL Doc::alias("cxxClassInheritsDetail") #define CXXCLASSNESTED Doc::alias("cxxClassNested") #define CXXCLASSNESTEDCLASS Doc::alias("cxxClassNestedClass") #define CXXCLASSNESTEDDETAIL Doc::alias("cxxClassNestedDetail") #define CXXCLASSNESTEDSTRUCT Doc::alias("cxxClassNestedStruct") #define CXXCLASSNESTEDUNION Doc::alias("cxxClassNestedUnion") #define CXXCLASSTEMPLATEPARAMETER Doc::alias("cxxClassTemplateParameter") #define CXXCLASSTEMPLATEPARAMETERS Doc::alias("cxxClassTemplateParameters") #define CXXCLASSTEMPLATEPARAMETERTYPE Doc::alias("cxxClassTemplateParameterType") #define CXXCLASSVARIABLEINHERITED Doc::alias("cxxClassVariableInherited") #define CXXDEFINE Doc::alias("cxxDefine") #define CXXDEFINEACCESSSPECIFIER Doc::alias("cxxDefineAccessSpecifier") #define CXXDEFINEAPIITEMLOCATION Doc::alias("cxxDefineAPIItemLocation") #define CXXDEFINEDECLARATIONFILE Doc::alias("cxxDefineDeclarationFile") #define CXXDEFINEDECLARATIONFILELINE Doc::alias("cxxDefineDeclarationFileLine") #define CXXDEFINEDEFINITION Doc::alias("cxxDefineDefinition") #define CXXDEFINEDETAIL Doc::alias("cxxDefineDetail") #define CXXDEFINENAMELOOKUP Doc::alias("cxxDefineNameLookup") #define CXXDEFINEPARAMETER Doc::alias("cxxDefineParameter") #define CXXDEFINEPARAMETERDECLARATIONNAME Doc::alias("cxxDefineParameterDeclarationName") #define CXXDEFINEPARAMETERS Doc::alias("cxxDefineParameters") #define CXXDEFINEPROTOTYPE Doc::alias("cxxDefinePrototype") #define CXXDEFINEREIMPLEMENTED Doc::alias("cxxDefineReimplemented") #define CXXENUMERATION Doc::alias("cxxEnumeration") #define CXXENUMERATIONACCESSSPECIFIER Doc::alias("cxxEnumerationAccessSpecifier") #define CXXENUMERATIONAPIITEMLOCATION Doc::alias("cxxEnumerationAPIItemLocation") #define CXXENUMERATIONDECLARATIONFILE Doc::alias("cxxEnumerationDeclarationFile") #define CXXENUMERATIONDECLARATIONFILELINE Doc::alias("cxxEnumerationDeclarationFileLine") #define CXXENUMERATIONDEFINITION Doc::alias("cxxEnumerationDefinition") #define CXXENUMERATIONDEFINITIONFILE Doc::alias("cxxEnumerationDefinitionFile") #define CXXENUMERATIONDEFINITIONFILELINEEND Doc::alias("cxxEnumerationDefinitionFileLineEnd") #define CXXENUMERATIONDEFINITIONFILELINESTART Doc::alias("cxxEnumerationDefinitionFileLineStart") #define CXXENUMERATIONDETAIL Doc::alias("cxxEnumerationDetail") #define CXXENUMERATIONNAMELOOKUP Doc::alias("cxxEnumerationNameLookup") #define CXXENUMERATIONPROTOTYPE Doc::alias("cxxEnumerationPrototype") #define CXXENUMERATIONREIMPLEMENTED Doc::alias("cxxEnumerationReimplemented") #define CXXENUMERATIONSCOPEDNAME Doc::alias("cxxEnumerationScopedName") #define CXXENUMERATOR Doc::alias("cxxEnumerator") #define CXXENUMERATORAPIITEMLOCATION Doc::alias("cxxEnumeratorAPIItemLocation") #define CXXENUMERATORDECLARATIONFILE Doc::alias("cxxEnumeratorDeclarationFile") #define CXXENUMERATORDECLARATIONFILELINE Doc::alias("cxxEnumeratorDeclarationFileLine") #define CXXENUMERATORINITIALISER Doc::alias("cxxEnumeratorInitialiser") #define CXXENUMERATORNAMELOOKUP Doc::alias("cxxEnumeratorNameLookup") #define CXXENUMERATORPROTOTYPE Doc::alias("cxxEnumeratorPrototype") #define CXXENUMERATORS Doc::alias("cxxEnumerators") #define CXXENUMERATORSCOPEDNAME Doc::alias("cxxEnumeratorScopedName") #define CXXFILE_INFO_TYPES Doc::alias("cxxFile-info-types") #define CXXFILE_TYPES_DEFAULT Doc::alias("cxxFile-types-default") #define CXXFILE Doc::alias("cxxFile") #define CXXFILEAPIITMELOCATION Doc::alias("cxxFileAPIItemLocation") #define CXXFILEDECLARATIONFILE Doc::alias("cxxFileDeclarationFile") #define CXXFUNCTION Doc::alias("cxxFunction") #define CXXFUNCTIONACCESSSPECIFIER Doc::alias("cxxFunctionAccessSpecifier") #define CXXFUNCTIONAPIITEMLOCATION Doc::alias("cxxFunctionAPIItemLocation") #define CXXFUNCTIONCONST Doc::alias("cxxFunctionConst") #define CXXFUNCTIONCONSTRUCTOR Doc::alias("cxxFunctionConstructor") #define CXXFUNCTIONDECLARATIONFILE Doc::alias("cxxFunctionDeclarationFile") #define CXXFUNCTIONDECLARATIONFILELINE Doc::alias("cxxFunctionDeclarationFileLine") #define CXXFUNCTIONDECLAREDTYPE Doc::alias("cxxFunctionDeclaredType") #define CXXFUNCTIONDEFINITION Doc::alias("cxxFunctionDefinition") #define CXXFUNCTIONDEFINITIONFILE Doc::alias("cxxFunctionDefinitionFile") #define CXXFUNCTIONDEFINITIONFILELINEEND Doc::alias("cxxFunctionDefinitionFileLineEnd") #define CXXFUNCTIONDEFINITIONFILELINESTART Doc::alias("cxxFunctionDefinitionFileLineStart") #define CXXFUNCTIONDESTRUCTOR Doc::alias("cxxFunctionDestructor") #define CXXFUNCTIONDETAIL Doc::alias("cxxFunctionDetail") #define CXXFUNCTIONEXPLICIT Doc::alias("cxxFunctionExplicit") #define CXXFUNCTIONINLINE Doc::alias("cxxFunctionInline") #define CXXFUNCTIONNAMELOOKUP Doc::alias("cxxFunctionNameLookup") #define CXXFUNCTIONPARAMETER Doc::alias("cxxFunctionParameter") #define CXXFUNCTIONPARAMETERDECLARATIONNAME Doc::alias("cxxFunctionParameterDeclarationName") #define CXXFUNCTIONPARAMETERDECLAREDTYPE Doc::alias("cxxFunctionParameterDeclaredType") #define CXXFUNCTIONPARAMETERDEFAULTVALUE Doc::alias("cxxFunctionParameterDefaultValue") #define CXXFUNCTIONPARAMETERDEFINITIONNAME Doc::alias("cxxFunctionParameterDefinitionName") #define CXXFUNCTIONPARAMETERS Doc::alias("cxxFunctionParameters") #define CXXFUNCTIONPROTOTYPE Doc::alias("cxxFunctionPrototype") #define CXXFUNCTIONPUREVIRTUAL Doc::alias("cxxFunctionPureVirtual") #define CXXFUNCTIONREIMPLEMENTED Doc::alias("cxxFunctionReimplemented") #define CXXFUNCTIONRETURNTYPE Doc::alias("cxxFunctionReturnType") #define CXXFUNCTIONSCOPEDNAME Doc::alias("cxxFunctionScopedName") #define CXXFUNCTIONSTORAGECLASSSPECIFIEREXTERN Doc::alias("cxxFunctionStorageClassSpecifierExtern") #define CXXFUNCTIONSTORAGECLASSSPECIFIERMUTABLE Doc::alias("cxxFunctionStorageClassSpecifierMutable") #define CXXFUNCTIONSTORAGECLASSSPECIFIERSTATIC Doc::alias("cxxFunctionStorageClassSpecifierStatic") #define CXXFUNCTIONTEMPLATEPARAMETER Doc::alias("cxxFunctionTemplateParameter") #define CXXFUNCTIONTEMPLATEPARAMETERS Doc::alias("cxxFunctionTemplateParameters") #define CXXFUNCTIONTEMPLATEPARAMETERTYPE Doc::alias("cxxFunctionTemplateParameterType") #define CXXFUNCTIONVIRTUAL Doc::alias("cxxFunctionVirtual") #define CXXFUNCTIONVOLATILE Doc::alias("cxxFunctionVolatile") #define CXXSTRUCT Doc::alias("cxxStruct") #define CXXSTRUCTABSTRACT Doc::alias("cxxStructAbstract") #define CXXSTRUCTACCESSSPECIFIER Doc::alias("cxxStructAccessSpecifier") #define CXXSTRUCTAPIITEMLOCATION Doc::alias("cxxStructAPIItemLocation") #define CXXSTRUCTBASECLASS Doc::alias("cxxStructBaseClass") #define CXXSTRUCTBASESTRUCT Doc::alias("cxxStructBaseStruct") #define CXXSTRUCTBASEUNION Doc::alias("cxxStructBaseUnion") #define CXXSTRUCTDECLARATIONFILE Doc::alias("cxxStructDeclarationFile") #define CXXSTRUCTDECLARATIONFILELINE Doc::alias("cxxStructDeclarationFileLine") #define CXXSTRUCTDEFINITION Doc::alias("cxxStructDefinition") #define CXXSTRUCTDEFINITIONFILE Doc::alias("cxxStructDefinitionFile") #define CXXSTRUCTDEFINITIONFILELINEEND Doc::alias("cxxStructDefinitionFileLineEnd") #define CXXSTRUCTDEFINITIONFILELINESTART Doc::alias("cxxStructDefinitionFileLineStart") #define CXXSTRUCTDERIVATION Doc::alias("cxxStructDerivation") #define CXXSTRUCTDERIVATIONACCESSSPECIFIER Doc::alias("cxxStructDerivationAccessSpecifier") #define CXXSTRUCTDERIVATIONS Doc::alias("cxxStructDerivations") #define CXXSTRUCTDERIVATIONVIRTUAL Doc::alias("cxxStructDerivationVirtual") #define CXXSTRUCTDETAIL Doc::alias("cxxStructDetail") #define CXXSTRUCTENUMERATIONINHERITED Doc::alias("cxxStructEnumerationInherited") #define CXXSTRUCTENUMERATORINHERITED Doc::alias("cxxStructEnumeratorInherited") #define CXXSTRUCTFUNCTIONINHERITED Doc::alias("cxxStructFunctionInherited") #define CXXSTRUCTINHERITS Doc::alias("cxxStructInherits") #define CXXSTRUCTINHERITSDETAIL Doc::alias("cxxStructInheritsDetail") #define CXXSTRUCTNESTED Doc::alias("cxxStructNested") #define CXXSTRUCTNESTEDCLASS Doc::alias("cxxStructNestedClass") #define CXXSTRUCTNESTEDDETAIL Doc::alias("cxxStructNestedDetail") #define CXXSTRUCTNESTEDSTRUCT Doc::alias("cxxStructNestedStruct") #define CXXSTRUCTNESTEDUNION Doc::alias("cxxStructNestedUnion") #define CXXSTRUCTTEMPLATEPARAMETER Doc::alias("cxxStructTemplateParameter") #define CXXSTRUCTTEMPLATEPARAMETERS Doc::alias("cxxStructTemplateParameters") #define CXXSTRUCTTEMPLATEPARAMETERTYPE Doc::alias("cxxStructTemplateParameterType") #define CXXSTRUCTVARIABLEINHERITED Doc::alias("cxxStructVariableInherited") #define CXXTYPEDEF Doc::alias("cxxTypedef") #define CXXTYPEDEFACCESSSPECIFIER Doc::alias("cxxTypedefAccessSpecifier") #define CXXTYPEDEFAPIITEMLOCATION Doc::alias("cxxTypedefAPIItemLocation") #define CXXTYPEDEFDECLARATIONFILE Doc::alias("cxxTypedefDeclarationFile") #define CXXTYPEDEFDECLARATIONFILELINE Doc::alias("cxxTypedefDeclarationFileLine") #define CXXTYPEDEFDECLAREDTYPE Doc::alias("cxxTypedefDeclaredType") #define CXXTYPEDEFDEFINITION Doc::alias("cxxTypedefDefinition") #define CXXTYPEDEFDETAIL Doc::alias("cxxTypedefDetail") #define CXXTYPEDEFNAMELOOKUP Doc::alias("cxxTypedefNameLookup") #define CXXTYPEDEFPROTOTYPE Doc::alias("cxxTypedefPrototype") #define CXXTYPEDEFREIMPLEMENTED Doc::alias("cxxTypedefReimplemented") #define CXXTYPEDEFSCOPEDNAME Doc::alias("cxxTypedefScopedName") #define CXXUNION Doc::alias("cxxUnion") #define CXXUNIONABSTRACT Doc::alias("cxxUnionAbstract") #define CXXUNIONACCESSSPECIFIER Doc::alias("cxxUnionAccessSpecifier") #define CXXUNIONAPIITEMLOCATION Doc::alias("cxxUnionAPIItemLocation") #define CXXUNIONDECLARATIONFILE Doc::alias("cxxUnionDeclarationFile") #define CXXUNIONDECLARATIONFILELINE Doc::alias("cxxUnionDeclarationFileLine") #define CXXUNIONDEFINITION Doc::alias("cxxUnionDefinition") #define CXXUNIONDEFINITIONFILE Doc::alias("cxxUnionDefinitionFile") #define CXXUNIONDEFINITIONFILELINEEND Doc::alias("cxxUnionDefinitionFileLineEnd") #define CXXUNIONDEFINITIONFILELINESTART Doc::alias("cxxUnionDefinitionFileLineStart") #define CXXUNIONDETAIL Doc::alias("cxxUnionDetail") #define CXXUNIONNESTED Doc::alias("cxxUnionNested") #define CXXUNIONNESTEDCLASS Doc::alias("cxxUnionNestedClass") #define CXXUNIONNESTEDDETAIL Doc::alias("cxxUnionNestedDetail") #define CXXUNIONNESTEDSTRUCT Doc::alias("cxxUnionNestedStruct") #define CXXUNIONNESTEDUNION Doc::alias("cxxUnionNestedUnion") #define CXXUNIONTEMPLATEPARAMETER Doc::alias("cxxUnionTemplateParameter") #define CXXUNIONTEMPLATEPARAMETERS Doc::alias("cxxUnionTemplateParameters") #define CXXUNIONTEMPLATEPARAMETERTYPE Doc::alias("cxxUnionTemplateParameterType") #define CXXVARIABLE Doc::alias("cxxVariable") #define CXXVARIABLEACCESSSPECIFIER Doc::alias("cxxVariableAccessSpecifier") #define CXXVARIABLEAPIITEMLOCATION Doc::alias("cxxVariableAPIItemLocation") #define CXXVARIABLECONST Doc::alias("cxxVariableConst") #define CXXVARIABLEDECLARATIONFILE Doc::alias("cxxVariableDeclarationFile") #define CXXVARIABLEDECLARATIONFILELINE Doc::alias("cxxVariableDeclarationFileLine") #define CXXVARIABLEDECLAREDTYPE Doc::alias("cxxVariableDeclaredType") #define CXXVARIABLEDEFINITION Doc::alias("cxxVariableDefinition") #define CXXVARIABLEDETAIL Doc::alias("cxxVariableDetail") #define CXXVARIABLENAMELOOKUP Doc::alias("cxxVariableNameLookup") #define CXXVARIABLEPROTOTYPE Doc::alias("cxxVariablePrototype") #define CXXVARIABLEREIMPLEMENTED Doc::alias("cxxVariableReimplemented") #define CXXVARIABLESCOPEDNAME Doc::alias("cxxVariableScopedName") #define CXXVARIABLESTORAGECLASSSPECIFIEREXTERN Doc::alias("cxxVariableStorageClassSpecifierExtern") #define CXXVARIABLESTORAGECLASSSPECIFIERMUTABLE Doc::alias("cxxVariableStorageClassSpecifierMutable") #define CXXVARIABLESTORAGECLASSSPECIFIERSTATIC Doc::alias("cxxVariableStorageClassSpecifierStatic") #define CXXVARIABLEVOLATILE Doc::alias("cxxVariableVolatile") #define APIREF Doc::alias("apiRef") #define APINAME Doc::alias("apiName") #define APIDETAIL Doc::alias("apiDetail") #define APISYNTAX Doc::alias("apiSyntax") #define APISYNTAXTEXT Doc::alias("apiSyntaxText") #define APISYNTAXITEM Doc::alias("apiSyntaxItem") #define APIDEF Doc::alias("apiDef") #define APIQUALIFIER Doc::alias("apiQualifier") #define APIRELATION Doc::alias("apiRelation") #define APITYPE Doc::alias("apiType") #define APIARRAY Doc::alias("apiArray") #define APIDATA Doc::alias("apiData") #define APIDEFNOTE Doc::alias("apiDefNote") #define APIDEFITEM Doc::alias("apiDefItem") #define APIITEMNAME Doc::alias("apiItemName") #define APIDESC Doc::alias("apiDesc") #define APIIMPL Doc::alias("apiImpl") #define APIPACKAGE Doc::alias("apiPackage") #define APICLASSIFIER Doc::alias("apiClassifier") #define APICLASSIFIERDETAIL Doc::alias("apiClassifierDetail") #define APICLASSIFIERDEF Doc::alias("apiClassifierDef") #define APICLASSIFIERMEMBER Doc::alias("apiClassifierMember") #define APIOTHERCLASSIFIER Doc::alias("apiOtherClassifier") #define APIBASECLASSIFIER Doc::alias("apiBaseClassifier") #define APIOPERATION Doc::alias("apiOperation") #define APIOPERATIONDETAIL Doc::alias("apiOperationDetail") #define APIOPERATIONDEF Doc::alias("apiOperationDef") #define APIRETURN Doc::alias("apiReturn") #define APIPARAM Doc::alias("apiParam") #define APIEVENT Doc::alias("apiEvent") #define APIOPERATIONDEFITEM Doc::alias("apiOperationDefItem") #define APIOPERATIONCLASSIFIER Doc::alias("apiOperationClassifier") #define APICONSTRUCTORDEF Doc::alias("apiConstructorDef") #define APIVALUE Doc::alias("apiValue") #define APIVALUEDETAIL Doc::alias("apiValueDetail") #define APIVALUEDEF Doc::alias("apiValueDef") #define APIVALUEMEMBER Doc::alias("apiValueMember") #define APIVALUECLASSIFIER Doc::alias("apiValueClassifier") #define APIclassifier Doc::alias("apiclassifier") #define APIoperation Doc::alias("apioperation") #define APIpackage Doc::alias("apipackage") #define APIvalue Doc::alias("apivalue") #define APIMAP Doc::alias("apiMap") #define APIITEMREF Doc::alias("apiItemRef") #define SHORTDESC Doc::alias("shortdesc") 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", "" }; static bool showBrokenLinks = false; static void addLink(const QString &linkTarget, const QStringRef &nestedStuff, QString *res) { if (!linkTarget.isEmpty()) { *res += ""; *res += nestedStuff; *res += ""; } else { *res += nestedStuff; } } DitaXmlGenerator::DitaXmlGenerator() : inLink(false), inContents(false), inSectionHeading(false), inTableHeader(false), numTableRows(0), threeColumnEnumValueTable(true), offlineDocs(true), funcLeftParen("\\S(\\()"), myTree(0), slow(false), obsoleteLinks(false), noLinks(0) { } DitaXmlGenerator::~DitaXmlGenerator() { // nothing yet. } void DitaXmlGenerator::initializeGenerator(const Config &config) { static const struct { const char *key; const char *tag; } defaults[] = { { ATOM_FORMATTING_BOLD, "b" }, { ATOM_FORMATTING_INDEX, ""); break; case Atom::FormatElse: case Atom::FormatEndif: case Atom::FormatIf: break; case Atom::FormattingLeft: writer.writeStartElement(formattingLeftMap()[atom->string()]); 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())) { writer.writeCharacters(subscriptRegExp.cap(1)); writer.writeStartElement("sub"); writer.writeCharacters(subscriptRegExp.cap(2)); writer.writeEndElement(); // skipAhead = 1; } } } break; case Atom::FormattingRight: if (atom->string() == ATOM_FORMATTING_LINK) { endLink(); } else { writer.writeEndElement(); // ? } 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().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); } } else if (atom->string() == "relatedinline") { const FakeNode *fake = static_cast(relative); if (fake && !fake->groupMembers().isEmpty()) { // Reverse the list into the original scan order. // Should be sorted. But on what? It may not be a // regular class or page definition. QList list; foreach (const Node *node, fake->groupMembers()) list.prepend(node); foreach (const Node *node, list) generateBody(node, marker); } } 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. */ writer.writeStartElement("ul"); s = sections.constBegin(); while (s != sections.constEnd()) { if (!(*s).members.isEmpty()) { writer.writeStartElement("li"); writer.writeStartElement("xref"); writer.writeAttribute("href",QString("#" + Doc::canonicalTitle((*s).name))); writer.writeCharacters((*s).name); writer.writeEndElement(); // writer.writeEndElement(); // } ++s; } writer.writeEndElement(); // int idx = 0; s = sections.constBegin(); while (s != sections.constEnd()) { if (!(*s).members.isEmpty()) { writer.writeStartElement("p"); writeGuidAttribute(Doc::canonicalTitle((*s).name)); writer.writeAttribute("outputclass","h3"); writer.writeCharacters(protectEnc((*s).name)); writer.writeEndElement(); //

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(); writer.writeStartElement("p"); writer.writeCharacters("Class "); writer.writeStartElement("xref"); writer.writeAttribute("href",linkForNode(pmap.key(), 0)); QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); writer.writeCharacters(protectEnc(pieces.last())); writer.writeEndElement(); // writer.writeCharacters(":"); writer.writeEndElement(); //

generateSection(nlist, 0, marker, CodeMarker::Summary); writer.writeEmptyElement("br"); ++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 (atom->type() == Atom::Image) { writer.writeStartElement("p"); writer.writeAttribute("outputclass","centerAlign"); } if (fileName.isEmpty()) { writer.writeStartElement("font"); writer.writeAttribute("color","red"); writer.writeCharacters("[Missing image: "); writer.writeCharacters(protectEnc(atom->string())); writer.writeEndElement(); // } else { writer.writeStartElement("img"); writer.writeAttribute("src",protectEnc(fileName)); if (!text.isEmpty()) writer.writeAttribute("alt",protectEnc(text)); writer.writeEndElement(); // } if (atom->type() == Atom::Image) writer.writeEndElement(); //

} break; case Atom::ImageText: // nothing break; case Atom::LegaleseLeft: writer.writeStartElement("p"); writer.writeAttribute("outputclass","legalese"); break; case Atom::LegaleseRight: writer.writeEndElement(); //

break; case Atom::LineBreak: writer.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("Cannot link to '%1' in %2") .arg(atom->string()) .arg(marker->plainFullName(relative))); } beginLink(myLink, node, relative, marker); skipAhead = 1; } break; case Atom::LinkNode: { const Node *node = CodeMarker::nodeForString(atom->string()); beginLink(linkForNode(node, relative), node, relative, marker); skipAhead = 1; } break; case Atom::ListLeft: if (in_para) { writer.writeEndElement(); //

in_para = false; } if (atom->string() == ATOM_LIST_BULLET) { writer.writeStartElement("ul"); } else if (atom->string() == ATOM_LIST_TAG) { writer.writeStartElement("dl"); } else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { writer.writeStartElement("table"); writer.writeAttribute("outputclass","valuelist"); writer.writeStartElement("tr"); if (++numTableRows % 2 == 1) writer.writeAttribute("outputclass","odd"); else writer.writeAttribute("outputclass","even"); writer.writeStartElement("th"); writer.writeCharacters("Constant"); writer.writeEndElement(); // writer.writeStartElement("th"); writer.writeCharacters("Value"); writer.writeEndElement(); // writer.writeStartElement("th"); writer.writeCharacters("Description"); writer.writeEndElement(); // writer.writeEndElement(); // } else { writer.writeStartElement("table"); writer.writeAttribute("outputclass","valuelist"); writer.writeStartElement("tr"); writer.writeStartElement("th"); writer.writeCharacters("Constant"); writer.writeEndElement(); // writer.writeStartElement("th"); writer.writeCharacters("Value"); writer.writeEndElement(); // writer.writeEndElement(); // } } else { writer.writeStartElement("ol"); if (atom->string() == ATOM_LIST_UPPERALPHA) writer.writeAttribute("type","A"); else if (atom->string() == ATOM_LIST_LOWERALPHA) writer.writeAttribute("type","a"); else if (atom->string() == ATOM_LIST_UPPERROMAN) writer.writeAttribute("type","I"); else if (atom->string() == ATOM_LIST_LOWERROMAN) writer.writeAttribute("type","i"); else // (atom->string() == ATOM_LIST_NUMERIC) writer.writeAttribute("type","1"); if (atom->next() != 0 && atom->next()->string().toInt() != 1) writer.writeAttribute("start",atom->next()->string()); } break; case Atom::ListItemNumber: // nothing break; case Atom::ListTagLeft: if (atom->string() == ATOM_LIST_TAG) { writer.writeStartElement("dt"); } else { // (atom->string() == ATOM_LIST_VALUE) writer.writeStartElement("tr"); writer.writeStartElement("td"); writer.writeAttribute("outputclass","topAlign"); writer.writeStartElement("tt"); writer.writeCharacters(protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), relative)))); writer.writeEndElement(); // writer.writeEndElement(); // writer.writeStartElement("td"); writer.writeAttribute("outputclass","topAlign"); QString itemValue; if (relative->type() == Node::Enum) { const EnumNode *enume = static_cast(relative); itemValue = enume->itemValue(atom->next()->string()); } if (itemValue.isEmpty()) writer.writeCharacters("?"); else { writer.writeStartElement("tt"); writer.writeCharacters(protectEnc(itemValue)); writer.writeEndElement(); // } skipAhead = 1; } break; case Atom::ListTagRight: if (atom->string() == ATOM_LIST_TAG) writer.writeEndElement(); // break; case Atom::ListItemLeft: if (atom->string() == ATOM_LIST_TAG) { writer.writeStartElement("dd"); } else if (atom->string() == ATOM_LIST_VALUE) { if (threeColumnEnumValueTable) { writer.writeEndElement(); // writer.writeStartElement("td"); writer.writeAttribute("outputclass","topAlign"); if (matchAhead(atom, Atom::ListItemRight)) writer.writeCharacters(" "); } } else { writer.writeStartElement("li"); } if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; break; case Atom::ListItemRight: if (atom->string() == ATOM_LIST_TAG) { writer.writeEndElement(); // } else if (atom->string() == ATOM_LIST_VALUE) { writer.writeEndElement(); // writer.writeEndElement(); // } else { writer.writeEndElement(); // } break; case Atom::ListRight: if (atom->string() == ATOM_LIST_BULLET) { writer.writeEndElement(); // } else if (atom->string() == ATOM_LIST_TAG) { writer.writeEndElement(); // } else if (atom->string() == ATOM_LIST_VALUE) { writer.writeEndElement(); // } else { writer.writeEndElement(); // } break; case Atom::Nop: // nothing break; case Atom::ParaLeft: writer.writeStartElement("p"); in_para = true; break; case Atom::ParaRight: endLink(); if (in_para) { writer.writeEndElement(); // break; case Atom::RawString: writer.writeCharacters(atom->string()); break; case Atom::SectionLeft: writer.writeStartElement("p"); writeGuidAttribute(Doc::canonicalTitle(Text::sectionHeading(atom).toString())); writer.writeAttribute("outputclass","target"); writer.writeCharacters(protectEnc(Text::sectionHeading(atom).toString())); writer.writeEndElement(); //

break; case Atom::SectionRight: // nothing break; case Atom::SectionHeadingLeft: writer.writeStartElement("p"); hx = "h" + QString::number(atom->string().toInt() + hOffset(relative)); writer.writeAttribute("outputclass",hx); inSectionHeading = true; break; case Atom::SectionHeadingRight: writer.writeEndElement(); //

(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 { writer.writeCharacters(protectEnc(atom->string())); } break; case Atom::TableLeft: if (in_para) { writer.writeEndElement(); //

in_para = false; } writer.writeStartElement("table"); writer.writeAttribute("outputclass","generic"); numTableRows = 0; break; case Atom::TableRight: writer.writeEndElement(); // break; case Atom::TableHeaderLeft: writer.writeStartElement("thead"); writer.writeStartElement("tr"); writer.writeAttribute("outputclass","qt-style topAlign"); inTableHeader = true; break; case Atom::TableHeaderRight: writer.writeEndElement(); // if (matchAhead(atom, Atom::TableHeaderLeft)) { skipAhead = 1; writer.writeStartElement("tr"); writer.writeAttribute("outputclass","qt-style topAlign"); } else { writer.writeEndElement(); // inTableHeader = false; } break; case Atom::TableRowLeft: writer.writeStartElement("tr"); if (++numTableRows % 2 == 1) writer.writeAttribute("outputclass","odd topAlign"); else writer.writeAttribute("outputclass","even topAlign"); break; case Atom::TableRowRight: writer.writeEndElement(); // \n"; break; case Atom::TableItemLeft: { if (inTableHeader) writer.writeStartElement("th"); else writer.writeStartElement("td"); QStringList spans = atom->string().split(","); if (spans.size() == 2) { #if zzz if (spans.at(0) != "1") out() << " colspan=\"" << spans.at(0) << "\""; if (spans.at(1) != "1") out() << " rowspan=\"" << spans.at(1) << "\""; #endif if (!inTableHeader) writer.writeStartElement("p"); } if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; } break; case Atom::TableItemRight: if (inTableHeader) writer.writeEndElement(); // else { writer.writeEndElement(); //

writer.writeEndElement(); // } 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: writer.writeStartElement("p"); writeGuidAttribute(Doc::canonicalTitle(atom->string())); writer.writeAttribute("outputclass","target"); writer.writeCharacters(protectEnc(atom->string())); writer.writeEndElement(); //

break; case Atom::UnhandledFormat: writer.writeStartElement("b"); writer.writeAttribute("outputclass","redFont"); writer.writeCharacters("<Missing DITAXML>"); writer.writeEndElement(); // break; case Atom::UnknownCommand: writer.writeStartElement("b"); writer.writeAttribute("outputclass","redFont code"); writer.writeCharacters(protectEnc(atom->string())); writer.writeEndElement(); // break; #ifdef QDOC_QML case Atom::QmlText: case Atom::EndQmlText: // don't do anything with these. They are just tags. break; #endif default: // unknownAtom(atom); break; } return skipAhead; } /*! Generate a reference page for a C++ class. */ void DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* marker) { QList
sections; QList
::ConstIterator s; const ClassNode* cn = 0; const NamespaceNode *namespasse = 0; QString title; QString rawTitle; QString fullTitle; if (inner->type() == Node::Namespace) { namespasse = static_cast(inner); rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); title = rawTitle + " Namespace"; } else if (inner->type() == Node::Class) { cn = static_cast(inner); rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); title = rawTitle + " Class Reference"; generateHeader(inner); writer.writeStartElement(CXXCLASS); writeGuidAttribute(fullTitle); writer.writeStartElement(APINAME); writer.writeCharacters(fullTitle); writer.writeEndElement(); // generateBrief(inner, marker); writer.writeStartElement(CXXCLASSDETAIL); writer.writeStartElement(CXXCLASSDEFINITION); writer.writeStartElement(CXXCLASSACCESSSPECIFIER); writer.writeAttribute("value",inner->accessString()); writer.writeEndElement(); // writeDerivations(cn, marker); writeLocation(cn, marker); writer.writeEndElement(); // writer.writeStartElement(APIDESC); if (!inner->doc().isEmpty()) { writer.writeStartElement("p"); writer.writeAttribute("outputclass","h2"); writer.writeCharacters("Detailed Description"); writer.writeEndElement(); //

generateBody(inner, marker); // generateAlsoList(inner, marker); } writer.writeEndElement(); // writer.writeEndElement(); // writer.writeEndElement(); // } #ifdef WRITE_HTML Text subtitleText; if (rawTitle != fullTitle) subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak); QString shortVersion; shortVersion = project + " " + shortVersion + ": "; shortVersion = myTree->version(); if (shortVersion.count(QChar('.')) == 2) shortVersion.truncate(shortVersion.lastIndexOf(QChar('.'))); if (!shortVersion.isEmpty()) { if (project == "QSA") shortVersion = "QSA " + shortVersion + ": "; else shortVersion = "Qt " + shortVersion + ": "; } out() << " " << shortVersion << protectEnc(title) << "\n"; #if 0 out() << QString(postHeader).replace("\\" + COMMAND_VERSION, myTree->version()); generateBreadCrumbs(title,node,marker); out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, myTree->version()); #endif sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); generateTableOfContents(inner,marker,§ions); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); #ifdef QDOC_QML if (cn && !cn->qmlElement().isEmpty()) { generateInstantiatedBy(cn,marker); } #endif generateBrief(inner, marker); generateIncludes(inner, marker); generateStatus(inner, marker); if (cn) { generateInherits(cn, marker); generateInheritedBy(cn, marker); } generateThreadSafeness(inner, marker); generateSince(inner, marker); out() << "
    \n"; QString membersLink = generateListOfAllMemberFile(inner, marker); if (!membersLink.isEmpty()) out() << "
  • " << "List of all members, including inherited members
  • \n"; QString obsoleteLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "
  • " << "Obsolete members
  • \n"; QString compatLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "
  • " << "Qt 3 support members
  • \n"; out() << "
\n"; bool needOtherSection = false; /* sections is built above for the call to generateTableOfContents(). */ s = sections.begin(); while (s != sections.end()) { if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { if (!s->inherited.isEmpty()) needOtherSection = true; } else { if (!s->members.isEmpty()) { out() << "
\n"; out() << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateSection(s->members, inner, marker, CodeMarker::Summary); } if (!s->reimpMembers.isEmpty()) { QString name = QString("Reimplemented ") + (*s).name; out() << "
\n"; out() << "\n"; out() << "

" << protectEnc(name) << "

\n"; generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); } if (!s->inherited.isEmpty()) { out() << "
    \n"; generateSectionInheritedList(*s, inner, marker, true); out() << "
\n"; } } ++s; } if (needOtherSection) { out() << "

Additional Inherited Members

\n" "
    \n"; s = sections.begin(); while (s != sections.end()) { if (s->members.isEmpty() && !s->inherited.isEmpty()) generateSectionInheritedList(*s, inner, marker); ++s; } out() << "
\n"; } out() << "\n"; if (!inner->doc().isEmpty()) { out() << "
\n" << "
\n" // QTBUG-9504 << "

" << "Detailed Description" << "

\n"; generateBody(inner, marker); out() << "
\n"; // QTBUG-9504 generateAlsoList(inner, marker); } sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "
\n"; if (!(*s).divClass.isEmpty()) out() << "
\n"; // QTBUG-9504 out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { if ((*m)->access() != Node::Private) { // ### check necessary? if ((*m)->type() != Node::Class) generateDetailedMember(*m, inner, marker); else { out() << "

class "; generateFullName(*m, inner, marker); out() << "

"; generateBrief(*m, marker, inner); } QStringList names; names << (*m)->name(); if ((*m)->type() == Node::Function) { const FunctionNode *func = reinterpret_cast(*m); if (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor || func->overloadNumber() != 1) names.clear(); } else if ((*m)->type() == Node::Property) { const PropertyNode *prop = reinterpret_cast(*m); if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name())) names << prop->getters().first()->name(); if (!prop->setters().isEmpty()) names << prop->setters().first()->name(); if (!prop->resetters().isEmpty()) names << prop->resetters().first()->name(); } else if ((*m)->type() == Node::Enum) { const EnumNode *enume = reinterpret_cast(*m); if (enume->flagsType()) names << enume->flagsType()->name(); foreach (const QString &enumName, enume->doc().enumItemNames().toSet() - enume->doc().omitEnumItemNames().toSet()) names << plainCode(marker->markedUpEnumValue(enumName, enume)); } } ++m; } if (!(*s).divClass.isEmpty()) out() << "
\n"; // QTBUG-9504 ++s; } #endif } /*! 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) { return; // zzz SubTitleSize subTitleSize = LargeSubTitle; QList
sections; QList
::const_iterator s; QString fullTitle = fake->fullTitle(); QString htmlTitle = fullTitle; if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { subTitleSize = SmallSubTitle; htmlTitle += " (" + fake->subTitle() + ")"; } else if (fake->subType() == Node::QmlBasicType) { fullTitle = "QML Basic Type: " + fullTitle; htmlTitle = fullTitle; } generateHeader(fake); /* Generate the TOC for the new doc format. Don't generate a TOC for the home page. */ if (fake->name() != QString("index.html")) generateTableOfContents(fake,marker,0); generateTitle(fullTitle, Text() << fake->subTitle(), subTitleSize, fake, marker); if (fake->subType() == Node::Module) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); if (moduleNamespaceMap.contains(fake->name())) { out() << "\n"; out() << "

Namespaces

\n"; generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]); } if (moduleClassMap.contains(fake->name())) { out() << "\n"; out() << "

Classes

\n"; generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } } else if (fake->subType() == Node::HeaderFile) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); out() << "
    \n"; QString membersLink = generateListOfAllMemberFile(fake, marker); if (!membersLink.isEmpty()) out() << "
  • " << "List of all members, including inherited members
  • \n"; QString obsoleteLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "
  • " << "Obsolete members
  • \n"; QString compatLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "
  • " << "Qt 3 support members
  • \n"; out() << "
\n"; } #ifdef QDOC_QML else if (fake->subType() == Node::QmlClass) { const QmlClassNode* qml_cn = static_cast(fake); const ClassNode* cn = qml_cn->classNode(); generateQmlInherits(qml_cn, marker); generateQmlInstantiates(qml_cn, marker); generateBrief(qml_cn, marker); generateQmlInheritedBy(qml_cn, marker); sections = marker->qmlSections(qml_cn,CodeMarker::Summary); s = sections.begin(); while (s != sections.end()) { out() << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateQmlSummary(*s,fake,marker); ++s; } out() << "\n"; out() << "

" << "Detailed Description" << "

\n"; generateBody(fake, marker); if (cn) generateQmlText(cn->doc().body(), cn, marker, fake->name()); generateAlsoList(fake, marker); out() << "
\n"; sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); s = sections.begin(); while (s != sections.end()) { out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { generateDetailedQmlMember(*m, fake, marker); out() << "
\n"; ++m; } ++s; } return; } #endif sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "\n"; out() << "

" << protectEnc((*s).name) << "

\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } Text brief = fake->doc().briefText(); if (fake->subType() == Node::Module && !brief.isEmpty()) { out() << "\n"; out() << "
\n"; // QTBUG-9504 out() << "

" << "Detailed Description" << "

\n"; } else out() << "
\n"; // QTBUG-9504 generateBody(fake, marker); out() << "
\n"; // QTBUG-9504 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); } sections = marker->sections(fake, CodeMarker::Detailed, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "
\n"; out() << "

" << protectEnc((*s).name) << "

\n"; NodeList::ConstIterator m = (*s).members.begin(); while (m != (*s).members.end()) { generateDetailedMember(*m, fake, marker); ++m; } ++s; } } /*! Returns "xml" for this subclass of Generator. */ QString DitaXmlGenerator::fileExtension(const Node * /* node */) const { return "xml"; } /*! Output breadcrumb list in the html file. */ void DitaXmlGenerator::generateBreadCrumbs(const QString& title, const Node *node, CodeMarker *marker) { Text breadcrumb; if (node->type() == Node::Class) { const ClassNode* cn = static_cast(node); QString name = node->moduleName(); out() << "
  • All Modules
  • "; if (!name.isEmpty()) { out() << "
  • "; breadcrumb << Atom(Atom::AutoLink,name); generateText(breadcrumb, node, marker); out() << "
  • \n"; } breadcrumb.clear(); if (!cn->name().isEmpty()) { out() << "
  • "; breadcrumb << Atom(Atom::AutoLink,cn->name()); generateText(breadcrumb, 0, marker); out() << "
  • \n"; } } else if (node->type() == Node::Fake) { const FakeNode* fn = static_cast(node); if (node->subType() == Node::Module) { out() << "
  • All Modules
  • "; QString name = node->name(); if (!name.isEmpty()) { out() << "
  • "; breadcrumb << Atom(Atom::AutoLink,name); generateText(breadcrumb, 0, marker); out() << "
  • \n"; } } else if (node->subType() == Node::Group) { if (fn->name() == QString("modules")) out() << "
  • All Modules
  • "; else { out() << "
  • name() << "\">" << title << "
  • "; } } else if (node->subType() == Node::Page) { if (fn->name() == QString("examples.html")) { out() << "
  • Examples
  • "; } else if (fn->name().startsWith("examples-")) { out() << "
  • Examples
  • "; out() << "
  • name() << "\">" << title << "
  • "; } else if (fn->name() == QString("namespaces.html")) { out() << "
  • All Namespaces
  • "; } else { out() << "
  • name() << "\">" << title << "
  • "; } } else if (node->subType() == Node::QmlClass) { out() << "
  • QML Elements
  • "; out() << "
  • name() << "\">" << title << "
  • "; } else if (node->subType() == Node::Example) { out() << "
  • Examples
  • "; QStringList sl = fn->name().split('/'); QString name = "examples-" + sl.at(0) + ".html"; QString t = CodeParser::titleFromName(name); out() << "
  • " << t << "
  • "; out() << "
  • " << title << "
  • "; } } else if (node->type() == Node::Namespace) { const NamespaceNode* nsn = static_cast(node); out() << "
  • All Namespaces
  • "; out() << "
  • " << title << "
  • "; } } void DitaXmlGenerator::generateHeader(const Node* node) { writer.setDevice(out().device()); writer.setAutoFormatting(true); writer.setAutoFormattingIndent(4); writer.writeStartDocument(); if (!node) return; QString docType; QString dtd; QString version; if (node->type() == Node::Class) { docType = "cxxClass"; dtd = "dtd/cxxClass.dtd"; version = "0.6.0"; } QString doctype = ""; writer.writeDTD(doctype); writer.writeComment(node->doc().location().fileName()); } void DitaXmlGenerator::generateTitle(const QString& title, const Text &subTitle, SubTitleSize subTitleSize, const Node *relative, CodeMarker *marker) { if (!title.isEmpty()) out() << "

    " << protectEnc(title) << "

    \n"; if (!subTitle.isEmpty()) { out() << ""; else out() << " class=\"subtitle\">"; generateText(subTitle, relative, marker); out() << "\n"; } } /*! Outputs the brief command as a doc().briefText(); if (!brief.isEmpty()) { ++noLinks; writer.writeStartElement(SHORTDESC); generateText(brief, node, marker); writer.writeEndElement(); // shortdesc --noLinks; } } void DitaXmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) { if (!inner->includes().isEmpty()) { out() << "
    "
                  << trimmedTrailing(highlightedCode(indent(codeIndent,
                                                            marker->markedUpIncludes(inner->includes())),
                                                     marker,inner))
                  << "
    "; } } /*! Generates a table of contents begining at \a node. */ void DitaXmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, Doc::SectioningUnit sectioningUnit, int numColumns, const Node *relative) { return; if (!node->doc().hasTableOfContents()) return; QList toc = node->doc().tableOfContents(); if (toc.isEmpty()) return; QString nodeName = ""; if (node != relative) nodeName = node->name(); QStringList sectionNumber; int columnSize = 0; QString tdTag; if (numColumns > 1) { tdTag = ""; /* width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">";*/ out() << "\n" << tdTag << "\n"; } // disable nested links in table of contents inContents = true; inLink = true; for (int i = 0; i < toc.size(); ++i) { Atom *atom = toc.at(i); int nextLevel = atom->string().toInt(); if (nextLevel > (int)sectioningUnit) continue; if (sectionNumber.size() < nextLevel) { do { out() << "
      "; sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); } else { while (sectionNumber.size() > nextLevel) { out() << "
    \n"; sectionNumber.removeLast(); } sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); } int numAtoms; Text headingText = Text::sectionHeading(atom); if (sectionNumber.size() == 1 && columnSize > toc.size() / numColumns) { out() << "" << tdTag << "
      \n"; columnSize = 0; } out() << "
    • "; out() << ""; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "
    • \n"; ++columnSize; } while (!sectionNumber.isEmpty()) { out() << "
    \n"; sectionNumber.removeLast(); } if (numColumns > 1) out() << "
    \n"; inContents = false; inLink = false; } /*! Revised for the new doc format. Generates a table of contents begining at \a node. */ void DitaXmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, QList
    * sections) { QList toc; if (node->doc().hasTableOfContents()) toc = node->doc().tableOfContents(); if (toc.isEmpty() && !sections && (node->subType() != Node::Module)) return; QStringList sectionNumber; int detailsBase = 0; // disable nested links in table of contents inContents = true; inLink = true; out() << "
    \n"; out() << "

    Contents

    \n"; sectionNumber.append("1"); out() << "
      \n"; if (node->subType() == Node::Module) { if (moduleNamespaceMap.contains(node->name())) { out() << "
    • Namespaces
    • \n"; } if (moduleClassMap.contains(node->name())) { out() << "
    • Classes
    • \n"; } out() << "
    • Detailed Description
    • \n"; for (int i = 0; i < toc.size(); ++i) { if (toc.at(i)->string().toInt() == 1) { detailsBase = 1; break; } } } else if (sections && (node->type() == Node::Class)) { QList
      ::ConstIterator s = sections->begin(); while (s != sections->end()) { if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) { out() << "
    • " << (*s).name << "
    • \n"; } ++s; } out() << "
    • Detailed Description
    • \n"; for (int i = 0; i < toc.size(); ++i) { if (toc.at(i)->string().toInt() == 1) { detailsBase = 1; break; } } } for (int i = 0; i < toc.size(); ++i) { Atom *atom = toc.at(i); int nextLevel = atom->string().toInt() + detailsBase; if (sectionNumber.size() < nextLevel) { do { sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); } else { while (sectionNumber.size() > nextLevel) { sectionNumber.removeLast(); } sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1); } int numAtoms; Text headingText = Text::sectionHeading(atom); QString s = headingText.toString(); out() << "
    • "; out() << ""; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "
    • \n"; } while (!sectionNumber.isEmpty()) { sectionNumber.removeLast(); } out() << "
    \n"; out() << "
    \n"; inContents = false; inLink = false; } QString DitaXmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker) { QList
    sections; QList
    ::ConstIterator s; sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay); if (sections.isEmpty()) return QString(); QString fileName = fileBase(inner) + "-members." + fileExtension(inner); beginSubPage(inner->location(), fileName); QString title = "List of All Members for " + inner->name(); generateHeader(inner); generateTitle(title, Text(), SmallSubTitle, inner, marker); out() << "

    This is the complete list of members for "; generateFullName(inner, 0, marker); out() << ", including inherited members.

    \n"; Section section = sections.first(); generateSectionList(section, 0, marker, CodeMarker::SeparateList); endSubPage(); return fileName; } QString DitaXmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker, CodeMarker::Status status) { QList
    sections = marker->sections(inner, CodeMarker::Summary, status); QMutableListIterator
    j(sections); while (j.hasNext()) { if (j.next().members.size() == 0) j.remove(); } if (sections.isEmpty()) return QString(); int i; QString title; QString fileName; if (status == CodeMarker::Compat) { title = "Qt 3 Support Members for " + inner->name(); fileName = fileBase(inner) + "-qt3." + fileExtension(inner); } else { title = "Obsolete Members for " + inner->name(); fileName = fileBase(inner) + "-obsolete." + fileExtension(inner); } beginSubPage(inner->location(), fileName); generateHeader(inner); generateTitle(title, Text(), SmallSubTitle, inner, marker); if (status == CodeMarker::Compat) { out() << "

    The following class members are part of the " "Qt 3 support layer. " "They are provided to help you port old code to Qt 4. We advise against " "using them in new code.

    \n"; } else { out() << "

    The following class members are obsolete. " << "They are provided to keep old source code working. " << "We strongly advise against using them in new code.

    \n"; } out() << "

    • " << protectEnc(inner->name()) << " class reference

    \n"; for (i = 0; i < sections.size(); ++i) { out() << "

    " << protectEnc(sections.at(i).name) << "

    \n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } sections = marker->sections(inner, CodeMarker::Detailed, status); for (i = 0; i < sections.size(); ++i) { out() << "
    \n"; out() << "

    " << protectEnc(sections.at(i).name) << "

    \n"; NodeList::ConstIterator m = sections.at(i).members.begin(); while (m != sections.at(i).members.end()) { if ((*m)->access() != Node::Private) generateDetailedMember(*m, inner, marker); ++m; } } endSubPage(); return fileName; } void DitaXmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker, const QMap &classMap) { if (classMap.isEmpty()) return; NodeMap topLevel; NodeMap::ConstIterator c = classMap.begin(); while (c != classMap.end()) { const ClassNode *classe = static_cast(*c); if (classe->baseClasses().isEmpty()) topLevel.insert(classe->name(), classe); ++c; } QStack stack; stack.push(topLevel); out() << "
      \n"; while (!stack.isEmpty()) { if (stack.top().isEmpty()) { stack.pop(); out() << "
    \n"; } else { const ClassNode *child = static_cast(*stack.top().begin()); out() << "
  • "; generateFullName(child, relative, marker); out() << "
  • \n"; stack.top().erase(stack.top().begin()); NodeMap newTop; foreach (const RelatedClass &d, child->derivedClasses()) { if (d.access != Node::Private) newTop.insert(d.node->name(), d.node); } if (!newTop.isEmpty()) { stack.push(newTop); out() << "
      \n"; } } } } void DitaXmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, const NodeMap &nodeMap) { out() << "\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { const Node *node = nodeMap[name]; if (node->status() == Node::Obsolete) continue; if (++row % 2 == 1) out() << ""; else out() << ""; out() << ""; if (!(node->type() == Node::Fake)) { Text brief = node->doc().trimmedBriefText(name); if (!brief.isEmpty()) { out() << ""; } } else { out() << ""; } out() << "\n"; } out() << "

      "; generateFullName(node, relative, marker); out() << "

      "; generateText(brief, node, marker); out() << "

      "; out() << protectEnc(node->doc().briefText().toString()); out() << "

      \n"; } /*! This function finds the common prefix of the names of all the classes in \a classMap and then generates a compact list of the class names alphabetized on the part of the name not including the common prefix. You can tell the function to use \a comonPrefix as the common prefix, but normally you let it figure it out itself by looking at the name of the first and last classes in \a classMap. */ void DitaXmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker, const NodeMap &classMap, bool includeAlphabet, QString commonPrefix) { const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' if (classMap.isEmpty()) return; /* If commonPrefix is not empty, then the caller knows what the common prefix is and has passed it in, so just use that one. */ int commonPrefixLen = commonPrefix.length(); if (commonPrefixLen == 0) { QString first; QString last; /* The caller didn't pass in a common prefix, so get the common prefix by looking at the class names of the first and last classes in the class map. Discard any namespace names and just use the bare class names. For Qt, the prefix is "Q". Note that the algorithm used here to derive the common prefix from the first and last classes in alphabetical order (QAccel and QXtWidget in Qt 2.1), fails if either class name does not begin with Q. */ NodeMap::const_iterator iter = classMap.begin(); while (iter != classMap.end()) { if (!iter.key().contains("::")) { first = iter.key(); break; } ++iter; } if (first.isEmpty()) first = classMap.begin().key(); iter = classMap.end(); while (iter != classMap.begin()) { --iter; if (!iter.key().contains("::")) { last = iter.key(); break; } } if (last.isEmpty()) last = classMap.begin().key(); if (classMap.size() > 1) { while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1 && first[commonPrefixLen] == last[commonPrefixLen]) ++commonPrefixLen; } commonPrefix = first.left(commonPrefixLen); } /* Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z, underscore (_). QAccel will fall in paragraph 10 (A) and QXtWidget in paragraph 33 (X). This is the only place where we assume that NumParagraphs is 37. Each paragraph is a NodeMap. */ NodeMap paragraph[NumParagraphs+1]; QString paragraphName[NumParagraphs+1]; QSet usedParagraphNames; NodeMap::ConstIterator c = classMap.begin(); while (c != classMap.end()) { QStringList pieces = c.key().split("::"); QString key; int idx = commonPrefixLen; if (!pieces.last().startsWith(commonPrefix)) idx = 0; if (pieces.size() == 1) key = pieces.last().mid(idx).toLower(); else key = pieces.last().toLower(); int paragraphNr = NumParagraphs - 1; if (key[0].digitValue() != -1) { paragraphNr = key[0].digitValue(); } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { paragraphNr = 10 + key[0].unicode() - 'a'; } paragraphName[paragraphNr] = key[0].toUpper(); usedParagraphNames.insert(key[0].toLower().cell()); paragraph[paragraphNr].insert(key, c.value()); ++c; } /* Each paragraph j has a size: paragraph[j].count(). In the discussion, we will assume paragraphs 0 to 5 will have sizes 3, 1, 4, 1, 5, 9. We now want to compute the paragraph offset. Paragraphs 0 to 6 start at offsets 0, 3, 4, 8, 9, 14, 23. */ int paragraphOffset[NumParagraphs + 1]; // 37 + 1 paragraphOffset[0] = 0; for (int i=0; i"; for (int i = 0; i < 26; i++) { QChar ch('a' + i); if (usedParagraphNames.contains(char('a' + i))) out() << QString("%2 ").arg(ch).arg(ch.toUpper()); } out() << "

      \n"; } /* Output a
      element to contain all the
      elements. */ out() << "
      \n"; for (int i=0; i. */ if (curParOffset == 0) { if (i > 0) out() << "
      \n"; if (++numTableRows % 2 == 1) out() << "
      "; else out() << "
      "; out() << "
      "; if (includeAlphabet) { QChar c = paragraphName[curParNr][0].toLower(); out() << QString("").arg(c); } out() << "" << paragraphName[curParNr] << ""; out() << "
      \n"; } /* Output a
      for the current offset in the current paragraph. */ out() << "
      "; if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) { NodeMap::Iterator it; it = paragraph[curParNr].begin(); for (int i=0; i"; QStringList pieces; if (it.value()->subType() == Node::QmlClass) pieces << it.value()->name(); else pieces = fullName(it.value(), relative, marker).split("::"); out() << protectEnc(pieces.last()); out() << ""; if (pieces.size() > 1) { out() << " ("; generateFullName(it.value()->parent(), relative, marker); out() << ")"; } } out() << "
      \n"; curParOffset++; } out() << "
      \n"; out() << "
      \n"; } void DitaXmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker) { out() << "

      "; for (int i = 0; i < 26; i++) { QChar ch('a' + i); out() << QString("%2 ").arg(ch).arg(ch.toUpper()); } out() << "

      \n"; char nextLetter = 'a'; char currentLetter; #if 1 out() << "
        \n"; #endif QMap::ConstIterator f = funcIndex.begin(); while (f != funcIndex.end()) { #if 1 out() << "
      • "; #else out() << "

        "; #endif out() << protectEnc(f.key()) << ":"; currentLetter = f.key()[0].unicode(); while (islower(currentLetter) && currentLetter >= nextLetter) { out() << QString("").arg(nextLetter); nextLetter++; } NodeMap::ConstIterator s = (*f).begin(); while (s != (*f).end()) { out() << " "; generateFullName((*s)->parent(), relative, marker, *s); ++s; } #if 1 out() << "

      • "; #else out() << "

        "; #endif out() << "\n"; ++f; } #if 1 out() << "
      \n"; #endif } void DitaXmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker) { QMap::ConstIterator it = legaleseTexts.begin(); while (it != legaleseTexts.end()) { Text text = it.key(); out() << "
      \n"; generateText(text, relative, marker); out() << "
        \n"; do { out() << "
      • "; generateFullName(it.value(), relative, marker); out() << "
      • \n"; ++it; } while (it != legaleseTexts.end() && it.key() == text); out() << "
      \n"; } } /*void DitaXmlGenerator::generateSynopsis(const Node *node, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style) { QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])"), "\\1\\2"); marked.replace("<@param>", ""); marked.replace("", ""); if (style == CodeMarker::Summary) marked.replace("@name>", "b>"); if (style == CodeMarker::SeparateList) { QRegExp extraRegExp("<@extra>.*"); extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); } else { marked.replace("<@extra>", "  "); marked.replace("", ""); } if (style != CodeMarker::Detailed) { marked.replace("<@type>", ""); marked.replace("", ""); } out() << highlightedCode(marked, marker, relative); }*/ #ifdef QDOC_QML void DitaXmlGenerator::generateQmlItem(const Node *node, const Node *relative, CodeMarker *marker, bool summary) { QString marked = marker->markedUpQmlItem(node,summary); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])"), "\\1\\2"); marked.replace("<@param>", ""); marked.replace("", ""); if (summary) marked.replace("@name>", "b>"); marked.replace("<@extra>", ""); marked.replace("", ""); if (summary) { marked.replace("<@type>", ""); marked.replace("", ""); } out() << highlightedCode(marked, marker, relative); } #endif void DitaXmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) { QMap > fakeNodeMap; QMap groupTitlesMap; QMap uncategorizedNodeMap; QRegExp singleDigit("\\b([0-9])\\b"); const NodeList children = myTree->root()->childNodes(); foreach (Node *child, children) { if (child->type() == Node::Fake && child != relative) { FakeNode *fakeNode = static_cast(child); // Check whether the page is part of a group or is the group // definition page. QString group; bool isGroupPage = false; if (fakeNode->doc().metaCommandsUsed().contains("group")) { group = fakeNode->doc().metaCommandArgs("group")[0]; isGroupPage = true; } // there are too many examples; they would clutter the list if (fakeNode->subType() == Node::Example) continue; // not interested either in individual (Qt Designer etc.) manual chapters if (fakeNode->links().contains(Node::ContentsLink)) continue; // Discard external nodes. if (fakeNode->subType() == Node::ExternalPage) continue; QString sortKey = fakeNode->fullTitle().toLower(); if (sortKey.startsWith("the ")) sortKey.remove(0, 4); sortKey.replace(singleDigit, "0\\1"); if (!group.isEmpty()) { if (isGroupPage) { // If we encounter a group definition page, we add all // the pages in that group to the list for that group. foreach (Node *member, fakeNode->groupMembers()) { if (member->type() != Node::Fake) continue; FakeNode *page = static_cast(member); if (page) { QString sortKey = page->fullTitle().toLower(); if (sortKey.startsWith("the ")) sortKey.remove(0, 4); sortKey.replace(singleDigit, "0\\1"); fakeNodeMap[const_cast(fakeNode)].insert(sortKey, page); groupTitlesMap[fakeNode->fullTitle()] = const_cast(fakeNode); } } } else if (!isGroupPage) { // If we encounter a page that belongs to a group then // we add that page to the list for that group. const FakeNode *groupNode = static_cast(myTree->root()->findNode(group, Node::Fake)); if (groupNode) fakeNodeMap[groupNode].insert(sortKey, fakeNode); //else // uncategorizedNodeMap.insert(sortKey, fakeNode); }// else // uncategorizedNodeMap.insert(sortKey, fakeNode); }// else // uncategorizedNodeMap.insert(sortKey, fakeNode); } } // We now list all the pages found that belong to groups. // If only certain pages were found for a group, but the definition page // for that group wasn't listed, the list of pages will be intentionally // incomplete. However, if the group definition page was listed, all the // pages in that group are listed for completeness. if (!fakeNodeMap.isEmpty()) { foreach (const QString &groupTitle, groupTitlesMap.keys()) { const FakeNode *groupNode = groupTitlesMap[groupTitle]; out() << QString("

      %2

      \n").arg( linkForNode(groupNode, relative)).arg( protectEnc(groupNode->fullTitle())); if (fakeNodeMap[groupNode].count() == 0) continue; out() << "
        \n"; foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) { QString title = fakeNode->fullTitle(); if (title.startsWith("The ")) title.remove(0, 4); out() << "
      • " << protectEnc(title) << "
      • \n"; } out() << "
      \n"; } } if (!uncategorizedNodeMap.isEmpty()) { out() << QString("

      Miscellaneous

      \n"); out() << "
        \n"; foreach (const FakeNode *fakeNode, uncategorizedNodeMap) { QString title = fakeNode->fullTitle(); if (title.startsWith("The ")) title.remove(0, 4); out() << "
      • " << protectEnc(title) << "
      • \n"; } out() << "
      \n"; } } void DitaXmlGenerator::generateSection(const NodeList& nl, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style) { bool name_alignment = true; if (!nl.isEmpty()) { bool twoColumn = false; if (style == CodeMarker::SeparateList) { name_alignment = false; twoColumn = (nl.count() >= 16); } else if (nl.first()->type() == Node::Property) { twoColumn = (nl.count() >= 5); name_alignment = false; } if (name_alignment) { out() << "\n"; } else { if (twoColumn) out() << "
      \n" << "\n"; else out() << "\n"; i++; ++m; } if (name_alignment) out() << "
      "; out() << "
        \n"; } int i = 0; NodeList::ConstIterator m = nl.begin(); while (m != nl.end()) { if ((*m)->access() == Node::Private) { ++m; continue; } if (name_alignment) { out() << "
      "; } else { if (twoColumn && i == (int) (nl.count() + 1) / 2) out() << "
        \n"; out() << "
      • "; } generateSynopsis(*m, relative, marker, style, name_alignment); if (name_alignment) out() << "
      \n"; else { out() << "
    \n"; if (twoColumn) out() << "\n\n"; } } } void DitaXmlGenerator::generateSectionList(const Section& section, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style) { bool name_alignment = true; if (!section.members.isEmpty()) { bool twoColumn = false; if (style == CodeMarker::SeparateList) { name_alignment = false; twoColumn = (section.members.count() >= 16); } else if (section.members.first()->type() == Node::Property) { twoColumn = (section.members.count() >= 5); name_alignment = false; } if (name_alignment) { out() << "\n"; } else { if (twoColumn) out() << "
    \n" << "\n"; else out() << "\n"; i++; ++m; } if (name_alignment) out() << "
    "; out() << "
      \n"; } int i = 0; NodeList::ConstIterator m = section.members.begin(); while (m != section.members.end()) { if ((*m)->access() == Node::Private) { ++m; continue; } if (name_alignment) { out() << "
    "; } else { if (twoColumn && i == (int) (section.members.count() + 1) / 2) out() << "
      \n"; out() << "
    • "; } generateSynopsis(*m, relative, marker, style, name_alignment); if (name_alignment) out() << "
    \n"; else { out() << "\n"; if (twoColumn) out() << "\n\n"; } } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { out() << "
      \n"; generateSectionInheritedList(section, relative, marker, name_alignment); out() << "
    \n"; } } void DitaXmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative, CodeMarker *marker, bool nameAlignment) { QList >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { if (nameAlignment) out() << "
  • "; else out() << "
  • "; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; } else { out() << section.pluralMember; } out() << " inherited from " << protectEnc(marker->plainFullName((*p).first, relative)) << "
  • \n"; ++p; } } void DitaXmlGenerator::generateSynopsis(const Node *node, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style, bool nameAlignment) { QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); if (marked.indexOf(templateTag) != -1) { QString contents = protectEnc(marked.mid(templateTag.pos(1), templateTag.cap(1).length())); marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])"), "\\1\\2"); marked.replace("<@param>", ""); marked.replace("", ""); if (style == CodeMarker::Summary) { marked.replace("<@name>", ""); // was "" marked.replace("", ""); // was "" } if (style == CodeMarker::SeparateList) { QRegExp extraRegExp("<@extra>.*"); extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); } else { marked.replace("<@extra>", ""); marked.replace("", ""); } if (style != CodeMarker::Detailed) { marked.replace("<@type>", ""); marked.replace("", ""); } out() << highlightedCode(marked, marker, relative, style, nameAlignment); } QString DitaXmlGenerator::highlightedCode(const QString& markedCode, CodeMarker *marker, const Node *relative, CodeMarker::SynopsisStyle , bool nameAlignment) { QString src = markedCode; QString html; QStringRef arg; QStringRef par1; const QChar charLangle = '<'; const QChar charAt = '@'; // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*()" static const QString linkTag("link"); bool done = false; for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { if (nameAlignment && !done) {// && (i != 0)) Why was this here? html += ""; done = true; } i += 2; if (parseArg(src, linkTag, &i, n, &arg, &par1)) { html += ""; QString link = linkForNode( CodeMarker::nodeForString(par1.toString()), relative); addLink(link, arg, &html); html += ""; } else { html += charLangle; html += charAt; } } else { html += src.at(i++); } } if (slow) { // is this block ever used at all? // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)()" src = html; html = QString(); static const QString funcTag("func"); for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; if (parseArg(src, funcTag, &i, n, &arg, &par1)) { QString link = linkForNode( marker->resolveTarget(par1.toString(), myTree, relative), relative); addLink(link, arg, &html); par1 = QStringRef(); } else { html += charLangle; html += charAt; } } else { html += src.at(i++); } } } // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()" tags src = html; html = QString(); static const QString typeTags[] = { "type", "headerfile", "func" }; for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; bool handled = false; for (int k = 0; k != 3; ++k) { if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) { par1 = QStringRef(); QString link = linkForNode( marker->resolveTarget(arg.toString(), myTree, relative), relative); addLink(link, arg, &html); handled = true; break; } } if (!handled) { html += charLangle; html += charAt; } } else { html += src.at(i++); } } // replace all // "<@comment>" -> ""; // "<@preprocessor>" -> ""; // "<@string>" -> ""; // "<@char>" -> ""; // "" -> "" src = html; html = QString(); static const QString spanTags[] = { "<@comment>", "", "<@preprocessor>", "", "<@string>", "", "<@char>", "", "", "", "","", "", "", "", "" // "<@char>", "", // "", "", // "<@func>", "", // "", "", // "<@id>", "", // "", "", // "<@keyword>", "", // "", "", // "<@number>", "", // "", "", // "<@op>", "", // "", "", // "<@param>", "", // "", "", // "<@string>", "", // "", "", }; for (int i = 0, n = src.size(); i < n;) { if (src.at(i) == charLangle) { bool handled = false; for (int k = 0; k != 8; ++k) { const QString & tag = spanTags[2 * k]; if (tag == QStringRef(&src, i, tag.length())) { html += spanTags[2 * k + 1]; i += tag.length(); handled = true; break; } } if (!handled) { ++i; if (src.at(i) == charAt || (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) { // drop 'our' unknown tags (the ones still containing '@') while (i < n && src.at(i) != QLatin1Char('>')) ++i; ++i; } else { // retain all others html += charLangle; } } } else { html += src.at(i); ++i; } } return html; } void DitaXmlGenerator::generateLink(const Atom* atom, const Node* /* relative */, CodeMarker* marker) { static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { // hack for C++: move () outside of link int k = funcLeftParen.pos(1); writer.writeCharacters(protectEnc(atom->string().left(k))); if (link.isEmpty()) { if (showBrokenLinks) writer.writeEndElement(); // } else { writer.writeEndElement(); // } inLink = false; writer.writeCharacters(protectEnc(atom->string().mid(k))); } else if (marker->recognizeLanguage("Java")) { // hack for Java: remove () and use when appropriate bool func = atom->string().endsWith("()"); bool tt = (func || atom->string().contains(camelCase)); if (tt) writer.writeStartElement("tt"); if (func) { writer.writeCharacters(protectEnc(atom->string().left(atom->string().length() - 2))); } else { writer.writeCharacters(protectEnc(atom->string())); } writer.writeEndElement(); // } else { writer.writeCharacters(protectEnc(atom->string())); } } QString DitaXmlGenerator::cleanRef(const QString& ref) { QString clean; if (ref.isEmpty()) return clean; clean.reserve(ref.size() + 20); const QChar c = ref[0]; const uint u = c.unicode(); if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9')) { clean += c; } else if (u == '~') { clean += "dtor."; } else if (u == '_') { clean += "underscore."; } else { clean += "A"; } for (int i = 1; i < (int) ref.length(); i++) { const QChar c = ref[i]; const uint u = c.unicode(); if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9') || u == '-' || u == '_' || u == ':' || u == '.') { clean += c; } else if (c.isSpace()) { clean += "-"; } else if (u == '!') { clean += "-not"; } else if (u == '&') { clean += "-and"; } else if (u == '<') { clean += "-lt"; } else if (u == '=') { clean += "-eq"; } else if (u == '>') { clean += "-gt"; } else if (u == '#') { clean += "#"; } else { clean += "-"; clean += QString::number((int)u, 16); } } return clean; } QString DitaXmlGenerator::registerRef(const QString& ref) { QString clean = DitaXmlGenerator::cleanRef(ref); for (;;) { QString& prevRef = refMap[clean.toLower()]; if (prevRef.isEmpty()) { prevRef = ref; break; } else if (prevRef == ref) { break; } clean += "x"; } return clean; } QString DitaXmlGenerator::protectEnc(const QString &string) { return protect(string, outputEncoding); } QString DitaXmlGenerator::protect(const QString &string, const QString &outputEncoding) { #define APPEND(x) \ if (xml.isEmpty()) { \ xml = string; \ xml.truncate(i); \ } \ xml += (x); QString xml; int n = string.length(); for (int i = 0; i < n; ++i) { QChar ch = string.at(i); if (ch == QLatin1Char('&')) { APPEND("&"); } else if (ch == QLatin1Char('<')) { APPEND("<"); } else if (ch == QLatin1Char('>')) { APPEND(">"); } else if (ch == QLatin1Char('"')) { APPEND("""); } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F) || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator APPEND("&#x"); xml += QString::number(ch.unicode(), 16); xml += QLatin1Char(';'); } else { if (!xml.isEmpty()) xml += ch; } } if (!xml.isEmpty()) return xml; return string; #undef APPEND } QString DitaXmlGenerator::fileBase(const Node *node) { QString result; result = PageGenerator::fileBase(node); if (!node->isInnerNode()) { switch (node->status()) { case Node::Compat: result += "-qt3"; break; case Node::Obsolete: result += "-obsolete"; break; default: ; } } return result; } #if 0 QString DitaXmlGenerator::fileBase(const Node *node, const SectionIterator& section) { QStringList::ConstIterator s = section.sectionNumber().end(); QStringList::ConstIterator b = section.baseNameStack().end(); QString suffix; QString base = fileBase(node); while (s != section.sectionNumber().begin()) { --s; --b; if (!(*b).isEmpty()) { base = *b; break; } suffix.prepend("-" + *s); } return base + suffix; } #endif QString DitaXmlGenerator::fileName(const Node *node) { if (node->type() == Node::Fake) { if (static_cast(node)->subType() == Node::ExternalPage) return node->name(); if (static_cast(node)->subType() == Node::Image) return node->name(); } return PageGenerator::fileName(node); } QString DitaXmlGenerator::refForNode(const Node *node) { const FunctionNode *func; const TypedefNode *typedeffe; QString ref; switch (node->type()) { case Node::Namespace: case Node::Class: default: break; case Node::Enum: ref = node->name() + "-enum"; break; case Node::Typedef: typedeffe = static_cast(node); if (typedeffe->associatedEnum()) { return refForNode(typedeffe->associatedEnum()); } else { ref = node->name() + "-typedef"; } break; case Node::Function: func = static_cast(node); if (func->associatedProperty()) { return refForNode(func->associatedProperty()); } else { ref = func->name(); if (func->overloadNumber() != 1) ref += "-" + QString::number(func->overloadNumber()); } break; #ifdef QDOC_QML case Node::Fake: if (node->subType() != Node::QmlPropertyGroup) break; case Node::QmlProperty: #endif case Node::Property: ref = node->name() + "-prop"; break; #ifdef QDOC_QML case Node::QmlSignal: ref = node->name() + "-signal"; break; case Node::QmlMethod: ref = node->name() + "-method"; break; #endif case Node::Variable: ref = node->name() + "-var"; break; case Node::Target: return protectEnc(node->name()); } return registerRef(ref); } QString DitaXmlGenerator::linkForNode(const Node *node, const Node *relative) { QString link; QString fn; QString ref; if (node == 0 || node == relative) return QString(); if (!node->url().isEmpty()) return node->url(); if (fileBase(node).isEmpty()) return QString(); if (node->access() == Node::Private) return QString(); fn = fileName(node); link += fn; if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) { ref = refForNode(node); if (relative && fn == fileName(relative) && ref == refForNode(relative)) return QString(); link += "#"; link += ref; } return link; } QString DitaXmlGenerator::refForAtom(Atom *atom, const Node * /* node */) { if (atom->type() == Atom::SectionLeft) { return Doc::canonicalTitle(Text::sectionHeading(atom).toString()); } else if (atom->type() == Atom::Target) { return Doc::canonicalTitle(atom->string()); } else { return QString(); } } void DitaXmlGenerator::generateFullName(const Node *apparentNode, const Node *relative, CodeMarker *marker, const Node *actualNode) { if (actualNode == 0) actualNode = apparentNode; out() << "status() != actualNode->status()) { switch (actualNode->status()) { case Node::Obsolete: out() << "\" class=\"obsolete"; break; case Node::Compat: out() << "\" class=\"compat"; break; default: ; } } out() << "\">"; out() << protectEnc(fullName(apparentNode, relative, marker)); out() << ""; } void DitaXmlGenerator::generateDetailedMember(const Node *node, const InnerNode *relative, CodeMarker *marker) { const EnumNode *enume; #ifdef GENERATE_MAC_REFS generateMacRef(node, marker); #endif if (node->type() == Node::Enum && (enume = static_cast(node))->flagsType()) { #ifdef GENERATE_MAC_REFS generateMacRef(enume->flagsType(), marker); #endif out() << "

    "; out() << ""; generateSynopsis(enume, relative, marker, CodeMarker::Detailed); out() << "
    "; generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed); out() << "

    \n"; } else { out() << "

    "; out() << ""; generateSynopsis(node, relative, marker, CodeMarker::Detailed); out() << "

    \n"; } generateStatus(node, marker); generateBody(node, marker); generateThreadSafeness(node, marker); generateSince(node, marker); if (node->type() == Node::Property) { const PropertyNode *property = static_cast(node); Section section; section.members += property->getters(); section.members += property->setters(); section.members += property->resetters(); if (!section.members.isEmpty()) { out() << "

    Access functions:

    \n"; generateSectionList(section, node, marker, CodeMarker::Accessors); } Section notifiers; notifiers.members += property->notifiers(); if (!notifiers.members.isEmpty()) { out() << "

    Notifier signal:

    \n"; //out() << "

    This signal is emitted when the property value is changed.

    \n"; generateSectionList(notifiers, node, marker, CodeMarker::Accessors); } } else if (node->type() == Node::Enum) { const EnumNode *enume = static_cast(node); if (enume->flagsType()) { out() << "

    The " << protectEnc(enume->flagsType()->name()) << " type is a typedef for " << "QFlags<" << protectEnc(enume->name()) << ">. It stores an OR combination of " << protectEnc(enume->name()) << " values.

    \n"; } } generateAlsoList(node, marker); } void DitaXmlGenerator::findAllClasses(const InnerNode *node) { NodeList::const_iterator c = node->childNodes().constBegin(); while (c != node->childNodes().constEnd()) { if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) { if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { QString className = (*c)->name(); if ((*c)->parent() && (*c)->parent()->type() == Node::Namespace && !(*c)->parent()->name().isEmpty()) className = (*c)->parent()->name()+"::"+className; if (!(static_cast(*c))->hideFromMainList()) { if ((*c)->status() == Node::Compat) { compatClasses.insert(className, *c); } else if ((*c)->status() == Node::Obsolete) { obsoleteClasses.insert(className, *c); } else { nonCompatClasses.insert(className, *c); if ((*c)->status() == Node::Main) mainClasses.insert(className, *c); } } QString moduleName = (*c)->moduleName(); if (moduleName == "Qt3SupportLight") { moduleClassMap[moduleName].insert((*c)->name(), *c); moduleName = "Qt3Support"; } if (!moduleName.isEmpty()) moduleClassMap[moduleName].insert((*c)->name(), *c); QString serviceName = (static_cast(*c))->serviceName(); if (!serviceName.isEmpty()) serviceClasses.insert(serviceName, *c); } else if ((*c)->isInnerNode()) { findAllClasses(static_cast(*c)); } } ++c; } } /*! For generating the "New Classes... in 4.6" section on the What's New in 4.6" page. */ void DitaXmlGenerator::findAllSince(const InnerNode *node) { NodeList::const_iterator child = node->childNodes().constBegin(); while (child != node->childNodes().constEnd()) { QString sinceVersion = (*child)->since(); if (((*child)->access() != Node::Private) && !sinceVersion.isEmpty()) { NewSinceMaps::iterator nsmap = newSinceMaps.find(sinceVersion); if (nsmap == newSinceMaps.end()) nsmap = newSinceMaps.insert(sinceVersion,NodeMultiMap()); NewClassMaps::iterator ncmap = newClassMaps.find(sinceVersion); if (ncmap == newClassMaps.end()) ncmap = newClassMaps.insert(sinceVersion,NodeMap()); NewClassMaps::iterator nqcmap = newQmlClassMaps.find(sinceVersion); if (nqcmap == newQmlClassMaps.end()) nqcmap = newQmlClassMaps.insert(sinceVersion,NodeMap()); if ((*child)->type() == Node::Function) { FunctionNode *func = static_cast(*child); if ((func->status() > Node::Obsolete) && (func->metaness() != FunctionNode::Ctor) && (func->metaness() != FunctionNode::Dtor)) { nsmap.value().insert(func->name(),(*child)); } } else if ((*child)->url().isEmpty()) { if ((*child)->type() == Node::Class && !(*child)->doc().isEmpty()) { QString className = (*child)->name(); if ((*child)->parent() && (*child)->parent()->type() == Node::Namespace && !(*child)->parent()->name().isEmpty()) className = (*child)->parent()->name()+"::"+className; nsmap.value().insert(className,(*child)); ncmap.value().insert(className,(*child)); } else if ((*child)->subType() == Node::QmlClass) { QString className = (*child)->name(); if ((*child)->parent() && (*child)->parent()->type() == Node::Namespace && !(*child)->parent()->name().isEmpty()) className = (*child)->parent()->name()+"::"+className; nsmap.value().insert(className,(*child)); nqcmap.value().insert(className,(*child)); } } else { QString name = (*child)->name(); if ((*child)->parent() && (*child)->parent()->type() == Node::Namespace && !(*child)->parent()->name().isEmpty()) name = (*child)->parent()->name()+"::"+name; nsmap.value().insert(name,(*child)); } if ((*child)->isInnerNode()) { findAllSince(static_cast(*child)); } } ++child; } } #if 0 const QRegExp versionSeparator("[\\-\\.]"); const int minorIndex = version.indexOf(versionSeparator); const int patchIndex = version.indexOf(versionSeparator, minorIndex+1); version = version.left(patchIndex); #endif void DitaXmlGenerator::findAllFunctions(const InnerNode *node) { NodeList::ConstIterator c = node->childNodes().begin(); while (c != node->childNodes().end()) { if ((*c)->access() != Node::Private) { if ((*c)->isInnerNode() && (*c)->url().isEmpty()) { findAllFunctions(static_cast(*c)); } else if ((*c)->type() == Node::Function) { const FunctionNode *func = static_cast(*c); if ((func->status() > Node::Obsolete) && (func->metaness() != FunctionNode::Ctor) && (func->metaness() != FunctionNode::Dtor)) { funcIndex[(*c)->name()].insert(myTree->fullDocumentName((*c)->parent()), *c); } } } ++c; } } void DitaXmlGenerator::findAllLegaleseTexts(const InnerNode *node) { NodeList::ConstIterator c = node->childNodes().begin(); while (c != node->childNodes().end()) { if ((*c)->access() != Node::Private) { if (!(*c)->doc().legaleseText().isEmpty()) legaleseTexts.insertMulti((*c)->doc().legaleseText(), *c); if ((*c)->isInnerNode()) findAllLegaleseTexts(static_cast(*c)); } ++c; } } void DitaXmlGenerator::findAllNamespaces(const InnerNode *node) { NodeList::ConstIterator c = node->childNodes().begin(); while (c != node->childNodes().end()) { if ((*c)->access() != Node::Private) { if ((*c)->isInnerNode() && (*c)->url().isEmpty()) { findAllNamespaces(static_cast(*c)); if ((*c)->type() == Node::Namespace) { const NamespaceNode *nspace = static_cast(*c); // Ensure that the namespace's name is not empty (the root // namespace has no name). if (!nspace->name().isEmpty()) { namespaceIndex.insert(nspace->name(), *c); QString moduleName = (*c)->moduleName(); if (moduleName == "Qt3SupportLight") { moduleNamespaceMap[moduleName].insert((*c)->name(), *c); moduleName = "Qt3Support"; } if (!moduleName.isEmpty()) moduleNamespaceMap[moduleName].insert((*c)->name(), *c); } } } } ++c; } } int DitaXmlGenerator::hOffset(const Node *node) { switch (node->type()) { case Node::Namespace: case Node::Class: return 2; case Node::Fake: return 1; #if 0 if (node->doc().briefText().isEmpty()) return 1; else return 2; #endif case Node::Enum: case Node::Typedef: case Node::Function: case Node::Property: default: return 3; } } bool DitaXmlGenerator::isThreeColumnEnumValueTable(const Atom *atom) { while (atom != 0 && !(atom->type() == Atom::ListRight && atom->string() == ATOM_LIST_VALUE)) { if (atom->type() == Atom::ListItemLeft && !matchAhead(atom, Atom::ListItemRight)) return true; atom = atom->next(); } return false; } const Node *DitaXmlGenerator::findNodeForTarget(const QString &target, const Node *relative, CodeMarker *marker, const Atom *atom) { const Node *node = 0; if (target.isEmpty()) { node = relative; } else if (target.endsWith(".html")) { node = myTree->root()->findNode(target, Node::Fake); } else if (marker) { node = marker->resolveTarget(target, myTree, relative); if (!node) node = myTree->findFakeNodeByTitle(target); if (!node && atom) { node = myTree->findUnambiguousTarget(target, *const_cast(&atom)); } } if (!node) relative->doc().location().warning(tr("Cannot link to '%1'").arg(target)); return node; } const QPair DitaXmlGenerator::anchorForNode(const Node *node) { QPair anchorPair; anchorPair.first = PageGenerator::fileName(node); if (node->type() == Node::Fake) { const FakeNode *fakeNode = static_cast(node); anchorPair.second = fakeNode->title(); } return anchorPair; } QString DitaXmlGenerator::getLink(const Atom *atom, const Node *relative, CodeMarker *marker, const Node** node) { QString link; *node = 0; inObsoleteLink = false; if (atom->string().contains(":") && (atom->string().startsWith("file:") || atom->string().startsWith("http:") || atom->string().startsWith("https:") || atom->string().startsWith("ftp:") || atom->string().startsWith("mailto:"))) { link = atom->string(); } else { QStringList path; if (atom->string().contains('#')) { path = atom->string().split('#'); } else { path.append(atom->string()); } Atom *targetAtom = 0; QString first = path.first().trimmed(); if (first.isEmpty()) { *node = relative; } else if (first.endsWith(".html")) { *node = myTree->root()->findNode(first, Node::Fake); } else { *node = marker->resolveTarget(first, myTree, relative); if (!*node) { *node = myTree->findFakeNodeByTitle(first); } if (!*node) { *node = myTree->findUnambiguousTarget(first, targetAtom); } } if (*node) { if (!(*node)->url().isEmpty()) return (*node)->url(); else path.removeFirst(); } else { *node = relative; } if (*node) { if ((*node)->status() == Node::Obsolete) { if (relative) { if (relative->parent() != *node) { if (relative->status() != Node::Obsolete) { bool porting = false; if (relative->type() == Node::Fake) { const FakeNode* fake = static_cast(relative); if (fake->title().startsWith("Porting")) porting = true; } QString name = marker->plainFullName(relative); if (!porting && !name.startsWith("Q3")) { if (obsoleteLinks) { relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") .arg(atom->string()) .arg(name)); } inObsoleteLink = true; } } } } else { qDebug() << "Link to Obsolete entity" << (*node)->name() << "no relative"; } } #if 0 else if ((*node)->status() == Node::Deprecated) { qDebug() << "Link to Deprecated entity"; } else if ((*node)->status() == Node::Internal) { qDebug() << "Link to Internal entity"; } #endif } while (!path.isEmpty()) { targetAtom = myTree->findTarget(path.first(), *node); if (targetAtom == 0) break; path.removeFirst(); } if (path.isEmpty()) { link = linkForNode(*node, relative); if (*node && (*node)->subType() == Node::Image) link = "images/used-in-examples/" + link; if (targetAtom) link += "#" + refForAtom(targetAtom, *node); } } return link; } void DitaXmlGenerator::generateIndex(const QString &fileBase, const QString &url, const QString &title) { myTree->generateIndex(outputDir() + "/" + fileBase + ".index", url, title); } void DitaXmlGenerator::generateStatus(const Node *node, CodeMarker *marker) { Text text; switch (node->status()) { case Node::Obsolete: if (node->isInnerNode()) Generator::generateStatus(node, marker); break; case Node::Compat: if (node->isInnerNode()) { text << Atom::ParaLeft << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) << "This " << typeString(node) << " is part of the Qt 3 support library." << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " It is provided to keep old source code working. " << "We strongly advise against " << "using it in new code. See "; const FakeNode *fakeNode = myTree->findFakeNodeByTitle("Porting To Qt 4"); Atom *targetAtom = 0; if (fakeNode && node->type() == Node::Class) { QString oldName(node->name()); targetAtom = myTree->findTarget(oldName.replace("3", ""), fakeNode); } if (targetAtom) { text << Atom(Atom::Link, linkForNode(fakeNode, node) + "#" + refForAtom(targetAtom, fakeNode)); } else text << Atom(Atom::Link, "Porting to Qt 4"); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, "Porting to Qt 4") << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << " for more information." << Atom::ParaRight; } generateText(text, node, marker); break; default: Generator::generateStatus(node, marker); } } #ifdef GENERATE_MAC_REFS /* No longer valid. */ void DitaXmlGenerator::generateMacRef(const Node *node, CodeMarker *marker) { if (!pleaseGenerateMacRef || marker == 0) return; QStringList macRefs = marker->macRefsForNode(node); foreach (const QString &macRef, macRefs) out() << "\n"; } #endif void DitaXmlGenerator::beginLink(const QString &link, const Node *node, const Node *relative, CodeMarker *marker) { Q_UNUSED(marker) Q_UNUSED(relative) this->link = link; if (link.isEmpty()) { if (showBrokenLinks) writer.writeStartElement("i"); } else if (node == 0 || (relative != 0 && node->status() == relative->status())) { writer.writeStartElement("xref"); writer.writeAttribute("href",link); } else { switch (node->status()) { case Node::Obsolete: writer.writeStartElement("xref"); writer.writeAttribute("href",link); writer.writeAttribute("outputclass","obsolete"); break; case Node::Compat: writer.writeStartElement("xref"); writer.writeAttribute("href",link); writer.writeAttribute("outputclass","compat"); break; default: writer.writeStartElement("xref"); writer.writeAttribute("href",link); } } inLink = true; } void DitaXmlGenerator::endLink() { if (inLink) { if (link.isEmpty()) { if (showBrokenLinks) writer.writeEndElement(); // i } else { if (inObsoleteLink) { writer.writeStartElement("sup"); writer.writeCharacters("(obsolete)"); writer.writeEndElement(); // sup } writer.writeEndElement(); // xref } } inLink = false; inObsoleteLink = false; } #ifdef QDOC_QML /*! Generates the summary for the \a section. Only used for sections of QML element documentation. Currently handles only the QML property group. */ void DitaXmlGenerator::generateQmlSummary(const Section& section, const Node *relative, CodeMarker *marker) { if (!section.members.isEmpty()) { NodeList::ConstIterator m; int count = section.members.size(); bool twoColumn = false; if (section.members.first()->type() == Node::QmlProperty) { twoColumn = (count >= 5); } if (twoColumn) out() << "\n"; if (++numTableRows % 2 == 1) out() << ""; else out() << ""; // << "\n
    "; out() << "
      \n"; int row = 0; m = section.members.begin(); while (m != section.members.end()) { if (twoColumn && row == (int) (count + 1) / 2) out() << "
      \n"; out() << "
    • "; generateQmlItem(*m,relative,marker,true); out() << "
    • \n"; row++; ++m; } out() << "
    \n"; if (twoColumn) out() << "
    \n"; } } /*! Outputs the html detailed documentation for a section on a QML element reference page. */ void DitaXmlGenerator::generateDetailedQmlMember(const Node *node, const InnerNode *relative, CodeMarker *marker) { const QmlPropertyNode* qpn = 0; #ifdef GENERATE_MAC_REFS generateMacRef(node, marker); #endif out() << "
    "; if (node->subType() == Node::QmlPropertyGroup) { const QmlPropGroupNode* qpgn = static_cast(node); NodeList::ConstIterator p = qpgn->childNodes().begin(); out() << "
    "; out() << ""; while (p != qpgn->childNodes().end()) { if ((*p)->type() == Node::QmlProperty) { qpn = static_cast(*p); if (++numTableRows % 2 == 1) out() << ""; else out() << ""; out() << ""; } ++p; } out() << "

    "; //out() << "

    "; // old out() << ""; if (!qpn->isWritable()) out() << "read-only"; if (qpgn->isDefault()) out() << "default"; generateQmlItem(qpn, relative, marker, false); out() << "
    "; out() << "
    "; } else if (node->type() == Node::QmlSignal) { const FunctionNode* qsn = static_cast(node); out() << "
    "; out() << ""; //out() << ""; if (++numTableRows % 2 == 1) out() << ""; else out() << ""; out() << ""; out() << "

    "; out() << ""; generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false); //generateQmlItem(qsn,relative,marker,false); out() << "

    "; out() << "
    "; } else if (node->type() == Node::QmlMethod) { const FunctionNode* qmn = static_cast(node); out() << "
    "; out() << ""; //out() << ""; if (++numTableRows % 2 == 1) out() << ""; else out() << ""; out() << ""; out() << "

    "; out() << ""; generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); out() << "

    "; out() << "
    "; } out() << "
    "; generateStatus(node, marker); generateBody(node, marker); generateThreadSafeness(node, marker); generateSince(node, marker); generateAlsoList(node, marker); out() << "
    "; out() << "
    "; } /*! Output the "Inherits" line for the QML element, if there should be one. */ void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* cn, CodeMarker* marker) { if (cn && !cn->links().empty()) { if (cn->links().contains(Node::InheritsLink)) { QPair linkPair; linkPair = cn->links()[Node::InheritsLink]; QStringList strList(linkPair.first); const Node* n = myTree->findNode(strList,Node::Fake); if (n && n->subType() == Node::QmlClass) { const QmlClassNode* qcn = static_cast(n); out() << "

    "; Text text; text << "[Inherits "; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, linkPair.second); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << "]"; generateText(text, cn, marker); out() << "

    "; } } } } /*! Output the "Inherit by" list for the QML element, if it is inherited by any other elements. */ void DitaXmlGenerator::generateQmlInheritedBy(const QmlClassNode* cn, CodeMarker* marker) { if (cn) { NodeList subs; QmlClassNode::subclasses(cn->name(),subs); if (!subs.isEmpty()) { Text text; text << Atom::ParaLeft << "Inherited by "; appendSortedQmlNames(text,cn,subs,marker); text << Atom::ParaRight; generateText(text, cn, marker); } } } /*! Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]" line for the QML element, if there should be one. If there is no class node, or if the class node status is set to Node::Internal, do nothing. */ void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker) { const ClassNode* cn = qcn->classNode(); if (cn && (cn->status() != Node::Internal)) { out() << "

    "; Text text; text << "["; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, qcn->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << " instantiates the C++ class "; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, cn->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << "]"; generateText(text, qcn, marker); out() << "

    "; } } /*! Output the "[QmlGraphicsXxx is instantiated by QML element Xxx]" line for the class, if there should be one. If there is no QML element, or if the class node status is set to Node::Internal, do nothing. */ void DitaXmlGenerator::generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker) { if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { const Node* n = myTree->root()->findNode(cn->qmlElement(),Node::Fake); if (n && n->subType() == Node::QmlClass) { out() << "

    "; Text text; text << "["; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, cn->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << " is instantiated by QML element "; text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, n->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); text << "]"; generateText(text, cn, marker); out() << "

    "; } } } /*! Generate the element for the given \a node using the \a writer. Return true if a element was written; otherwise return false. */ bool DitaXmlGenerator::generatePageElement(QXmlStreamWriter& writer, const Node* node, CodeMarker* marker) const { if (node->pageType() == Node::NoPageType) return false; if (node->name().isEmpty()) return true; if (node->access() == Node::Private) return false; if (!node->isInnerNode()) return false; QString title; QString rawTitle; QString fullTitle; const InnerNode* inner = static_cast(node); writer.writeStartElement("page"); QXmlStreamAttributes attributes; QString t; t.setNum(id++); switch (node->type()) { case Node::Fake: { const FakeNode* fake = static_cast(node); title = fake->fullTitle(); break; } case Node::Class: { title = node->name() + " Class Reference"; break; } case Node::Namespace: { rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); title = rawTitle + " Namespace Reference"; break; } default: title = node->name(); break; } writer.writeAttribute("id",t); writer.writeStartElement("pageWords"); writer.writeCharacters(title); if (!inner->pageKeywords().isEmpty()) { const QStringList& w = inner->pageKeywords(); for (int i = 0; i < w.size(); ++i) { writer.writeCharacters(" "); writer.writeCharacters(w.at(i).toLocal8Bit().constData()); } } writer.writeEndElement(); writer.writeStartElement("pageTitle"); writer.writeCharacters(title); writer.writeEndElement(); writer.writeStartElement("pageUrl"); writer.writeCharacters(PageGenerator::fileName(node)); writer.writeEndElement(); writer.writeStartElement("pageType"); switch (node->pageType()) { case Node::ApiPage: writer.writeCharacters("APIPage"); break; case Node::ArticlePage: writer.writeCharacters("Article"); break; case Node::ExamplePage: writer.writeCharacters("Example"); break; default: break; } writer.writeEndElement(); writer.writeEndElement(); return true; } /*! Traverse the tree recursively and generate the elements. */ void DitaXmlGenerator::generatePageElements(QXmlStreamWriter& writer, const Node* node, CodeMarker* marker) const { if (generatePageElement(writer, node, marker)) { if (node->isInnerNode()) { const InnerNode *inner = static_cast(node); // Recurse to write an element for this child node and all its children. foreach (const Node *child, inner->childNodes()) generatePageElements(writer, child, marker); } } } /*! Outputs the file containing the index used for searching the html docs. */ void DitaXmlGenerator::generatePageIndex(const QString& fileName, CodeMarker* marker) const { QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) return ; QXmlStreamWriter writer(&file); writer.setAutoFormatting(true); writer.writeStartDocument(); writer.writeStartElement("qtPageIndex"); generatePageElements(writer, myTree->root(), marker); writer.writeEndElement(); // qtPageIndex writer.writeEndDocument(); file.close(); } #endif void DitaXmlGenerator::writeDerivations(const ClassNode* cn, CodeMarker* marker) { QList::ConstIterator r; int index; if (!cn->baseClasses().isEmpty()) { writer.writeStartElement(CXXCLASSDERIVATIONS); r = cn->baseClasses().begin(); index = 0; while (r != cn->baseClasses().end()) { writer.writeStartElement(CXXCLASSDERIVATION); writer.writeStartElement(CXXCLASSDERIVATIONACCESSSPECIFIER); writer.writeAttribute("value",(*r).accessString()); writer.writeEndElement(); // writer.writeStartElement(CXXCLASSBASECLASS); QString fullTitle = marker->plainFullName((*r).node); QString guid = lookupGuid(fullTitle); writer.writeAttribute("href",guid); writer.writeCharacters(fullTitle); writer.writeEndElement(); // writer.writeEndElement(); // ++r; } writer.writeEndElement(); // } } void DitaXmlGenerator::writeLocation(const ClassNode* cn, CodeMarker* marker) { writer.writeStartElement(CXXCLASSAPIITEMLOCATION); writer.writeStartElement(CXXCLASSDECLARATIONFILE); writer.writeAttribute("name","filePath"); writer.writeAttribute("value",cn->location().filePath()); writer.writeEndElement(); // writer.writeStartElement(CXXCLASSDECLARATIONFILELINE); writer.writeAttribute("name","lineNumber"); QString lineNr; writer.writeAttribute("value",lineNr.setNum(cn->location().lineNo())); writer.writeEndElement(); // writer.writeEndElement(); // } QT_END_NAMESPACE