1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools applications of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
47 #include <QDomDocument>
51 #include "htmlgenerator.h"
59 struct InheritanceBound
63 QString dataTypeWithTemplateArgs
;
67 : access(Node::Public
) { }
68 InheritanceBound(Node::Access access0
,
69 const QStringList
& basePath0
,
70 const QString
&dataTypeWithTemplateArgs0
,
72 : access(access0
), basePath(basePath0
),
73 dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0
),
84 typedef QMap
<PropertyNode::FunctionRole
, QString
> RoleMap
;
85 typedef QMap
<PropertyNode
*, RoleMap
> PropertyMap
;
86 typedef QMultiMap
<QString
, Node
*> GroupMap
;
87 typedef QMultiHash
<QString
, FakeNode
*> FakeNodeHash
;
88 typedef QMultiHash
<QString
, Target
> TargetHash
;
93 QMap
<ClassNode
*, QList
<InheritanceBound
> > unresolvedInheritanceMap
;
94 PropertyMap unresolvedPropertyMap
;
96 QMultiMap
<QString
, QString
> publicGroupMap
;
97 FakeNodeHash fakeNodesByTitle
;
98 TargetHash targetHash
;
99 QList
<QPair
<ClassNode
*,QString
> > basesList
;
100 QList
<QPair
<FunctionNode
*,QString
> > relatedList
;
108 The default constructor is the only constructor.
113 priv
= new TreePrivate
;
117 The destructor deletes the internal, private tree.
126 Node
*Tree::findNode(const QStringList
&path
, Node
*relative
, int findFlags
)
128 return const_cast<Node
*>(const_cast<const Tree
*>(this)->findNode(path
,
135 const Node
*Tree::findNode(const QStringList
&path
,
136 const Node
*relative
,
143 const Node
*node
= relative
;
146 for (i
= 0; i
< path
.size(); ++i
) {
147 if (node
== 0 || !node
->isInnerNode())
151 static_cast<const InnerNode
*>(node
)->findNode(path
.at(i
));
152 if (!next
&& (findFlags
& SearchEnumValues
) && i
== path
.size()-1)
153 next
= static_cast<const InnerNode
*>(node
)->findEnumNodeForValue(path
.at(i
));
155 if (!next
&& node
->type() == Node::Class
&& (findFlags
& SearchBaseClasses
)) {
156 NodeList baseClasses
= allBaseClasses(static_cast<const ClassNode
*>(node
));
157 foreach (const Node
*baseClass
, baseClasses
) {
158 next
= static_cast<const InnerNode
*>(baseClass
)->findNode(path
.at(i
));
159 if (!next
&& (findFlags
& SearchEnumValues
) && i
== path
.size() - 1)
160 next
= static_cast<const InnerNode
*>(baseClass
)
161 ->findEnumNodeForValue(path
.at(i
));
168 if (node
&& i
== path
.size()
169 && (!(findFlags
& NonFunction
) || node
->type() != Node::Function
170 || ((FunctionNode
*)node
)->metaness() == FunctionNode::MacroWithoutParams
))
172 relative
= relative
->parent();
179 Find the node with the specified \a path name of the
182 Node
*Tree::findNode(const QStringList
&path
,
187 return const_cast<Node
*>(const_cast<const Tree
*>(this)->findNode(path
,
194 Find the node with the specified \a path name of the
197 const Node
*Tree::findNode(const QStringList
&path
,
199 const Node
*relative
,
202 const Node
*node
= findNode(path
, relative
, findFlags
);
203 if (node
!= 0 && node
->type() == type
)
210 FunctionNode
*Tree::findFunctionNode(const QStringList
& path
,
214 return const_cast<FunctionNode
*>(
215 const_cast<const Tree
*>(this)->findFunctionNode(path
,
222 const FunctionNode
*Tree::findFunctionNode(const QStringList
&path
,
223 const Node
*relative
,
230 const Node
*node
= relative
;
233 for (i
= 0; i
< path
.size(); ++i
) {
234 if (node
== 0 || !node
->isInnerNode())
238 if (i
== path
.size() - 1)
239 next
= ((InnerNode
*) node
)->findFunctionNode(path
.at(i
));
241 next
= ((InnerNode
*) node
)->findNode(path
.at(i
));
243 if (!next
&& node
->type() == Node::Class
&&
244 (findFlags
& SearchBaseClasses
)) {
245 NodeList baseClasses
= allBaseClasses(static_cast<const ClassNode
*>(node
));
246 foreach (const Node
*baseClass
, baseClasses
) {
247 if (i
== path
.size() - 1)
248 next
= static_cast<const InnerNode
*>(baseClass
)->findFunctionNode(path
.at(i
));
250 next
= static_cast<const InnerNode
*>(baseClass
)->findNode(path
.at(i
));
259 if (node
&& i
== path
.size() && node
->isFunction()) {
260 // CppCodeParser::processOtherMetaCommand ensures that reimplemented
261 // functions are private.
262 const FunctionNode
*func
= static_cast<const FunctionNode
*>(node
);
263 while (func
->access() == Node::Private
) {
264 const FunctionNode
*from
= func
->reimplementedFrom();
266 if (from
->access() != Node::Private
)
276 relative
= relative
->parent();
284 FunctionNode
*Tree::findFunctionNode(const QStringList
&parentPath
,
285 const FunctionNode
*clone
,
289 return const_cast<FunctionNode
*>(
290 const_cast<const Tree
*>(this)->findFunctionNode(parentPath
,
298 const FunctionNode
*Tree::findFunctionNode(const QStringList
&parentPath
,
299 const FunctionNode
*clone
,
300 const Node
*relative
,
303 const Node
*parent
= findNode(parentPath
, relative
, findFlags
);
304 if (parent
== 0 || !parent
->isInnerNode()) {
308 return ((InnerNode
*)parent
)->findFunctionNode(clone
);
312 static const int NumSuffixes
= 3;
313 static const char * const suffixes
[NumSuffixes
] = { "", "s", "es" };
317 const FakeNode
*Tree::findFakeNodeByTitle(const QString
&title
) const
319 for (int pass
= 0; pass
< NumSuffixes
; ++pass
) {
320 FakeNodeHash::const_iterator i
=
321 priv
->fakeNodesByTitle
.find(Doc::canonicalTitle(title
+ suffixes
[pass
]));
322 if (i
!= priv
->fakeNodesByTitle
.constEnd()) {
323 FakeNodeHash::const_iterator j
= i
;
325 if (j
!= priv
->fakeNodesByTitle
.constEnd() && j
.key() == i
.key()) {
326 QList
<Location
> internalLocations
;
327 while (j
!= priv
->fakeNodesByTitle
.constEnd()) {
328 if (j
.key() == i
.key() && j
.value()->url().isEmpty())
329 internalLocations
.append(j
.value()->doc().location());
332 if (internalLocations
.size() > 0) {
333 i
.value()->doc().location().warning(
334 tr("Page '%1' defined in more than one location:").arg(title
));
335 foreach (const Location
&location
, internalLocations
)
336 location
.warning(tr("(defined here)"));
348 Tree::findUnambiguousTarget(const QString
&target
, Atom
*&atom
) const
350 Target bestTarget
= {0, 0, INT_MAX
};
351 int numBestTargets
= 0;
353 for (int pass
= 0; pass
< NumSuffixes
; ++pass
) {
354 TargetHash::const_iterator i
=
355 priv
->targetHash
.find(Doc::canonicalTitle(target
+ suffixes
[pass
]));
356 if (i
!= priv
->targetHash
.constEnd()) {
357 TargetHash::const_iterator j
= i
;
359 const Target
&candidate
= j
.value();
360 if (candidate
.priority
< bestTarget
.priority
) {
361 bestTarget
= candidate
;
363 } else if (candidate
.priority
== bestTarget
.priority
) {
367 } while (j
!= priv
->targetHash
.constEnd() && j
.key() == i
.key());
369 if (numBestTargets
== 1) {
370 atom
= bestTarget
.atom
;
371 return bestTarget
.node
;
380 Atom
*Tree::findTarget(const QString
&target
, const Node
*node
) const
382 for (int pass
= 0; pass
< NumSuffixes
; ++pass
) {
383 QString key
= Doc::canonicalTitle(target
+ suffixes
[pass
]);
384 TargetHash::const_iterator i
= priv
->targetHash
.find(key
);
386 if (i
!= priv
->targetHash
.constEnd()) {
388 if (i
.value().node
== node
)
389 return i
.value().atom
;
391 } while (i
!= priv
->targetHash
.constEnd() && i
.key() == key
);
399 void Tree::addBaseClass(ClassNode
*subclass
, Node::Access access
,
400 const QStringList
&basePath
,
401 const QString
&dataTypeWithTemplateArgs
,
404 priv
->unresolvedInheritanceMap
[subclass
].append(
405 InheritanceBound(access
,
407 dataTypeWithTemplateArgs
,
415 void Tree::addPropertyFunction(PropertyNode
*property
,
416 const QString
&funcName
,
417 PropertyNode::FunctionRole funcRole
)
419 priv
->unresolvedPropertyMap
[property
].insert(funcRole
, funcName
);
423 This function adds the \a node to the \a group. The group
424 can be listed anywhere using the \e{annotated list} command.
426 void Tree::addToGroup(Node
*node
, const QString
&group
)
428 priv
->groupMap
.insert(group
, node
);
433 QMultiMap
<QString
, Node
*> Tree::groups() const
435 return priv
->groupMap
;
440 void Tree::addToPublicGroup(Node
*node
, const QString
&group
)
442 priv
->publicGroupMap
.insert(node
->name(), group
);
443 addToGroup(node
, group
);
448 QMultiMap
<QString
, QString
> Tree::publicGroups() const
450 return priv
->publicGroupMap
;
455 void Tree::resolveInheritance(NamespaceNode
*rootNode
)
460 for (int pass
= 0; pass
< 2; pass
++) {
461 NodeList::ConstIterator c
= rootNode
->childNodes().begin();
462 while (c
!= rootNode
->childNodes().end()) {
463 if ((*c
)->type() == Node::Class
)
464 resolveInheritance(pass
, (ClassNode
*) *c
);
465 else if ((*c
)->type() == Node::Namespace
) {
466 NamespaceNode
*ns
= static_cast<NamespaceNode
*>(*c
);
467 resolveInheritance(ns
);
471 if (rootNode
== root())
472 priv
->unresolvedInheritanceMap
.clear();
478 void Tree::resolveProperties()
480 PropertyMap::ConstIterator propEntry
;
482 propEntry
= priv
->unresolvedPropertyMap
.begin();
483 while (propEntry
!= priv
->unresolvedPropertyMap
.end()) {
484 PropertyNode
*property
= propEntry
.key();
485 InnerNode
*parent
= property
->parent();
486 QString getterName
= (*propEntry
)[PropertyNode::Getter
];
487 QString setterName
= (*propEntry
)[PropertyNode::Setter
];
488 QString resetterName
= (*propEntry
)[PropertyNode::Resetter
];
489 QString notifierName
= (*propEntry
)[PropertyNode::Notifier
];
491 NodeList::ConstIterator c
= parent
->childNodes().begin();
492 while (c
!= parent
->childNodes().end()) {
493 if ((*c
)->type() == Node::Function
) {
494 FunctionNode
*function
= static_cast<FunctionNode
*>(*c
);
495 if (function
->access() == property
->access() &&
496 (function
->status() == property
->status() ||
497 function
->doc().isEmpty())) {
498 if (function
->name() == getterName
) {
499 property
->addFunction(function
, PropertyNode::Getter
);
500 } else if (function
->name() == setterName
) {
501 property
->addFunction(function
, PropertyNode::Setter
);
502 } else if (function
->name() == resetterName
) {
503 property
->addFunction(function
, PropertyNode::Resetter
);
504 } else if (function
->name() == notifierName
) {
505 property
->addSignal(function
, PropertyNode::Notifier
);
514 propEntry
= priv
->unresolvedPropertyMap
.begin();
515 while (propEntry
!= priv
->unresolvedPropertyMap
.end()) {
516 PropertyNode
*property
= propEntry
.key();
517 // redo it to set the property functions
518 if (property
->overriddenFrom())
519 property
->setOverriddenFrom(property
->overriddenFrom());
523 priv
->unresolvedPropertyMap
.clear();
528 void Tree::resolveInheritance(int pass
, ClassNode
*classe
)
531 QList
<InheritanceBound
> bounds
= priv
->unresolvedInheritanceMap
[classe
];
532 QList
<InheritanceBound
>::ConstIterator b
= bounds
.begin();
533 while (b
!= bounds
.end()) {
534 ClassNode
*baseClass
= (ClassNode
*)findNode((*b
).basePath
,
536 if (!baseClass
&& (*b
).parent
)
537 baseClass
= (ClassNode
*)findNode((*b
).basePath
,
541 classe
->addBaseClass((*b
).access
,
543 (*b
).dataTypeWithTemplateArgs
);
548 NodeList::ConstIterator c
= classe
->childNodes().begin();
549 while (c
!= classe
->childNodes().end()) {
550 if ((*c
)->type() == Node::Function
) {
551 FunctionNode
*func
= (FunctionNode
*) *c
;
552 FunctionNode
*from
= findVirtualFunctionInBaseClasses(classe
, func
);
554 if (func
->virtualness() == FunctionNode::NonVirtual
)
555 func
->setVirtualness(FunctionNode::ImpureVirtual
);
556 func
->setReimplementedFrom(from
);
559 else if ((*c
)->type() == Node::Property
) {
560 fixPropertyUsingBaseClasses(classe
, static_cast<PropertyNode
*>(*c
));
569 void Tree::resolveGroups()
571 GroupMap::const_iterator i
;
573 for (i
= priv
->groupMap
.constBegin(); i
!= priv
->groupMap
.constEnd(); ++i
) {
574 if (i
.value()->access() == Node::Private
)
578 static_cast<FakeNode
*>(findNode(QStringList(i
.key()),Node::Fake
));
579 if (fake
&& fake
->subType() == Node::Group
) {
580 fake
->addGroupMember(i
.value());
584 if (prevGroup
!= i
.key())
585 i
.value()->doc().location().warning(tr("No such group '%1'").arg(i
.key()));
592 //priv->groupMap.clear();
597 void Tree::resolveTargets()
601 foreach (Node
*child
, roo
.childNodes()) {
602 if (child
->type() == Node::Fake
) {
603 FakeNode
*node
= static_cast<FakeNode
*>(child
);
604 priv
->fakeNodesByTitle
.insert(Doc::canonicalTitle(node
->title()), node
);
607 if (child
->doc().hasTableOfContents()) {
608 const QList
<Atom
*> &toc
= child
->doc().tableOfContents();
613 for (int i
= 0; i
< toc
.size(); ++i
) {
614 target
.atom
= toc
.at(i
);
615 QString title
= Text::sectionHeading(target
.atom
).toString();
616 if (!title
.isEmpty())
617 priv
->targetHash
.insert(Doc::canonicalTitle(title
), target
);
620 if (child
->doc().hasKeywords()) {
621 const QList
<Atom
*> &keywords
= child
->doc().keywords();
626 for (int i
= 0; i
< keywords
.size(); ++i
) {
627 target
.atom
= keywords
.at(i
);
628 priv
->targetHash
.insert(Doc::canonicalTitle(target
.atom
->string()), target
);
631 if (child
->doc().hasTargets()) {
632 const QList
<Atom
*> &toc
= child
->doc().targets();
637 for (int i
= 0; i
< toc
.size(); ++i
) {
638 target
.atom
= toc
.at(i
);
639 priv
->targetHash
.insert(Doc::canonicalTitle(target
.atom
->string()), target
);
647 void Tree::fixInheritance(NamespaceNode
*rootNode
)
652 NodeList::ConstIterator c
= rootNode
->childNodes().begin();
653 while (c
!= rootNode
->childNodes().end()) {
654 if ((*c
)->type() == Node::Class
)
655 static_cast<ClassNode
*>(*c
)->fixBaseClasses();
656 else if ((*c
)->type() == Node::Namespace
) {
657 NamespaceNode
*ns
= static_cast<NamespaceNode
*>(*c
);
666 FunctionNode
*Tree::findVirtualFunctionInBaseClasses(ClassNode
*classe
,
669 QList
<RelatedClass
>::ConstIterator r
= classe
->baseClasses().begin();
670 while (r
!= classe
->baseClasses().end()) {
672 if (((func
= findVirtualFunctionInBaseClasses((*r
).node
, clone
)) != 0 ||
673 (func
= (*r
).node
->findFunctionNode(clone
)) != 0)) {
674 if (func
->virtualness() != FunctionNode::NonVirtual
)
684 void Tree::fixPropertyUsingBaseClasses(ClassNode
*classe
,
685 PropertyNode
*property
)
687 QList
<RelatedClass
>::const_iterator r
= classe
->baseClasses().begin();
688 while (r
!= classe
->baseClasses().end()) {
689 PropertyNode
*baseProperty
=
690 static_cast<PropertyNode
*>(r
->node
->findNode(property
->name(),
693 fixPropertyUsingBaseClasses(r
->node
, baseProperty
);
694 property
->setOverriddenFrom(baseProperty
);
697 fixPropertyUsingBaseClasses(r
->node
, property
);
705 NodeList
Tree::allBaseClasses(const ClassNode
*classe
) const
708 foreach (const RelatedClass
&r
, classe
->baseClasses()) {
710 result
+= allBaseClasses(r
.node
);
717 void Tree::readIndexes(const QStringList
&indexFiles
)
719 foreach (const QString
&indexFile
, indexFiles
)
720 readIndexFile(indexFile
);
724 Read the QDomDocument at \a path and get the index from it.
726 void Tree::readIndexFile(const QString
&path
)
729 if (file
.open(QFile::ReadOnly
)) {
730 QDomDocument document
;
731 document
.setContent(&file
);
734 QDomElement indexElement
= document
.documentElement();
735 QString indexUrl
= indexElement
.attribute("url", "");
736 priv
->basesList
.clear();
737 priv
->relatedList
.clear();
739 // Scan all elements in the XML file, constructing a map that contains
740 // base classes for each class found.
742 QDomElement child
= indexElement
.firstChildElement();
743 while (!child
.isNull()) {
744 readIndexSection(child
, root(), indexUrl
);
745 child
= child
.nextSiblingElement();
748 // Now that all the base classes have been found for this index,
749 // arrange them into an inheritance hierarchy.
757 void Tree::readIndexSection(const QDomElement
&element
,
759 const QString
&indexUrl
)
761 QString name
= element
.attribute("name");
762 QString href
= element
.attribute("href");
767 if (element
.nodeName() == "namespace") {
768 section
= new NamespaceNode(parent
, name
);
770 if (!indexUrl
.isEmpty())
771 location
= Location(indexUrl
+ "/" + name
.toLower() + ".html");
772 else if (!indexUrl
.isNull())
773 location
= Location(name
.toLower() + ".html");
776 else if (element
.nodeName() == "class") {
777 section
= new ClassNode(parent
, name
);
778 priv
->basesList
.append(QPair
<ClassNode
*,QString
>(
779 static_cast<ClassNode
*>(section
), element
.attribute("bases")));
781 if (!indexUrl
.isEmpty())
782 location
= Location(indexUrl
+ "/" + name
.toLower() + ".html");
783 else if (!indexUrl
.isNull())
784 location
= Location(name
.toLower() + ".html");
787 else if (element
.nodeName() == "page") {
788 Node::SubType subtype
;
789 if (element
.attribute("subtype") == "example")
790 subtype
= Node::Example
;
791 else if (element
.attribute("subtype") == "header")
792 subtype
= Node::HeaderFile
;
793 else if (element
.attribute("subtype") == "file")
794 subtype
= Node::File
;
795 else if (element
.attribute("subtype") == "group")
796 subtype
= Node::Group
;
797 else if (element
.attribute("subtype") == "module")
798 subtype
= Node::Module
;
799 else if (element
.attribute("subtype") == "page")
800 subtype
= Node::Page
;
801 else if (element
.attribute("subtype") == "externalpage")
802 subtype
= Node::ExternalPage
;
806 FakeNode
*fakeNode
= new FakeNode(parent
, name
, subtype
);
807 fakeNode
->setTitle(element
.attribute("title"));
809 if (element
.hasAttribute("location"))
810 name
= element
.attribute("location", "");
812 if (!indexUrl
.isEmpty())
813 location
= Location(indexUrl
+ "/" + name
);
814 else if (!indexUrl
.isNull())
815 location
= Location(name
);
820 else if (element
.nodeName() == "enum") {
821 EnumNode
*enumNode
= new EnumNode(parent
, name
);
823 if (!indexUrl
.isEmpty())
825 Location(indexUrl
+ "/" + parent
->name().toLower() + ".html");
826 else if (!indexUrl
.isNull())
827 location
= Location(parent
->name().toLower() + ".html");
829 QDomElement child
= element
.firstChildElement("value");
830 while (!child
.isNull()) {
831 EnumItem
item(child
.attribute("name"), child
.attribute("value"));
832 enumNode
->addItem(item
);
833 child
= child
.nextSiblingElement("value");
838 } else if (element
.nodeName() == "typedef") {
839 section
= new TypedefNode(parent
, name
);
841 if (!indexUrl
.isEmpty())
843 Location(indexUrl
+ "/" + parent
->name().toLower() + ".html");
844 else if (!indexUrl
.isNull())
845 location
= Location(parent
->name().toLower() + ".html");
848 else if (element
.nodeName() == "property") {
849 section
= new PropertyNode(parent
, name
);
851 if (!indexUrl
.isEmpty())
853 Location(indexUrl
+ "/" + parent
->name().toLower() + ".html");
854 else if (!indexUrl
.isNull())
855 location
= Location(parent
->name().toLower() + ".html");
857 } else if (element
.nodeName() == "function") {
858 FunctionNode::Virtualness virt
;
859 if (element
.attribute("virtual") == "non")
860 virt
= FunctionNode::NonVirtual
;
861 else if (element
.attribute("virtual") == "impure")
862 virt
= FunctionNode::ImpureVirtual
;
863 else if (element
.attribute("virtual") == "pure")
864 virt
= FunctionNode::PureVirtual
;
868 FunctionNode::Metaness meta
;
869 if (element
.attribute("meta") == "plain")
870 meta
= FunctionNode::Plain
;
871 else if (element
.attribute("meta") == "signal")
872 meta
= FunctionNode::Signal
;
873 else if (element
.attribute("meta") == "slot")
874 meta
= FunctionNode::Slot
;
875 else if (element
.attribute("meta") == "constructor")
876 meta
= FunctionNode::Ctor
;
877 else if (element
.attribute("meta") == "destructor")
878 meta
= FunctionNode::Dtor
;
879 else if (element
.attribute("meta") == "macro")
880 meta
= FunctionNode::MacroWithParams
;
881 else if (element
.attribute("meta") == "macrowithparams")
882 meta
= FunctionNode::MacroWithParams
;
883 else if (element
.attribute("meta") == "macrowithoutparams")
884 meta
= FunctionNode::MacroWithoutParams
;
888 FunctionNode
*functionNode
= new FunctionNode(parent
, name
);
889 functionNode
->setReturnType(element
.attribute("return"));
890 functionNode
->setVirtualness(virt
);
891 functionNode
->setMetaness(meta
);
892 functionNode
->setConst(element
.attribute("const") == "true");
893 functionNode
->setStatic(element
.attribute("static") == "true");
894 functionNode
->setOverload(element
.attribute("overload") == "true");
896 if (element
.hasAttribute("relates")
897 && element
.attribute("relates") != parent
->name()) {
898 priv
->relatedList
.append(
899 QPair
<FunctionNode
*,QString
>(functionNode
,
900 element
.attribute("relates")));
903 QDomElement child
= element
.firstChildElement("parameter");
904 while (!child
.isNull()) {
905 // Do not use the default value for the parameter; it is not
906 // required, and has been known to cause problems.
907 Parameter
parameter(child
.attribute("left"),
908 child
.attribute("right"),
909 child
.attribute("name"),
910 ""); // child.attribute("default")
911 functionNode
->addParameter(parameter
);
912 child
= child
.nextSiblingElement("parameter");
915 section
= functionNode
;
917 if (!indexUrl
.isEmpty())
919 Location(indexUrl
+ "/" + parent
->name().toLower() + ".html");
920 else if (!indexUrl
.isNull())
921 location
= Location(parent
->name().toLower() + ".html");
924 else if (element
.nodeName() == "variable") {
925 section
= new VariableNode(parent
, name
);
927 if (!indexUrl
.isEmpty())
928 location
= Location(indexUrl
+ "/" + parent
->name().toLower() + ".html");
929 else if (!indexUrl
.isNull())
930 location
= Location(parent
->name().toLower() + ".html");
933 else if (element
.nodeName() == "keyword") {
935 target
.node
= parent
;
937 target
.atom
= new Atom(Atom::Target
, name
);
938 priv
->targetHash
.insert(name
, target
);
942 else if (element
.nodeName() == "target") {
944 target
.node
= parent
;
946 target
.atom
= new Atom(Atom::Target
, name
);
947 priv
->targetHash
.insert(name
, target
);
951 else if (element
.nodeName() == "contents") {
953 target
.node
= parent
;
955 target
.atom
= new Atom(Atom::Target
, name
);
956 priv
->targetHash
.insert(name
, target
);
963 QString access
= element
.attribute("access");
964 if (access
== "public")
965 section
->setAccess(Node::Public
);
966 else if (access
== "protected")
967 section
->setAccess(Node::Protected
);
968 else if (access
== "private")
969 section
->setAccess(Node::Private
);
971 section
->setAccess(Node::Public
);
973 if (element
.nodeName() != "page") {
974 QString threadSafety
= element
.attribute("threadsafety");
975 if (threadSafety
== "non-reentrant")
976 section
->setThreadSafeness(Node::NonReentrant
);
977 else if (threadSafety
== "reentrant")
978 section
->setThreadSafeness(Node::Reentrant
);
979 else if (threadSafety
== "thread safe")
980 section
->setThreadSafeness(Node::ThreadSafe
);
982 section
->setThreadSafeness(Node::UnspecifiedSafeness
);
985 section
->setThreadSafeness(Node::UnspecifiedSafeness
);
987 QString status
= element
.attribute("status");
988 if (status
== "compat")
989 section
->setStatus(Node::Compat
);
990 else if (status
== "obsolete")
991 section
->setStatus(Node::Obsolete
);
992 else if (status
== "deprecated")
993 section
->setStatus(Node::Deprecated
);
994 else if (status
== "preliminary")
995 section
->setStatus(Node::Preliminary
);
996 else if (status
== "commendable")
997 section
->setStatus(Node::Commendable
);
998 else if (status
== "internal")
999 section
->setStatus(Node::Internal
);
1000 else if (status
== "main")
1001 section
->setStatus(Node::Main
);
1003 section
->setStatus(Node::Commendable
);
1005 section
->setModuleName(element
.attribute("module"));
1006 if (!indexUrl
.isEmpty()) {
1007 if (indexUrl
.startsWith("."))
1008 section
->setUrl(href
);
1010 section
->setUrl(indexUrl
+ "/" + href
);
1013 // Create some content for the node.
1014 QSet
<QString
> emptySet
;
1016 Doc
doc(location
, location
, " ", emptySet
); // placeholder
1017 section
->setDoc(doc
);
1019 if (section
->isInnerNode()) {
1020 InnerNode
*inner
= static_cast<InnerNode
*>(section
);
1022 QDomElement child
= element
.firstChildElement();
1024 while (!child
.isNull()) {
1025 if (element
.nodeName() == "class")
1026 readIndexSection(child
, inner
, indexUrl
);
1027 else if (element
.nodeName() == "page")
1028 readIndexSection(child
, inner
, indexUrl
);
1029 else if (element
.nodeName() == "namespace" && !name
.isEmpty())
1030 // The root node in the index is a namespace with an empty name.
1031 readIndexSection(child
, inner
, indexUrl
);
1033 readIndexSection(child
, parent
, indexUrl
);
1035 child
= child
.nextSiblingElement();
1043 QString
Tree::readIndexText(const QDomElement
&element
)
1046 QDomNode child
= element
.firstChild();
1047 while (!child
.isNull()) {
1049 text
+= child
.toText().nodeValue();
1050 child
= child
.nextSibling();
1057 void Tree::resolveIndex()
1059 QPair
<ClassNode
*,QString
> pair
;
1061 foreach (pair
, priv
->basesList
) {
1062 foreach (const QString
&base
, pair
.second
.split(",")) {
1063 Node
*baseClass
= root()->findNode(base
, Node::Class
);
1065 pair
.first
->addBaseClass(Node::Public
,
1066 static_cast<ClassNode
*>(baseClass
));
1071 QPair
<FunctionNode
*,QString
> relatedPair
;
1073 foreach (relatedPair
, priv
->relatedList
) {
1074 Node
*classNode
= root()->findNode(relatedPair
.second
, Node::Class
);
1076 relatedPair
.first
->setRelates(static_cast<ClassNode
*>(classNode
));
1081 Generate the index section with the given \a writer for the \a node
1082 specified, returning true if an element was written; otherwise returns
1085 bool Tree::generateIndexSection(QXmlStreamWriter
&writer
,
1087 bool generateInternalNodes
) const
1089 if (!node
->url().isEmpty())
1093 switch (node
->type()) {
1094 case Node::Namespace
:
1095 nodeName
= "namespace";
1107 nodeName
= "typedef";
1109 case Node::Property
:
1110 nodeName
= "property";
1112 case Node::Function
:
1113 nodeName
= "function";
1115 case Node::Variable
:
1116 nodeName
= "variable";
1119 nodeName
= "target";
1126 switch (node
->access()) {
1130 case Node::Protected
:
1131 access
= "protected";
1134 // Do not include private non-internal nodes in the index.
1135 // (Internal public and protected nodes are marked as private
1136 // by qdoc. We can check their internal status to determine
1137 // whether they were really private to begin with.)
1138 if (node
->status() == Node::Internal
&& generateInternalNodes
)
1139 access
= "internal";
1147 QString objName
= node
->name();
1149 // Special case: only the root node should have an empty name.
1150 if (objName
.isEmpty() && node
!= root())
1153 writer
.writeStartElement(nodeName
);
1155 QXmlStreamAttributes attributes
;
1156 writer
.writeAttribute("access", access
);
1158 if (node
->type() != Node::Fake
) {
1159 QString threadSafety
;
1160 switch (node
->threadSafeness()) {
1161 case Node::NonReentrant
:
1162 threadSafety
= "non-reentrant";
1164 case Node::Reentrant
:
1165 threadSafety
= "reentrant";
1167 case Node::ThreadSafe
:
1168 threadSafety
= "thread safe";
1170 case Node::UnspecifiedSafeness
:
1172 threadSafety
= "unspecified";
1175 writer
.writeAttribute("threadsafety", threadSafety
);
1179 switch (node
->status()) {
1183 case Node::Obsolete
:
1184 status
= "obsolete";
1186 case Node::Deprecated
:
1187 status
= "deprecated";
1189 case Node::Preliminary
:
1190 status
= "preliminary";
1192 case Node::Commendable
:
1193 status
= "commendable";
1195 case Node::Internal
:
1196 status
= "internal";
1203 writer
.writeAttribute("status", status
);
1205 writer
.writeAttribute("name", objName
);
1206 QString fullName
= fullDocumentName(node
);
1207 if (fullName
!= objName
)
1208 writer
.writeAttribute("fullname", fullName
);
1209 writer
.writeAttribute("href", fullDocumentLocation(node
));
1210 if (node
->type() != Node::Fake
)
1211 writer
.writeAttribute("location", node
->location().fileName());
1213 switch (node
->type()) {
1217 // Classes contain information about their base classes.
1219 const ClassNode
*classNode
= static_cast<const ClassNode
*>(node
);
1220 QList
<RelatedClass
> bases
= classNode
->baseClasses();
1221 QSet
<QString
> baseStrings
;
1222 foreach (const RelatedClass
&related
, bases
) {
1223 ClassNode
*baseClassNode
= related
.node
;
1224 baseStrings
.insert(baseClassNode
->name());
1226 writer
.writeAttribute("bases", QStringList(baseStrings
.toList()).join(","));
1227 writer
.writeAttribute("module", node
->moduleName());
1231 case Node::Namespace
:
1232 writer
.writeAttribute("module", node
->moduleName());
1238 Fake nodes (such as manual pages) contain subtypes,
1239 titles and other attributes.
1242 const FakeNode
*fakeNode
= static_cast<const FakeNode
*>(node
);
1243 switch (fakeNode
->subType()) {
1245 writer
.writeAttribute("subtype", "example");
1247 case Node::HeaderFile
:
1248 writer
.writeAttribute("subtype", "header");
1251 writer
.writeAttribute("subtype", "file");
1254 writer
.writeAttribute("subtype", "group");
1257 writer
.writeAttribute("subtype", "module");
1260 writer
.writeAttribute("subtype", "page");
1262 case Node::ExternalPage
:
1263 writer
.writeAttribute("subtype", "externalpage");
1268 writer
.writeAttribute("title", fakeNode
->title());
1269 writer
.writeAttribute("fulltitle", fakeNode
->fullTitle());
1270 writer
.writeAttribute("subtitle", fakeNode
->subTitle());
1271 writer
.writeAttribute("location", fakeNode
->doc().location().fileName());
1275 case Node::Function
:
1278 Function nodes contain information about the type of
1279 function being described.
1282 const FunctionNode
*functionNode
=
1283 static_cast<const FunctionNode
*>(node
);
1285 switch (functionNode
->virtualness()) {
1286 case FunctionNode::NonVirtual
:
1287 writer
.writeAttribute("virtual", "non");
1289 case FunctionNode::ImpureVirtual
:
1290 writer
.writeAttribute("virtual", "impure");
1292 case FunctionNode::PureVirtual
:
1293 writer
.writeAttribute("virtual", "pure");
1298 switch (functionNode
->metaness()) {
1299 case FunctionNode::Plain
:
1300 writer
.writeAttribute("meta", "plain");
1302 case FunctionNode::Signal
:
1303 writer
.writeAttribute("meta", "signal");
1305 case FunctionNode::Slot
:
1306 writer
.writeAttribute("meta", "slot");
1308 case FunctionNode::Ctor
:
1309 writer
.writeAttribute("meta", "constructor");
1311 case FunctionNode::Dtor
:
1312 writer
.writeAttribute("meta", "destructor");
1314 case FunctionNode::MacroWithParams
:
1315 writer
.writeAttribute("meta", "macrowithparams");
1317 case FunctionNode::MacroWithoutParams
:
1318 writer
.writeAttribute("meta", "macrowithoutparams");
1323 writer
.writeAttribute("const", functionNode
->isConst()?"true":"false");
1324 writer
.writeAttribute("static", functionNode
->isStatic()?"true":"false");
1325 writer
.writeAttribute("overload", functionNode
->isOverload()?"true":"false");
1326 if (functionNode
->isOverload())
1327 writer
.writeAttribute("overload-number", QString::number(functionNode
->overloadNumber()));
1328 if (functionNode
->relates())
1329 writer
.writeAttribute("relates", functionNode
->relates()->name());
1330 const PropertyNode
*propertyNode
= functionNode
->associatedProperty();
1332 writer
.writeAttribute("associated-property", propertyNode
->name());
1333 writer
.writeAttribute("type", functionNode
->returnType());
1337 case Node::Property
:
1339 const PropertyNode
*propertyNode
= static_cast<const PropertyNode
*>(node
);
1340 writer
.writeAttribute("type", propertyNode
->dataType());
1341 foreach (const Node
*fnNode
, propertyNode
->getters()) {
1343 const FunctionNode
*functionNode
= static_cast<const FunctionNode
*>(fnNode
);
1344 writer
.writeStartElement("getter");
1345 writer
.writeAttribute("name", functionNode
->name());
1346 writer
.writeEndElement(); // getter
1349 foreach (const Node
*fnNode
, propertyNode
->setters()) {
1351 const FunctionNode
*functionNode
= static_cast<const FunctionNode
*>(fnNode
);
1352 writer
.writeStartElement("setter");
1353 writer
.writeAttribute("name", functionNode
->name());
1354 writer
.writeEndElement(); // getter
1357 foreach (const Node
*fnNode
, propertyNode
->resetters()) {
1359 const FunctionNode
*functionNode
= static_cast<const FunctionNode
*>(fnNode
);
1360 writer
.writeStartElement("resetter");
1361 writer
.writeAttribute("name", functionNode
->name());
1362 writer
.writeEndElement(); // getter
1368 case Node::Variable
:
1370 const VariableNode
*variableNode
=
1371 static_cast<const VariableNode
*>(node
);
1372 writer
.writeAttribute("type", variableNode
->dataType());
1373 writer
.writeAttribute("static",
1374 variableNode
->isStatic() ? "true" : "false");
1381 // Inner nodes and function nodes contain child nodes of some sort, either
1382 // actual child nodes or function parameters. For these, we close the
1383 // opening tag, create child elements, then add a closing tag for the
1384 // element. Elements for all other nodes are closed in the opening tag.
1386 if (node
->isInnerNode()) {
1388 const InnerNode
*inner
= static_cast<const InnerNode
*>(node
);
1390 // For internal pages, we canonicalize the target, keyword and content
1391 // item names so that they can be used by qdoc for other sets of
1393 // The reason we do this here is that we don't want to ruin
1394 // externally composed indexes, containing non-qdoc-style target names
1395 // when reading in indexes.
1397 if (inner
->doc().hasTargets()) {
1398 bool external
= false;
1399 if (inner
->type() == Node::Fake
) {
1400 const FakeNode
*fakeNode
= static_cast<const FakeNode
*>(inner
);
1401 if (fakeNode
->subType() == Node::ExternalPage
)
1405 foreach (const Atom
*target
, inner
->doc().targets()) {
1406 QString targetName
= target
->string();
1408 targetName
= Doc::canonicalTitle(targetName
);
1410 writer
.writeStartElement("target");
1411 writer
.writeAttribute("name", targetName
);
1412 writer
.writeEndElement(); // target
1415 if (inner
->doc().hasKeywords()) {
1416 foreach (const Atom
*keyword
, inner
->doc().keywords()) {
1417 writer
.writeStartElement("keyword");
1418 writer
.writeAttribute("name",
1419 Doc::canonicalTitle(keyword
->string()));
1420 writer
.writeEndElement(); // keyword
1423 if (inner
->doc().hasTableOfContents()) {
1424 for (int i
= 0; i
< inner
->doc().tableOfContents().size(); ++i
) {
1425 Atom
*item
= inner
->doc().tableOfContents()[i
];
1426 int level
= inner
->doc().tableOfContentsLevels()[i
];
1428 QString title
= Text::sectionHeading(item
).toString();
1429 writer
.writeStartElement("contents");
1430 writer
.writeAttribute("name", Doc::canonicalTitle(title
));
1431 writer
.writeAttribute("title", title
);
1432 writer
.writeAttribute("level", QString::number(level
));
1433 writer
.writeEndElement(); // contents
1438 else if (node
->type() == Node::Function
) {
1440 const FunctionNode
*functionNode
= static_cast<const FunctionNode
*>(node
);
1441 // Write a signature attribute for convenience.
1442 QStringList signatureList
;
1443 QStringList resolvedParameters
;
1445 foreach (const Parameter
¶meter
, functionNode
->parameters()) {
1446 QString leftType
= parameter
.leftType();
1447 const Node
*leftNode
=
1448 const_cast<Tree
*>(this)->findNode(parameter
.leftType().split("::"),
1449 Node::Typedef
, 0, SearchBaseClasses
|NonFunction
);
1451 leftNode
= const_cast<Tree
*>(this)->findNode(
1452 parameter
.leftType().split("::"), Node::Typedef
,
1453 node
->parent(), SearchBaseClasses
|NonFunction
);
1456 if (leftNode
->type() == Node::Typedef
) {
1457 const TypedefNode
*typedefNode
=
1458 static_cast<const TypedefNode
*>(leftNode
);
1459 if (typedefNode
->associatedEnum()) {
1460 leftType
= "QFlags<"+fullDocumentName(typedefNode
->associatedEnum())+">";
1464 leftType
= fullDocumentName(leftNode
);
1466 resolvedParameters
.append(leftType
);
1467 signatureList
.append(leftType
+ " " + parameter
.name());
1470 QString signature
= functionNode
->name()+"("+signatureList
.join(", ")+")";
1471 if (functionNode
->isConst())
1472 signature
+= " const";
1473 writer
.writeAttribute("signature", signature
);
1475 for (int i
= 0; i
< functionNode
->parameters().size(); ++i
) {
1476 Parameter parameter
= functionNode
->parameters()[i
];
1477 writer
.writeStartElement("parameter");
1478 writer
.writeAttribute("left", resolvedParameters
[i
]);
1479 writer
.writeAttribute("right", parameter
.rightType());
1480 writer
.writeAttribute("name", parameter
.name());
1481 writer
.writeAttribute("default", parameter
.defaultValue());
1482 writer
.writeEndElement(); // parameter
1486 else if (node
->type() == Node::Enum
) {
1488 const EnumNode
*enumNode
= static_cast<const EnumNode
*>(node
);
1489 if (enumNode
->flagsType()) {
1490 writer
.writeAttribute("typedef",
1491 fullDocumentName(enumNode
->flagsType()));
1493 foreach (const EnumItem
&item
, enumNode
->items()) {
1494 writer
.writeStartElement("value");
1495 writer
.writeAttribute("name", item
.name());
1496 writer
.writeAttribute("value", item
.value());
1497 writer
.writeEndElement(); // value
1501 else if (node
->type() == Node::Typedef
) {
1503 const TypedefNode
*typedefNode
= static_cast<const TypedefNode
*>(node
);
1504 if (typedefNode
->associatedEnum()) {
1505 writer
.writeAttribute("enum",
1506 fullDocumentName(typedefNode
->associatedEnum()));
1515 void Tree::generateIndexSections(QXmlStreamWriter
&writer
,
1517 bool generateInternalNodes
) const
1519 if (generateIndexSection(writer
, node
, generateInternalNodes
)) {
1521 if (node
->isInnerNode()) {
1522 const InnerNode
*inner
= static_cast<const InnerNode
*>(node
);
1524 // Recurse to write an element for this child node and all its children.
1525 foreach (const Node
*child
, inner
->childNodes())
1526 generateIndexSections(writer
, child
, generateInternalNodes
);
1529 foreach (const Node *child, inner->relatedNodes()) {
1530 QDomElement childElement = generateIndexSections(document, child);
1531 element.appendChild(childElement);
1535 writer
.writeEndElement();
1540 Outputs an index file.
1542 void Tree::generateIndex(const QString
&fileName
,
1544 const QString
&title
,
1545 bool generateInternalNodes
) const
1547 QFile
file(fileName
);
1548 if (!file
.open(QFile::WriteOnly
| QFile::Text
))
1551 QXmlStreamWriter
writer(&file
);
1552 writer
.setAutoFormatting(true);
1553 writer
.writeStartDocument();
1554 writer
.writeDTD("<!DOCTYPE QDOCINDEX>");
1556 writer
.writeStartElement("INDEX");
1557 writer
.writeAttribute("url", url
);
1558 writer
.writeAttribute("title", title
);
1559 writer
.writeAttribute("version", version());
1561 generateIndexSections(writer
, root(), generateInternalNodes
);
1563 writer
.writeEndElement(); // INDEX
1564 writer
.writeEndElement(); // QDOCINDEX
1565 writer
.writeEndDocument();
1570 Generate the tag file section with the given \a writer for the \a node
1571 specified, returning true if an element was written; otherwise returns
1574 void Tree::generateTagFileCompounds(QXmlStreamWriter
&writer
,
1575 const InnerNode
*inner
) const
1577 foreach (const Node
*node
, inner
->childNodes()) {
1579 if (!node
->url().isEmpty())
1583 switch (node
->type()) {
1584 case Node::Namespace
:
1592 case Node::Property
:
1593 case Node::Function
:
1594 case Node::Variable
:
1601 switch (node
->access()) {
1605 case Node::Protected
:
1606 access
= "protected";
1613 QString objName
= node
->name();
1615 // Special case: only the root node should have an empty name.
1616 if (objName
.isEmpty() && node
!= root())
1619 // *** Write the starting tag for the element here. ***
1620 writer
.writeStartElement("compound");
1621 writer
.writeAttribute("kind", kind
);
1623 if (node
->type() == Node::Class
) {
1624 writer
.writeTextElement("name", fullDocumentName(node
));
1625 writer
.writeTextElement("filename", fullDocumentLocation(node
));
1627 // Classes contain information about their base classes.
1628 const ClassNode
*classNode
= static_cast<const ClassNode
*>(node
);
1629 QList
<RelatedClass
> bases
= classNode
->baseClasses();
1630 foreach (const RelatedClass
&related
, bases
) {
1631 ClassNode
*baseClassNode
= related
.node
;
1632 writer
.writeTextElement("base", baseClassNode
->name());
1635 // Recurse to write all members.
1636 generateTagFileMembers(writer
, static_cast<const InnerNode
*>(node
));
1637 writer
.writeEndElement();
1639 // Recurse to write all compounds.
1640 generateTagFileCompounds(writer
, static_cast<const InnerNode
*>(node
));
1642 writer
.writeTextElement("name", fullDocumentName(node
));
1643 writer
.writeTextElement("filename", fullDocumentLocation(node
));
1645 // Recurse to write all members.
1646 generateTagFileMembers(writer
, static_cast<const InnerNode
*>(node
));
1647 writer
.writeEndElement();
1649 // Recurse to write all compounds.
1650 generateTagFileCompounds(writer
, static_cast<const InnerNode
*>(node
));
1657 void Tree::generateTagFileMembers(QXmlStreamWriter
&writer
,
1658 const InnerNode
*inner
) const
1660 foreach (const Node
*node
, inner
->childNodes()) {
1662 if (!node
->url().isEmpty())
1667 switch (node
->type()) {
1669 nodeName
= "member";
1673 nodeName
= "member";
1676 case Node::Property
:
1677 nodeName
= "member";
1680 case Node::Function
:
1681 nodeName
= "member";
1684 case Node::Namespace
:
1685 nodeName
= "namespace";
1690 case Node::Variable
:
1697 switch (node
->access()) {
1701 case Node::Protected
:
1702 access
= "protected";
1709 QString objName
= node
->name();
1711 // Special case: only the root node should have an empty name.
1712 if (objName
.isEmpty() && node
!= root())
1715 // *** Write the starting tag for the element here. ***
1716 writer
.writeStartElement(nodeName
);
1717 if (!kind
.isEmpty())
1718 writer
.writeAttribute("kind", kind
);
1720 switch (node
->type()) {
1723 writer
.writeCharacters(fullDocumentName(node
));
1724 writer
.writeEndElement();
1726 case Node::Namespace
:
1727 writer
.writeCharacters(fullDocumentName(node
));
1728 writer
.writeEndElement();
1730 case Node::Function
:
1733 Function nodes contain information about
1734 the type of function being described.
1737 const FunctionNode
*functionNode
=
1738 static_cast<const FunctionNode
*>(node
);
1739 writer
.writeAttribute("protection", access
);
1741 switch (functionNode
->virtualness()) {
1742 case FunctionNode::NonVirtual
:
1743 writer
.writeAttribute("virtualness", "non");
1745 case FunctionNode::ImpureVirtual
:
1746 writer
.writeAttribute("virtualness", "virtual");
1748 case FunctionNode::PureVirtual
:
1749 writer
.writeAttribute("virtual", "pure");
1754 writer
.writeAttribute("static",
1755 functionNode
->isStatic() ? "yes" : "no");
1757 if (functionNode
->virtualness() == FunctionNode::NonVirtual
)
1758 writer
.writeTextElement("type", functionNode
->returnType());
1760 writer
.writeTextElement("type",
1761 "virtual " + functionNode
->returnType());
1763 writer
.writeTextElement("name", objName
);
1764 QStringList pieces
= fullDocumentLocation(node
).split("#");
1765 writer
.writeTextElement("anchorfile", pieces
[0]);
1766 writer
.writeTextElement("anchor", pieces
[1]);
1768 // Write a signature attribute for convenience.
1769 QStringList signatureList
;
1771 foreach (const Parameter
¶meter
, functionNode
->parameters()) {
1772 QString leftType
= parameter
.leftType();
1773 const Node
*leftNode
= const_cast<Tree
*>(this)->findNode(parameter
.leftType().split("::"),
1774 Node::Typedef
, 0, SearchBaseClasses
|NonFunction
);
1776 leftNode
= const_cast<Tree
*>(this)->findNode(
1777 parameter
.leftType().split("::"), Node::Typedef
,
1778 node
->parent(), SearchBaseClasses
|NonFunction
);
1781 const TypedefNode
*typedefNode
= static_cast<const TypedefNode
*>(leftNode
);
1782 if (typedefNode
->associatedEnum()) {
1783 leftType
= "QFlags<"+fullDocumentName(typedefNode
->associatedEnum())+">";
1786 signatureList
.append(leftType
+ " " + parameter
.name());
1789 QString signature
= "("+signatureList
.join(", ")+")";
1790 if (functionNode
->isConst())
1791 signature
+= " const";
1792 if (functionNode
->virtualness() == FunctionNode::PureVirtual
)
1793 signature
+= " = 0";
1794 writer
.writeTextElement("arglist", signature
);
1796 writer
.writeEndElement(); // member
1799 case Node::Property
:
1801 const PropertyNode
*propertyNode
= static_cast<const PropertyNode
*>(node
);
1802 writer
.writeAttribute("type", propertyNode
->dataType());
1803 writer
.writeTextElement("name", objName
);
1804 QStringList pieces
= fullDocumentLocation(node
).split("#");
1805 writer
.writeTextElement("anchorfile", pieces
[0]);
1806 writer
.writeTextElement("anchor", pieces
[1]);
1807 writer
.writeTextElement("arglist", "");
1809 writer
.writeEndElement(); // member
1814 const EnumNode
*enumNode
= static_cast<const EnumNode
*>(node
);
1815 writer
.writeTextElement("name", objName
);
1816 QStringList pieces
= fullDocumentLocation(node
).split("#");
1817 writer
.writeTextElement("anchor", pieces
[1]);
1818 writer
.writeTextElement("arglist", "");
1819 writer
.writeEndElement(); // member
1821 for (int i
= 0; i
< enumNode
->items().size(); ++i
) {
1822 EnumItem item
= enumNode
->items().value(i
);
1823 writer
.writeStartElement("member");
1824 writer
.writeAttribute("name", item
.name());
1825 writer
.writeTextElement("anchor", pieces
[1]);
1826 writer
.writeTextElement("arglist", "");
1827 writer
.writeEndElement(); // member
1834 const TypedefNode
*typedefNode
= static_cast<const TypedefNode
*>(node
);
1835 if (typedefNode
->associatedEnum())
1836 writer
.writeAttribute("type", fullDocumentName(typedefNode
->associatedEnum()));
1838 writer
.writeAttribute("type", "");
1839 writer
.writeTextElement("name", objName
);
1840 QStringList pieces
= fullDocumentLocation(node
).split("#");
1841 writer
.writeTextElement("anchorfile", pieces
[0]);
1842 writer
.writeTextElement("anchor", pieces
[1]);
1843 writer
.writeTextElement("arglist", "");
1845 writer
.writeEndElement(); // member
1848 case Node::Variable
:
1858 void Tree::generateTagFile(const QString
&fileName
) const
1860 QFile
file(fileName
);
1861 if (!file
.open(QFile::WriteOnly
| QFile::Text
))
1864 QXmlStreamWriter
writer(&file
);
1865 writer
.setAutoFormatting(true);
1866 writer
.writeStartDocument();
1868 writer
.writeStartElement("tagfile");
1870 generateTagFileCompounds(writer
, root());
1872 writer
.writeEndElement(); // tagfile
1873 writer
.writeEndDocument();
1879 void Tree::addExternalLink(const QString
&url
, const Node
*relative
)
1881 FakeNode
*fakeNode
= new FakeNode(root(), url
, Node::ExternalPage
);
1882 fakeNode
->setAccess(Node::Public
);
1884 // Create some content for the node.
1885 QSet
<QString
> emptySet
;
1886 Location
location(relative
->doc().location());
1887 Doc
doc(location
, location
, " ", emptySet
); // placeholder
1888 fakeNode
->setDoc(doc
);
1892 Returns the full document location for HTML-based documentation.
1893 This should be moved into the HTML generator.
1895 QString
Tree::fullDocumentLocation(const Node
*node
) const
1899 if (!node
->url().isEmpty())
1905 if (node
->type() == Node::Namespace
) {
1907 // The root namespace has no name - check for this before creating
1908 // an attribute containing the location of any documentation.
1910 if (!node
->fileBase().isEmpty())
1911 parentName
= node
->fileBase() + ".html";
1915 else if (node
->type() == Node::Fake
) {
1917 if (node
->subType() == Node::QmlClass
)
1918 return "qml-" + node
->fileBase() + ".html";
1921 parentName
= node
->fileBase() + ".html";
1923 else if (node
->fileBase().isEmpty())
1926 Node
*parentNode
= 0;
1928 if ((parentNode
= node
->relates()))
1929 parentName
= fullDocumentLocation(node
->relates());
1930 else if ((parentNode
= node
->parent()))
1931 parentName
= fullDocumentLocation(node
->parent());
1933 switch (node
->type()) {
1935 case Node::Namespace
:
1936 if (parentNode
&& !parentNode
->name().isEmpty())
1937 parentName
= parentName
.replace(".html", "") + "-"
1938 + node
->fileBase().toLower() + ".html";
1940 parentName
= node
->fileBase() + ".html";
1942 case Node::Function
:
1945 Functions can be destructors, overloaded, or
1946 have associated properties.
1948 const FunctionNode
*functionNode
=
1949 static_cast<const FunctionNode
*>(node
);
1951 if (functionNode
->metaness() == FunctionNode::Dtor
)
1952 anchorRef
= "#dtor." + functionNode
->name().mid(1);
1954 else if (functionNode
->associatedProperty())
1955 return fullDocumentLocation(functionNode
->associatedProperty());
1957 else if (functionNode
->overloadNumber() > 1)
1958 anchorRef
= "#" + functionNode
->name()
1959 + "-" + QString::number(functionNode
->overloadNumber());
1961 anchorRef
= "#" + functionNode
->name();
1965 Use node->name() instead of node->fileBase() as
1966 the latter returns the name in lower-case. For
1967 HTML anchors, we need to preserve the case.
1971 anchorRef
= "#" + node
->name() + "-enum";
1974 anchorRef
= "#" + node
->name() + "-typedef";
1976 case Node::Property
:
1977 anchorRef
= "#" + node
->name() + "-prop";
1979 case Node::Variable
:
1980 anchorRef
= "#" + node
->name() + "-var";
1983 anchorRef
= "#" + Doc::canonicalTitle(node
->name());
1988 Use node->fileBase() for fake nodes because they are represented
1989 by pages whose file names are lower-case.
1991 parentName
= node
->fileBase();
1992 parentName
.replace("/", "-").replace(".", "-");
1993 parentName
+= ".html";
2000 // Various objects can be compat (deprecated) or obsolete.
2001 if (node
->type() != Node::Class
&& node
->type() != Node::Namespace
) {
2002 switch (node
->status()) {
2004 parentName
.replace(".html", "-qt3.html");
2006 case Node::Obsolete
:
2007 parentName
.replace(".html", "-obsolete.html");
2014 return parentName
.toLower() + anchorRef
;
2019 QString
Tree::fullDocumentName(const Node
*node
) const
2025 const Node
*n
= node
;
2028 if (!n
->name().isEmpty())
2029 pieces
.insert(0, n
->name());
2031 if (n
->type() == Node::Fake
)
2034 // Examine the parent node if one exists.
2041 // Create a name based on the type of the ancestor node.
2042 if (n
->type() == Node::Fake
)
2043 return pieces
.join("#");
2045 return pieces
.join("::");