qdoc: Give documenter more control of linking

This update is preparation for implementing the actual task
described in the bug. To implement it required converting
the QML type node and the QML basic type node to be first
order tree nodes instead of subtypes of the documentation
node. This cleans up a lot of messy logic in some places.

It was also necessary to split the getLink() function in the
html output generator into two functions, one still called
getLink(), which handles the \l command, and one called
qetAutoLink() which is called for generating auto links.
This should make qdoc run faster.

The basic infrastructure was also added for parsing the
string in the square brackets for the \l command.

There will be a further update to complete this task.
Note that some autolinks might not be generated due to
this change. I haven't seen any yet, but I believe there
will be some. This can be fixed later, if it is a problem.

Task-number: QTBUG-39221
Change-Id: I8135229984398408205ba901b9ef95ceac74683c
Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
This commit is contained in:
Martin Smith 2014-05-23 13:26:36 +02:00 committed by The Qt Project
parent bb794270ec
commit 46959875cf
21 changed files with 816 additions and 609 deletions

View File

@ -42,31 +42,12 @@
#include <qregexp.h>
#include "atom.h"
#include "location.h"
#include "qdocdatabase.h"
#include <stdio.h>
#include <qdebug.h>
QT_BEGIN_NAMESPACE
QLatin1String Atom::BOLD_ ("bold");
QLatin1String Atom::INDEX_ ("index");
QLatin1String Atom::ITALIC_ ("italic");
QLatin1String Atom::LINK_ ("link");
QLatin1String Atom::PARAMETER_ ("parameter");
QLatin1String Atom::SPAN_ ("span");
QLatin1String Atom::SUBSCRIPT_ ("subscript");
QLatin1String Atom::SUPERSCRIPT_ ("superscript");
QLatin1String Atom::TELETYPE_ ("teletype");
QLatin1String Atom::UICONTROL_ ("uicontrol");
QLatin1String Atom::UNDERLINE_ ("underline");
QLatin1String Atom::BULLET_ ("bullet");
QLatin1String Atom::TAG_ ("tag");
QLatin1String Atom::VALUE_ ("value");
QLatin1String Atom::LOWERALPHA_ ("loweralpha");
QLatin1String Atom::LOWERROMAN_ ("lowerroman");
QLatin1String Atom::NUMERIC_ ("numeric");
QLatin1String Atom::UPPERALPHA_ ("upperalpha");
QLatin1String Atom::UPPERROMAN_ ("upperroman");
/*! \class Atom
\brief The Atom class is the fundamental unit for representing
documents internally.
@ -387,4 +368,28 @@ void Atom::dump() const
str.toLatin1().data());
}
/*!
The only constructor for LinkAtom. It only create an Atom
of type Atom::Link with \a p1 being the link text. \a p2
contains some search parameters.
*/
LinkAtom::LinkAtom(const QString& p1, const QString& p2)
: Atom(Link, p1), qml_(false), goal_(Node::NoType), domain_(0)
{
QStringList params = p2.toLower().split(QLatin1Char(' '));
foreach (const QString& p, params) {
if (p == "qml")
qml_ = true;
else {
if (!domain_) {
domain_ = QDocDatabase::qdocDB()->findTree(p);
if (domain_)
continue;
}
if (goal_ == Node::NoType)
goal_ = Node::goal(p);
}
}
}
QT_END_NAMESPACE

View File

@ -39,17 +39,16 @@
**
****************************************************************************/
/*
atom.h
*/
#ifndef ATOM_H
#define ATOM_H
#include <qstringlist.h>
#include "node.h"
QT_BEGIN_NAMESPACE
class Tree;
class Atom
{
public:
@ -169,6 +168,8 @@ public:
previous->next_ = this;
}
virtual ~Atom() { }
void appendChar(QChar ch) { strs[0] += ch; }
void appendString(const QString& string) { strs[0] += string; }
void chopString() { strs[0].chop(1); }
@ -186,33 +187,34 @@ public:
int count() const { return strs.size(); }
void dump() const;
static QLatin1String BOLD_;
static QLatin1String INDEX_;
static QLatin1String ITALIC_;
static QLatin1String LINK_;
static QLatin1String PARAMETER_;
static QLatin1String SPAN_;
static QLatin1String SUBSCRIPT_;
static QLatin1String SUPERSCRIPT_;
static QLatin1String TELETYPE_;
static QLatin1String UICONTROL_;
static QLatin1String UNDERLINE_;
virtual bool qml() const { return false; }
virtual bool specifiesDomain() const { return false; }
virtual Tree* domain() const { return 0; }
virtual Node::Type goal() const { return Node::NoType; }
static QLatin1String BULLET_;
static QLatin1String TAG_;
static QLatin1String VALUE_;
static QLatin1String LOWERALPHA_;
static QLatin1String LOWERROMAN_;
static QLatin1String NUMERIC_;
static QLatin1String UPPERALPHA_;
static QLatin1String UPPERROMAN_;
private:
protected:
Atom* next_;
Type type_;
QStringList strs;
};
class LinkAtom : public Atom
{
public:
LinkAtom(const QString& p1, const QString& p2);
virtual ~LinkAtom() { }
virtual bool qml() const { return qml_; }
virtual bool specifiesDomain() const { return (domain_ != 0); }
virtual Tree* domain() const { return domain_; }
virtual Node::Type goal() const { return goal_; }
protected:
bool qml_;
Node::Type goal_;
Tree* domain_;
};
#define ATOM_FORMATTING_BOLD "bold"
#define ATOM_FORMATTING_INDEX "index"
#define ATOM_FORMATTING_ITALIC "italic"

View File

