qdoc: Allow documenting a C++ class as a QML type.

Now qdoc can handle the case where a C++ class is
documented as a QML type of the same name, or as
both a C++ class and a QML type of the same name.

And collisions pages are created for both the HTML
and the DITA XML output. A collision page is created
when two items have the same name. The collision
pages will be augmented later to include the list
of pages where ambiguous links to one of the items
listed on the collision page are actually located,
so the writer can go back to those links and add
the appropriate qualifier.

Change-Id: I5a9632b2d2209e0784392047056bed8962005624
Reviewed-by: Martin Smith <martin.smith@nokia.com>
Reviewed-by: Casper van Donderen <casper.vandonderen@nokia.com>
This commit is contained in:
Martin Smith 2012-03-30 13:43:46 +02:00 committed by Qt by Nokia
parent f733a0044e
commit 9b0c0823c0
15 changed files with 997 additions and 728 deletions

View File

@ -649,7 +649,6 @@ QStringList CodeMarker::macRefsForNode(Node *node)
}
case Node::Namespace:
case Node::Fake:
case Node::Target:
default:
return QStringList();
}

View File

@ -826,61 +826,38 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner,
return sections;
}
/*!
Search the \a tree for a node named \a target
*/
const Node *CppCodeMarker::resolveTarget(const QString& target,
const Tree* tree,
const Node* relative,
const Node* self)
{
const Node* node = 0;
if (target.endsWith("()")) {
const FunctionNode *func;
QString funcName = target;
funcName.chop(2);
QStringList path = funcName.split("::");
if ((func = tree->findFunctionNode(path,
relative,
Tree::SearchBaseClasses))
&& func->metaness() != FunctionNode::MacroWithoutParams)
return func;
const FunctionNode* fn = tree->findFunctionNode(path, relative, Tree::SearchBaseClasses);
if (fn) {
/*
Why is this case not accepted?
*/
if (fn->metaness() != FunctionNode::MacroWithoutParams)
node = fn;
}
}
else if (target.contains(QLatin1Char('#'))) {
// ### this doesn't belong here; get rid of TargetNode hack
int hashAt = target.indexOf(QLatin1Char('#'));
QString link = target.left(hashAt);
QString ref = target.mid(hashAt + 1);
const Node *node;
if (link.isEmpty()) {
node = relative;
}
else {
QStringList path(link);
node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
}
if (node && node->isInnerNode()) {
const Atom *atom = node->doc().body().firstAtom();
while (atom) {
if (atom->type() == Atom::Target && atom->string() == ref) {
Node *parentNode = const_cast<Node *>(node);
return new TargetNode(static_cast<InnerNode*>(parentNode),
ref);
}
atom = atom->next();
}
}
// This error message is never printed; I think we can remove the case.
qDebug() << "qdoc: target case not handled:" << target;
}
else {
QStringList path = target.split("::");
const Node *node;
int flags = Tree::SearchBaseClasses |
Tree::SearchEnumValues |
Tree::NonFunction;
if ((node = tree->findNode(path,
relative,
flags,
self)))
return node;
int flags = Tree::SearchBaseClasses | Tree::SearchEnumValues | Tree::NonFunction;
node = tree->findNode(path, relative, flags, self);
}
return 0;
return node;
}
static const char * const typeTable[] = {

View File

@ -79,7 +79,6 @@ QT_BEGIN_NAMESPACE
#define COMMAND_PROPERTY Doc::alias("property")
#define COMMAND_REIMP Doc::alias("reimp")
#define COMMAND_RELATES Doc::alias("relates")
#define COMMAND_SERVICE Doc::alias("service")
#define COMMAND_STARTPAGE Doc::alias("startpage")
#define COMMAND_TYPEDEF Doc::alias("typedef")
#define COMMAND_VARIABLE Doc::alias("variable")
@ -119,7 +118,7 @@ QStringList CppCodeParser::exampleDirs;
This is used for fuzzy matching only, which in turn is only used
for Qt Jambi.
*/
static QString cleanType(const QString &type, const Tree *tree)
static QString cleanType(const QString &type, Tree* tree)
{
QString result = type;
result.replace("qlonglong", "long long");
@ -145,14 +144,13 @@ static QString cleanType(const QString &type, const Tree *tree)
while ((pos = result.indexOf(regExp, pos)) != -1) {
// we assume that the path for the associated enum
// is the same as for the flag typedef
QStringList path = regExp.cap(2).split("::",
QString::SkipEmptyParts);
const EnumNode *enume = static_cast<const EnumNode *>(
tree->findNode(QStringList(path) << regExp.cap(3),
Node::Enum));
if (enume && enume->flagsType())
result.replace(pos, regExp.matchedLength(),
(QStringList(path) << enume->flagsType()->name()).join("::"));
QStringList path = regExp.cap(2).split("::", QString::SkipEmptyParts);
QStringList tmpPath = QStringList(path) << regExp.cap(3);
EnumNode* en = tree->findEnumNode(tmpPath);
if (en && en->flagsType()) {
tmpPath = QStringList(path) << en->flagsType()->name();
result.replace(pos, regExp.matchedLength(), tmpPath.join("::"));
}
++pos;
}
}
@ -191,9 +189,12 @@ void CppCodeParser::initializeParser(const Config &config)
{
CodeParser::initializeParser(config);
/*
All these can appear in a C++ namespace. Don't add
anything that can't be in a C++ namespace.
*/
nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace);
nodeTypeMap.insert(COMMAND_CLASS, Node::Class);
nodeTypeMap.insert(COMMAND_SERVICE, Node::Class);
nodeTypeMap.insert(COMMAND_ENUM, Node::Enum);
nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef);
nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
@ -306,7 +307,13 @@ void CppCodeParser::parseSourceFile(const Location& location,
Tokenizer fileTokenizer(fileLocation, in);
tokenizer = &fileTokenizer;
readToken();
usedNamespaces.clear();
/*
The set of active namespaces is cleared before parsing
each source file. The word "source" here means cpp file.
*/
activeNamespaces_.clear();
matchDocsAndStuff();
in.close();
}
@ -403,14 +410,14 @@ const FunctionNode *CppCodeParser::findFunctionNode(const QString& synopsis,
This is necessary because Roberto's parser resolves typedefs.
*/
if (!func && fuzzy) {
func = tre->findFunctionNode(parentPath +
func = tree_->findFunctionNode(parentPath +
QStringList(clone->name()),
relative,
flags);
if (!func && clone->name().contains('_')) {
QStringList path = parentPath;
path << clone->name().split('_');
func = tre->findFunctionNode(path, relative, flags);
func = tree_->findFunctionNode(path, relative, flags);
}
if (func) {
@ -512,7 +519,6 @@ QSet<QString> CppCodeParser::topicCommands()
<< COMMAND_NAMESPACE
<< COMMAND_PAGE
<< COMMAND_PROPERTY
<< COMMAND_SERVICE
<< COMMAND_TYPEDEF
<< COMMAND_VARIABLE
<< COMMAND_QMLCLASS
@ -543,21 +549,21 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
doc.location().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN));
}
else {
if (!usedNamespaces.isEmpty()) {
foreach (const QString &usedNamespace, usedNamespaces) {
QStringList newPath = usedNamespace.split("::") + parentPath;
func = tre->findFunctionNode(newPath, clone);
if (!activeNamespaces_.isEmpty()) {
foreach (const QString& usedNamespace_, activeNamespaces_) {
QStringList newPath = usedNamespace_.split("::") + parentPath;
func = tree_->findFunctionNode(newPath, clone);
if (func)
break;
}
}
// Search the root namespace if no match was found.
if (func == 0)
func = tre->findFunctionNode(parentPath, clone);
func = tree_->findFunctionNode(parentPath, clone);
if (func == 0) {
if (parentPath.isEmpty() && !lastPath.isEmpty())
func = tre->findFunctionNode(lastPath, clone);
func = tree_->findFunctionNode(lastPath, clone);
if (func == 0) {
doc.location().warning(tr("Cannot find '%1' in '\\%2'")
.arg(clone->name() + "(...)")
@ -589,7 +595,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QStringList parentPath;
FunctionNode *func = 0;
if (makeFunctionNode(arg, &parentPath, &func, tre->root())) {
if (makeFunctionNode(arg, &parentPath, &func, tree_->root())) {
if (!parentPath.isEmpty()) {
doc.location().warning(tr("Invalid syntax in '\\%1'")
.arg(COMMAND_MACRO));
@ -610,7 +616,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return func;
}
else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg)) {
func = new FunctionNode(tre->root(), arg);
func = new FunctionNode(tree_->root(), arg);
func->setAccess(Node::Public);
func->setLocation(doc.location());
func->setMetaness(FunctionNode::MacroWithoutParams);
@ -624,25 +630,45 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
else if (nodeTypeMap.contains(command)) {
/*
The command was neither "fn" nor "macro" .
We should only get in here if the command refers to
something that can appear in a C++ namespace,
i.e. a class, another namespace, an enum, a typedef,
a property or a variable. I think these are handled
this way to allow the writer to refer to the entity
without including the namespace qualifier.
*/
// ### split(QLatin1Char(' ')) hack is there to support header file syntax
Node::Type type = nodeTypeMap[command];
Node::SubType subtype = Node::NoSubType;
if (type == Node::Fake)
subtype = Node::QmlClass;
QStringList paths = arg.split(QLatin1Char(' '));
QStringList path = paths[0].split("::");
Node *node = 0;
if (!usedNamespaces.isEmpty()) {
foreach (const QString &usedNamespace, usedNamespaces) {
QStringList newPath = usedNamespace.split("::") + path;
node = tre->findNode(newPath, nodeTypeMap[command]);
/*
If the command refers to something that can be in a
C++ namespace, search for it first in all the known
C++ namespaces.
*/
if (!activeNamespaces_.isEmpty()) {
foreach (const QString& usedNamespace_, activeNamespaces_) {
QStringList newPath = usedNamespace_.split("::") + path;
node = tree_->findNodeByNameAndType(newPath, type, subtype, 0);
if (node) {
path = newPath;
break;
}
}
}
// Search the root namespace if no match was found.
if (node == 0)
node = tre->findNode(path, nodeTypeMap[command]);
/*
If the node was not found in a C++ namespace, search
for it in the root namespace.
*/
if (node == 0) {
node = tree_->findNodeByNameAndType(path, type, subtype, 0);
}
if (node == 0) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
@ -650,63 +676,40 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
lastPath = path;
}
else if (command == COMMAND_SERVICE) {
// If the command is "\service", then we need to tag the
// class with the actual service name.
QStringList args = arg.split(QLatin1Char(' '));
if (args.size() > 1) {
ClassNode *cnode = static_cast<ClassNode *>(node);
cnode->setServiceName(args[1]);
cnode->setHideFromMainList(true);
}
}
else if (node->isInnerNode()) {
/*
This treets a class as a namespace.
*/
if (path.size() > 1) {
path.pop_back();
usedNamespaces.insert(path.join("::"));
QString ns = path.join("::");
activeNamespaces_.insert(ns);
}
}
#if 0
/*
This code apparently does nothing. After further
investigation to verify it is useless, it will
be removed.
*/
if (command == COMMAND_CLASS) {
if (paths.size() > 1) {
if (!paths[1].endsWith(".h")) {
ClassNode* cnode = static_cast<ClassNode*>(node);
cnode->setQmlElement(paths[1]);
}
}
}
#endif
return node;
}
else if (command == COMMAND_EXAMPLE) {
if (Config::generateExamples) {
ExampleNode* en = new ExampleNode(tre->root(), arg);
createExampleFileNodes(en);
return en;
}
ExampleNode* en = new ExampleNode(tree_->root(), arg);
createExampleFileNodes(en);
return en;
}
else if (command == COMMAND_EXTERNALPAGE) {
return new FakeNode(tre->root(), arg, Node::ExternalPage, Node::ArticlePage);
return new FakeNode(tree_->root(), arg, Node::ExternalPage, Node::ArticlePage);
}
else if (command == COMMAND_FILE) {
return new FakeNode(tre->root(), arg, Node::File, Node::NoPageType);
return new FakeNode(tree_->root(), arg, Node::File, Node::NoPageType);
}
else if (command == COMMAND_GROUP) {
return new FakeNode(tre->root(), arg, Node::Group, Node::OverviewPage);
return new FakeNode(tree_->root(), arg, Node::Group, Node::OverviewPage);
}
else if (command == COMMAND_HEADERFILE) {
return new FakeNode(tre->root(), arg, Node::HeaderFile, Node::ApiPage);
return new FakeNode(tree_->root(), arg, Node::HeaderFile, Node::ApiPage);
}
else if (command == COMMAND_MODULE) {
return new FakeNode(tre->root(), arg, Node::Module, Node::OverviewPage);
return new FakeNode(tree_->root(), arg, Node::Module, Node::OverviewPage);
}
else if (command == COMMAND_QMLMODULE) {
return new FakeNode(tre->root(), arg, Node::QmlModule, Node::OverviewPage);
return new FakeNode(tree_->root(), arg, Node::QmlModule, Node::OverviewPage);
}
else if (command == COMMAND_PAGE) {
Node::PageType ptype = Node::ArticlePage;
@ -740,30 +743,27 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
If there is no collision, just create a new Page
node and return that one.
*/
NameCollisionNode* ncn = tre->checkForCollision(args[0]);
NameCollisionNode* ncn = tree_->checkForCollision(args[0]);
FakeNode* fn = 0;
if (ptype == Node::DitaMapPage)
fn = new DitaMapNode(tre->root(), args[0]);
fn = new DitaMapNode(tree_->root(), args[0]);
else
fn = new FakeNode(tre->root(), args[0], Node::Page, ptype);
fn = new FakeNode(tree_->root(), args[0], Node::Page, ptype);
if (ncn) {
ncn->addCollision(fn);
}
return fn;
}
else if (command == COMMAND_DITAMAP) {
FakeNode* fn = new DitaMapNode(tre->root(), arg);
FakeNode* fn = new DitaMapNode(tree_->root(), arg);
return fn;
}
else if (command == COMMAND_QMLCLASS) {
const ClassNode* classNode = 0;
ClassNode* classNode = 0;
QStringList names = arg.split(QLatin1Char(' '));
if (names.size() > 1) {
Node* n = tre->findNode(names[1].split("::"),Node::Class);
if (n) {
classNode = static_cast<const ClassNode*>(n);
}
}
if (names.size() > 1)
classNode = tree_->findClassNode(names[1].split("::"));
/*
Search for a node with the same name. If there is one,
then there is a collision, so create a collision node
@ -775,15 +775,14 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
If there is no collision, just create a new QML class
node and return that one.
*/
NameCollisionNode* ncn = tre->checkForCollision(names[0]);
QmlClassNode* qcn = new QmlClassNode(tre->root(), names[0], classNode);
if (ncn) {
NameCollisionNode* ncn = tree_->checkForCollision(names[0]);
QmlClassNode* qcn = new QmlClassNode(tree_->root(), names[0], classNode);
if (ncn)
ncn->addCollision(qcn);
}
return qcn;
}
else if (command == COMMAND_QMLBASICTYPE) {
return new QmlBasicTypeNode(tre->root(), arg);
return new QmlBasicTypeNode(tree_->root(), arg);
}
else if ((command == COMMAND_QMLSIGNAL) ||
(command == COMMAND_QMLMETHOD) ||
@ -793,7 +792,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QString element;
QString type;
if (splitQmlMethodArg(doc,arg,type,module,element)) {
QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
QmlClassNode* qmlClass = tree_->findQmlClassNode(module,element);
if (qmlClass) {
if (command == COMMAND_QMLSIGNAL)
return makeFunctionNode(doc,arg,qmlClass,Node::QmlSignal,false,COMMAND_QMLSIGNAL);
@ -936,18 +935,18 @@ Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
bool attached = (command == COMMAND_QMLATTACHEDPROPERTY);
QStringList::ConstIterator arg = args.begin();
if (splitQmlPropertyArg(doc,(*arg),type,module,element,property)) {
QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
QmlClassNode* qmlClass = tree_->findQmlClassNode(module,element);
if (qmlClass) {
qmlPropGroup = new QmlPropGroupNode(qmlClass,property,attached);
}
}
if (qmlPropGroup) {
const ClassNode *correspondingClass = static_cast<const QmlClassNode*>(qmlPropGroup->parent())->classNode();
ClassNode *correspondingClass = static_cast<QmlClassNode*>(qmlPropGroup->parent())->classNode();
QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached);
const PropertyNode *correspondingProperty = 0;
if (correspondingClass) {
correspondingProperty = qmlPropNode->correspondingProperty(tre);
correspondingProperty = qmlPropNode->correspondingProperty(tree_);
}
if (correspondingProperty) {
bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
@ -1053,28 +1052,37 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_RELATES) {
InnerNode *pseudoParent;
/*
Find the node that this node relates to.
*/
Node* n = 0;
if (arg.startsWith(QLatin1Char('<')) || arg.startsWith('"')) {
pseudoParent =
static_cast<InnerNode *>(tre->findNode(QStringList(arg),
Node::Fake));
/*
It should be a header file, I think.
*/
n = tree_->findNodeByNameAndType(QStringList(arg), Node::Fake, Node::NoSubType, 0);
}
else {
/*
If it wasn't a file, it should be either a class or a namespace.
*/
QStringList newPath = arg.split("::");
pseudoParent =
static_cast<InnerNode*>(tre->findNode(QStringList(newPath),
Node::Class));
if (!pseudoParent)
pseudoParent =
static_cast<InnerNode*>(tre->findNode(QStringList(newPath),
Node::Namespace));
n = tree_->findClassNode(QStringList(newPath));
if (!n)
n = tree_->findNamespaceNode(QStringList(newPath));
}
if (!pseudoParent) {
doc.location().warning(tr("Cannot find '%1' in '\\%2'")
.arg(arg).arg(COMMAND_RELATES));
if (!n) {
/*
Didn't ind it. Error...
*/
doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES));
}
else {
node->setRelates(pseudoParent);
/*
Found it. This node relates to it.
*/
node->setRelates(static_cast<InnerNode*>(n));
}
}
else if (command == COMMAND_CONTENTSPAGE) {
@ -1136,7 +1144,7 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else {
processCommonMetaCommand(doc.location(),command,arg,node,tre);
processCommonMetaCommand(doc.location(),command,arg,node,tree_);
}
}
@ -1165,7 +1173,7 @@ void CppCodeParser::processOtherMetaCommands(const Doc& doc, Node *node)
*/
void CppCodeParser::reset(Tree *tree)
{
tre = tree;
tree_ = tree;
tokenizer = 0;
tok = 0;
access = Node::Public;
@ -1691,7 +1699,7 @@ bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass)
if (!matchDataType(&baseClass))
return false;
tre->addBaseClass(classe,
tree_->addBaseClass(classe,
access,
baseClass.toPath(),
baseClass.toString(),
@ -1773,18 +1781,18 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
So far, so good. We have 'namespace Foo {'.
*/
QString namespaceName = previousLexeme();
NamespaceNode *namespasse = 0;
NamespaceNode* ns = 0;
if (parent) {
namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace));
ns = static_cast<NamespaceNode*>(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace));
}
if (!namespasse) {
namespasse = new NamespaceNode(parent, namespaceName);
namespasse->setAccess(access);
namespasse->setLocation(location());
if (!ns) {
ns = new NamespaceNode(parent, namespaceName);
ns->setAccess(access);
ns->setLocation(location());
}
readToken(); // skip '{'
bool matched = matchDeclList(namespasse);
bool matched = matchDeclList(ns);
return matched && match(Tok_RightBrace);
}
@ -1817,7 +1825,7 @@ bool CppCodeParser::matchUsingDecl()
/*
So far, so good. We have 'using namespace Foo;'.
*/
usedNamespaces.insert(name);
activeNamespaces_.insert(name);
return true;
}
@ -1915,10 +1923,10 @@ bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
if (!match(Tok_Semicolon))
return false;
if (parent && !parent->findNode(name, Node::Typedef)) {
TypedefNode *typedeffe = new TypedefNode(parent, name);
typedeffe->setAccess(access);
typedeffe->setLocation(location());
if (parent && !parent->findChildNodeByNameAndType(name, Node::Typedef)) {
TypedefNode* td = new TypedefNode(parent, name);
td->setAccess(access);
td->setLocation(location());
}
return true;
}
@ -1977,9 +1985,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent)
}
if (key == "READ")
tre->addPropertyFunction(property, value, PropertyNode::Getter);
tree_->addPropertyFunction(property, value, PropertyNode::Getter);
else if (key == "WRITE") {
tre->addPropertyFunction(property, value, PropertyNode::Setter);
tree_->addPropertyFunction(property, value, PropertyNode::Setter);
property->setWritable(true);
}
else if (key == "STORED")
@ -1996,9 +2004,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent)
}
}
else if (key == "RESET")
tre->addPropertyFunction(property, value, PropertyNode::Resetter);
tree_->addPropertyFunction(property, value, PropertyNode::Resetter);
else if (key == "NOTIFY") {
tre->addPropertyFunction(property, value, PropertyNode::Notifier);
tree_->addPropertyFunction(property, value, PropertyNode::Notifier);
} else if (key == "REVISION") {
int revision;
bool ok;
@ -2130,15 +2138,13 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
if (match(Tok_LeftParen) && match(Tok_Ident)) {
QString flagsType = previousLexeme();
if (match(Tok_Comma) && match(Tok_Ident)) {
QString enumType = previousLexeme();
QString name = previousLexeme();
TypedefNode *flagsNode = new TypedefNode(parent, flagsType);
flagsNode->setAccess(access);
flagsNode->setLocation(location());
EnumNode *enumNode =
static_cast<EnumNode*>(parent->findNode(enumType,
Node::Enum));
if (enumNode)
enumNode->setFlagsType(flagsNode);
EnumNode* en = static_cast<EnumNode*>(parent->findChildNodeByNameAndType(name, Node::Enum));
if (en)
en->setFlagsType(flagsNode);
}
}
match(Tok_RightParen);
@ -2219,14 +2225,14 @@ bool CppCodeParser::matchDocsAndStuff()
FunctionNode *func = 0;
if (matchFunctionDecl(0, &parentPath, &clone)) {
foreach (const QString &usedNamespace, usedNamespaces) {
QStringList newPath = usedNamespace.split("::") + parentPath;
func = tre->findFunctionNode(newPath, clone);
foreach (const QString& usedNamespace_, activeNamespaces_) {
QStringList newPath = usedNamespace_.split("::") + parentPath;
func = tree_->findFunctionNode(newPath, clone);
if (func)
break;
}
if (func == 0)
func = tre->findFunctionNode(parentPath, clone);
func = tree_->findFunctionNode(parentPath, clone);
if (func) {
func->borrowParameterNames(clone);
@ -2280,7 +2286,7 @@ bool CppCodeParser::matchDocsAndStuff()
if ((*n)->isInnerNode() &&
((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast<InnerNode *>(*n);
while (m->parent() != tre->root())
while (m->parent() != tree_->root())
m = m->parent();
if (m == *n)
((InnerNode *)*n)->addInclude((*n)->name());
@ -2309,7 +2315,7 @@ bool CppCodeParser::matchDocsAndStuff()
Signals are implemented in uninteresting files
generated by moc.
*/
node = tre->findFunctionNode(parentPath, clone);
node = tree_->findFunctionNode(parentPath, clone);
if (node != 0 && node->metaness() != FunctionNode::Signal)
node->setLocation(clone->location());
delete clone;
@ -2421,7 +2427,7 @@ void CppCodeParser::instantiateIteratorMacro(const QString &container,
Tokenizer stringTokenizer(loc, latin1);
tokenizer = &stringTokenizer;
readToken();
matchDeclList(tre->root());
matchDeclList(tree_->root());
}
void CppCodeParser::createExampleFileNodes(FakeNode *fake)

View File

@ -165,7 +165,7 @@ private:
void createExampleFileNodes(FakeNode *fake);
QMap<QString, Node::Type> nodeTypeMap;
Tree *tre;
Tree* tree_;
Tokenizer *tokenizer;
int tok;
Node::Access access;
@ -179,7 +179,7 @@ private:
QString mutableSequentialIteratorDefinition;
QString associativeIteratorDefinition;
QString mutableAssociativeIteratorDefinition;
QSet<QString> usedNamespaces;
QSet<QString> activeNamespaces_;
QMap<QString, QString> sequentialIteratorClasses;
QMap<QString, QString> mutableSequentialIteratorClasses;
QMap<QString, QString> associativeIteratorClasses;

View File

@ -418,7 +418,6 @@ DitaXmlGenerator::DitaXmlGenerator()
sectionNestingLevel(0),
tableColumnCount(0),
funcLeftParen("\\S(\\()"),
tree_(0),
nodeTypeMaps(Node::LastType,0),
nodeSubtypeMaps(Node::LastSubtype,0),
pageTypeMaps(Node::OnBeyondZebra,0)
@ -618,7 +617,7 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
This is where the DITA XML files are written.
\note The file is created in PageGenerator::generateTree().
*/
void DitaXmlGenerator::generateTree(const Tree *tree)
void DitaXmlGenerator::generateTree(Tree *tree)
{
tree_ = tree;
nonCompatClasses.clear();
@ -638,6 +637,7 @@ void DitaXmlGenerator::generateTree(const Tree *tree)
findAllSince(tree->root());
Generator::generateTree(tree);
generateCollisionPages();
writeDitaMap(tree);
}
@ -1269,19 +1269,15 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
const Node *node = 0;
QString myLink = getLink(atom, relative, marker, &node);
if (myLink.isEmpty()) {
relative->doc().location().warning(tr("Can't link to '%1' in %2")
.arg(atom->string())
.arg(marker->plainFullName(relative)));
myLink = getCollisionLink(atom);
}
if (myLink.isEmpty()) {
relative->doc().location().warning(tr("Can't link to '%1'")
.arg(atom->string()));
}
else if (!inSectionHeading) {
beginLink(myLink);
}
#if 0
else {
//xmlWriter().writeCharacters(atom->string());
//qDebug() << "MYLINK:" << myLink << outFileName() << atom->string();
}
#endif
skipAhead = 1;
}
break;
@ -1744,7 +1740,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
for marking up the code. I don't know what that means exactly.
*/
void
DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* marker)
DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
QList<Section>::ConstIterator s;
@ -2143,8 +2139,8 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark
writeEndTag(); // </cxxClass>
}
else if ((inner->type() == Node::Fake) && (inner->subType() == Node::QmlClass)) {
const QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner));
const ClassNode* cn = qcn->classNode();
QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner));
ClassNode* cn = qcn->classNode();
rawTitle = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
title = rawTitle + " Element";
@ -2248,7 +2244,7 @@ void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& tex
Generate the DITA page for a qdoc file that doesn't map
to an underlying c++ file.
*/
void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker)
void DitaXmlGenerator::generateFakeNode(FakeNode* fake, CodeMarker* marker)
{
/*
If the fake node is a page node, and if the page type
@ -2499,6 +2495,9 @@ void DitaXmlGenerator::generateHeader(const Node* node,
case Node::ExternalPage: // not used
outputclass = "externalpage";
break;
case Node::Collision:
outputclass = "collision";
break;
default:
outputclass = "page";
}
@ -3302,16 +3301,11 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative, CodeMarker* /*
else if (!isGroupPage) {
// If we encounter a page that belongs to a group then
// we add that page to the list for that group.
const FakeNode* groupNode =
static_cast<const FakeNode*>(tree_->root()->findNode(group, Node::Fake));
if (groupNode)
fakeNodeMap[groupNode].insert(sortKey, fakeNode);
//else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
const FakeNode* gn = tree_->findGroupNode(QStringList(group));
if (gn)
fakeNodeMap[gn].insert(sortKey, fakeNode);
}
}
}
}
@ -3877,8 +3871,6 @@ QString DitaXmlGenerator::guidForNode(const Node* node)
return node->guid();
case Node::Variable:
return node->guid();
case Node::Target:
return node->guid();
}
return QString();
}
@ -4143,7 +4135,7 @@ const Node* DitaXmlGenerator::findNodeForTarget(const QString& target,
node = relative;
}
else if (target.endsWith(".html")) {
node = tree_->root()->findNode(target, Node::Fake);
node = tree_->root()->findChildNodeByNameAndType(target, Node::Fake);
}
else if (marker) {
node = marker->resolveTarget(target, tree_, relative);
@ -4204,7 +4196,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom,
*node = relative;
}
else if (first.endsWith(".html")) {
*node = tree_->root()->findNode(first, Node::Fake);
*node = tree_->root()->findChildNodeByNameAndType(first, Node::Fake);
}
else {
*node = marker->resolveTarget(first, tree_, relative);
@ -4292,17 +4284,6 @@ QString DitaXmlGenerator::getLink(const Atom* atom,
return link;
}
/*!
This function can be called if getLink() returns an empty
string.
*/
QString DitaXmlGenerator::getDisambiguationLink(const Atom *, CodeMarker *)
{
qDebug() << "Unimplemented function called: "
<< "QString DitaXmlGenerator::getDisambiguationLink()";
return QString();
}
void DitaXmlGenerator::generateIndex(const QString& fileBase,
const QString& url,
const QString& title)
@ -4419,19 +4400,19 @@ void DitaXmlGenerator::generateQmlSummary(const Section& section,
Outputs the DITA detailed documentation for a section
on a QML element reference page.
*/
void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
void DitaXmlGenerator::generateDetailedQmlMember(Node* node,
const InnerNode* relative,
CodeMarker* marker)
{
QString marked;
const QmlPropertyNode* qpn = 0;
QmlPropertyNode* qpn = 0;
if (node->subType() == Node::QmlPropertyGroup) {
const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node);
NodeList::ConstIterator p = qpgn->childNodes().begin();
writeStartTag(DT_ul);
while (p != qpgn->childNodes().end()) {
if ((*p)->type() == Node::QmlProperty) {
qpn = static_cast<const QmlPropertyNode*>(*p);
qpn = static_cast<QmlPropertyNode*>(*p);
writeStartTag(DT_li);
writeGuidAttribute((Node*)qpn);
QString attr;
@ -4457,7 +4438,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
writeEndTag(); // </ul>
}
else if (node->type() == Node::QmlProperty) {
qpn = static_cast<const QmlPropertyNode*>(node);
qpn = static_cast<QmlPropertyNode*>(node);
/*
If the QML property node has a single subproperty,
override, replace qpn with that override node and
@ -4466,7 +4447,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
if (qpn->qmlPropNodes().size() == 1) {
Node* n = qpn->qmlPropNodes().at(0);
if (n->type() == Node::QmlProperty)
qpn = static_cast<const QmlPropertyNode*>(n);
qpn = static_cast<QmlPropertyNode*>(n);
}
/*
Now qpn either has no overrides, or it has more
@ -4600,10 +4581,9 @@ void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker*
If there is no class node, or if the class node status
is set to Node::Internal, do nothing.
*/
void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
CodeMarker* marker)
void DitaXmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker)
{
const ClassNode* cn = qcn->classNode();
ClassNode* cn = qcn->classNode();
if (cn && (cn->status() != Node::Internal)) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","instantiates");
@ -4631,8 +4611,7 @@ void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
If there is no QML element, or if the class node status
is set to Node::Internal, do nothing.
*/
void DitaXmlGenerator::generateInstantiatedBy(const ClassNode* cn,
CodeMarker* marker)
void DitaXmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker)
{
if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
const QmlClassNode* qcn = cn->qmlElement();
@ -5628,13 +5607,13 @@ void DitaXmlGenerator::writeNestedClasses(const Section& s,
Recursive writing of DITA XML files from the root \a node.
*/
void
DitaXmlGenerator::generateInnerNode(const InnerNode* node)
DitaXmlGenerator::generateInnerNode(InnerNode* node)
{
if (!node->url().isNull())
return;
if (node->type() == Node::Fake) {
const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
FakeNode* fakeNode = static_cast<FakeNode*>(node);
if (fakeNode->subType() == Node::ExternalPage)
return;
if (fakeNode->subType() == Node::Image)
@ -5653,27 +5632,38 @@ DitaXmlGenerator::generateInnerNode(const InnerNode* node)
CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
if (node->parent() != 0) {
if (!node->name().endsWith(".ditamap"))
beginSubPage(node, fileName(node));
if (node->type() == Node::Namespace || node->type() == Node::Class) {
generateClassLikeNode(node, marker);
/*
Skip name collision nodes here and process them
later in generateCollisionPages(). Each one is
appended to a list for later.
*/
if ((node->type() == Node::Fake) && (node->subType() == Node::Collision)) {
NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
}
else if (node->type() == Node::Fake) {
if (node->subType() == Node::HeaderFile)
else {
if (!node->name().endsWith(".ditamap"))
beginSubPage(node, fileName(node));
if (node->type() == Node::Namespace || node->type() == Node::Class) {
generateClassLikeNode(node, marker);
else if (node->subType() == Node::QmlClass)
generateClassLikeNode(node, marker);
else
generateFakeNode(static_cast<const FakeNode*>(node), marker);
}
else if (node->type() == Node::Fake) {
if (node->subType() == Node::HeaderFile)
generateClassLikeNode(node, marker);
else if (node->subType() == Node::QmlClass)
generateClassLikeNode(node, marker);
else
generateFakeNode(static_cast<FakeNode*>(node), marker);
}
if (!node->name().endsWith(".ditamap"))
endSubPage();
}
if (!node->name().endsWith(".ditamap"))
endSubPage();
}
NodeList::ConstIterator c = node->childNodes().begin();
while (c != node->childNodes().end()) {
if ((*c)->isInnerNode() && (*c)->access() != Node::Private)
generateInnerNode((const InnerNode*) *c);
generateInnerNode((InnerNode*)*c);
++c;
}
}
@ -5819,8 +5809,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
break;
case Node::Variable:
break;
case Node::Target:
break;
case Node::QmlProperty:
break;
case Node::QmlSignal:
@ -5840,7 +5828,7 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
Creates the DITA map for the qdoc run. The map is written
to the file \e{qt.ditamap" in the DITA XML output directory.
*/
void DitaXmlGenerator::writeDitaMap(const Tree *tree)
void DitaXmlGenerator::writeDitaMap(Tree *tree)
{
QString doctype;
@ -6374,5 +6362,125 @@ QString DitaXmlGenerator::stripMarkup(const QString& src) const
return text;
}
/*!
We delayed generation of the collision pages until now, after
all the other pages have been generated. We do this because we might
encounter a link command that tries to link to a target on a QML
type page, but the link doesn't specify the module identifer
for the QML type, and the QML type name without a module
identifier is ambiguous. When such a link is found, qdoc can't find
the target, so it appends the target to the NameCollisionNode. After
the tree has been traversed and all these ambiguous links have been
added to the name collision nodes, this function is called. The list
of collision nodes is traversed here, and the collision page for
each collision is generated. The collision page will not only
disambiguate links to the QML type pages, but it will also disambiguate
links to properties, section headers, etc.
*/
void DitaXmlGenerator::generateCollisionPages()
{
if (collisionNodes.isEmpty())
return;
for (int i=0; i<collisionNodes.size(); ++i) {
NameCollisionNode* ncn = collisionNodes.at(i);
if (!ncn)
continue;
NodeList collisions;
const NodeList& nl = ncn->childNodes();
if (!nl.isEmpty()) {
NodeList::ConstIterator it = nl.begin();
while (it != nl.end()) {
if (!(*it)->isInternal())
collisions.append(*it);
++it;
}
}
if (collisions.size() <= 1)
continue;
ncn->clearCurrentChild();
beginSubPage(ncn, Generator::fileName(ncn));
QString fullTitle = ncn->fullTitle();
QString ditaTitle = fullTitle;
CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
if (ncn->isQmlNode()) {
// Replace the marker with a QML code marker.
if (ncn->isQmlNode())
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
}
generateHeader(ncn, ditaTitle);
writeProlog(ncn);
writeStartTag(DT_body);
enterSection(QString(),QString());
NodeMap nm;
for (int i=0; i<collisions.size(); ++i) {
Node* n = collisions.at(i);
QString t;
if (!n->qmlModuleIdentifier().isEmpty())
t = n->qmlModuleIdentifier() + " ";
t += protectEnc(fullTitle);
nm.insertMulti(t,n);
}
generateAnnotatedList(ncn, marker, nm);
QList<QString> targets;
if (!ncn->linkTargets().isEmpty()) {
QMap<QString,QString>::ConstIterator t = ncn->linkTargets().begin();
while (t != ncn->linkTargets().end()) {
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
if (n->findChildNodeByName(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
break;
}
}
}
++t;
}
}
if (!targets.isEmpty()) {
QList<QString>::ConstIterator t = targets.begin();
while (t != targets.end()) {
writeStartTag(DT_p);
writeGuidAttribute(Doc::canonicalTitle(*t));
xmlWriter().writeAttribute("outputclass","h2");
writeCharacters(protectEnc(*t));
writeEndTag(); // </p>
writeStartTag(DT_ul);
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
Node* p = n->findChildNodeByName(*t);
if (p) {
QString link = linkForNode(p,0);
QString label;
if (!n->qmlModuleIdentifier().isEmpty())
label = n->qmlModuleIdentifier() + "::";
label += n->name() + "::" + p->name();
writeStartTag(DT_li);
writeStartTag(DT_xref);
xmlWriter().writeAttribute("href", link);
writeCharacters(protectEnc(label));
writeEndTag(); // </xref>
writeEndTag(); // </li>
}
}
writeEndTag(); // </ul>
++t;
}
}
leaveSection(); // </section>
writeEndTag(); // </body>
endSubPage();
}
}
QT_END_NAMESPACE

View File

@ -266,8 +266,8 @@ public:
virtual void terminateGenerator();
virtual QString format();
virtual bool canHandleFormat(const QString& format);
virtual void generateTree(const Tree *tree);
virtual void generateDisambiguationPages() { }
virtual void generateTree(Tree *tree);
void generateCollisionPages();
QString protectEnc(const QString& string);
static QString protect(const QString& string, const QString& encoding = "ISO-8859-1");
@ -279,8 +279,8 @@ protected:
virtual int generateAtom(const Atom* atom,
const Node* relative,
CodeMarker* marker);
virtual void generateClassLikeNode(const InnerNode* inner, CodeMarker* marker);
virtual void generateFakeNode(const FakeNode* fake, CodeMarker* marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateFakeNode(FakeNode* fake, CodeMarker* marker);
virtual QString fileExtension(const Node* node) const;
virtual QString guidForNode(const Node* node);
virtual QString linkForNode(const Node* node, const Node* relative);
@ -377,12 +377,12 @@ private:
const Node* relative,
CodeMarker* marker,
bool summary);
void generateDetailedQmlMember(const Node* node,
void generateDetailedQmlMember(Node* node,
const InnerNode* relative,
CodeMarker* marker);
void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker);
void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker);
void generateSection(const NodeList& nl,
const Node* relative,
@ -421,7 +421,6 @@ private:
const Node *relative,
CodeMarker *marker,
const Node **node);
QString getDisambiguationLink(const Atom* atom, CodeMarker* marker);
virtual void generateIndex(const QString& fileBase,
const QString& url,
const QString& title);
@ -437,11 +436,11 @@ private:
GuidMap* lookupGuidMap(const QString& fileName);
virtual void beginSubPage(const InnerNode* node, const QString& fileName);
virtual void endSubPage();
virtual void generateInnerNode(const InnerNode* node);
virtual void generateInnerNode(InnerNode* node);
QXmlStreamWriter& xmlWriter();
void writeApiDesc(const Node* node, CodeMarker* marker, const QString& title);
void addLink(const QString& href, const QStringRef& text, DitaTag t = DT_xref);
void writeDitaMap(const Tree* tree);
void writeDitaMap(Tree* tree);
void writeDitaMap(const DitaMapNode* node);
void writeStartTag(DitaTag t);
bool writeEndTag(DitaTag t=DT_NONE);
@ -501,7 +500,6 @@ private:
QStringList vrm;
QStringList stylesheets;
QStringList customHeadElements;
const Tree* tree_;
QMap<QString, QString> refMap;
QMap<QString, QString> name2guidMap;
GuidMaps guidMaps;

View File

@ -102,7 +102,8 @@ Generator::Generator()
gt("&gt;"),
lt("&lt;"),
quot("&quot;"),
tag("</?@[^>]*>")
tag("</?@[^>]*>"),
tree_(0)
{
generators.prepend(this);
}
@ -452,11 +453,12 @@ QString Generator::fullName(const Node *node,
{
if (node->type() == Node::Fake) {
const FakeNode* fn = static_cast<const FakeNode *>(node);
#if 0
// Removed for QTBUG-22870
// Unremoved by mws 30/03/12
if (!fn->qmlModuleIdentifier().isEmpty())
return fn->qmlModuleIdentifier() + QLatin1Char(' ') + fn->title();
#endif
return fn->qmlModuleIdentifier() + "::" + fn->title();
return fn->title();
}
else if (node->type() == Node::Class &&
@ -700,8 +702,7 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
void Generator::generateClassLikeNode(const InnerNode * /* classe */,
CodeMarker * /* marker */)
void Generator::generateClassLikeNode(InnerNode* /* classe */, CodeMarker* /* marker */)
{
}
@ -713,8 +714,7 @@ void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker)
generateFileList(fake, marker, Node::Image, QString("Images:"));
}
void Generator::generateFakeNode(const FakeNode * /* fake */,
CodeMarker * /* marker */)
void Generator::generateFakeNode(FakeNode* /* fake */, CodeMarker* /* marker */)
{
}
@ -837,16 +837,16 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
Recursive writing of HTML files from the root \a node.
\note NameCollisionNodes are skipped here and processed
later. See HtmlGenerator::generateDisambiguationPages()
for more on this.
later. See HtmlGenerator::generateCollisionPages() for
more on this.
*/
void Generator::generateInnerNode(const InnerNode* node)
void Generator::generateInnerNode(InnerNode* node)
{
if (!node->url().isNull())
return;
if (node->type() == Node::Fake) {
const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
FakeNode* fakeNode = static_cast<FakeNode*>(node);
if (fakeNode->subType() == Node::ExternalPage)
return;
if (fakeNode->subType() == Node::Image)
@ -867,11 +867,11 @@ void Generator::generateInnerNode(const InnerNode* node)
if (node->parent() != 0) {
/*
Skip name collision nodes here and process them
later in generateDisambiguationPages(). Each one
is appended to a list for later.
later in generateCollisionPages(). Each one is
appended to a list for later.
*/
if ((node->type() == Node::Fake) && (node->subType() == Node::Collision)) {
const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node);
NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
}
else {
@ -880,7 +880,7 @@ void Generator::generateInnerNode(const InnerNode* node)
generateClassLikeNode(node, marker);
}
else if (node->type() == Node::Fake) {
generateFakeNode(static_cast<const FakeNode *>(node), marker);
generateFakeNode(static_cast<FakeNode*>(node), marker);
}
endSubPage();
}
@ -889,7 +889,7 @@ void Generator::generateInnerNode(const InnerNode* node)
NodeList::ConstIterator c = node->childNodes().begin();
while (c != node->childNodes().end()) {
if ((*c)->isInnerNode() && (*c)->access() != Node::Private) {
generateInnerNode((const InnerNode *) *c);
generateInnerNode((InnerNode*)*c);
}
++c;
}
@ -1249,8 +1249,9 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
/*!
This function is recursive.
*/
void Generator::generateTree(const Tree *tree)
void Generator::generateTree(Tree *tree)
{
tree_ = tree;
generateInnerNode(tree->root());
}
@ -1265,6 +1266,40 @@ Generator *Generator::generatorForFormat(const QString& format)
return 0;
}
/*!
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
element or component without a module qualifier. If so, it
constructs a link to the <name> clause on the disambiguation
page for <element> and returns that link string. It also
adds the <name> as a target in the NameCollisionNode for
<element>. These clauses are then constructed when the
disambiguation page is actually generated.
*/
QString Generator::getCollisionLink(const Atom* atom)
{
QString link;
if (!atom->string().contains("::"))
return link;
QStringList path = atom->string().split("::");
NameCollisionNode* ncn = tree_->findCollisionNode(path[0]);
if (ncn) {
QString label;
if (atom->next() && atom->next()->next()) {
if (atom->next()->type() == Atom::FormattingLeft &&
atom->next()->next()->type() == Atom::String)
label = atom->next()->next()->string();
}
ncn->addLinkTarget(path[1],label);
link = fileName(ncn);
link += QLatin1Char('#');
link += Doc::canonicalTitle(path[1]);
}
return link;
}
/*!
Looks up the tag \a t in the map of metadata values for the
current topic in \a inner. If a value for the tag is found,

View File

@ -85,7 +85,7 @@ public:
virtual bool canHandleFormat(const QString &format) { return format == this->format(); }
virtual QString format() = 0;
virtual void generateTree(const Tree *tree);
virtual void generateTree(Tree *tree);
virtual void initializeGenerator(const Config &config);
virtual void terminateGenerator();
@ -109,13 +109,13 @@ protected:
const Node *relative,
CodeMarker *marker);
virtual void generateBody(const Node *node, CodeMarker *marker);
virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker);
virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateFakeNode(FakeNode* fake, CodeMarker* marker);
virtual void generateInheritedBy(const ClassNode *classe,
CodeMarker *marker);
virtual void generateInherits(const ClassNode *classe,
CodeMarker *marker);
virtual void generateInnerNode(const InnerNode *node);
virtual void generateInnerNode(InnerNode* node);
virtual void generateMaintainerList(const InnerNode* node, CodeMarker* marker);
virtual void generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker);
virtual void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
@ -155,6 +155,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 getMetadataElement(const InnerNode* inner, const QString& t);
QStringList getMetadataElements(const InnerNode* inner, const QString& t);
QString indent(int level, const QString& markedCode);
@ -230,6 +231,9 @@ private:
QString lt;
QString quot;
QRegExp tag;
protected:
Tree* tree_;
};
QT_END_NAMESPACE

View File

@ -117,13 +117,10 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
typeHash["function"] = Node::Function;
typeHash["property"] = Node::Property;
typeHash["variable"] = Node::Variable;
typeHash["target"] = Node::Target;
#ifdef QDOC_QML
typeHash["qmlproperty"] = Node::QmlProperty;
typeHash["qmlsignal"] = Node::QmlSignal;
typeHash["qmlsignalhandler"] = Node::QmlSignalHandler;
typeHash["qmlmethod"] = Node::QmlMethod;
#endif
QHash<QString, Node::SubType> subTypeHash;
subTypeHash["example"] = Node::Example;
@ -133,11 +130,9 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
subTypeHash["module"] = Node::Module;
subTypeHash["page"] = Node::Page;
subTypeHash["externalpage"] = Node::ExternalPage;
#ifdef QDOC_QML
subTypeHash["qmlclass"] = Node::QmlClass;
subTypeHash["qmlpropertygroup"] = Node::QmlPropertyGroup;
subTypeHash["qmlbasictype"] = Node::QmlBasicType;
#endif
QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values());

View File

@ -100,7 +100,6 @@ HtmlGenerator::HtmlGenerator()
numTableRows(0),
threeColumnEnumValueTable(true),
funcLeftParen("\\S(\\()"),
myTree(0),
obsoleteLinks(false)
{
}
@ -255,9 +254,9 @@ QString HtmlGenerator::format()
\note The HTML file generation is done in the base class,
PageGenerator::generateTree().
*/
void HtmlGenerator::generateTree(const Tree *tree)
void HtmlGenerator::generateTree(Tree *tree)
{
myTree = tree;
tree_ = tree;
nonCompatClasses.clear();
mainClasses.clear();
compatClasses.clear();
@ -268,6 +267,7 @@ void HtmlGenerator::generateTree(const Tree *tree)
legaleseTexts.clear();
serviceClasses.clear();
qmlClasses.clear();
findAllClasses(tree->root());
findAllFunctions(tree->root());
findAllLegaleseTexts(tree->root());
@ -275,13 +275,13 @@ void HtmlGenerator::generateTree(const Tree *tree)
findAllSince(tree->root());
Generator::generateTree(tree);
reportOrphans(tree->root());
generateDisambiguationPages();
//reportOrphans(tree->root());
generateCollisionPages();
QString fileBase = project.toLower().simplified().replace(" ", "-");
generateIndex(fileBase, projectUrl, projectDescription);
helpProjectWriter->generate(myTree);
helpProjectWriter->generate(tree_);
generateManifestFiles();
}
@ -492,7 +492,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
break;
case Atom::AnnotatedList:
{
QList<Node*> values = myTree->groups().values(atom->string());
QList<Node*> values = tree_->groups().values(atom->string());
NodeMap nodeMap;
for (int i = 0; i < values.size(); ++i) {
const Node* n = values.at(i);
@ -538,7 +538,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
// Add additional groups and remove groups of classes that
// should be excluded from the edition.
QMultiMap <QString, Node *> groups = myTree->groups();
QMultiMap <QString, Node *> groups = tree_->groups();
foreach (const QString &groupName, editionGroupMap[editionName]) {
QList<Node *> groupClasses;
if (groupName.startsWith(QLatin1Char('-'))) {
@ -833,7 +833,7 @@ int HtmlGenerator::generateAtom(const Atom *atom,
const Node *node = 0;
QString myLink = getLink(atom, relative, marker, &node);
if (myLink.isEmpty()) {
myLink = getDisambiguationLink(atom, marker);
myLink = getCollisionLink(atom);
if (myLink.isEmpty()) {
relative->doc().location().warning(tr("Can't create link to '%1'")
.arg(atom->string()));
@ -1160,13 +1160,12 @@ int HtmlGenerator::generateAtom(const Atom *atom,
/*!
Generate a reference page for a C++ class.
*/
void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
CodeMarker *marker)
void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
QList<Section> sections;
QList<Section>::ConstIterator s;
const ClassNode *classe = 0;
ClassNode* classe = 0;
QString title;
QString rawTitle;
@ -1177,7 +1176,7 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
title = rawTitle + " Namespace";
}
else if (inner->type() == Node::Class) {
classe = static_cast<const ClassNode *>(inner);
classe = static_cast<ClassNode*>(inner);
rawTitle = marker->plainName(inner);
fullTitle = marker->plainFullName(inner);
title = rawTitle + " Class";
@ -1370,15 +1369,32 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
disambiguate links to the component pages, but it will also disambiguate
links to properties, section headers, etc.
*/
void HtmlGenerator::generateDisambiguationPages()
void HtmlGenerator::generateCollisionPages()
{
if (collisionNodes.isEmpty())
return;
for (int i=0; i<collisionNodes.size(); ++i) {
NameCollisionNode* ncn = collisionNodes.at(i);
if (!ncn)
continue;
NodeList collisions;
const NodeList& nl = ncn->childNodes();
if (!nl.isEmpty()) {
NodeList::ConstIterator it = nl.begin();
while (it != nl.end()) {
if (!(*it)->isInternal())
collisions.append(*it);
++it;
}
}
if (collisions.size() <= 1)
continue;
ncn->clearCurrentChild();
beginSubPage(ncn, Generator::fileName(ncn));
QString fullTitle = "Name Collision: " + ncn->fullTitle();
QString fullTitle = ncn->fullTitle();
QString htmlTitle = fullTitle;
CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
if (ncn->isQmlNode()) {
@ -1390,36 +1406,56 @@ void HtmlGenerator::generateDisambiguationPages()
generateHeader(htmlTitle, ncn, marker);
if (!fullTitle.isEmpty())
out() << "<h1 class=\"title\">" << protectEnc(fullTitle) << "</h1>\n";
const NodeList& nl = ncn->childNodes();
NodeMap nm;
NodeList::ConstIterator it = nl.begin();
while (it != nl.end()) {
QString t = (*it)->qmlModuleIdentifier() + " " + protectEnc(fullTitle);
nm.insertMulti(t,(*it));
++it;
for (int i=0; i<collisions.size(); ++i) {
Node* n = collisions.at(i);
QString t;
if (!n->qmlModuleIdentifier().isEmpty())
t = n->qmlModuleIdentifier() + "::";
t += protectEnc(fullTitle);
nm.insertMulti(t,n);
}
generateAnnotatedList(ncn, marker, nm, true);
const QMap<QString,QString>& targets = ncn->linkTargets();
QList<QString> targets;
if (!ncn->linkTargets().isEmpty()) {
QMap<QString,QString>::ConstIterator t = ncn->linkTargets().begin();
while (t != ncn->linkTargets().end()) {
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
if (n->findChildNodeByName(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
break;
}
}
}
++t;
}
}
if (!targets.isEmpty()) {
QMap<QString,QString>::ConstIterator t = targets.begin();
QList<QString>::ConstIterator t = targets.begin();
while (t != targets.end()) {
out() << "<a name=\"" << Doc::canonicalTitle(t.key()) << "\"></a>";
out() << "<h2 class=\"title\">" << protectEnc(t.key()) << "</h2>\n";
out() << "<a name=\"" << Doc::canonicalTitle(*t) << "\"></a>";
out() << "<h2 class=\"title\">" << protectEnc(*t) << "</h2>\n";
out() << "<ul>\n";
it = nl.begin();
while (it != nl.end()) {
InnerNode* n = static_cast<InnerNode*>(*it);
Node* p = n->findNode(t.key());
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
Node* p = n->findChildNodeByName(*t);
if (p) {
QString link = linkForNode(p,0);
QString label = n->qmlModuleIdentifier() + "::" + n->name() + "::" + p->name();
QString label;
if (!n->qmlModuleIdentifier().isEmpty())
label = n->qmlModuleIdentifier() + "::";
label += n->name() + "::" + p->name();
out() << "<li>";
out() << "<a href=\"" << link << "\">";
out() << protectEnc(label) << "</a>";
out() << "</li>\n";
}
++it;
}
out() << "</ul>\n";
++t;
@ -1435,7 +1471,7 @@ void HtmlGenerator::generateDisambiguationPages()
Generate the HTML page for an entity that doesn't map
to any underlying parsable C++ class or QML component.
*/
void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
void HtmlGenerator::generateFakeNode(FakeNode* fake, CodeMarker* marker)
{
/*
If the fake node is a page node, and if the page type
@ -1471,9 +1507,9 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
Generate the TOC for the new doc format.
Don't generate a TOC for the home page.
*/
const QmlClassNode* qml_cn = 0;
QmlClassNode* qml_cn = 0;
if (fake->subType() == Node::QmlClass) {
qml_cn = static_cast<const QmlClassNode*>(fake);
qml_cn = static_cast<QmlClassNode*>(fake);
sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
generateTableOfContents(fake,marker,&sections);
@ -1537,7 +1573,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
}
else if (fake->subType() == Node::QmlClass) {
const_cast<FakeNode*>(fake)->setCurrentChild();
const ClassNode* cn = qml_cn->classNode();
ClassNode* cn = qml_cn->classNode();
generateBrief(qml_cn, marker);
generateQmlInherits(qml_cn, marker);
generateQmlInheritedBy(qml_cn, marker);
@ -1793,7 +1829,7 @@ void HtmlGenerator::generateHeader(const QString& title,
if (node && !node->doc().location().isEmpty())
out() << "<!-- " << node->doc().location().fileName() << " -->\n";
QString shortVersion = myTree->version();
QString shortVersion = tree_->version();
if (shortVersion.count(QChar('.')) == 2)
shortVersion.truncate(shortVersion.lastIndexOf(QChar('.')));
if (!project.isEmpty())
@ -1814,9 +1850,9 @@ void HtmlGenerator::generateHeader(const QString& title,
generateMacRef(node, marker);
#endif
out() << QString(postHeader).replace("\\" + COMMAND_VERSION, myTree->version());
out() << QString(postHeader).replace("\\" + COMMAND_VERSION, tree_->version());
generateBreadCrumbs(title,node,marker);
out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, myTree->version());
out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, tree_->version());
navigationLinks.clear();
@ -1901,8 +1937,8 @@ void HtmlGenerator::generateFooter(const Node *node)
if (node && !node->links().empty())
out() << "<p class=\"naviNextPrevious footerNavi\">\n" << navigationLinks << "</p>\n";
out() << QString(footer).replace("\\" + COMMAND_VERSION, myTree->version())
<< QString(address).replace("\\" + COMMAND_VERSION, myTree->version());
out() << QString(footer).replace("\\" + COMMAND_VERSION, tree_->version())
<< QString(address).replace("\\" + COMMAND_VERSION, tree_->version());
out() << "</body>\n";
out() << "</html>\n";
@ -2633,7 +2669,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
QMap<QString, FakeNode *> uncategorizedNodeMap;
QRegExp singleDigit("\\b([0-9])\\b");
const NodeList children = myTree->root()->childNodes();
const NodeList children = tree_->root()->childNodes();
foreach (Node *child, children) {
if (child->type() == Node::Fake && child != relative) {
FakeNode *fakeNode = static_cast<FakeNode *>(child);
@ -2685,15 +2721,11 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m
else if (!isGroupPage) {
// If we encounter a page that belongs to a group then
// we add that page to the list for that group.
const FakeNode *groupNode = static_cast<const FakeNode *>(myTree->root()->findNode(group, Node::Fake));
if (groupNode)
fakeNodeMap[groupNode].insert(sortKey, fakeNode);
//else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
}// else
// uncategorizedNodeMap.insert(sortKey, fakeNode);
const FakeNode* gn = tree_->findGroupNode(QStringList(group));
if (gn)
fakeNodeMap[gn].insert(sortKey, fakeNode);
}
}
}
}
@ -2994,7 +3026,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
const Node* n = marker->resolveTarget(par1.toString(),
myTree,
tree_,
relative);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
@ -3020,7 +3052,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
bool handled = false;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = marker->resolveTarget(arg.toString(), myTree, relative, self);
const Node* n = marker->resolveTarget(arg.toString(), tree_, relative, self);
html += QLatin1String("<span class=\"type\">");
if (n && n->subType() == Node::QmlBasicType) {
if (relative && relative->subType() == Node::QmlClass)
@ -3035,13 +3067,13 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = marker->resolveTarget(arg.toString(), myTree, relative);
const Node* n = marker->resolveTarget(arg.toString(), tree_, relative);
addLink(linkForNode(n,relative), arg, &html);
handled = true;
}
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
const Node* n = marker->resolveTarget(arg.toString(), myTree, relative);
const Node* n = marker->resolveTarget(arg.toString(), tree_, relative);
addLink(linkForNode(n,relative), arg, &html);
handled = true;
}
@ -3352,8 +3384,6 @@ QString HtmlGenerator::refForNode(const Node *node)
case Node::Variable:
ref = node->name() + "-var";
break;
case Node::Target:
return protectEnc(node->name());
}
return registerRef(ref);
}
@ -3699,15 +3729,15 @@ const Node *HtmlGenerator::findNodeForTarget(const QString &target,
node = relative;
}
else if (target.endsWith(".html")) {
node = myTree->root()->findNode(target, Node::Fake);
node = tree_->root()->findChildNodeByNameAndType(target, Node::Fake);
}
else if (marker) {
node = marker->resolveTarget(target, myTree, relative);
node = marker->resolveTarget(target, tree_, relative);
if (!node) {
node = myTree->findFakeNodeByTitle(target, relative);
node = tree_->findFakeNodeByTitle(target, relative);
}
if (!node && atom) {
node = myTree->findUnambiguousTarget(target, *const_cast<Atom**>(&atom), relative);
node = tree_->findUnambiguousTarget(target, *const_cast<Atom**>(&atom), relative);
}
}
@ -3762,15 +3792,21 @@ QString HtmlGenerator::getLink(const Atom *atom,
*node = relative;
}
else if (first.endsWith(".html")) {
*node = myTree->root()->findNode(first, Node::Fake);
/*
This is not a recursive search. That's ok in
this case, because we are searching for a page
node, which must be a direct child of the tree
root.
*/
*node = tree_->root()->findChildNodeByNameAndType(first, Node::Fake);
}
else {
*node = marker->resolveTarget(first, myTree, relative);
*node = marker->resolveTarget(first, tree_, relative);
if (!*node) {
*node = myTree->findFakeNodeByTitle(first, relative);
*node = tree_->findFakeNodeByTitle(first, relative);
}
if (!*node) {
*node = myTree->findUnambiguousTarget(first, targetAtom, relative);
*node = tree_->findUnambiguousTarget(first, targetAtom, relative);
}
}
if (*node) {
@ -3824,7 +3860,7 @@ QString HtmlGenerator::getLink(const Atom *atom,
target.
*/
while (!path.isEmpty()) {
targetAtom = myTree->findTarget(path.first(), *node);
targetAtom = tree_->findTarget(path.first(), *node);
if (targetAtom == 0)
break;
path.removeFirst();
@ -3861,44 +3897,11 @@ QString HtmlGenerator::getLink(const Atom *atom,
return link;
}
/*!
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
element or component without a module qualifier. If so, it
constructs a link to the <name> clause on the disambiguation
page for <element> and returns that link string. It also
adds the <name> as a target in the NameCollisionNode for
<element>. These clauses are then constructed when the
disambiguation page is actually generated.
*/
QString HtmlGenerator::getDisambiguationLink(const Atom *atom, CodeMarker *)
{
QString link;
if (!atom->string().contains("::"))
return link;
QStringList path = atom->string().split("::");
NameCollisionNode* ncn = myTree->findCollisionNode(path[0]);
if (ncn) {
QString label;
if (atom->next() && atom->next()->next()) {
if (atom->next()->type() == Atom::FormattingLeft &&
atom->next()->next()->type() == Atom::String)
label = atom->next()->next()->string();
}
ncn->addLinkTarget(path[1],label);
link = fileName(ncn);
link += QLatin1Char('#');
link += Doc::canonicalTitle(path[1]);
}
return link;
}
void HtmlGenerator::generateIndex(const QString &fileBase,
const QString &url,
const QString &title)
{
myTree->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", url, title);
tree_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", url, title);
}
void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
@ -3922,12 +3925,12 @@ void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
<< "We strongly advise against "
<< "using it in new code. See ";
const FakeNode *fakeNode = myTree->findFakeNodeByTitle("Porting To Qt 4");
const FakeNode *fakeNode = tree_->findFakeNodeByTitle("Porting To Qt 4");
Atom *targetAtom = 0;
if (fakeNode && node->type() == Node::Class) {
QString oldName(node->name());
oldName.remove(QLatin1Char('3'));
targetAtom = myTree->findTarget(oldName,
targetAtom = tree_->findTarget(oldName,
fakeNode);
}
@ -4044,11 +4047,11 @@ void HtmlGenerator::generateQmlSummary(const Section& section,
Outputs the html detailed documentation for a section
on a QML element reference page.
*/
void HtmlGenerator::generateDetailedQmlMember(const Node *node,
void HtmlGenerator::generateDetailedQmlMember(Node *node,
const InnerNode *relative,
CodeMarker *marker)
{
const QmlPropertyNode* qpn = 0;
QmlPropertyNode* qpn = 0;
#ifdef GENERATE_MAC_REFS
generateMacRef(node, marker);
#endif
@ -4061,14 +4064,14 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
out() << "<table class=\"qmlname\">";
while (p != qpgn->childNodes().end()) {
if ((*p)->type() == Node::QmlProperty) {
qpn = static_cast<const QmlPropertyNode*>(*p);
qpn = static_cast<QmlPropertyNode*>(*p);
out() << "<tr valign=\"top\" class=\"odd\">";
out() << "<td class=\"tblQmlPropNode\"><p>";
out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
int ro = qpn->getReadOnly();
if (ro < 0) {
if (!qpn->isWritable(myTree)) {
if (!qpn->isWritable(tree_)) {
out() << "<span class=\"qmlreadonly\">read-only</span>";
}
}
@ -4086,7 +4089,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
out() << "</div>";
}
else if (node->type() == Node::QmlProperty) {
qpn = static_cast<const QmlPropertyNode*>(node);
qpn = static_cast<QmlPropertyNode*>(node);
/*
If the QML property node has a single subproperty,
override, replace qpn with that override node and
@ -4095,7 +4098,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
if (qpn->qmlPropNodes().size() == 1) {
Node* n = qpn->qmlPropNodes().at(0);
if (n->type() == Node::QmlProperty)
qpn = static_cast<const QmlPropertyNode*>(n);
qpn = static_cast<QmlPropertyNode*>(n);
}
/*
Now qpn either has no overrides, or it has more
@ -4110,7 +4113,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
int ro = qpn->getReadOnly();
if (ro < 0) {
const ClassNode* cn = qpn->declarativeCppNode();
if (cn && !qpn->isWritable(myTree)) {
if (cn && !qpn->isWritable(tree_)) {
out() << "<span class=\"qmlreadonly\">read-only</span>";
}
}
@ -4142,7 +4145,7 @@ void HtmlGenerator::generateDetailedQmlMember(const Node *node,
int ro = qpn->getReadOnly();
if (ro < 0) {
if (!qpn->isWritable(myTree)) {
if (!qpn->isWritable(tree_)) {
out() << "<span class=\"qmlreadonly\">read-only</span>";
}
}
@ -4235,9 +4238,9 @@ void HtmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* mar
If there is no class node, or if the class node status
is set to Node::Internal, do nothing.
*/
void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker)
void HtmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker)
{
const ClassNode* cn = qcn->classNode();
ClassNode* cn = qcn->classNode();
if (cn && (cn->status() != Node::Internal)) {
Text text;
text << Atom::ParaLeft;
@ -4269,7 +4272,7 @@ void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker*
If there is no QML element, or if the class node status
is set to Node::Internal, do nothing.
*/
void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker)
void HtmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker)
{
if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
const QmlClassNode* qcn = cn->qmlElement();
@ -4460,9 +4463,6 @@ QString HtmlGenerator::fullDocumentLocation(const Node *node, bool subdir)
case Node::Variable:
anchorRef = QLatin1Char('#') + node->name() + "-var";
break;
case Node::Target:
anchorRef = QLatin1Char('#') + Doc::canonicalTitle(node->name());
break;
case Node::Fake:
{
/*
@ -4753,8 +4753,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
if (!related)
child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message));
break;
case Node::Target:
break;
case Node::QmlProperty:
if (!related)
child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message));
@ -4863,7 +4861,7 @@ void HtmlGenerator::writeDitaRefs(const DitaRefList& ditarefs)
xmlWriter().writeStartElement("topicref");
xmlWriter().writeAttribute("navtitle",t->navtitle());
if (t->href().isEmpty()) {
const FakeNode* fn = myTree->findFakeNodeByTitle(t->navtitle());
const FakeNode* fn = tree_->findFakeNodeByTitle(t->navtitle());
if (fn)
xmlWriter().writeAttribute("href",fileName(fn));
}

View File

@ -86,8 +86,8 @@ public:
virtual void initializeGenerator(const Config& config);
virtual void terminateGenerator();
virtual QString format();
virtual void generateTree(const Tree *tree);
virtual void generateDisambiguationPages();
virtual void generateTree(Tree *tree);
void generateCollisionPages();
void generateManifestFiles();
QString protectEnc(const QString &string);
@ -101,8 +101,8 @@ protected:
virtual int generateAtom(const Atom *atom,
const Node *relative,
CodeMarker *marker);
virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker);
virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
virtual void generateFakeNode(FakeNode* fake, CodeMarker* marker);
virtual QString fileExtension(const Node *node) const;
virtual QString refForNode(const Node *node);
virtual QString linkForNode(const Node *node, const Node *relative);
@ -176,12 +176,12 @@ private:
const Node *relative,
CodeMarker *marker,
bool summary);
void generateDetailedQmlMember(const Node *node,
void generateDetailedQmlMember(Node *node,
const InnerNode *relative,
CodeMarker *marker);
void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker);
void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker);
void generateSection(const NodeList& nl,
const Node *relative,
@ -227,7 +227,6 @@ private:
const Node *relative,
CodeMarker *marker,
const Node** node);
QString getDisambiguationLink(const Atom* atom, CodeMarker* marker);
virtual void generateIndex(const QString &fileBase,
const QString &url,
const QString &title);
@ -278,7 +277,6 @@ private:
QString manifestDir;
QStringList stylesheets;
QStringList customHeadElements;
const Tree *myTree;
bool obsoleteLinks;
QMap<QString, NodeMap > moduleClassMap;
QMap<QString, NodeMap > moduleNamespaceMap;

View File

@ -237,8 +237,6 @@ QString Node::nodeTypeString(unsigned t)
return "property";
case Variable:
return "variable";
case Target:
return "target";
case QmlProperty:
return "QML property";
case QmlSignal:
@ -524,14 +522,14 @@ QString Node::ditaXmlHref()
If it is a child of a QML class node, return a pointer to
the QML class node. Otherwise, return 0;
*/
const QmlClassNode* Node::qmlClassNode() const
QmlClassNode* Node::qmlClassNode()
{
if (isQmlNode()) {
const Node* n = this;
Node* n = this;
while (n && n->subType() != Node::QmlClass)
n = n->parent();
if (n && n->subType() == Node::QmlClass)
return static_cast<const QmlClassNode*>(n);
return static_cast<QmlClassNode*>(n);
}
return 0;
}
@ -543,14 +541,29 @@ const QmlClassNode* Node::qmlClassNode() const
class node is a component. It will be non-null if
the QML class node is a QML element.
*/
const ClassNode* Node::declarativeCppNode() const
ClassNode* Node::declarativeCppNode()
{
const QmlClassNode* qcn = qmlClassNode();
QmlClassNode* qcn = qmlClassNode();
if (qcn)
return qcn->classNode();
return 0;
}
/*!
Returns true if the node's status is Internal, or if its
parent is a class with internal status.
*/
bool Node::isInternal() const
{
if (status() == Internal)
return true;
if (parent() && parent()->status() == Internal)
return true;
if (relates() && relates()->status() == Internal)
return true;
return false;
}
/*!
\class InnerNode
*/
@ -571,7 +584,7 @@ InnerNode::~InnerNode()
sure to also look in the children of its property
group nodes. Return the matching node or 0.
*/
Node *InnerNode::findNode(const QString& name)
Node *InnerNode::findChildNodeByName(const QString& name)
{
Node *node = childMap.value(name);
if (node && node->subType() != QmlPropertyGroup)
@ -580,7 +593,7 @@ Node *InnerNode::findNode(const QString& name)
for (int i=0; i<children.size(); ++i) {
Node* n = children.at(i);
if (n->subType() == QmlPropertyGroup) {
node = static_cast<InnerNode*>(n)->findNode(name);
node = static_cast<InnerNode*>(n)->findChildNodeByName(name);
if (node)
return node;
}
@ -604,7 +617,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
for (int i=0; i<children.size(); ++i) {
node = children.at(i);
if (node->subType() == QmlPropertyGroup) {
node = static_cast<InnerNode*>(node)->findNode(name);
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
if (node) {
n.append(node);
return;
@ -628,7 +641,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
if (node->subType() != QmlPropertyGroup)
n.append(node);
else {
node = static_cast<InnerNode*>(node)->findNode(name);
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
if (node)
n.append(node);
}
@ -644,13 +657,14 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
/*!
Find the node in this node's children that has the given \a name. If
this node is a QML class node, be sure to also look in the children
of its property group nodes. Return the matching node or 0.
of its property group nodes. Return the matching node or 0. This is
not a recearsive search.
If \a qml is true, only match a node for which node->isQmlNode()
returns true. If \a qml is false, only match a node for which
node->isQmlNode() returns false.
*/
Node* InnerNode::findNode(const QString& name, bool qml)
Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
{
QList<Node*> nodes = childMap.values(name);
if (!nodes.isEmpty()) {
@ -668,7 +682,7 @@ Node* InnerNode::findNode(const QString& name, bool qml)
for (int i=0; i<children.size(); ++i) {
Node* node = children.at(i);
if (node->subType() == QmlPropertyGroup) {
node = static_cast<InnerNode*>(node)->findNode(name);
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
if (node)
return node;
}
@ -678,28 +692,31 @@ Node* InnerNode::findNode(const QString& name, bool qml)
}
/*!
Same as the other findNode(), but if the node with the
specified \a name is not of the specified \a type, return
0.
This function is like findChildNodeByName(), but if a node
with the specified \a name is found but it is not of the
specified \a type, 0 is returned.
This function is not recursive and therefore can't handle
collisions. If it finds a collision node named \a name, it
will return that node. But it might not find the collision
node because it looks up \a name in the child map, not the
list.
*/
Node *InnerNode::findNode(const QString& name, Type type)
Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
{
if (type == Function) {
if (type == Function)
return primaryFunctionMap.value(name);
}
else {
Node *node = childMap.value(name);
if (node && node->type() == type) {
if (node && node->type() == type)
return node;
}
else {
return 0;
}
}
return 0;
}
/*!
Find the function node in this node for the function named \a name.
Find a function node that is a child of this nose, such
that the function node has the specified \a name.
*/
FunctionNode *InnerNode::findFunctionNode(const QString& name)
{
@ -707,12 +724,13 @@ FunctionNode *InnerNode::findFunctionNode(const QString& name)
}
/*!
Find the function node in this node that has the same name as \a clone.
Find the function node that is a child of this node, such
that the function has the same name and signature as the
\a clone node.
*/
FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
{
QMap<QString, Node *>::ConstIterator c =
primaryFunctionMap.find(clone->name());
QMap<QString,Node*>::ConstIterator c = primaryFunctionMap.find(clone->name());
if (c != primaryFunctionMap.end()) {
if (isSameSignature(clone, (FunctionNode *) *c)) {
return (FunctionNode *) *c;
@ -907,10 +925,10 @@ void InnerNode::deleteChildren()
/*!
*/
const Node *InnerNode::findNode(const QString& name) const
const Node *InnerNode::findChildNodeByName(const QString& name) const
{
InnerNode *that = (InnerNode *) this;
return that->findNode(name);
return that->findChildNodeByName(name);
}
/*!
@ -918,22 +936,26 @@ const Node *InnerNode::findNode(const QString& name) const
returns true. If \a qml is false, only match a node for which
node->isQmlNode() returns false.
*/
const Node* InnerNode::findNode(const QString& name, bool qml) const
const Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
{
InnerNode*that = (InnerNode*) this;
return that->findNode(name, qml);
return that->findChildNodeByName(name, qml);
}
/*!
Searches this node's children for a child named \a name
with the specified node \a type.
*/
const Node *InnerNode::findNode(const QString& name, Type type) const
const Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) const
{
InnerNode *that = (InnerNode *) this;
return that->findNode(name, type);
return that->findChildNodeByNameAndType(name, type);
}
/*!
Find the function node in this node that has the given \a name.
Find a function node that is a child of this nose, such
that the function node has the specified \a name. This
function calls the non-const version of itself.
*/
const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
{
@ -942,7 +964,9 @@ const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
}
/*!
Find the function node in this node that has the same name as \a clone.
Find the function node that is a child of this node, such
that the function has the same name and signature as the
\a clone node. This function calls the non-const version.
*/
const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
{
@ -1196,13 +1220,9 @@ void InnerNode::removeRelated(Node *pseudoChild)
\class LeafNode
*/
/*!
/*! \fn bool LeafNode::isInnerNode() const
Returns false because this is a LeafNode.
*/
bool LeafNode::isInnerNode() const
{
return false;
}
/*!
Constructs a leaf node named \a name of the specified
@ -1339,19 +1359,19 @@ void ClassNode::fixBaseClasses()
Search the child list to find the property node with the
specified \a name.
*/
const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
PropertyNode* ClassNode::findPropertyNode(const QString& name)
{
const Node *n = findNode(name, Node::Property);
Node* n = findChildNodeByNameAndType(name, Node::Property);
if (n)
return static_cast<const PropertyNode*>(n);
return static_cast<PropertyNode*>(n);
const PropertyNode *pn = 0;
PropertyNode* pn = 0;
const QList<RelatedClass> &bases = baseClasses();
if (!bases.isEmpty()) {
for (int i = 0; i < bases.size(); ++i) {
const ClassNode *cn = bases[i].node;
ClassNode* cn = bases[i].node;
pn = cn->findPropertyNode(name);
if (pn)
break;
@ -1360,7 +1380,7 @@ const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
if (!ignoredBases.isEmpty()) {
for (int i = 0; i < ignoredBases.size(); ++i) {
const ClassNode *cn = ignoredBases[i].node;
ClassNode* cn = ignoredBases[i].node;
pn = cn->findPropertyNode(name);
if (pn)
break;
@ -1376,20 +1396,20 @@ const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
finds one, it returns the pointer to that QML element. If
it doesn't find one, it returns null.
*/
const QmlClassNode* ClassNode::findQmlBaseNode() const
QmlClassNode* ClassNode::findQmlBaseNode()
{
const QmlClassNode* result = 0;
QmlClassNode* result = 0;
const QList<RelatedClass>& bases = baseClasses();
if (!bases.isEmpty()) {
for (int i = 0; i < bases.size(); ++i) {
const ClassNode* cn = bases[i].node;
ClassNode* cn = bases[i].node;
if (cn && cn->qmlElement()) {
return cn->qmlElement();
}
}
for (int i = 0; i < bases.size(); ++i) {
const ClassNode* cn = bases[i].node;
ClassNode* cn = bases[i].node;
if (cn) {
result = cn->findQmlBaseNode();
if (result != 0) {
@ -1467,12 +1487,15 @@ QString FakeNode::fullTitle() const
else
return title();
}
else if ((nodeSubtype_ == HeaderFile) || (nodeSubtype_ == Collision)) {
else if (nodeSubtype_ == HeaderFile) {
if (title().isEmpty())
return name();
else
return name() + " - " + title();
}
else if (nodeSubtype_ == Collision) {
return title();
}
else {
return title();
}
@ -1832,21 +1855,6 @@ QString FunctionNode::signature(bool values) const
return s;
}
/*!
Returns true if the node's status is Internal, or if its
parent is a class with internal status.
*/
bool FunctionNode::isInternal() const
{
if (status() == Internal)
return true;
if (parent() && parent()->status() == Internal)
return true;
if (relates() && relates()->status() == Internal)
return true;
return false;
}
/*!
Print some debugging stuff.
*/
@ -1964,25 +1972,6 @@ bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
}
}
/*!
\class TargetNode
*/
/*!
*/
TargetNode::TargetNode(InnerNode *parent, const QString& name)
: LeafNode(Target, parent, name)
{
}
/*!
Returns false because this is a TargetNode.
*/
bool TargetNode::isInnerNode() const
{
return false;
}
bool QmlClassNode::qmlOnly = false;
QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
QMap<QString, QmlClassNode*> QmlClassNode::moduleMap;
@ -1996,7 +1985,7 @@ QMap<QString, QmlClassNode*> QmlClassNode::moduleMap;
*/
QmlClassNode::QmlClassNode(InnerNode *parent,
const QString& name,
const ClassNode* cn)
ClassNode* cn)
: FakeNode(parent, name, QmlClass, Node::ApiPage),
abstract(false),
cnode_(cn),
@ -2132,15 +2121,15 @@ void QmlClassNode::clearCurrentChild()
to output the line in the documentation that specifies the
QML element that a QML element inherits.
*/
void QmlClassNode::resolveInheritance(const Tree* tree)
void QmlClassNode::resolveInheritance(Tree* tree)
{
if (!links().empty() && links().contains(Node::InheritsLink)) {
QPair<QString,QString> linkPair;
linkPair = links()[Node::InheritsLink];
QStringList strList = linkPair.first.split("::");
const Node* n = tree->findNode(strList,Node::Fake);
if (n && (n->subType() == Node::QmlClass || n->subType() == Node::Collision)) {
base_ = static_cast<const FakeNode*>(n);
Node* n = tree->findQmlClassNode(strList);
if (n) {
base_ = static_cast<FakeNode*>(n);
if (base_ && base_->subType() == Node::QmlClass) {
return;
}
@ -2152,7 +2141,7 @@ void QmlClassNode::resolveInheritance(const Tree* tree)
QString qmid = importList_.at(i).first + importList_.at(i).second;
for (int j=0; j<children.size(); ++j) {
if (qmid == children.at(j)->qmlModuleIdentifier()) {
base_ = static_cast<const FakeNode*>(children.at(j));
base_ = static_cast<FakeNode*>(children.at(j));
return;
}
}
@ -2160,7 +2149,7 @@ void QmlClassNode::resolveInheritance(const Tree* tree)
QString qmid = qmlModuleIdentifier();
for (int k=0; k<children.size(); ++k) {
if (qmid == children.at(k)->qmlModuleIdentifier()) {
base_ = static_cast<const QmlClassNode*>(children.at(k));
base_ = static_cast<QmlClassNode*>(children.at(k));
return;
}
}
@ -2169,7 +2158,7 @@ void QmlClassNode::resolveInheritance(const Tree* tree)
return;
}
if (cnode_) {
const QmlClassNode* qcn = cnode_->findQmlBaseNode();
QmlClassNode* qcn = cnode_->findQmlBaseNode();
if (qcn != 0)
base_ = qcn;
}
@ -2302,12 +2291,12 @@ bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
doesn't work for qmlproperty bool PropertyChanges::explicit,
because the tokenizer gets confused on "explicit".
*/
bool QmlPropertyNode::isWritable(const Tree* tree) const
bool QmlPropertyNode::isWritable(Tree* tree)
{
if (wri != Trool_Default)
return fromTrool(wri, false);
const PropertyNode *pn = correspondingProperty(tree);
PropertyNode* pn = correspondingProperty(tree);
if (pn)
return pn->isWritable();
else {
@ -2316,16 +2305,16 @@ bool QmlPropertyNode::isWritable(const Tree* tree) const
}
}
const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) const
PropertyNode* QmlPropertyNode::correspondingProperty(Tree *tree)
{
const PropertyNode *pn;
PropertyNode* pn;
Node* n = parent();
while (n && n->subType() != Node::QmlClass)
n = n->parent();
if (n) {
const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
const ClassNode* cn = qcn->classNode();
QmlClassNode* qcn = static_cast<QmlClassNode*>(n);
ClassNode* cn = qcn->classNode();
if (cn) {
QStringList dotSplit = name().split(QChar('.'));
pn = cn->findPropertyNode(dotSplit[0]);
@ -2335,10 +2324,10 @@ const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) con
// the property group, <group>.<property>.
QStringList path(extractClassName(pn->qualifiedDataType()));
const Node* nn = tree->findNode(path,Class);
Node* nn = tree->findClassNode(path);
if (nn) {
const ClassNode* cn = static_cast<const ClassNode*>(nn);
const PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
ClassNode* cn = static_cast<ClassNode*>(nn);
PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
if (pn2)
return pn2; // Return the property for the QML property.
else
@ -2374,7 +2363,7 @@ const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) con
NameCollisionNode::NameCollisionNode(InnerNode* child)
: FakeNode(child->parent(), child->name(), Collision, Node::NoPageType)
{
setTitle("Name Collisions For: " + child->name());
setTitle("Name Collision: " + child->name());
addCollision(child);
current = 0;
}
@ -2431,7 +2420,7 @@ bool NameCollisionNode::isQmlNode() const
Find any of this collision node's children that has type \a t
and subtype \a st and return a pointer to it.
*/
const InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st) const
InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st)
{
if (current) {
if (current->type() == t && current->subType() == st)
@ -2441,7 +2430,7 @@ const InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st) cons
NodeList::ConstIterator i = cn.begin();
while (i != cn.end()) {
if ((*i)->type() == t && (*i)->subType() == st)
return static_cast<const InnerNode*>(*i);
return static_cast<InnerNode*>(*i);
++i;
}
return 0;
@ -2756,9 +2745,6 @@ QString Node::idForNode() const
case Node::Variable:
str = "var-" + name();
break;
case Node::Target:
str = name();
break;
default:
qDebug() << "ERROR: A case was not handled in Node::idForNode():"
<< "type():" << type() << "subType():" << subType();

View File

@ -83,7 +83,6 @@ public:
Function,
Property,
Variable,
Target,
QmlProperty,
QmlSignal,
QmlSignalHandler,
@ -177,14 +176,17 @@ public:
virtual void setOutputFileName(const QString& ) { }
virtual bool isInnerNode() const = 0;
virtual bool isLeaf() const { return false; }
virtual bool isReimp() const { return false; }
virtual bool isFunction() const { return false; }
virtual bool isQmlNode() const { return false; }
virtual bool isInternal() const { return false; }
virtual bool isQtQuickNode() const { return false; }
virtual bool isAbstract() const { return false; }
virtual bool isQmlPropertyGroup() const { return false; }
virtual bool isCollisionNode() const { return false; }
virtual void setAbstract(bool ) { }
virtual QString title() const { return QString(); }
bool isInternal() const;
bool isIndexNode() const { return indexNodeFlag_; }
Type type() const { return nodeType_; }
virtual SubType subType() const { return NoSubType; }
@ -196,6 +198,8 @@ public:
QString url() const;
virtual QString nameForLists() const { return name_; }
virtual QString outputFileName() const { return QString(); }
virtual void addGroupMember(Node* ) { }
virtual void addQmlModuleMember(Node* ) { }
Access access() const { return access_; }
QString accessString() const;
@ -223,13 +227,13 @@ public:
virtual QString qmlModuleVersion() const { return qmlModuleVersion_; }
virtual QString qmlModuleIdentifier() const { return qmlModuleName_ + qmlModuleVersion_; }
virtual void setQmlModuleName(const QString& );
virtual const ClassNode* classNode() const { return 0; }
virtual ClassNode* classNode() { return 0; }
virtual void clearCurrentChild() { }
virtual const ImportList* importList() const { return 0; }
virtual void setImportList(const ImportList& ) { }
virtual const Node* applyModuleIdentifier(const Node* ) const { return 0; }
const QmlClassNode* qmlClassNode() const;
const ClassNode* declarativeCppNode() const;
QmlClassNode* qmlClassNode();
ClassNode* declarativeCppNode();
const QString& outputSubdirectory() const { return outSubDir_; }
QString fullDocumentName() const;
static QString cleanId(QString str);
@ -290,9 +294,9 @@ class InnerNode : public Node
public:
virtual ~InnerNode();
Node* findNode(const QString& name);
Node* findNode(const QString& name, bool qml);
Node* findNode(const QString& name, Type type);
Node* findChildNodeByName(const QString& name);
Node* findChildNodeByName(const QString& name, bool qml);
Node* findChildNodeByNameAndType(const QString& name, Type type);
void findNodes(const QString& name, QList<Node*>& n);
FunctionNode* findFunctionNode(const QString& name);
FunctionNode* findFunctionNode(const FunctionNode* clone);
@ -306,9 +310,10 @@ public:
void removeFromRelated();
virtual bool isInnerNode() const { return true; }
const Node* findNode(const QString& name) const;
const Node* findNode(const QString& name, bool qml) const;
const Node* findNode(const QString& name, Type type) const;
virtual bool isLeaf() const { return false; }
const Node* findChildNodeByName(const QString& name) const;
const Node* findChildNodeByName(const QString& name, bool qml) const;
const Node* findChildNodeByNameAndType(const QString& name, Type type) const;
const FunctionNode* findFunctionNode(const QString& name) const;
const FunctionNode* findFunctionNode(const FunctionNode* clone) const;
const EnumNode* findEnumNodeForValue(const QString &enumValue) const;
@ -358,7 +363,8 @@ public:
LeafNode();
virtual ~LeafNode() { }
virtual bool isInnerNode() const;
virtual bool isInnerNode() const { return false; }
virtual bool isLeaf() const { return true; }
protected:
LeafNode(Type type, InnerNode* parent, const QString& name);
@ -412,12 +418,12 @@ public:
QString serviceName() const { return sname; }
void setServiceName(const QString& value) { sname = value; }
const QmlClassNode* qmlElement() const { return qmlelement; }
QmlClassNode* qmlElement() { return qmlelement; }
void setQmlElement(QmlClassNode* qcn) { qmlelement = qcn; }
virtual bool isAbstract() const { return abstract; }
virtual void setAbstract(bool b) { abstract = b; }
const PropertyNode* findPropertyNode(const QString& name) const;
const QmlClassNode* findQmlBaseNode() const;
PropertyNode* findPropertyNode(const QString& name);
QmlClassNode* findQmlBaseNode();
private:
QList<RelatedClass> bases;
@ -441,8 +447,8 @@ public:
void setTitle(const QString &title) { title_ = title; }
void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
void addGroupMember(Node* node) { nodeList.append(node); }
void addQmlModuleMember(Node* node) { nodeList.append(node); }
virtual void addGroupMember(Node* node) { nodeList.append(node); }
virtual void addQmlModuleMember(Node* node) { nodeList.append(node); }
SubType subType() const { return nodeSubtype_; }
virtual QString title() const;
@ -453,6 +459,7 @@ public:
const NodeList& qmlModuleMembers() const { return nodeList; }
virtual QString nameForLists() const { return title(); }
virtual void setImageFileName(const QString& ) { }
virtual bool isQmlPropertyGroup() const { return (nodeSubtype_ == QmlPropertyGroup); }
protected:
SubType nodeSubtype_;
@ -470,8 +477,9 @@ public:
virtual void setCurrentChild(InnerNode* child) { current = child; }
virtual void clearCurrentChild() { current = 0; }
virtual bool isQmlNode() const;
virtual bool isCollisionNode() const { return true; }
virtual const Node* applyModuleIdentifier(const Node* origin) const;
const InnerNode* findAny(Node::Type t, Node::SubType st) const;
InnerNode* findAny(Node::Type t, Node::SubType st);
void addCollision(InnerNode* child);
const QMap<QString,QString>& linkTargets() const { return targets; }
void addLinkTarget(const QString& t, const QString& v) { targets.insert(t,v); }
@ -503,11 +511,11 @@ class QmlClassNode : public FakeNode
public:
QmlClassNode(InnerNode* parent,
const QString& name,
const ClassNode* cn);
ClassNode* cn);
virtual ~QmlClassNode();
virtual bool isQmlNode() const { return true; }
virtual bool isQtQuickNode() const { return (qmlModuleName() == QLatin1String("QtQuick")); }
virtual const ClassNode* classNode() const { return cnode_; }
virtual ClassNode* classNode() { return cnode_; }
virtual QString fileBase() const;
virtual void setCurrentChild();
virtual void clearCurrentChild();
@ -516,7 +524,7 @@ public:
virtual bool isAbstract() const { return abstract; }
virtual void setAbstract(bool b) { abstract = b; }
const FakeNode* qmlBase() const { return base_; }
void resolveInheritance(const Tree* tree);
void resolveInheritance(Tree* tree);
static void addInheritedBy(const QString& base, Node* sub);
static void subclasses(const QString& base, NodeList& subs);
static void terminate();
@ -528,8 +536,8 @@ public:
private:
bool abstract;
const ClassNode* cnode_;
const FakeNode* base_;
ClassNode* cnode_;
FakeNode* base_;
ImportList importList_;
};
@ -601,7 +609,7 @@ public:
bool isDefault() const { return isdefault_; }
bool isStored() const { return fromTrool(sto,true); }
bool isDesignable() const { return fromTrool(des,false); }
bool isWritable(const Tree* tree) const;
bool isWritable(Tree* tree);
bool isAttached() const { return attached_; }
bool isReadOnly() const { return (readOnly_ > 0); }
virtual bool isQmlNode() const { return true; }
@ -610,7 +618,7 @@ public:
virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); }
virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
const PropertyNode *correspondingProperty(const Tree *tree) const;
PropertyNode* correspondingProperty(Tree* tree);
const QString& element() const { return static_cast<QmlPropGroupNode*>(parent())->element(); }
void appendQmlPropNode(QmlPropertyNode* p) { qmlPropNodes_.append(p); }
@ -784,7 +792,6 @@ public:
QString signature(bool values = false) const;
const QString& element() const { return parent()->name(); }
bool isAttached() const { return attached_; }
virtual bool isInternal() const;
virtual bool isQmlNode() const {
return ((type() == QmlSignal) ||
(type() == QmlMethod) ||
@ -945,15 +952,6 @@ inline VariableNode::VariableNode(InnerNode* parent, const QString &name)
// nothing.
}
class TargetNode : public LeafNode
{
public:
TargetNode(InnerNode* parent, const QString& name);
virtual ~TargetNode() { }
virtual bool isInnerNode() const;
};
class DitaMapNode : public FakeNode
{
public:

View File

@ -124,18 +124,7 @@ Tree::~Tree()
delete priv;
}
/*!
This function simply calls the const version of itself and
returns the result.
*/
Node* Tree::findNode(const QStringList& path, Node* relative, int findFlags, const Node* self)
{
return const_cast<Node*>(const_cast<const Tree*>(this)->findNode(path,
relative,
findFlags,
self));
}
// 1 calls 2
/*!
Searches the tree for a node that matches the \a path. The
search begins at \a start but can move up the parent chain
@ -162,16 +151,16 @@ const Node* Tree::findNode(const QStringList& path,
return n;
}
// 2 is private; it is only called by 1.
/*!
This code in this function was extracted from the other
version of findNode() that has the same signature without
the last bool parameter \a qml. This function is called
only by that other findNode(). It can be called a second
time if the first call returns null. If \a qml is false,
the search will only match a node that is not a QML node.
If \a qml is true, the search will only match a node that
is a QML node.
*/
This overload function was extracted from the one above that has the
same signature without the last bool parameter, \a qml. This version
is called only by that other one. It is therefore private. It can
be called a second time by that other version, if the first call
returns null. If \a qml is false, the search will only match a node
that is not a QML node. If \a qml is true, the search will only
match a node that is a QML node.
*/
const Node* Tree::findNode(const QStringList& path,
const Node* start,
int findFlags,
@ -204,7 +193,7 @@ const Node* Tree::findNode(const QStringList& path,
if (node == 0 || !node->isInnerNode())
break;
const Node* next = static_cast<const InnerNode*>(node)->findNode(path.at(i), qml);
const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml);
if (!next && (findFlags & SearchEnumValues) && i == path.size()-1)
next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
@ -212,10 +201,9 @@ const Node* Tree::findNode(const QStringList& path,
if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) {
next = static_cast<const InnerNode*>(baseClass)->findNode(path.at(i));
next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)
->findEnumNodeForValue(path.at(i));
next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
if (next)
break;
}
@ -238,45 +226,6 @@ const Node* Tree::findNode(const QStringList& path,
return 0;
}
/*!
Find the node with the specified \a path name of the
specified \a type.
*/
Node* Tree::findNode(const QStringList& path,
Node::Type type,
Node* relative,
int findFlags)
{
return const_cast<Node*>(const_cast<const Tree*>(this)->findNode(path,
type,
relative,
findFlags));
}
/*!
This function just calls the const version of itself and returns
a pointer to the QML class node, or null.
*/
QmlClassNode* Tree::findQmlClassNode(const QString& module, const QString& element)
{
return const_cast<QmlClassNode*>(const_cast<const Tree*>(this)->findQmlClassNode(module, element));
}
/*!
Find the node with the specified \a path name of the
specified \a type.
*/
const Node* Tree::findNode(const QStringList& path,
Node::Type type,
const Node* relative,
int findFlags) const
{
const Node* node = findNode(path, relative, findFlags);
if (node != 0 && node->type() == type)
return node;
return 0;
}
/*!
Find the QML class node for the specified \a module and \a name
identifiers. The \a module identifier may be empty. If the module
@ -286,17 +235,17 @@ const Node* Tree::findNode(const QStringList& path,
child is a QML class. If the collision node does not have a child
that is a QML class node, return 0.
*/
const QmlClassNode* Tree::findQmlClassNode(const QString& module, const QString& name) const
QmlClassNode* Tree::findQmlClassNode(const QString& module, const QString& name)
{
if (module.isEmpty()) {
const Node* n = findNode(QStringList(name), Node::Fake);
Node* n = findQmlClassNode(QStringList(name));
if (n) {
if (n->subType() == Node::QmlClass)
return static_cast<const QmlClassNode*>(n);
return static_cast<QmlClassNode*>(n);
else if (n->subType() == Node::Collision) {
const NameCollisionNode* ncn;
ncn = static_cast<const NameCollisionNode*>(n);
return static_cast<const QmlClassNode*>(ncn->findAny(Node::Fake,Node::QmlClass));
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
return static_cast<QmlClassNode*>(ncn->findAny(Node::Fake,Node::QmlClass));
}
}
return 0;
@ -397,16 +346,15 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = ((InnerNode*) node)->findFunctionNode(path.at(i));
else
next = ((InnerNode*) node)->findNode(path.at(i));
next = ((InnerNode*) node)->findChildNodeByName(path.at(i));
if (!next && node->type() == Node::Class &&
(findFlags & SearchBaseClasses)) {
if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
foreach (const Node* baseClass, baseClasses) {
if (i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findFunctionNode(path.at(i));
else
next = static_cast<const InnerNode*>(baseClass)->findNode(path.at(i));
next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
if (next)
break;
@ -474,6 +422,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& parentPath,
return ((InnerNode*)parent)->findFunctionNode(clone);
}
}
//findNode(parameter.leftType().split("::"), 0, SearchBaseClasses|NonFunction);
static const int NumSuffixes = 3;
static const char* const suffixes[NumSuffixes] = { "", "s", "es" };
@ -768,17 +717,12 @@ void Tree::resolveInheritance(int pass, ClassNode* classe)
QList<InheritanceBound> bounds = priv->unresolvedInheritanceMap[classe];
QList<InheritanceBound>::ConstIterator b = bounds.begin();
while (b != bounds.end()) {
ClassNode* baseClass = (ClassNode*)findNode((*b).basePath,
Node::Class);
if (!baseClass && (*b).parent) {
baseClass = (ClassNode*)findNode((*b).basePath,
Node::Class,
(*b).parent);
Node* n = findClassNode((*b).basePath);
if (!n && (*b).parent) {
n = findClassNode((*b).basePath, (*b).parent);
}
if (baseClass) {
classe->addBaseClass((*b).access,
baseClass,
(*b).dataTypeWithTemplateArgs);
if (n) {
classe->addBaseClass((*b).access, static_cast<ClassNode*>(n), (*b).dataTypeWithTemplateArgs);
}
++b;
}
@ -814,11 +758,9 @@ void Tree::resolveGroups()
if (i.value()->access() == Node::Private)
continue;
FakeNode* fake =
static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake));
if (fake && fake->subType() == Node::Group) {
fake->addGroupMember(i.value());
}
Node* n = findGroupNode(QStringList(i.key()));
if (n)
n->addGroupMember(i.value());
}
}
@ -830,11 +772,9 @@ void Tree::resolveQmlModules()
{
NodeMultiMap::const_iterator i;
for (i = priv->qmlModuleMap.constBegin(); i != priv->qmlModuleMap.constEnd(); ++i) {
FakeNode* fake =
static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake));
if (fake && fake->subType() == Node::QmlModule) {
fake->addQmlModuleMember(i.value());
}
Node* n = findQmlModuleNode(QStringList(i.key()));
if (n)
n->addQmlModuleMember(i.value());
}
}
@ -978,15 +918,13 @@ FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classe,
/*!
*/
void Tree::fixPropertyUsingBaseClasses(ClassNode* classe,
PropertyNode* property)
void Tree::fixPropertyUsingBaseClasses(ClassNode* classe, PropertyNode* property)
{
QList<RelatedClass>::const_iterator r = classe->baseClasses().begin();
while (r != classe->baseClasses().end()) {
PropertyNode* baseProperty =
static_cast<PropertyNode*>(r->node->findNode(property->name(),
Node::Property));
if (baseProperty) {
Node* n = r->node->findChildNodeByNameAndType(property->name(), Node::Property);
if (n) {
PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
fixPropertyUsingBaseClasses(r->node, baseProperty);
property->setOverriddenFrom(baseProperty);
}
@ -1414,10 +1352,9 @@ void Tree::resolveIndex()
foreach (pair, priv->basesList) {
foreach (const QString& base, pair.second.split(QLatin1Char(','))) {
Node* baseClass = root()->findNode(base, Node::Class);
if (baseClass) {
pair.first->addBaseClass(Node::Public,
static_cast<ClassNode*>(baseClass));
Node* n = root()->findChildNodeByNameAndType(base, Node::Class);
if (n) {
pair.first->addBaseClass(Node::Public, static_cast<ClassNode*>(n));
}
}
}
@ -1425,9 +1362,9 @@ void Tree::resolveIndex()
QPair<FunctionNode*,QString> relatedPair;
foreach (relatedPair, priv->relatedList) {
Node* classNode = root()->findNode(relatedPair.second, Node::Class);
if (classNode)
relatedPair.first->setRelates(static_cast<ClassNode*>(classNode));
Node* n = root()->findChildNodeByNameAndType(relatedPair.second, Node::Class);
if (n)
relatedPair.first->setRelates(static_cast<ClassNode*>(n));
}
}
@ -1437,8 +1374,8 @@ void Tree::resolveIndex()
false.
*/
bool Tree::generateIndexSection(QXmlStreamWriter& writer,
const Node* node,
bool generateInternalNodes) const
Node* node,
bool generateInternalNodes)
{
if (!node->url().isEmpty())
return false;
@ -1473,9 +1410,6 @@ bool Tree::generateIndexSection(QXmlStreamWriter& writer,
case Node::Variable:
nodeName = "variable";
break;
case Node::Target:
nodeName = "target";
break;
case Node::QmlProperty:
nodeName = "qmlproperty";
break;
@ -1716,7 +1650,7 @@ bool Tree::generateIndexSection(QXmlStreamWriter& writer,
case Node::QmlProperty:
{
const QmlPropertyNode* qpn = static_cast<const QmlPropertyNode*>(node);
QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
writer.writeAttribute("type", qpn->dataType());
writer.writeAttribute("attached", qpn->isAttached() ? "true" : "false");
writer.writeAttribute("writable", qpn->isWritable(this) ? "true" : "false");
@ -1840,22 +1774,18 @@ bool Tree::generateIndexSection(QXmlStreamWriter& writer,
foreach (const Parameter& parameter, functionNode->parameters()) {
QString leftType = parameter.leftType();
const Node* leftNode =
const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
Node::Typedef, 0, SearchBaseClasses|NonFunction);
if (!leftNode) {
leftNode = const_cast<Tree*>(this)->findNode(
parameter.leftType().split("::"), Node::Typedef,
const Node* leftNode = const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
0, SearchBaseClasses|NonFunction);
if (!leftNode || leftNode->type() != Node::Typedef) {
leftNode = const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
node->parent(), SearchBaseClasses|NonFunction);
}
if (leftNode) {
if (leftNode && leftNode->type() == Node::Typedef) {
if (leftNode->type() == Node::Typedef) {
const TypedefNode* typedefNode =
static_cast<const TypedefNode*>(leftNode);
if (typedefNode->associatedEnum()) {
leftType = "QFlags<" +
typedefNode->associatedEnum()->fullDocumentName() +
QLatin1Char('>');
leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() + QLatin1Char('>');
}
}
else
@ -1973,8 +1903,8 @@ bool compareNodes(const Node* n1, const Node* n2)
they will be omitted.
*/
void Tree::generateIndexSections(QXmlStreamWriter& writer,
const Node* node,
bool generateInternalNodes) const
Node* node,
bool generateInternalNodes)
{
if (generateIndexSection(writer, node, generateInternalNodes)) {
@ -1984,7 +1914,7 @@ void Tree::generateIndexSections(QXmlStreamWriter& writer,
NodeList cnodes = inner->childNodes();
qSort(cnodes.begin(), cnodes.end(), compareNodes);
foreach (const Node* child, cnodes) {
foreach (Node* child, cnodes) {
/*
Don't generate anything for a QML property group node.
It is just a place holder for a collection of QML property
@ -1993,7 +1923,7 @@ void Tree::generateIndexSections(QXmlStreamWriter& writer,
*/
if (child->subType() == Node::QmlPropertyGroup) {
const InnerNode* pgn = static_cast<const InnerNode*>(child);
foreach (const Node* c, pgn->childNodes()) {
foreach (Node* c, pgn->childNodes()) {
generateIndexSections(writer, c, generateInternalNodes);
}
}
@ -2018,7 +1948,7 @@ void Tree::generateIndexSections(QXmlStreamWriter& writer,
void Tree::generateIndex(const QString& fileName,
const QString& url,
const QString& title,
bool generateInternalNodes) const
bool generateInternalNodes)
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
@ -2047,8 +1977,7 @@ void Tree::generateIndex(const QString& fileName,
specified, returning true if an element was written; otherwise returns
false.
*/
void Tree::generateTagFileCompounds(QXmlStreamWriter& writer,
const InnerNode* inner) const
void Tree::generateTagFileCompounds(QXmlStreamWriter& writer, const InnerNode* inner)
{
foreach (const Node* node, inner->childNodes()) {
@ -2068,7 +1997,6 @@ void Tree::generateTagFileCompounds(QXmlStreamWriter& writer,
case Node::Property:
case Node::Function:
case Node::Variable:
case Node::Target:
default:
continue;
}
@ -2130,8 +2058,7 @@ void Tree::generateTagFileCompounds(QXmlStreamWriter& writer,
/*!
*/
void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
const InnerNode* inner) const
void Tree::generateTagFileMembers(QXmlStreamWriter& writer, const InnerNode* inner)
{
foreach (const Node* node, inner->childNodes()) {
@ -2164,7 +2091,6 @@ void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
nodeName = "class";
break;
case Node::Variable:
case Node::Target:
default:
continue;
}
@ -2247,18 +2173,15 @@ void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
foreach (const Parameter& parameter, functionNode->parameters()) {
QString leftType = parameter.leftType();
const Node* leftNode = const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
Node::Typedef, 0, SearchBaseClasses|NonFunction);
if (!leftNode) {
leftNode = const_cast<Tree*>(this)->findNode(
parameter.leftType().split("::"), Node::Typedef,
node->parent(), SearchBaseClasses|NonFunction);
0, SearchBaseClasses|NonFunction);
if (!leftNode || leftNode->type() != Node::Typedef) {
leftNode = const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
node->parent(), SearchBaseClasses|NonFunction);
}
if (leftNode) {
if (leftNode && leftNode->type() == Node::Typedef) {
const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode);
if (typedefNode->associatedEnum()) {
leftType = "QFlags<" +
typedefNode->associatedEnum()->fullDocumentName() +
QLatin1Char('>');
leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() + QLatin1Char('>');
}
}
signatureList.append(leftType + QLatin1Char(' ') + parameter.name());
@ -2324,7 +2247,6 @@ void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
break;
case Node::Variable:
case Node::Target:
default:
break;
}
@ -2332,8 +2254,9 @@ void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
}
/*!
Writes a tag file named \a fileName.
*/
void Tree::generateTagFile(const QString& fileName) const
void Tree::generateTagFile(const QString& fileName)
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text))
@ -2366,4 +2289,239 @@ void Tree::addExternalLink(const QString& url, const Node* relative)
fakeNode->setDoc(doc);
}
/*!
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{Fake}.
*/
Node* Tree::findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
Node* start,
bool acceptCollision)
{
if (!start)
start = const_cast<NamespaceNode*>(root());
Node* result = findNodeRecursive(path, 0, start, type, subtype, acceptCollision);
return result;
}
#if 0
if (result)
qDebug() << "FOUND:" << path << Node::nodeTypeString(type)
<< Node::nodeSubtypeString(subtype);
else
qDebug() << "NOT FOUND:" << path << Node::nodeTypeString(type)
<< Node::nodeSubtypeString(subtype);
#endif
/*!
Recursive search for a node identified by \a path. Each
path element is a name. \a pathIndex specifies the index
of the name in \a path to try to match. \a start is the
node whose children shoulod be searched for one that has
that name. Each time a match is found, increment the
\a pathIndex and call this function recursively.
If the end of the path is reached (i.e. if a matching
node is found for each name in the \a path), the \a type
must match the type of the last matching node, and if the
type is \e{Fake}, the \a subtype must match as well.
If the algorithm is successful, the pointer to the final
node is returned. Otherwise 0 is returned.
*/
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision)
{
if (!start || path.isEmpty())
return 0; // no place to start, or nothing to search for.
if (start->isLeaf()) {
if (pathIndex >= path.size())
return start; // found a match.
return 0; // premature leaf
}
if (pathIndex >= path.size())
return 0; // end of search path.
InnerNode* current = static_cast<InnerNode*>(start);
const NodeList& children = current->childNodes();
const QString& name = path.at(pathIndex);
for (int i=0; i<children.size(); ++i) {
Node* n = children.at(i);
if (!n)
continue;
if (n->isQmlPropertyGroup()) {
if (type == Node::QmlProperty) {
n = findNodeRecursive(path, pathIndex, n, type, subtype);
if (n)
return n;
}
}
else if (n->name() == name) {
if (pathIndex+1 >= path.size()) {
if (n->type() == type) {
if (type == Node::Fake) {
if (n->subType() == subtype)
return n;
else if (n->subType() == Node::Collision && acceptCollision)
return n;
else if (subtype == Node::NoSubType)
return n; // don't care what subtype is.
return 0;
}
else
return n;
}
else if (n->isCollisionNode()) {
if (acceptCollision)
return n;
return n = findNodeRecursive(path, pathIndex, n, type, subtype);
if (n)
return n;
}
else
return 0;
}
else { // Not at the end of the path.
n = findNodeRecursive(path, pathIndex+1, n, type, subtype);
if (n)
return n;
}
}
}
return 0;
}
/*!
Find the Enum type node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only an Enum type node named \a path is
acceptible. If one is not found, 0 is returned.
*/
EnumNode* Tree::findEnumNode(const QStringList& path, Node* start)
{
return static_cast<EnumNode*>(findNodeRecursive(path, 0, start, Node::Enum, Node::NoSubType));
}
/*!
Find the C++ class node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a C++ class node named \a path is
acceptible. If one is not found, 0 is returned.
*/
ClassNode* Tree::findClassNode(const QStringList& path, Node* start)
{
return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType));
}
/*!
Find the Qml class node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a Qml class node named \a path is
acceptible. If one is not found, 0 is returned.
*/
QmlClassNode* Tree::findQmlClassNode(const QStringList& path, Node* start)
{
/*
If the path contains one or two double colons ("::"),
check first to see if the first two path strings refer
to a QML element. If yes, that reference identifies a
QML class node.
*/
if (path.size() >= 2) {
QmlClassNode* qcn = QmlClassNode::moduleMap.value(path[0]+ "::" +path[1]);
if (qcn)
return qcn;
}
return static_cast<QmlClassNode*>(findNodeRecursive(path, 0, start, Node::Fake, Node::QmlClass));
}
/*!
Find the Namespace node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a Namespace node named \a path is
acceptible. If one is not found, 0 is returned.
*/
NamespaceNode* Tree::findNamespaceNode(const QStringList& path, Node* start)
{
return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType));
}
/*!
Find the Group node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a Group node named \a path is
acceptible. If one is not found, 0 is returned.
*/
FakeNode* Tree::findGroupNode(const QStringList& path, Node* start)
{
return static_cast<FakeNode*>(findNodeRecursive(path, 0, start, Node::Fake, Node::Group));
}
/*!
Find the Qml module node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
at the root of the tree. Only a Qml module node named \a path is
acceptible. If one is not found, 0 is returned.
*/
FakeNode* Tree::findQmlModuleNode(const QStringList& path, Node* start)
{
return static_cast<FakeNode*>(findNodeRecursive(path, 0, start, Node::Fake, Node::QmlModule));
}
QT_END_NAMESPACE
#if 0
const Node* Tree::findNodeXXX(const QStringList& path, bool qml) const
{
const Node* current = root();
do {
const Node* node = current;
int i;
int start_idx = 0;
/*
If the path contains one or two double colons ("::"),
check first to see if the first two path strings refer
to a QML element. If yes, that reference identifies a
QML class node.
*/
if (qml && path.size() >= 2) {
QmlClassNode* qcn = QmlClassNode::moduleMap.value(path[0]+ "::" +path[1]);
if (qcn) {
node = qcn;
if (path.size() == 2)
return node;
start_idx = 2;
}
}
for (i = start_idx; i < path.size(); ++i) {
if (node == 0 || !node->isInnerNode())
break;
const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml);
node = next;
}
if (node && i == path.size()) {
if (node->subType() != Node::QmlPropertyGroup) {
if (node->subType() == Node::Collision) {
node = node->applyModuleIdentifier(start);
}
return node;
}
}
current = current->parent();
} while (current);
return 0;
}
#endif

View File

@ -65,19 +65,39 @@ public:
Tree();
~Tree();
Node* findNode(const QStringList &path,
Node* relative=0,
int findFlags=0,
const Node* self=0);
Node* findNode(const QStringList &path,
Node::Type type,
Node* relative = 0,
int findFlags = 0);
EnumNode* findEnumNode(const QStringList& path, Node* start = 0);
ClassNode* findClassNode(const QStringList& path, Node* start = 0);
QmlClassNode* findQmlClassNode(const QStringList& path, Node* start = 0);
NamespaceNode* findNamespaceNode(const QStringList& path, Node* start = 0);
FakeNode* findGroupNode(const QStringList& path, Node* start = 0);
FakeNode* findQmlModuleNode(const QStringList& path, Node* start = 0);
Node* findNodeByNameAndType(const QStringList& path,
Node::Type type,
Node::SubType subtype,
Node* start,
bool acceptCollision = false);
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
Node::Type type,
Node::SubType subtype,
bool acceptCollision = false);
const Node* findNode(const QStringList &path,
const Node* relative = 0,
int findFlags = 0,
const Node* self=0) const;
private:
const Node* findNode(const QStringList& path,
const Node* start,
int findFlags,
const Node* self,
bool qml) const;
public:
QmlClassNode* findQmlClassNode(const QString& module, const QString& name);
NameCollisionNode* checkForCollision(const QString& name) const;
NameCollisionNode* findCollisionNode(const QString& name) const;
@ -111,17 +131,8 @@ public:
void fixInheritance(NamespaceNode *rootNode = 0);
void setVersion(const QString &version) { vers = version; }
NamespaceNode *root() { return &roo; }
QString version() const { return vers; }
const Node* findNode(const QStringList &path,
const Node* relative = 0,
int findFlags = 0,
const Node* self=0) const;
const Node* findNode(const QStringList &path,
Node::Type type, const
Node* relative = 0,
int findFlags = 0) const;
const QmlClassNode* findQmlClassNode(const QString& module, const QString& element) const;
const FunctionNode *findFunctionNode(const QStringList &path,
const Node *relative = 0,
int findFlags = 0) const;
@ -134,19 +145,17 @@ public:
Atom *findTarget(const QString &target, const Node *node) const;
const NamespaceNode *root() const { return &roo; }
void readIndexes(const QStringList &indexFiles);
bool generateIndexSection(QXmlStreamWriter &writer, const Node *node,
bool generateInternalNodes = false) const;
void generateIndexSections(QXmlStreamWriter &writer, const Node *node,
bool generateInternalNodes = false) const;
bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
void generateIndex(const QString &fileName,
const QString &url,
const QString &title,
bool generateInternalNodes = false) const;
bool generateInternalNodes = false);
void generateTagFileCompounds(QXmlStreamWriter &writer,
const InnerNode *inner) const;
const InnerNode *inner);
void generateTagFileMembers(QXmlStreamWriter &writer,
const InnerNode *inner) const;
void generateTagFile(const QString &fileName) const;
const InnerNode *inner);
void generateTagFile(const QString &fileName);
void addExternalLink(const QString &url, const Node *relative);
QString fullDocumentLocation(const Node *node) const;
void resolveQmlInheritance();