@ -273,7 +273,7 @@ QString CodeMarker::taggedNode(const Node* node)
case Node::Property:
tag = QLatin1String("@property");
break;
case Node::Document:
case Node::QmlType:
/*
Remove the "QML:" prefix, if present.
There shouldn't be any of these "QML:"
@ -282,10 +282,11 @@ QString CodeMarker::taggedNode(const Node* node)
qualifiers, but this code is kept to
be backward compatible.
*/
if (node->subType() == Node::QmlClass) {
if (node->name().startsWith(QLatin1String("QML:")))
name = name.mid(4);
}
if (node->name().startsWith(QLatin1String("QML:")))
name = name.mid(4);
tag = QLatin1String("@property");
break;
case Node::Document:
tag = QLatin1String("@property");
break;
case Node::QmlMethod:
@ -400,9 +401,8 @@ void CodeMarker::insert(FastSection &fastSection,
InnerNode* p = node->parent();
if (p->type() == Node::QmlPropertyGroup)
p = p->parent();
if (p != fastSection.parent_) { // && !node->parent()->isAbstract()) {
if (p->subType() != Node::QmlClass || !p->isAbstract()) {
//if (node->type() != Node::QmlProperty) {
if (p != fastSection.parent_) {
if (!p->isQmlType() || !p->isAbstract()) {
inheritedMember = true;
}
}
@ -622,6 +622,7 @@ QStringList CodeMarker::macRefsForNode(Node *node)
}
case Node::Namespace:
case Node::Document:
case Node::QmlType:
default:
return QStringList();
}

View File

@ -408,17 +408,13 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
without including the namespace qualifier.
*/
Node::Type type = nodeTypeMap[command];
Node::SubType subtype = Node::NoSubType;
if (type == Node::Document)
subtype = Node::QmlClass;
QStringList paths = arg.first.split(QLatin1Char(' '));
QStringList path = paths[0].split("::");
Node *node = 0;
node = qdb_->findNodeInOpenNamespace(path, type, subtype);
node = qdb_->findNodeInOpenNamespace(path, type);
if (node == 0)
node = qdb_->findNodeByNameAndType(path, type, subtype);
node = qdb_->findNodeByNameAndType(path, type);
if (node == 0) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
.arg(arg.first).arg(command));
@ -971,14 +967,14 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == arg)
doc.location().warning(tr("%1 tries to inherit itself").arg(arg));
else if (node->subType() == Node::QmlClass) {
else if (node->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(arg);
QmlClassNode::addInheritedBy(arg,node);
}
}
else if (command == COMMAND_QMLINSTANTIATES) {
if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
if (node->isQmlType()) {
ClassNode* classNode = qdb_->findClassNode(arg.split("::"));
if (classNode)
node->setClassNode(classNode);
@ -1023,9 +1019,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_QMLABSTRACT) {
if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
if (node->isQmlType())
node->setAbstract(true);
}
}
else {
processCommonMetaCommand(doc.location(),command,argLocPair,node);

View File

@ -819,7 +819,6 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
}
break;
case Atom::BriefRight:
// if (relative->type() != Node::Document)
writeEndTag(); // </shortdesc> or </p>
if (in_para)
in_para = false;
@ -1106,10 +1105,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
while (n != nsmap.constEnd()) {
const Node* node = n.value();
switch (node->type()) {
case Node::Document:
if (node->subType() == Node::QmlClass) {
sections[QmlClass].appendMember((Node*)node);
}
case Node::QmlType:
sections[QmlClass].appendMember((Node*)node);
break;
case Node::Namespace:
sections[Namespace].appendMember((Node*)node);
@ -1256,8 +1253,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
images.append(QLatin1Char('/'));
fileName = images + atom->string();
}
if (relative && (relative->type() == Node::Document) &&
(relative->subType() == Node::Example)) {
if (relative && relative->isExample()) {
const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
if (cen->imageFileName().isEmpty()) {
ExampleNode* en = const_cast<ExampleNode*>(cen);
@ -1313,8 +1309,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
{
const Node *node = 0;
QString myLink = getLink(atom, relative, &node);
if (myLink.isEmpty())
myLink = getCollisionLink(atom);
//if (myLink.isEmpty())
//myLink = getCollisionLink(atom);
if (myLink.isEmpty() && !noLinkErrors())
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
else if (!inSectionHeading_)
@ -2052,7 +2048,7 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); // </cxxClass>
}
else if ((inner->type() == Node::Document) && (inner->subType() == Node::HeaderFile)) {
else if (inner->isHeaderFile()) {
const DocNode* dn = const_cast<DocNode*>(static_cast<const DocNode*>(inner));
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
@ -2168,7 +2164,7 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); // </cxxClass>
}
else if ((inner->type() == Node::Document) && (inner->subType() == Node::QmlClass)) {
else if (inner->isQmlType()) {
QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner));
ClassNode* cn = qcn->classNode();
rawTitle = inner->plainName();
@ -2216,6 +2212,36 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
}
}
/*!
Generate the DITA page for a qdoc file that doesn't map
to an underlying c++ file.
*/
void DitaXmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
{
QList<Section> sections;
QList<Section>::const_iterator s;
QString fullTitle = "QML Basic Type: " + qbtn->fullTitle();
generateHeader(qbtn, fullTitle);
generateBrief(qbtn, marker); // <shortdesc>
writeProlog(qbtn);
writeStartTag(DT_body);
enterSection(QString(), QString());
if (!qbtn->doc().isEmpty()) {
generateBody(qbtn, marker);
generateAlsoList(qbtn, marker);
}
leaveSection(); // </section>
if (!writeEndTag()) { // </body>
qbtn->doc().location().warning(tr("Pop of empty XML tag stack; generating DITA for '%1'").arg(qbtn->name()));
return;
}
writeRelatedLinks(qbtn);
writeEndTag(); // </topic>
}
/*!
Write a list item for a \a link with the given \a text.
*/
@ -2251,10 +2277,7 @@ void DitaXmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
QList<Section>::const_iterator s;
QString fullTitle = dn->fullTitle();
if (dn->subType() == Node::QmlBasicType) {
fullTitle = "QML Basic Type: " + fullTitle;
}
else if (dn->subType() == Node::Collision) {
if (dn->subType() == Node::Collision) {
fullTitle = "Name Collision: " + fullTitle;
}
@ -2391,7 +2414,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
if (linkNode && linkNode->type() == Node::Document) {
if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@ -2402,7 +2425,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
if (linkNode && linkNode->type() == Node::Document) {
if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@ -2413,7 +2436,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
if (linkNode && linkNode->type() == Node::Document) {
if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@ -2804,7 +2827,7 @@ void DitaXmlGenerator::generateAnnotatedList(const Node* relative,
writeEndTag(); // </p>
writeEndTag(); // <entry>
if (!(node->type() == Node::Document)) {
if (!node->isDocNode()) {
Text brief = node->doc().trimmedBriefText(node->name());
if (!brief.isEmpty()) {
writeStartTag(DT_entry);
@ -3026,7 +3049,7 @@ void DitaXmlGenerator::generateCompactList(ListType , // currently not needed fo
writeHrefAttribute(linkForNode(it.value(), relative));
QStringList pieces;
if (it.value()->subType() == Node::QmlClass)
if (it.value()->isQmlType())
pieces << it.value()->name();
else
pieces = it.value()->fullName(relative).split("::");
@ -3435,8 +3458,8 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
}
par1 = QStringRef();
n = qdb_->resolveType(arg.toString(), relative);
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass)
if (n && n->isQmlBasicType()) {
if (relative && relative->isQmlType())
addLink(linkForNode(n, relative), arg);
else
writeCharacters(arg.toString());
@ -3712,7 +3735,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative)
QString fn = fileName(node);
if (node && relative && node->parent() != relative) {
if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
if (node->parent()->isQmlType() && relative->isQmlType()) {
if (node->parent()->isAbstract()) {
/*
This is a bit of a hack. What we discover with
@ -3775,6 +3798,7 @@ int DitaXmlGenerator::hOffset(const Node* node)
case Node::Namespace:
case Node::Class:
return 2;
case Node::QmlType:
case Node::Document:
return 1;
case Node::Enum:
@ -3836,7 +3860,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
if (first.isEmpty())
*node = relative;
else if (first.endsWith(".html"))
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
else if (first.endsWith("()")) // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
else {
@ -3860,7 +3884,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
if (relative && (relative->parent() != *node) &&
(relative->status() != Node::Obsolete)) {
bool porting = false;
if (relative->type() == Node::Document) {
if (relative->isDocNode()) {
const DocNode* fake = static_cast<const DocNode*>(relative);
if (fake->title().startsWith("Porting"))
porting = true;
@ -4607,7 +4631,7 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par
const Node* tn = qdb_->resolveType(arg.toString(), parent);
if (tn) {
//Do not generate a link from a C++ function to a QML Basic Type (such as int)
if (n->type() == Node::Function && tn->subType() == Node::QmlBasicType)
if (n->isFunction() && tn->isQmlBasicType())
writeCharacters(arg.toString());
else
addLink(linkForNode(tn,parent),arg,DT_apiRelation);
@ -4762,12 +4786,13 @@ void DitaXmlGenerator::writeEnumerations(const Section& s,
}
// not included: <cxxEnumeratorAPIItemLocation>
#if 0
if (!(*i).text().isEmpty()) {
writeStartTag(DT_apiDesc);
generateText((*i).text(), en, marker);
writeEndTag(); // </apiDesc>
}
#endif
writeEndTag(); // <cxxEnumerator>
++i;
}
@ -5268,7 +5293,7 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
if (!node->url().isNull())
return;
if (node->type() == Node::Document) {
if (node->isDocNode()) {
DocNode* docNode = static_cast<DocNode*>(node);
if (docNode->subType() == Node::ExternalPage)
return;
@ -5279,7 +5304,7 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title()));
}
}
else if (node->type() == Node::QmlPropertyGroup)
else if (node->isQmlPropertyGroup())
return;
/*
@ -5292,24 +5317,19 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
later in generateCollisionPages(). Each one is
appended to a list for later.
*/
if ((node->type() == Node::Document) && (node->subType() == Node::Collision)) {
if (node->isCollisionNode()) {
NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
}
else {
if (!node->name().endsWith(".ditamap"))
beginSubPage(node, fileName(node));
if (node->type() == Node::Namespace || node->type() == Node::Class) {
if (node->isNamespace() || node->isClass() || node->isQmlType() || node->isHeaderFile())
generateClassLikeNode(node, marker);
}
else if (node->type() == Node::Document) {
if (node->subType() == Node::HeaderFile)
generateClassLikeNode(node, marker);
else if (node->subType() == Node::QmlClass)
generateClassLikeNode(node, marker);
else
generateDocNode(static_cast<DocNode*>(node), marker);
}
else if (node->isDocNode())
generateDocNode(static_cast<DocNode*>(node), marker);
else if (node->isQmlBasicType())
generateQmlBasicTypePage(static_cast<QmlBasicTypeNode*>(node), marker);
if (!node->name().endsWith(".ditamap"))
endSubPage();
}
@ -5378,7 +5398,7 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
QString message;
for (int i=0; i<children.size(); ++i) {
Node* child = children[i];
if ((child->type() == Node::Document) && (child->subType() == Node::Collision)) {
if (child->isCollisionNode()) {
const DocNode* fake = static_cast<const DocNode*>(child);
Node* n = collectNodesByTypeAndSubtype(fake);
if (n)
@ -5401,6 +5421,14 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
if (!isDuplicate(nodeTypeMaps[Node::Class],child->name(),child))
nodeTypeMaps[Node::Class]->insert(child->name(),child);
break;
case Node::QmlType:
if (!isDuplicate(nodeTypeMaps[Node::QmlType],child->name(),child))
nodeTypeMaps[Node::QmlType]->insert(child->name(),child);
break;
case Node::QmlBasicType:
if (!isDuplicate(nodeTypeMaps[Node::QmlBasicType],child->title(),child))
nodeTypeMaps[Node::QmlBasicType]->insert(child->title(),child);
break;
case Node::Group:
if (!isDuplicate(nodeTypeMaps[Node::Group],child->title(),child))
nodeTypeMaps[Node::Group]->insert(child->title(),child);
@ -5435,14 +5463,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
if (!isDuplicate(nodeSubtypeMaps[Node::ExternalPage],child->title(),child))
nodeSubtypeMaps[Node::ExternalPage]->insert(child->title(),child);
break;
case Node::QmlClass:
if (!isDuplicate(nodeSubtypeMaps[Node::QmlClass],child->title(),child))
nodeSubtypeMaps[Node::QmlClass]->insert(child->title(),child);
break;
case Node::QmlBasicType:
if (!isDuplicate(nodeSubtypeMaps[Node::QmlBasicType],child->title(),child))
nodeSubtypeMaps[Node::QmlBasicType]->insert(child->title(),child);
break;
case Node::Collision:
if (!isDuplicate(nodeSubtypeMaps[Node::Collision],child->title(),child))
nodeSubtypeMaps[Node::Collision]->insert(child->title(),child);
@ -5551,10 +5571,10 @@ void DitaXmlGenerator::writeDitaMap()
writeTopicrefs(nodeTypeMaps[Node::QmlModule], "QML modules");
if (nodeTypeMaps[Node::QmlModule]->size() == 1)
writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types", nodeTypeMaps[Node::QmlModule]->values()[0]);
writeTopicrefs(nodeTypeMaps[Node::QmlType], "QML types", nodeTypeMaps[Node::QmlModule]->values()[0]);
else
writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types");
writeTopicrefs(nodeSubtypeMaps[Node::QmlBasicType], "QML basic types");
writeTopicrefs(nodeTypeMaps[Node::QmlType], "QML types");
writeTopicrefs(nodeTypeMaps[Node::QmlBasicType], "QML basic types");
if (nodeTypeMaps[Node::Module]->size() > 1)
writeTopicrefs(nodeTypeMaps[Node::Module], "Modules");
@ -5910,32 +5930,32 @@ DitaXmlGenerator::writeProlog(const InnerNode* inner)
if (!writeMetadataElement(inner,DT_category,false)) {
writeStartTag(DT_category);
QString category = "Page";
if (inner->type() == Node::Class)
if (inner->isClass())
category = "Class reference";
else if (inner->type() == Node::Namespace)
if (inner->isQmlType())
category = "QML Reference";
else if (inner->isQmlBasicType())
category = "QML Basic Type";
else if (inner->isNamespace())
category = "Namespace";
else if (inner->type() == Node::Module)
else if (inner->isModule())
category = "Module";
else if (inner->type() == Node::QmlModule)
else if (inner->isQmlModule())
category = "QML Module";
else if (inner->type() == Node::Group)
else if (inner->isGroup())
category = "Group";
else if (inner->type() == Node::Document) {
if (inner->subType() == Node::QmlClass)
category = "QML Reference";
else if (inner->subType() == Node::QmlBasicType)
category = "QML Basic Type";
else if (inner->subType() == Node::HeaderFile)
else if (inner->isDocNode()) {
if (inner->isHeaderFile())
category = "Header File";
else if (inner->subType() == Node::File)
category = "Example Source File";
else if (inner->subType() == Node::Example)
else if (inner->isExample())
category = "Example";
else if (inner->subType() == Node::Image)
category = "Image";
else if (inner->subType() == Node::Page)
category = "Page";
else if (inner->subType() == Node::ExternalPage)
else if (inner->isExternalPage())
category = "External Page"; // Is this necessary?
}
xmlWriter().writeCharacters(category);
@ -5977,8 +5997,7 @@ DitaXmlGenerator::writeProlog(const InnerNode* inner)
xmlWriter().writeAttribute("content",i.value());
writeEndTag(); // </othermeta>
}
if ((tagStack.first() == DT_cxxClass && !inner->includes().isEmpty()) ||
(inner->type() == Node::Document && inner->subType() == Node::HeaderFile)) {
if ((tagStack.first() == DT_cxxClass && !inner->includes().isEmpty()) || inner->isHeaderFile()) {
writeStartTag(DT_othermeta);
xmlWriter().writeAttribute("name","includeFile");
QString text;

View File

@ -315,6 +315,7 @@ protected:
const Node* relative,
CodeMarker* marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker);
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual QString fileExtension() const;

View File

@ -46,6 +46,7 @@
#include "openedlist.h"
#include "quoter.h"
#include "text.h"
#include "atom.h"
#include "tokenizer.h"
#include <qdatetime.h>
#include <qfile.h>
@ -63,7 +64,6 @@ Q_GLOBAL_STATIC(QSet<QString>, null_Set_QString)
Q_GLOBAL_STATIC(TopicList, nullTopicList)
Q_GLOBAL_STATIC(QStringList, null_QStringList)
Q_GLOBAL_STATIC(QList<Text>, null_QList_Text)
//Q_GLOBAL_STATIC(QStringMap, null_QStringMap)
Q_GLOBAL_STATIC(QStringMultiMap, null_QStringMultiMap)
struct Macro
@ -477,6 +477,7 @@ private:
void parseAlso();
void append(Atom::Type type, const QString& string = QString());
void append(Atom::Type type, const QString& p1, const QString& p2);
void append(const QString& p1, const QString& p2);
void appendChar(QChar ch);
void appendWord(const QString &word);
void appendToCode(const QString &code);
@ -495,6 +496,7 @@ private:
Doc::Sections getSectioningUnit();
QString getArgument(bool verbatim = false);
QString getBracedArgument(bool verbatim);
QString getBracketedArgument();
QString getOptionalArgument();
QString getRestOfLine();
QString getMetaCommandArgument(const QString &cmdStr);
@ -504,6 +506,7 @@ private:
bool isBlankLine();
bool isLeftBraceAhead();
bool isLeftBracketAhead();
void skipSpacesOnLine();
void skipSpacesOrOneEndl();
void skipAllSpaces();
@ -965,9 +968,11 @@ void DocParser::parse(const QString& source,
break;
case CMD_L:
enterPara();
if (isLeftBracketAhead())
p2 = getBracketedArgument();
if (isLeftBraceAhead()) {
p1 = getArgument();
append(Atom::Link, p1);
append(p1, p2);
if (isLeftBraceAhead()) {
currentLinkAtom = priv->text.lastAtom();
startFormat(ATOM_FORMATTING_LINK, cmd);
@ -980,7 +985,7 @@ void DocParser::parse(const QString& source,
}
else {
p1 = getArgument();
append(Atom::Link, p1);
append(p1, p2);
append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
append(Atom::String, cleanLink(p1));
append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
@ -1984,6 +1989,17 @@ void DocParser::append(Atom::Type type, const QString& p1, const QString& p2)
priv->text << Atom(type, p1, p2);
}
void DocParser::append(const QString& p1, const QString& p2)
{
Atom::Type lastType = priv->text.lastAtom()->type();
if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n")))
priv->text.lastAtom()->chopString();
if (p2.isEmpty())
priv->text << Atom(Atom::Link, p1, p2);
else
priv->text << LinkAtom(p1, p2);
}
void DocParser::appendChar(QChar ch)
{
if (priv->text.lastAtom()->type() != Atom::String)
@ -2245,10 +2261,10 @@ Doc::Sections DocParser::getSectioningUnit()
Gets an argument that is enclosed in braces and returns it
without the enclosing braces. On entry, the current character
is the left brace. On exit, the current character is the one
that comes afterr the right brace.
that comes after the right brace.
If \a verbatim is true, extra whitespace is retained in the
returned string. Otherwise, extr whitespace is removed.
returned string. Otherwise, extra whitespace is removed.
*/
QString DocParser::getBracedArgument(bool verbatim)
{
@ -2379,6 +2395,47 @@ QString DocParser::getArgument(bool verbatim)
return arg.simplified();
}
/*!
Gets an argument that is enclosed in brackets and returns it
without the enclosing brackets. On entry, the current character
is the left bracket. On exit, the current character is the one
that comes after the right bracket.
*/
QString DocParser::getBracketedArgument()
{
QString arg;
int delimDepth = 0;
skipSpacesOrOneEndl();
if (pos < in.length() && in[pos] == '[') {
pos++;
while (pos < in.length() && delimDepth >= 0) {
switch (in[pos].unicode()) {
case '[':
delimDepth++;
arg += QLatin1Char('[');
pos++;
break;
case ']':
delimDepth--;
if (delimDepth >= 0)
arg += QLatin1Char(']');
pos++;
break;
case '\\':
arg += in[pos];
pos++;
break;
default:
arg += in[pos];
pos++;
}
}
if (delimDepth > 0)
location().warning(tr("Missing ']'"));
}
return arg;
}
QString DocParser::getOptionalArgument()
{
skipSpacesOrOneEndl();
@ -2527,6 +2584,20 @@ bool DocParser::isLeftBraceAhead()
return numEndl < 2 && i < len && in[i] == '{';
}
bool DocParser::isLeftBracketAhead()
{
int numEndl = 0;
int i = pos;
while (i < len && in[i].isSpace() && numEndl < 2) {
// ### bug with '\\'
if (in[i] == '\n')
numEndl++;
i++;
}
return numEndl < 2 && i < len && in[i] == '[';
}
/*!
Skips to the next non-space character or EOL.
*/

View File

@ -325,19 +325,6 @@ QString Generator::fileBase(const Node *node) const
if (base.endsWith(".html"))
base.truncate(base.length() - 5);
if (node->isQmlNode()) {
if (!node->qmlModuleName().isEmpty()) {
base.prepend(node->qmlModuleName() + QLatin1Char('-'));
}
/*
To avoid file name conflicts in the html directory,
we prepend a prefix (by default, "qml-") to the file name of QML
element doc files.
*/
if ((node->subType() == Node::QmlClass) || (node->subType() == Node::QmlBasicType)) {
base.prepend(outputPrefix(QLatin1String("QML")));
}
}
if (node->isExample() || node->isExampleFile()) {
QString modPrefix(node->moduleName());
if (modPrefix.isEmpty()) {
@ -349,6 +336,18 @@ QString Generator::fileBase(const Node *node) const
base.append(QLatin1String("-example"));
}
}
else if (node->isQmlType() || node->isQmlBasicType()) {
base = node->name();
if (!node->qmlModuleName().isEmpty()) {
base.prepend(node->qmlModuleName() + QLatin1Char('-'));
}
/*
To avoid file name conflicts in the html directory,
we prepend a prefix (by default, "qml-") to the file name of QML
element doc files.
*/
base.prepend(outputPrefix(QLatin1String("QML")));
}
else if (node->isCollectionNode()) {
base = node->name();
if (base.endsWith(".html"))
@ -367,7 +366,7 @@ QString Generator::fileBase(const Node *node) const
forever {
const Node *pp = p->parent();
base.prepend(p->name());
if (!pp || pp->name().isEmpty() || pp->type() == Node::Document)
if (!pp || pp->name().isEmpty() || pp->isDocNode())
break;
base.prepend(QLatin1Char('-'));
p = pp;
@ -467,25 +466,23 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
else
return QString();
}
else if (node->isDocNode() || node->isCollectionNode()) {
if (node->isQmlType() || node->isQmlBasicType()) {
QString fb = fileBase(node);
if (fb.startsWith(Generator::outputPrefix(QLatin1String("QML"))))
return fb + QLatin1Char('.') + currentGenerator()->fileExtension();
else {
QString mq;
if (!node->qmlModuleName().isEmpty()) {
mq = node->qmlModuleName().replace(QChar('.'),QChar('-'));
mq = mq.toLower() + QLatin1Char('-');
}
return fdl+ Generator::outputPrefix(QLatin1String("QML")) + mq +
fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
}
}
else if (node->isQmlType() || node->isQmlBasicType()) {
QString fb = fileBase(node);
if (fb.startsWith(Generator::outputPrefix(QLatin1String("QML"))))
return fb + QLatin1Char('.') + currentGenerator()->fileExtension();
else {
parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
QString mq;
if (!node->qmlModuleName().isEmpty()) {
mq = node->qmlModuleName().replace(QChar('.'),QChar('-'));
mq = mq.toLower() + QLatin1Char('-');
}
return fdl+ Generator::outputPrefix(QLatin1String("QML")) + mq +
fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
}
}
else if (node->isDocNode() || node->isCollectionNode()) {
parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
}
else if (fileBase(node).isEmpty())
return QString();
@ -562,6 +559,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
case Node::Variable:
anchorRef = QLatin1Char('#') + node->name() + "-var";
break;
case Node::QmlType:
case Node::Document:
case Node::Group:
case Node::Module:
@ -577,7 +575,8 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
}
// Various objects can be compat (deprecated) or obsolete.
if (node->type() != Node::Class && node->type() != Node::Namespace) {
// Is this even correct?
if (!node->isClass() && !node->isNamespace()) {
switch (node->status()) {
case Node::Compat:
parentName.replace(QLatin1Char('.') + currentGenerator()->fileExtension(),
@ -682,6 +681,10 @@ const Atom *Generator::generateAtomList(const Atom *atom,
return 0;
}
/*!
Generate the body of the documentation from the qdoc comment
found with the entity represented by the \a node.
*/
void Generator::generateBody(const Node *node, CodeMarker *marker)
{
bool quiet = false;
@ -812,9 +815,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
if (node->type() == Node::Document) {
if (node->isDocNode()) {
const DocNode *dn = static_cast<const DocNode *>(node);
if (dn->subType() == Node::Example) {
if (dn->isExample()) {
generateExampleFiles(dn, marker);
}
else if (dn->subType() == Node::File) {
@ -968,6 +971,9 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
/*!
Recursive writing of HTML files from the root \a node.
\note DitaXmlGenerator overrides this function, but
HtmlGenerator does not.
\note NameCollisionNodes are skipped here and processed
later. See HtmlGenerator::generateCollisionPages() for
more on this.
@ -981,7 +987,7 @@ void Generator::generateInnerNode(InnerNode* node)
if (node->isInternal() && !showInternal_)
return;
if (node->type() == Node::Document) {
if (node->isDocNode()) {
DocNode* docNode = static_cast<DocNode*>(node);
if (docNode->subType() == Node::ExternalPage)
return;
@ -992,7 +998,7 @@ void Generator::generateInnerNode(InnerNode* node)
qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title()));
}
}
else if (node->type() == Node::QmlPropertyGroup)
else if (node->isQmlPropertyGroup())
return;
/*
@ -1016,11 +1022,23 @@ void Generator::generateInnerNode(InnerNode* node)
generateClassLikeNode(node, marker);
endSubPage();
}
if (node->isQmlType()) {
beginSubPage(node, fileName(node));
QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
generateQmlTypePage(qcn, marker);
endSubPage();
}
else if (node->isDocNode()) {
beginSubPage(node, fileName(node));
generateDocNode(static_cast<DocNode*>(node), marker);
endSubPage();
}
else if (node->isQmlBasicType()) {
beginSubPage(node, fileName(node));
QmlBasicTypeNode* qbtn = static_cast<QmlBasicTypeNode*>(node);
generateQmlBasicTypePage(qbtn, marker);
endSubPage();
}
else if (node->isCollectionNode()) {
CollectionNode* cn = static_cast<CollectionNode*>(node);
/*
@ -1243,6 +1261,11 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker)
generateText(text, node, marker);
}
/*!
Generate the documentation for \a relative. i.e. \a relative
is the node that reporesentas the entity where a qdoc comment
was found, and \a text represents the qdoc comment.
*/
bool Generator::generateText(const Text& text,
const Node *relative,
CodeMarker *marker)
@ -1420,7 +1443,14 @@ Generator *Generator::generatorForFormat(const QString& format)
return 0;
}
#if 0
/*!
This function might be useless now with the addition of
multiple node trees. It is called a few hundred times,
but it never finds a collision node. The single call has
been commented out by mws (19/05/2014). If it is no
longer needed, it will be removed.
This function can be called if getLink() returns an empty
string. It tests the \a atom string to see if it is a link
of the form <element> :: <name>, where <element> is a QML
@ -1452,7 +1482,7 @@ QString Generator::getCollisionLink(const Atom* atom)
}
return link;
}
#endif
/*!
Looks up the tag \a t in the map of metadata values for the
@ -1982,17 +2012,12 @@ QString Generator::typeString(const Node *node)
return "namespace";
case Node::Class:
return "class";
case Node::QmlType:
return "type";
case Node::QmlBasicType:
return "type";
case Node::Document:
{
switch (node->subType()) {
case Node::QmlClass:
return "type";
case Node::QmlBasicType:
return "type";
default:
return "documentation";
}
}
return "documentation";
case Node::Enum:
return "enum";
case Node::Typedef:

View File

@ -114,6 +114,8 @@ protected:
virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker);
virtual void generateBody(const Node *node, CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateQmlTypePage(QmlClassNode* , CodeMarker* ) { }
virtual void generateQmlBasicTypePage(QmlBasicTypeNode* , CodeMarker* ) { }
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual void generateInheritedBy(const ClassNode *classe, CodeMarker *marker);
@ -155,7 +157,7 @@ protected:
void generateSince(const Node *node, CodeMarker *marker);
void generateStatus(const Node *node, CodeMarker *marker);
void generateThreadSafeness(const Node *node, CodeMarker *marker);
QString getCollisionLink(const Atom* atom);
//QString getCollisionLink(const Atom* atom);
QString getMetadataElement(const InnerNode* inner, const QString& t);
QStringList getMetadataElements(const InnerNode* inner, const QString& t);
QString indent(int level, const QString& markedCode);

View File

@ -139,6 +139,8 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
typeHash["qmlsignalhandler"] = Node::QmlSignalHandler;
typeHash["qmlmethod"] = Node::QmlMethod;
typeHash["qmlpropertygroup"] = Node::QmlPropertyGroup;
typeHash["qmlclass"] = Node::QmlType;
typeHash["qmlbasictype"] = Node::QmlBasicType;
QHash<QString, Node::SubType> subTypeHash;
subTypeHash["example"] = Node::Example;
@ -146,8 +148,6 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
subTypeHash["file"] = Node::File;
subTypeHash["page"] = Node::Page;
subTypeHash["externalpage"] = Node::ExternalPage;
subTypeHash["qmlclass"] = Node::QmlClass;
subTypeHash["qmlbasictype"] = Node::QmlBasicType;
QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values());
@ -211,16 +211,14 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const
// "id"
details << node->parent()->name()+"::"+node->name();
}
else if (node->type() == Node::Document) {
else if (node->isQmlType() || node->isQmlBasicType()) {
details << node->name();
details << "QML." + node->name();
}
else if (node->isDocNode()) {
const DocNode *fake = static_cast<const DocNode *>(node);
if (fake->subType() == Node::QmlClass) {
details << (QmlClassNode::qmlOnly ? fake->name() : fake->fullTitle());
details << "QML." + fake->name();
}
else {
details << fake->fullTitle();
details << fake->fullTitle();
}
details << fake->fullTitle();
details << fake->fullTitle();
}
else {
details << node->name();
@ -248,7 +246,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
return false;
QString objName;
if (node->type() == Node::Document) {
if (node->isDocNode()) {
const DocNode *fake = static_cast<const DocNode *>(node);
objName = fake->fullTitle();
}
@ -288,6 +286,25 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
project.keywords.append(keywordDetails(node));
project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
case Node::QmlType:
case Node::QmlBasicType:
if (node->doc().hasKeywords()) {
foreach (const Atom* keyword, node->doc().keywords()) {
if (!keyword->string().isEmpty()) {
QStringList details;
details << keyword->string()
<< keyword->string()
<< gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()) +
QLatin1Char('#') + Doc::canonicalTitle(keyword->string());
project.keywords.append(details);
}
else
node->doc().location().warning(tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())));
}
}
project.keywords.append(keywordDetails(node));
project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
case Node::Namespace:
project.keywords.append(keywordDetails(node));
@ -558,17 +575,14 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write
if (href.isEmpty())
return;
Node::SubType subType = static_cast<const DocNode*>(node)->subType();
bool derivedClass = false;
if (node->type() == Node::Class)
derivedClass = !(static_cast<const ClassNode *>(node)->baseClasses().isEmpty());
// Do not generate a 'List of all members' for namespaces or header files,
// but always generate it for derived classes and QML classes
if (node->type() != Node::Namespace && subType != Node::HeaderFile &&
(derivedClass || subType == Node::QmlClass ||
!project.memberStatus[node].isEmpty())) {
if (!node->isNamespace() && !node->isHeaderFile() &&
(derivedClass || node->isQmlType() || !project.memberStatus[node].isEmpty())) {
QString membersPath = href + QStringLiteral("-members.html");
project.files.insert(membersPath);
if (writeSections)
@ -612,6 +626,14 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
writeSection(writer, href, objName);
break;
case Node::QmlType:
writer.writeStartElement("section");
writer.writeAttribute("ref", href);
writer.writeAttribute("title", tr("%1 Type Reference").arg(node->fullTitle()));
addMembers(project, writer, node);
writer.writeEndElement(); // section
break;
case Node::Document: {
// Document nodes (such as manual pages) contain subtypes, titles and other
// attributes.
@ -619,12 +641,9 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
writer.writeStartElement("section");
writer.writeAttribute("ref", href);
if (docNode->subType() == Node::QmlClass)
writer.writeAttribute("title", tr("%1 Type Reference").arg(docNode->fullTitle()));
else
writer.writeAttribute("title", docNode->fullTitle());
writer.writeAttribute("title", docNode->fullTitle());
if ((docNode->subType() == Node::HeaderFile) || (docNode->subType() == Node::QmlClass))
if (docNode->subType() == Node::HeaderFile)
addMembers(project, writer, node);
writer.writeEndElement(); // section
@ -695,7 +714,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
writer.writeStartElement("section");
const Node* node = qdb_->findDocNodeByTitle(project.indexTitle);
if (node == 0)
node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document, Node::Page);
node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document);
QString indexPath;
// Never use a collision node as a landing page
if (node && !node->isCollisionNode())

View File

@ -268,7 +268,7 @@ QString HtmlGenerator::format()
*/
void HtmlGenerator::generateDocs()
{
Node* qflags = qdb_->findNodeByNameAndType(QStringList("QFlags"), Node::Class, Node::NoSubType);
Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
if (!runPrepareOnly()) {
@ -315,17 +315,22 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::AutoLink:
if (!inLink_ && !inContents_ && !inSectionHeading_) {
const Node *node = 0;
QString link = getLink(atom, relative, &node);
if (!link.isEmpty()) {
QString link = getAutoLink(atom, relative, &node);
if (link.isEmpty()) {
if (autolinkErrors())
relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
}
else if (node && node->status() == Node::Obsolete) {
if ((relative->parent() != node) && !relative->isObsolete())
link.clear();
}
if (link.isEmpty())
out() << protectEnc(atom->string());
else {
beginLink(link, node, relative);
generateLink(atom, marker);
endLink();
}
else {
out() << protectEnc(atom->string());
if (autolinkErrors())
relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
}
}
else {
out() << protectEnc(atom->string());
@ -334,11 +339,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::BaseName:
break;
case Atom::BriefLeft:
if (relative->type() == Node::Document) {
if (relative->subType() != Node::Example) {
skipAhead = skipAtoms(atom, Atom::BriefRight);
break;
}
if (relative->isQmlBasicType() || (relative->isDocNode() && !relative->isExample())) {
skipAhead = skipAtoms(atom, Atom::BriefRight);
break;
}
out() << "<p>";
@ -372,7 +375,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
break;
case Atom::BriefRight:
if (relative->type() != Node::Document)
if (!relative->isDocNode())
out() << "</p>\n";
break;
case Atom::C:
@ -602,10 +605,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
while (n != nsmap.constEnd()) {
const Node* node = n.value();
switch (node->type()) {
case Node::Document:
if (node->subType() == Node::QmlClass) {
sections[QmlClass].appendMember((Node*)node);
}
case Node::QmlType:
sections[QmlClass].appendMember((Node*)node);
break;
case Node::Namespace:
sections[Namespace].appendMember((Node*)node);
@ -761,8 +762,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
out() << " alt=\"\"";
out() << " />";
helpProjectWriter->addExtraFile(fileName);
if ((relative->type() == Node::Document) &&
(relative->subType() == Node::Example)) {
if (relative->isExample()) {
const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
if (cen->imageFileName().isEmpty()) {
ExampleNode* en = const_cast<ExampleNode*>(cen);
@ -805,17 +805,26 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
break;
case Atom::Link:
{
inObsoleteLink = false;
const Node *node = 0;
QString myLink = getLink(atom, relative, &node);
if (myLink.isEmpty()) {
myLink = getCollisionLink(atom);
if (myLink.isEmpty() && !noLinkErrors()) {
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
}
else
node = 0;
QString link = getLink(atom, relative, &node);
if (link.isEmpty() && !noLinkErrors()) {
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
}
beginLink(myLink, node, relative);
else {
node = 0;
if (node && node->status() == Node::Obsolete) {
if ((relative->parent() != node) && !relative->isObsolete()) {
inObsoleteLink = true;
if (obsoleteLinks) {
relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
.arg(atom->string())
.arg(relative->plainFullName()));
}
}
}
}
beginLink(link, node, relative);
skipAhead = 1;
}
break;
@ -1128,7 +1137,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
/*!
Generate a reference page for a C++ class.
Generate a reference page for a C++ class or a C++ namespace.
*/
void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
@ -1314,6 +1323,97 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
generateFooter(inner);
}
/*!
Generate the HTML page for a QML type. \qcn is the QML type.
\marker is the code markeup object.
*/
void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
{
SubTitleSize subTitleSize = LargeSubTitle;
QList<Section>::const_iterator s;
QString fullTitle = qcn->fullTitle();
QString htmlTitle = fullTitle;
generateHeader(htmlTitle, qcn, marker);
QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary);
generateTableOfContents(qcn, marker, &sections);
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
generateTitle(fullTitle, Text() << qcn->subTitle(), subTitleSize, qcn, marker);
generateBrief(qcn, marker);
generateQmlRequisites(qcn, marker);
QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker);
if (!allQmlMembersLink.isEmpty()) {
out() << "<ul>\n";
out() << "<li><a href=\"" << allQmlMembersLink << "\">"
<< "List of all members, including inherited members</a></li>\n";
out() << "</ul>\n";
}
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<a name=\"" << registerRef((*s).name.toLower())
<< "\"></a>" << divNavTop << '\n';
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateQmlSummary(*s, qcn, marker);
++s;
}
generateExtractionMark(qcn, DetailedDescriptionMark);
out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
out() << "<h2>" << "Detailed Description" << "</h2>\n";
generateBody(qcn, marker);
ClassNode* cn = qcn->classNode();
if (cn)
generateQmlText(cn->doc().body(), cn, marker, qcn->name());
generateAlsoList(qcn, marker);
generateExtractionMark(qcn, EndMark);
//out() << "<hr />\n";
sections = marker->qmlSections(qcn,CodeMarker::Detailed);
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.constBegin();
while (m != (*s).members.constEnd()) {
generateDetailedQmlMember(*m, qcn, marker);
out() << "<br/>\n";
++m;
}
++s;
}
generateFooter(qcn);
}
/*!
Generate the HTML page for the QML basic type represented
by the QML basic type node \a qbtn.
*/
void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
{
SubTitleSize subTitleSize = LargeSubTitle;
QList<Section>::const_iterator s;
QString htmlTitle = qbtn->fullTitle();
QString fullTitle = "QML Basic Type: " + htmlTitle;
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
generateHeader(htmlTitle, qbtn, marker);
generateTitle(fullTitle,
Text() << qbtn->subTitle(),
subTitleSize,
qbtn,
marker);
generateExtractionMark(qbtn, DetailedDescriptionMark);
out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
generateBody(qbtn, marker);
out() << "</div>\n"; // QTBUG-9504
generateAlsoList(qbtn, marker);
generateExtractionMark(qbtn, EndMark);
generateFooter(qbtn);
}
/*!
We delayed generation of the disambiguation pages until now, after
all the other pages have been generated. We do this because we might
@ -1447,31 +1547,14 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
QList<Section>::const_iterator s;
QString fullTitle = dn->fullTitle();
if (dn->subType() == Node::QmlBasicType) {
fullTitle = "QML Basic Type: " + fullTitle;
// Replace the marker with a QML code marker.
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
}
else if (dn->subType() == Node::QmlClass) {
fullTitle = fullTitle + " QML Type";
}
generateHeader(fullTitle, dn, marker);
/*
Generate the TOC for the new doc format.
Don't generate a TOC for the home page.
*/
QmlClassNode* qml_cn = 0;
if (dn->subType() == Node::QmlClass) {
qml_cn = static_cast<QmlClassNode*>(dn);
sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
generateTableOfContents(dn,marker,&sections);
// Replace the marker with a QML code marker.
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
}
else if (dn->subType() != Node::Collision && dn->name() != QString("index.html") && dn->name() != QString("qtexamplesandtutorials.html"))
if ((dn->subType() != Node::Collision) &&
(dn->name() != QString("index.html")) &&
(dn->name() != QString("qtexamplesandtutorials.html")))
generateTableOfContents(dn,marker,0);
generateTitle(fullTitle,
@ -1510,53 +1593,6 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
out() << "</ul>\n";
}
else if (dn->subType() == Node::QmlClass) {
ClassNode* cn = qml_cn->classNode();
generateBrief(qml_cn, marker);
generateQmlRequisites(qml_cn, marker);
QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker);
if (!allQmlMembersLink.isEmpty()) {
out() << "<ul>\n";
out() << "<li><a href=\"" << allQmlMembersLink << "\">"
<< "List of all members, including inherited members</a></li>\n";
out() << "</ul>\n";
}
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<a name=\"" << registerRef((*s).name.toLower())
<< "\"></a>" << divNavTop << '\n';
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
generateQmlSummary(*s,dn,marker);
++s;
}
generateExtractionMark(dn, DetailedDescriptionMark);
out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
out() << "<h2>" << "Detailed Description" << "</h2>\n";
generateBody(dn, marker);
if (cn)
generateQmlText(cn->doc().body(), cn, marker, dn->name());
generateAlsoList(dn, marker);
generateExtractionMark(dn, EndMark);
//out() << "<hr />\n";
sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
NodeList::ConstIterator m = (*s).members.constBegin();
while (m != (*s).members.constEnd()) {
generateDetailedQmlMember(*m, dn, marker);
out() << "<br/>\n";
++m;
}
++s;
}
generateFooter(dn);
return;
}
sections = marker->sections(dn, CodeMarker::Summary, CodeMarker::Okay);
s = sections.constBegin();
@ -1707,7 +1743,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::AutoLink, landingpage)
<< Atom(Atom::ListItemRight);
if (node->type() == Node::Class) {
if (node->isClass()) {
const ClassNode *cn = static_cast<const ClassNode *>(node);
QString name = node->moduleName();
@ -1724,18 +1760,27 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::String, cn->name())
<< Atom(Atom::ListItemRight);
}
else if (node->type() == Node::Document) {
else if (node->isQmlType()) {
if (!qmltypespage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
<< Atom(Atom::Link, qmltypespage)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, QLatin1String("QML Types"))
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(Atom::ListItemRight);
}
else if (node->isQmlBasicType()) {
if (!qmltypespage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
<< Atom(Atom::Link, qmltypespage)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, QLatin1String("QML Types"))
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(Atom::ListItemRight);
}
else if (node->isDocNode()) {
const DocNode *dn = static_cast<const DocNode *>(node);
if (node->subType() == Node::QmlClass || node->subType() == Node::QmlBasicType) {
if (!qmltypespage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
<< Atom(Atom::Link, qmltypespage)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, QLatin1String("QML Types"))
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
<< Atom(Atom::ListItemRight);
}
else if (dn && dn->isExampleFile()) {
if (dn && dn->isExampleFile()) {
navigationbar << Atom(Atom::ListItemLeft)
<< Atom(Atom::Link, dn->parent()->name())
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
@ -2732,7 +2777,7 @@ void HtmlGenerator::generateCompactList(ListType listType,
}
QStringList pieces;
if (it.value()->subType() == Node::QmlClass)
if (it.value()->isQmlType())
pieces << it.value()->name();
else
pieces = it.value()->fullName(relative).split("::");
@ -3214,8 +3259,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
par1 = QStringRef();
const Node* n = qdb_->resolveType(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass)
if (n && n->isQmlBasicType()) {
if (relative && relative->isQmlType())
addLink(linkForNode(n,relative), arg, &html);
else
html += arg.toString();
@ -3576,7 +3621,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
QString fn = fileName(node);
if (node && relative && node->parent() != relative) {
if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
if (node->parent()->isQmlType() && relative->isQmlType()) {
if (node->parent()->isAbstract()) {
/*
This is a bit of a hack. What we discover with
@ -3719,6 +3764,7 @@ int HtmlGenerator::hOffset(const Node *node)
case Node::Namespace:
case Node::Class:
return 2;
case Node::QmlType:
case Node::Document:
return 1;
case Node::Enum:
@ -3754,32 +3800,48 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
return anchorPair;
}
/*!
This function is called for links, i.e. for words that
are marked with the qdoc link command. For autolinks
that are not marked with the qdoc link command, qdoc
calls getAutoLink().
Return the link represented by the \a atom, and set \a node
to point to the target node for that link. \a relative points
to the node holding the qdoc comment where the link command
was found.
*/
QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
{
QString link;
*node = 0;
inObsoleteLink = false;
if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
atom->string().startsWith("http:") ||
atom->string().startsWith("https:") ||
atom->string().startsWith("ftp:") ||
atom->string().startsWith("mailto:"))) {
link = atom->string(); // It's some kind of protocol.
return atom->string(); // It's some kind of protocol.
}
else {
QStringList path;
if (atom->string().contains('#'))
path = atom->string().split('#'); // The target is in the html file.
else
path.append(atom->string()); // It's a general case target.
QString ref;
QString first = path.first().trimmed();
if (first.isEmpty())
*node = relative;
else if (first.endsWith(".html")) // The target is an html file.
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
QString ref;
QString link;
QString first;
QStringList path;
*node = 0;
if (atom->string().contains('#')) {
path = atom->string().split('#');
first = path.first().trimmed();
path.removeFirst();
}
else
first = atom->string();
if (first.isEmpty())
*node = relative; // search for a target on the current page.
else {
if (first.endsWith(".html")) { // The target is an html file.
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
//Node* n = qdb_->findHtmlFileNode(atom);
}
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
}
@ -3795,71 +3857,77 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
}
}
}
if (*node) {
if (!(*node)->url().isEmpty())
return (*node)->url();
else
path.removeFirst();
}
else
*node = relative;
}
if (!(*node))
return link; // empty
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::Document) {
const DocNode* dn = static_cast<const DocNode*>(relative);
if (dn->title().startsWith("Porting"))
porting = true;
}
QString name = relative->plainFullName();
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 (!(*node)->url().isEmpty())
return (*node)->url();
if (!path.isEmpty()) {
ref = qdb_->findTarget(path.first(), *node);
if (ref.isEmpty())
return link; // empty
}
/*
Given that *node is not null, we now cconstruct a link
to the page that *node represents, and then if we found
a target on that page, we connect the target to the link
with '#'.
*/
link = linkForNode(*node, relative);
if (*node && (*node)->subType() == Node::Image)
link = "images/used-in-examples/" + link;
if (!ref.isEmpty())
link += QLatin1Char('#') + ref;
return link;
}
/*!
This function is called for autolinks, i.e. for words that
are not marked with the qdoc link command that qdoc has
reason to believe should be links. For links marked with
the qdoc link command, qdoc calls getLink().
Return the link represented by the \a atom, and set \a node
to point to the target node for that link. \a relative points
to the node holding the qdoc comment where the link command
was found.
*/
QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
{
QString ref;
QString link;
QString path = atom->string().trimmed();
*node = 0;
if (path.endsWith("()")) { // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(path, relative);
}
else {
*node = qdb_->resolveTarget(path, relative);
if (!(*node)) {
*node = qdb_->findDocNodeByTitle(path);
}
if (!(*node)) {
*node = qdb_->findUnambiguousTarget(path, ref);
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
QString final = (*node)->url() + "#" + ref;
return final;
}
}
/*
This loop really only makes sense if *node is not 0.
In that case, The node *node points to represents a
qdoc page, so the link will ultimately point to some
target on that page. This loop finds that target on
the page that *node represents. ref is that target.
*/
while (!path.isEmpty()) {
ref = qdb_->findTarget(path.first(), *node);
if (ref.isEmpty())
break;
path.removeFirst();
}
/*
Given that *node is not null, we now cconstruct a link
to the page that *node represents, and then if there is
a target on that page, we connect the target to the link
with '#'.
*/
if (path.isEmpty()) {
link = linkForNode(*node, relative);
if (*node && (*node)->subType() == Node::Image)
link = "images/used-in-examples/" + link;
if (!ref.isEmpty())
link += QLatin1Char('#') + ref;
}
}
if (!(*node))
return link; // empty
if (!(*node)->url().isEmpty())
return (*node)->url();
link = linkForNode(*node, relative);
if (!ref.isEmpty())
link += QLatin1Char('#') + ref;
return link;
}
@ -3884,19 +3952,7 @@ void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
<< "We strongly advise against "
<< "using it in new code. See ";
const DocNode *docNode = qdb_->findDocNodeByTitle("Porting To Qt 4");
QString ref;
if (docNode && node->type() == Node::Class) {
QString oldName(node->name());
oldName.remove(QLatin1Char('3'));
ref = qdb_->findTarget(oldName, docNode);
}
if (!ref.isEmpty()) {
text << Atom(Atom::Link, linkForNode(docNode, node) + QLatin1Char('#') + ref);
}
else
text << Atom(Atom::Link, "Porting to Qt 4");
text << Atom(Atom::Link, "Porting to Qt 4");
text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, "Porting to Qt 4")
@ -4525,6 +4581,10 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::Class:
break;
case Node::QmlType:
break;
case Node::QmlBasicType:
break;
case Node::Group:
break;
case Node::Module:
@ -4545,10 +4605,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::ExternalPage:
break;
case Node::QmlClass:
break;
case Node::QmlBasicType:
break;
case Node::Collision:
break;
default:

View File

@ -102,6 +102,8 @@ protected:
const Node *relative,
CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker);
virtual void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker);
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual QString fileExtension() const;
@ -215,6 +217,7 @@ private:
static int hOffset(const Node *node);
static bool isThreeColumnEnumValueTable(const Atom *atom);
QString getLink(const Atom *atom, const Node *relative, const Node** node);
QString getAutoLink(const Atom *atom, const Node *relative, const Node** node);
#ifdef GENERATE_MAC_REFS
void generateMacRef(const Node *node, CodeMarker *marker);
#endif

View File

@ -298,7 +298,8 @@ static void processQdocconfFile(const QString &fileName)
currentDir = QFileInfo(fileName).path();
Location::initialize(config);
config.load(fileName);
//qDebug() << "\nSTART PROJECT:" << config.getString(CONFIG_PROJECT).toLower();
QString project = config.getString(CONFIG_PROJECT).toLower();
//qDebug() << "\nSTART PROJECT:" << project;
/*
Add the defines to the configuration variables.
*/
@ -372,9 +373,11 @@ static void processQdocconfFile(const QString &fileName)
Location outputFormatsLocation = config.lastLocation();
//if (!Generator::runPrepareOnly())
Generator::debug(" loading index files");
loadIndexFiles(config);
qdb->newPrimaryTree(config.getString(CONFIG_PROJECT));
qdb->setSearchOrder();
Generator::debug(" done loading index files");
QSet<QString> excludedDirs;
QSet<QString> excludedFiles;
@ -458,7 +461,6 @@ static void processQdocconfFile(const QString &fileName)
to the big tree.
*/
QSet<CodeParser *> usedParsers;
//Config::debug_ = true;
Generator::debug("Parsing header files");
int parsed = 0;
@ -528,6 +530,8 @@ static void processQdocconfFile(const QString &fileName)
//Generator::writeOutFileNames();
Generator::debug("Shutting down qdoc");
if (Generator::debugging())
Generator::stopDebugging(project);
QDocDatabase::qdocDB()->setVersion(QString());
Generator::terminate();

View File

@ -51,6 +51,38 @@ QT_BEGIN_NAMESPACE
int Node::propertyGroupCount_ = 0;
QStringMap Node::operators_;
QMap<QString,Node::Type> Node::goals_;
/*!
Initialize the map of search goals. This is called once
by QDocDatabase::initializeDB(). The map key is a string
representing a value in the enum Node::Type. The map value
is the enum value.
There should be an entry in the map for each value in the
Type enum.
*/
void Node::initialize()
{
goals_.insert("class", Node::Class);
goals_.insert("qmltype", Node::QmlType);
goals_.insert("page", Node::Document);
goals_.insert("function", Node::Function);
goals_.insert("property", Node::Property);
goals_.insert("variable", Node::Variable);
goals_.insert("group", Node::Group);
goals_.insert("module", Node::Module);
goals_.insert("qmlmodule", Node::QmlModule);
goals_.insert("qmppropertygroup", Node::QmlPropertyGroup);
goals_.insert("qmlproperty", Node::QmlProperty);
goals_.insert("qmlsignal", Node::QmlSignal);
goals_.insert("qmlsignalhandler", Node::QmlSignalHandler);
goals_.insert("qmlmethod", Node::QmlMethod);
goals_.insert("qmlbasictype", Node::QmlBasicType);
goals_.insert("enum", Node::Enum);
goals_.insert("typedef", Node::Typedef);
goals_.insert("namespace", Node::Namespace);
}
/*!
Increment the number of property groups seen in the current
@ -328,6 +360,10 @@ QString Node::nodeTypeString(unsigned t)
return "group";
case Module:
return "module";
case QmlType:
return "QML type";
case QmlBasicType:
return "QML basic type";
case QmlModule:
return "QML module";
case QmlProperty:
@ -376,10 +412,6 @@ QString Node::nodeSubtypeString(unsigned t)
return "page";
case ExternalPage:
return "external page";
case QmlClass:
return "QML type";
case QmlBasicType:
return "QML basic type";
case DitaMap:
return "ditamap";
case Collision:
@ -616,9 +648,9 @@ QmlClassNode* Node::qmlClassNode()
{
if (isQmlNode()) {
Node* n = this;
while (n && n->subType() != Node::QmlClass)
while (n && !n->isQmlType())
n = n->parent();
if (n && n->subType() == Node::QmlClass)
if (n && n->isQmlType())
return static_cast<QmlClassNode*>(n);
}
return 0;
@ -654,6 +686,14 @@ bool Node::isInternal() const
return false;
}
/*!
Returns a pointer to the root of the Tree this node is in.
*/
const Node* Node::root() const
{
return (parent() ? parent()->root() : this);
}
/*!
\class InnerNode
*/
@ -1072,6 +1112,7 @@ InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
{
switch (type) {
case Class:
case QmlType:
case Namespace:
setPageType(ApiPage);
break;
@ -1313,6 +1354,7 @@ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
case QmlSignal:
case QmlSignalHandler:
case QmlMethod:
case QmlBasicType:
setPageType(ApiPage);
break;
default:
@ -1356,7 +1398,7 @@ LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
Constructs a namespace node.
*/
NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
: InnerNode(Namespace, parent, name)
: InnerNode(Namespace, parent, name), tree_(0)
{
setPageType(ApiPage);
}
@ -1562,10 +1604,6 @@ DocNode::DocNode(InnerNode* parent, const QString& name, SubType subtype, Node::
case DitaMap:
setPageType(ptype);
break;
case QmlClass:
case QmlBasicType:
setPageType(ApiPage);
break;
case Example:
setPageType(ExamplePage);
break;
@ -2051,12 +2089,11 @@ bool QmlClassNode::qmlOnly = false;
QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
/*!
Constructs a Qml class node (i.e. a Document node with the
subtype QmlClass. The new node has the given \a parent
and \a name.
Constructs a Qml class node. The new node has the given
\a parent and \a name.
*/
QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
: DocNode(parent, name, QmlClass, Node::ApiPage),
: InnerNode(QmlType, parent, name),
abstract_(false),
cnodeRequired_(false),
wrapper_(false),
@ -2070,6 +2107,7 @@ QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
i = 4;
}
setTitle(name.mid(i));
setPageType(Node::ApiPage);
}
/*!
@ -2187,13 +2225,12 @@ QString QmlClassNode::qmlModuleIdentifier() const
}
/*!
Constructs a Qml basic type node (i.e. a Document node with
the subtype QmlBasicType. The new node has the given
Constructs a Qml basic type node. The new node has the given
\a parent and \a name.
*/
QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
const QString& name)
: DocNode(parent, name, QmlBasicType, Node::ApiPage)
: InnerNode(QmlBasicType, parent, name)
{
setTitle(name);
}
@ -2293,7 +2330,7 @@ PropertyNode* QmlPropertyNode::findCorrespondingCppProperty()
{
PropertyNode* pn;
Node* n = parent();
while (n && n->subType() != Node::QmlClass)
while (n && !n->isQmlType())
n = n->parent();
if (n) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(n);
@ -2489,12 +2526,14 @@ QString Node::fullDocumentName() const
if (!n->name().isEmpty() && !n->isQmlPropertyGroup())
pieces.insert(0, n->name());
if (n->type() == Node::Document) {
if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty())
pieces.insert(0, n->qmlModuleName());
if (n->isQmlType() && !n->qmlModuleName().isEmpty()) {
pieces.insert(0, n->qmlModuleName());
break;
}
if (n->isDocNode())
break;
// Examine the parent node if one exists.
if (n->parent())
n = n->parent();
@ -2504,7 +2543,7 @@ QString Node::fullDocumentName() const
// Create a name based on the type of the ancestor node.
QString concatenator = "::";
if ((n->type() == Node::Document) && (n->subType() != Node::QmlClass))
if (n->isDocNode())
concatenator = QLatin1Char('#');
return pieces.join(concatenator);
@ -2679,16 +2718,15 @@ QString Node::idForNode() const
}
}
else if (parent_) {
if (parent_->type() == Class)
if (parent_->isClass())
str = "class-member-" + func->name();
else if (parent_->type() == Namespace)
else if (parent_->isNamespace())
str = "namespace-member-" + func->name();
else if (parent_->isQmlType())
str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
else if (parent_->type() == Document) {
if (parent_->subType() == QmlClass)
str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
else
qDebug() << "qdoc internal error: Node subtype not handled:"
<< parent_->subType() << func->name();
qDebug() << "qdoc internal error: Node subtype not handled:"
<< parent_->subType() << func->name();
}
else
qDebug() << "qdoc internal error: Node type not handled:"
@ -2699,12 +2737,15 @@ QString Node::idForNode() const
str += QLatin1Char('-') + QString::number(func->overloadNumber());
}
break;
case Node::QmlType:
str = "qml-class-" + name();
break;
case Node::QmlBasicType:
str = "qml-basic-type-" + name();
break;
case Node::Document:
{
switch (subType()) {
case Node::QmlClass:
str = "qml-class-" + name();
break;
case Node::Page:
case Node::HeaderFile:
str = title();
@ -2723,9 +2764,6 @@ QString Node::idForNode() const
str = name();
str.replace(QLatin1Char('/'), QLatin1Char('-'));
break;
case Node::QmlBasicType:
str = "qml-basic-type-" + name();
break;
case Node::Collision:
str = title();
str.replace(": ","-");

View File

@ -49,12 +49,11 @@
#include "codechunk.h"
#include "doc.h"
#include "location.h"
#include "text.h"
QT_BEGIN_NAMESPACE
class Node;
class Tree;
class EnumNode;
class ClassNode;
class InnerNode;
@ -83,6 +82,7 @@ class Node
public:
enum Type {
NoType,
Namespace,
Class,
Document,
@ -93,12 +93,14 @@ public:
Variable,
Group,
Module,
QmlType,
QmlModule,
QmlPropertyGroup,
QmlProperty,
QmlSignal,
QmlSignalHandler,
QmlMethod,
QmlBasicType,
LastType
};
@ -110,8 +112,6 @@ public:
Image,
Page,
ExternalPage,
QmlClass,
QmlBasicType,
DitaMap,
Collision,
LastSubtype
@ -248,11 +248,13 @@ public:
virtual bool wasSeen() const { return false; }
virtual void appendGroupName(const QString& ) { }
virtual QString element() const { return QString(); }
virtual Tree* tree() const { return 0; }
bool isIndexNode() const { return indexNodeFlag_; }
Type type() const { return nodeType_; }
virtual SubType subType() const { return NoSubType; }
bool match(const NodeTypeList& types) const;
InnerNode* parent() const { return parent_; }
const Node* root() const;
InnerNode* relates() const { return relatesTo_; }
const QString& name() const { return name_; }
QString moduleName() const;
@ -318,6 +320,8 @@ public:
static QString nodeSubtypeString(unsigned t);
static int incPropertyGroupCount();
static void clearPropertyGroupCount();
static void initialize();
static Type goal(const QString& t) { return goals_.value(t); }
protected:
Node(Type type, InnerNode* parent, const QString& name);
@ -347,6 +351,7 @@ private:
QString outSubDir_;
static QStringMap operators_;
static int propertyGroupCount_;
static QMap<QString,Node::Type> goals_;
};
class InnerNode : public Node
@ -435,6 +440,11 @@ public:
NamespaceNode(InnerNode* parent, const QString& name);
virtual ~NamespaceNode() { }
virtual bool isNamespace() const { return true; }
virtual Tree* tree() const { return tree_; }
void setTree(Tree* t) { tree_ = t; }
private:
Tree* tree_;
};
struct RelatedClass
@ -583,7 +593,7 @@ struct ImportRec {
typedef QList<ImportRec> ImportList;
class QmlClassNode : public DocNode
class QmlClassNode : public InnerNode
{
public:
QmlClassNode(InnerNode* parent, const QString& name);
@ -635,7 +645,7 @@ private:
ImportList importList_;
};
class QmlBasicTypeNode : public DocNode
class QmlBasicTypeNode : public InnerNode
{
public:
QmlBasicTypeNode(InnerNode* parent,
@ -719,17 +729,13 @@ public:
EnumItem() { }
EnumItem(const QString& name, const QString& value)
: nam(name), val(value) { }
EnumItem(const QString& name, const QString& value, const Text &txt)
: nam(name), val(value), txt(txt) { }
const QString& name() const { return nam; }
const QString& value() const { return val; }
const Text &text() const { return txt; }
private:
QString nam;
QString val;
Text txt;
};
class EnumNode : public LeafNode

View File

@ -286,6 +286,16 @@ void QDocForest::setSearchOrder()
}
forest_.clear();
}
/*
Rebuild the forest after constructing the search order.
It was destroyed during construction of the search order,
but it is needed for module-specific searches.
*/
for (int i=0; i<searchOrder_.size(); ++i) {
forest_.insert(moduleNames_.at(i).toLower(), searchOrder_.at(i));
}
#if 0
qDebug() << " SEARCH ORDER:";
for (int i=0; i<moduleNames_.size(); ++i)
@ -498,9 +508,12 @@ void QDocDatabase::destroyQdocDB()
include \c array and \c data, which are just generic names
used as place holders in function signatures that appear in
the documentation.
Also calls Node::initialize() to initialize the search goal map.
*/
void QDocDatabase::initializeDB()
{
Node::initialize();
typeNodeMap_.insert( "accepted", 0);
typeNodeMap_.insert( "actionPerformed", 0);
typeNodeMap_.insert( "activated", 0);
@ -776,14 +789,14 @@ QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name
}
QStringList path(name);
Node* n = forest_.findNodeByNameAndType(path, Node::Document, Node::QmlClass, true);
Node* n = forest_.findNodeByNameAndType(path, Node::QmlType);
if (n) {
if (n->subType() == Node::QmlClass)
if (n->isQmlType())
return static_cast<QmlClassNode*>(n);
else if (n->subType() == Node::Collision) {
else if (n->isCollisionNode()) {
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
return static_cast<QmlClassNode*>(ncn->findAny(Node::Document,Node::QmlClass));
return static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
}
}
return 0;
@ -992,9 +1005,7 @@ void QDocDatabase::findAllClasses(InnerNode* node)
serviceClasses_.insert(serviceName, *c);
}
}
else if ((*c)->type() == Node::Document &&
(*c)->subType() == Node::QmlClass &&
!(*c)->doc().isEmpty()) {
else if ((*c)->isQmlType() && !(*c)->doc().isEmpty()) {
QString qmlTypeName = (*c)->name();
if (qmlTypeName.startsWith(QLatin1String("QML:")))
qmlClasses_.insert(qmlTypeName.mid(4),*c);
@ -1103,7 +1114,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
name = (*c)->parent()->name() + "::" + name;
obsoleteClasses_.insert(name, *c);
}
else if ((*c)->type() == Node::Document && (*c)->subType() == Node::QmlClass) {
else if ((*c)->isQmlType()) {
if (name.startsWith(QLatin1String("QML:")))
name = name.mid(4);
name = (*c)->qmlModuleName() + "::" + name;
@ -1139,7 +1150,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
++p;
}
}
else if ((*c)->type() == Node::Document && (*c)->subType() == Node::QmlClass) {
else if ((*c)->isQmlType()) {
InnerNode* n = static_cast<InnerNode*>(*c);
bool inserted = false;
NodeList::const_iterator p = n->childNodes().constBegin();
@ -1154,7 +1165,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
Node* parent = (*c)->parent();
if (parent->type() == Node::QmlPropertyGroup && parent->parent())
parent = parent->parent();
if (parent && parent->subType() == Node::QmlClass && !parent->name().isEmpty())
if (parent && parent->isQmlType() && !parent->name().isEmpty())
name = parent->name() + "::" + name;
}
qmlTypesWithObsoleteMembers_.insert(name,*c);
@ -1223,7 +1234,7 @@ void QDocDatabase::findAllSince(InnerNode* node)
nsmap.value().insert(className,(*child));
ncmap.value().insert(className,(*child));
}
else if ((*child)->subType() == Node::QmlClass) {
else if ((*child)->isQmlType()) {
// Insert QML elements into the since and element maps.
QString className = (*child)->name();
if ((*child)->parent() && !(*child)->parent()->name().isEmpty()) {
@ -1344,7 +1355,7 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
if (target.isEmpty())
node = relative;
else if (target.endsWith(".html")) {
node = findNodeByNameAndType(QStringList(target), Node::Document, Node::NoSubType);
node = findNodeByNameAndType(QStringList(target), Node::Document);
}
else {
node = resolveTarget(target, relative);
@ -1366,7 +1377,7 @@ void QDocDatabase::resolveQmlInheritance(InnerNode* root)
NodeMap previousSearches;
// Do we need recursion?
foreach (Node* child, root->childNodes()) {
if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
if (child->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
if (qcn->qmlBaseNodeNotSet() && !qcn->qmlBaseName().isEmpty()) {
QmlClassNode* bqcn = static_cast<QmlClassNode*>(previousSearches.value(qcn->qmlBaseName()));
@ -1463,18 +1474,16 @@ FunctionNode* QDocDatabase::findNodeInOpenNamespace(const QStringList& parentPat
}
/*!
Find a node of the specified \a type and \a subtype that is
reached with the specified \a path qualified with the name
of one of the open namespaces (might not be any open ones).
If the node is found in an open namespace, prefix \a path
with the name of the open namespace and "::" and return a
pointer to the node. Othewrwise return 0.
Find a node of the specified \a type that is reached with
the specified \a path qualified with the name of one of the
open namespaces (might not be any open ones). If the node
is found in an open namespace, prefix \a path with the name
of the open namespace and "::" and return a pointer to the
node. Othewrwise return 0.
This function only searches in the current primary tree.
*/
Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
Node::Type type,
Node::SubType subtype)
Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path, Node::Type type)
{
if (path.isEmpty())
return 0;
@ -1486,7 +1495,7 @@ Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
p = t.split("::") + path;
else
p = path;
n = primaryTree()->findNodeByNameAndType(p, type, subtype);
n = primaryTree()->findNodeByNameAndType(p, type);
if (n) {
path = p;
break;

View File

@ -46,6 +46,7 @@
#include <qmap.h>
#include "tree.h"
#include "config.h"
#include "text.h"
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@ -79,6 +80,7 @@ class QDocForest
Tree* firstTree();
Tree* nextTree();
Tree* primaryTree() { return primaryTree_; }
Tree* findTree(const QString& t) { return forest_.value(t); }
NamespaceNode* primaryTreeRoot() { return (primaryTree_ ? primaryTree_->root() : 0); }
bool isEmpty() { return searchOrder().isEmpty(); }
bool done() { return (currentIndex_ >= searchOrder().size()); }
@ -93,20 +95,15 @@ class QDocForest
return n;
relative = 0;
}
//qDebug() << "FAILED SEARCH 1" << path;
return 0;
}
Node* findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false) {
Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
foreach (Tree* t, searchOrder()) {
Node* n = t->findNodeByNameAndType(path, type, subtype, acceptCollision);
Node* n = t->findNodeByNameAndType(path, type);
if (n)
return n;
}
//qDebug() << "FAILED SEARCH 2" << path << type << subtype;
return 0;
}
@ -116,7 +113,6 @@ class QDocForest
if (n)
return n;
}
//qDebug() << "FAILED SEARCH 3" << path;
return 0;
}
@ -126,7 +122,6 @@ class QDocForest
if (n)
return n;
}
//qDebug() << "FAILED SEARCH 4" << path;
return 0;
}
@ -149,21 +144,9 @@ class QDocForest
return n;
relative = 0;
}
//qDebug() << "FAILED SEARCH 5" << path;
return 0;
}
QString findTarget(const QString& target, const Node* node)
{
foreach (Tree* t, searchOrder()) {
QString ref = t->findTarget(target, node);
if (!ref.isEmpty())
return ref;
}
//qDebug() << "FAILED SEARCH 7" << target;
return QString();
}
const Node* findUnambiguousTarget(const QString& target, QString& ref)
{
foreach (Tree* t, searchOrder()) {
@ -171,7 +154,6 @@ class QDocForest
if (n)
return n;
}
//qDebug() << "FAILED SEARCH 8" << target;
return 0;
}
@ -182,7 +164,6 @@ class QDocForest
if (n)
return n;
}
//qDebug() << "FAILED SEARCH 9" << title;
return 0;
}
@ -229,6 +210,7 @@ class QDocDatabase
static void destroyQdocDB();
~QDocDatabase();
Tree* findTree(const QString& t) { return forest_.findTree(t); }
const CNMap& groups() { return primaryTree()->groups(); }
const CNMap& modules() { return primaryTree()->modules(); }
const CNMap& qmlModules() { return primaryTree()->qmlModules(); }
@ -307,7 +289,7 @@ class QDocDatabase
return primaryTree()->findFunctionNode(parentPath, clone);
}
FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype);
Node* findNodeInOpenNamespace(QStringList& path, Node::Type type);
NameCollisionNode* findCollisionNode(const QString& name) {
return primaryTree()->findCollisionNode(name);
}
@ -321,9 +303,6 @@ class QDocDatabase
********************************************************************/
ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
QString findTarget(const QString& target, const Node* node) {
return forest_.findTarget(target, node);
}
const Node* resolveTarget(const QString& target, const Node* relative) {
return forest_.resolveTarget(target, relative);
}
@ -338,11 +317,14 @@ class QDocDatabase
const Node* findUnambiguousTarget(const QString& target, QString& ref) {
return forest_.findUnambiguousTarget(target, ref);
}
Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
return forest_.findNodeByNameAndType(path, type, subtype, false);
Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
return forest_.findNodeByNameAndType(path, type);
}
/*******************************************************************/
QString findTarget(const QString& target, const Node* node) {
return node->root()->tree()->findTarget(target, node);
}
void addPropertyFunction(PropertyNode* property,
const QString& funcName,
PropertyNode::FunctionRole funcRole) {

View File

@ -206,8 +206,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
abstract = true;
node->setAbstract(abstract);
}
else if ((element.nodeName() == "qmlclass") ||
((element.nodeName() == "page") && (element.attribute("subtype") == "qmlclass"))) {
else if (element.nodeName() == "qmlclass") {
QmlClassNode* qcn = new QmlClassNode(parent, name);
qcn->setTitle(element.attribute("title"));
QString qmlModuleName = element.attribute("qml-module-name");
@ -260,11 +259,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
if (element.attribute("writable") == "false")
readonly = true;
QmlPropertyNode* qpn = 0;
if (parent->type() == Node::Document) {
if (parent->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(parent);
qpn = new QmlPropertyNode(qcn, name, type, attached);
}
else if (parent->type() == Node::QmlPropertyGroup) {
else if (parent->isQmlPropertyGroup()) {
QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(parent);
qpn = new QmlPropertyNode(qpgn, name, type, attached);
}
@ -332,14 +331,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
subtype = Node::ExternalPage;
ptype = Node::ArticlePage;
}
else if (attr == "qmlclass") {
subtype = Node::QmlClass;
ptype = Node::ApiPage;
}
else if (attr == "qmlbasictype") {
subtype = Node::QmlBasicType;
ptype = Node::ApiPage;
}
else
return;
@ -614,7 +605,7 @@ void QDocIndexFiles::resolveIndex()
foreach (pair, basesList_) {
foreach (const QString& base, pair.second.split(QLatin1Char(','))) {
QStringList basePath = base.split(QString("::"));
Node* n = qdb_->findNodeByNameAndType(basePath, Node::Class, Node::NoSubType);
Node* n = qdb_->findClassNode(basePath);
if (n)
pair.first->addResolvedBaseClass(Node::Public, static_cast<ClassNode*>(n));
else
@ -661,17 +652,20 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::Class:
nodeName = "class";
break;
case Node::Document:
nodeName = "page";
if (node->subType() == Node::QmlClass) {
case Node::QmlType:
{
nodeName = "qmlclass";
QmlModuleNode* qmn = node->qmlModule();
if (qmn)
qmlModuleName = qmn->qmlModuleName();
qmlFullBaseName = node->qmlFullBaseName();
}
else if (node->subType() == Node::QmlBasicType)
nodeName = "qmlbasictype";
break;
case Node::QmlBasicType:
nodeName = "qmlbasictype";
break;
case Node::Document:
nodeName = "page";
break;
case Node::Group:
nodeName = "group";
@ -755,10 +749,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QXmlStreamAttributes attributes;
if ((node->type() != Node::Document) &&
(node->type() != Node::Group) &&
(node->type() != Node::Module) &&
(node->type() != Node::QmlModule)) {
if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
QString threadSafety;
switch (node->threadSafeness()) {
case Node::NonReentrant:
@ -843,10 +834,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("href", href);
writer.writeAttribute("status", status);
if ((node->type() != Node::Document) &&
(node->type() != Node::Group) &&
(node->type() != Node::Module) &&
(node->type() != Node::QmlModule)) {
if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
writer.writeAttribute("access", access);
if (node->isAbstract())
writer.writeAttribute("abstract", "true");
@ -896,6 +884,18 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("brief", brief);
}
break;
case Node::QmlType:
{
const QmlClassNode* qcn = static_cast<const QmlClassNode*>(node);
writer.writeAttribute("title", qcn->title());
writer.writeAttribute("fulltitle", qcn->fullTitle());
writer.writeAttribute("subtitle", qcn->subTitle());
if (!qcn->groupNames().isEmpty())
writer.writeAttribute("groups", qcn->groupNames().join(","));
if (!brief.isEmpty())
writer.writeAttribute("brief", brief);
}
break;
case Node::Document:
{
/*
@ -923,12 +923,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::ExternalPage:
writer.writeAttribute("subtype", "externalpage");
break;
case Node::QmlClass:
//writer.writeAttribute("subtype", "qmlclass");
break;
case Node::QmlBasicType:
//writer.writeAttribute("subtype", "qmlbasictype");
break;
default:
break;
}
@ -1289,7 +1283,7 @@ bool compareNodes(const Node* n1, const Node* n2)
return false;
}
if (n1->type() == Node::Document && n2->type() == Node::Document) {
if (n1->isDocNode() && n2->isDocNode()) {
const DocNode* f1 = static_cast<const DocNode*>(n1);
const DocNode* f2 = static_cast<const DocNode*>(n2);
if (f1->fullTitle() < f2->fullTitle())

View File

@ -365,7 +365,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
QString command = *i;
ArgList args = doc.metaCommandArgs(command);
if (command == COMMAND_QMLABSTRACT) {
if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
if (node->isQmlType()) {
node->setAbstract(true);
}
}
@ -378,7 +378,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == args[0].first)
doc.location().warning(tr("%1 tries to inherit itself").arg(args[0].first));
else if (node->subType() == Node::QmlClass) {
else if (node->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(args[0].first);
QmlClassNode::addInheritedBy(args[0].first,node);
@ -541,7 +541,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
switch (member->type) {
case QQmlJS::AST::UiPublicMember::Signal:
{
if (current->type() == Node::Document) {
if (current->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
if (qmlClass) {
@ -564,7 +564,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
{
QString type = member->memberType.toString();
QString name = member->name.toString();
if (current->type() == Node::Document) {
if (current->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
if (qmlClass) {
QString name = member->name.toString();
@ -608,7 +608,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
if (nestingLevel > 1) {
return true;
}
if (current->type() == Node::Document) {
if (current->isQmlType()) {
QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
if (qmlClass) {
QString name = fd->name.toString();
@ -661,7 +661,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* )
if (nestingLevel > 1) {
return true;
}
if (current->type() == Node::Document) {
if (current->isQmlType()) {
QString handler = sb->qualifiedId->name.toString();
if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);

View File

@ -77,6 +77,7 @@ Tree::Tree(const QString& module, QDocDatabase* qdb)
: module_(module), qdb_(qdb), root_(0, QString())
{
root_.setModuleName(module_);
root_.setTree(this);
}
/*!
@ -103,7 +104,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
{
if (!start)
start = const_cast<NamespaceNode*>(root());
return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType));
return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class));
}
/*!
@ -114,7 +115,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
{
Node* start = const_cast<NamespaceNode*>(root());
return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType));
return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace));
}
/*!
@ -161,7 +162,7 @@ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
if (qcn)
return qcn;
}
return static_cast<QmlClassNode*>(findNodeRecursive(path, 0, root(), Node::Document, Node::QmlClass));
return static_cast<QmlClassNode*>(findNodeRecursive(path, 0, root(), Node::QmlType));
}
/*!
@ -224,14 +225,14 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
Node* n = findNodeByNameAndType(p, Node::Document, Node::QmlClass, true);
Node* n = findNodeByNameAndType(p, Node::QmlType);
if (n) {
if (n->subType() == Node::QmlClass)
if (n->isQmlType())
qcn = static_cast<QmlClassNode*>(n);
else if (n->subType() == Node::Collision) {
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::Document, Node::QmlClass));
qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
}
}
}
@ -489,7 +490,7 @@ void Tree::resolveCppToQmlLinks()
{
foreach (Node* child, root_.childNodes()) {
if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
if (child->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
ClassNode* cn = const_cast<ClassNode*>(qcn->classNode());
if (cn)
@ -558,15 +559,23 @@ NodeList Tree::allBaseClasses(const ClassNode* classNode) const
search at the tree root. \a subtype is not used unless
\a type is \c{Document}.
*/
Node* Tree::findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
bool acceptCollision) const
Node* Tree::findNodeByNameAndType(const QStringList& path, Node::Type type) const
{
Node* result = findNodeRecursive(path, 0, root(), type, subtype, acceptCollision);
return result;
return findNodeRecursive(path, 0, root(), type);
}
#if 0
/*!
Find the node with the specified \a path name that is of
the specified \a type and \a subtype. Begin the search at
the \a start node. If the \a start node is 0, begin the
search at the tree root. \a subtype is not used unless
\a type is \c{Document}.
*/
Node* Tree::findHtmlFileNode(const QStringList& path) const
{
return findNodeRecursive(path, 0, root());
}
#endif
/* internal members */
/*!
@ -588,9 +597,7 @@ Node* Tree::findNodeByNameAndType(const QStringList& path,
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision) const
Node::Type type) const
{
if (!start || path.isEmpty())
return 0; // no place to start, or nothing to search for.
@ -600,8 +607,6 @@ Node* Tree::findNodeRecursive(const QStringList& path,
return node; // found a match.
return 0; // premature leaf
}
if (pathIndex >= path.size())
return 0; // end of search path.
InnerNode* current = static_cast<InnerNode*>(node);
const NodeList& children = current->childNodes();
@ -612,39 +617,19 @@ Node* Tree::findNodeRecursive(const QStringList& path,
continue;
if (n->isQmlPropertyGroup()) {
if (type == Node::QmlProperty) {
n = findNodeRecursive(path, pathIndex, n, type, subtype);
n = findNodeRecursive(path, pathIndex, n, type);
if (n)
return n;
}
}
else if (n->name() == name) {
if (pathIndex+1 >= path.size()) {
if (n->type() == type) {
if (type == Node::Document) {
if (n->subType() == subtype)
return n;
else if (n->subType() == Node::Collision) {
if (acceptCollision)
return n;
return n->disambiguate(type, subtype);
}
else if (subtype == Node::NoSubType)
return n;
continue;
}
if (n->type() == type)
return n;
}
else if (n->isCollisionNode()) {
if (acceptCollision)
return n;
return findNodeRecursive(path, pathIndex, n, type, subtype);
}
else {
continue;
}
continue;
}
else { // Search the children of n for the next name in the path.
n = findNodeRecursive(path, pathIndex+1, n, type, subtype);
n = findNodeRecursive(path, pathIndex+1, n, type);
if (n)
return n;
}
@ -672,9 +657,6 @@ Node* Tree::findNodeRecursive(const QStringList& path,
Node* start,
const NodeTypeList& types) const
{
/*
Safety checks
*/
if (!start || path.isEmpty())
return 0;
if (start->isLeaf())
@ -1233,7 +1215,7 @@ QmlModuleNode* Tree::addToQmlModule(const QString& name, Node* node)
QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
qmn->addMember(node);
node->setQmlModule(qmn);
if (node->subType() == Node::QmlClass) {
if (node->isQmlType()) {
QmlClassNode* n = static_cast<QmlClassNode*>(node);
for (int i=0; i<qmid.size(); ++i) {
QString key = qmid[i] + "::" + node->name();

View File

@ -91,9 +91,7 @@ class Tree
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false) const;
Node::Type type) const;
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
@ -110,12 +108,7 @@ class Tree
QmlClassNode* findQmlTypeNode(const QStringList& path);
Node* findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false) const;
Node* findNodeByNameAndType(const QStringList& path, Node::Type type) const;
InnerNode* findRelatesNode(const QStringList& path);
NameCollisionNode* checkForCollision(const QString& name);
NameCollisionNode* findCollisionNode(const QString& name) const;