Files correlati : cg0.exe cg0700a.msk cg0700b.msk cg3.exe cg4.exe Bug : Commento: Merge 1.0 libraries
1808 lines
44 KiB
C++
1808 lines
44 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
/*
|
|
node.cpp
|
|
*/
|
|
|
|
#include "node.h"
|
|
#include "tree.h"
|
|
#include "codemarker.h"
|
|
#include <QUuid>
|
|
#include <qdebug.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
ExampleNodeMap ExampleNode::exampleNodeMap;
|
|
|
|
/*!
|
|
\class Node
|
|
\brief The Node class is a node in the Tree.
|
|
|
|
A Node represents a class or function or something else
|
|
from the source code..
|
|
*/
|
|
|
|
/*!
|
|
When this Node is destroyed, if it has a parent Node, it
|
|
removes itself from the parent node's child list.
|
|
*/
|
|
Node::~Node()
|
|
{
|
|
if (par)
|
|
par->removeChild(this);
|
|
if (rel)
|
|
rel->removeRelated(this);
|
|
}
|
|
|
|
/*!
|
|
Sets this Node's Doc to \a doc. If \a replace is false and
|
|
this Node already has a Doc, a warning is reported that the
|
|
Doc is being overridden, and it reports where the previous
|
|
Doc was found. If \a replace is true, the Doc is replaced
|
|
silently.
|
|
*/
|
|
void Node::setDoc(const Doc& doc, bool replace)
|
|
{
|
|
if (!d.isEmpty() && !replace) {
|
|
doc.location().warning(tr("Overrides a previous doc"));
|
|
d.location().warning(tr("(The previous doc is here)"));
|
|
}
|
|
d = doc;
|
|
}
|
|
|
|
/*!
|
|
Construct a node with the given \a type and having the
|
|
given \a parent and \a name. The new node is added to the
|
|
parent's child list.
|
|
*/
|
|
Node::Node(Type type, InnerNode *parent, const QString& name)
|
|
: typ(type),
|
|
acc(Public),
|
|
saf(UnspecifiedSafeness),
|
|
pageTyp(NoPageType),
|
|
sta(Commendable),
|
|
par(parent),
|
|
rel(0),
|
|
nam(name)
|
|
{
|
|
if (par)
|
|
par->addChild(this);
|
|
}
|
|
|
|
/*!
|
|
Returns the node's URL.
|
|
*/
|
|
QString Node::url() const
|
|
{
|
|
return u;
|
|
}
|
|
|
|
/*!
|
|
Sets the node's URL to \a url
|
|
*/
|
|
void Node::setUrl(const QString &url)
|
|
{
|
|
u = url;
|
|
}
|
|
|
|
void Node::setPageType(const QString& t)
|
|
{
|
|
if ((t == "API") || (t == "api"))
|
|
pageTyp = ApiPage;
|
|
else if (t == "article")
|
|
pageTyp = ArticlePage;
|
|
else if (t == "example")
|
|
pageTyp = ExamplePage;
|
|
}
|
|
|
|
/*!
|
|
Sets the pointer to the node that this node relates to.
|
|
*/
|
|
void Node::setRelates(InnerNode *pseudoParent)
|
|
{
|
|
if (rel)
|
|
rel->removeRelated(this);
|
|
rel = pseudoParent;
|
|
pseudoParent->related.append(this);
|
|
}
|
|
|
|
/*!
|
|
This function creates a pair that describes a link.
|
|
The pair is composed from \a link and \a desc. The
|
|
\a linkType is the map index the pair is filed under.
|
|
*/
|
|
void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
|
|
{
|
|
QPair<QString,QString> linkPair;
|
|
linkPair.first = link;
|
|
linkPair.second = desc;
|
|
linkMap[linkType] = linkPair;
|
|
}
|
|
|
|
/*!
|
|
Sets the information about the project and version a node was introduced
|
|
in. The string is simplified, removing excess whitespace before being
|
|
stored.
|
|
*/
|
|
void Node::setSince(const QString &since)
|
|
{
|
|
sinc = since.simplified();
|
|
}
|
|
|
|
/*!
|
|
Returns a string representing the access specifier.
|
|
*/
|
|
QString Node::accessString() const
|
|
{
|
|
switch (acc) {
|
|
case Protected:
|
|
return "protected";
|
|
case Private:
|
|
return "private";
|
|
case Public:
|
|
default:
|
|
break;
|
|
}
|
|
return "public";
|
|
}
|
|
|
|
/*!
|
|
Extract a class name from the type \a string and return it.
|
|
*/
|
|
QString Node::extractClassName(const QString &string) const
|
|
{
|
|
QString result;
|
|
for (int i=0; i<=string.size(); ++i) {
|
|
QChar ch;
|
|
if (i != string.size())
|
|
ch = string.at(i);
|
|
|
|
QChar lower = ch.toLower();
|
|
if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
|
|
ch.digitValue() >= 0 ||
|
|
ch == QLatin1Char('_') ||
|
|
ch == QLatin1Char(':')) {
|
|
result += ch;
|
|
}
|
|
else if (!result.isEmpty()) {
|
|
if (result != QLatin1String("const"))
|
|
return result;
|
|
result.clear();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*!
|
|
Returns a string representing the access specifier.
|
|
*/
|
|
QString RelatedClass::accessString() const
|
|
{
|
|
switch (access) {
|
|
case Node::Protected:
|
|
return "protected";
|
|
case Node::Private:
|
|
return "private";
|
|
case Node::Public:
|
|
default:
|
|
break;
|
|
}
|
|
return "public";
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Node::Status Node::inheritedStatus() const
|
|
{
|
|
Status parentStatus = Commendable;
|
|
if (par)
|
|
parentStatus = par->inheritedStatus();
|
|
return (Status)qMin((int)sta, (int)parentStatus);
|
|
}
|
|
|
|
/*!
|
|
Returns the thread safeness value for whatever this node
|
|
represents. But if this node has a parent and the thread
|
|
safeness value of the parent is the same as the thread
|
|
safeness value of this node, what is returned is the
|
|
value \c{UnspecifiedSafeness}. Why?
|
|
*/
|
|
Node::ThreadSafeness Node::threadSafeness() const
|
|
{
|
|
if (par && saf == par->inheritedThreadSafeness())
|
|
return UnspecifiedSafeness;
|
|
return saf;
|
|
}
|
|
|
|
/*!
|
|
If this node has a parent, the parent's thread safeness
|
|
value is returned. Otherwise, this node's thread safeness
|
|
value is returned. Why?
|
|
*/
|
|
Node::ThreadSafeness Node::inheritedThreadSafeness() const
|
|
{
|
|
if (par && saf == UnspecifiedSafeness)
|
|
return par->inheritedThreadSafeness();
|
|
return saf;
|
|
}
|
|
|
|
/*!
|
|
Returns the sanitized file name without the path.
|
|
If the the file is an html file, the html suffix
|
|
is removed. Why?
|
|
*/
|
|
QString Node::fileBase() const
|
|
{
|
|
QString base = name();
|
|
if (base.endsWith(".html"))
|
|
base.chop(5);
|
|
base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
|
|
base = base.trimmed();
|
|
base.replace(" ", "-");
|
|
return base.toLower();
|
|
}
|
|
|
|
/*!
|
|
Returns this node's Universally Unique IDentifier as a
|
|
QString. Creates the UUID first, if it has not been created.
|
|
*/
|
|
QString Node::guid() const
|
|
{
|
|
if (uuid.isEmpty()) {
|
|
QUuid quuid = QUuid::createUuid();
|
|
QString t = quuid.toString();
|
|
uuid = "id-" + t.mid(1,t.length()-2);
|
|
}
|
|
return uuid;
|
|
}
|
|
|
|
/*!
|
|
Composes a string to be used as an href attribute in DITA
|
|
XML. It is composed of the file name and the UUID separated
|
|
by a '#'. If this node is a class node, the file name is
|
|
taken from this node; if this node is a function node, the
|
|
file name is taken from the parent node of this node.
|
|
*/
|
|
QString Node::ditaXmlHref()
|
|
{
|
|
QString href;
|
|
if ((type() == Function) ||
|
|
(type() == Property) ||
|
|
(type() == Variable)) {
|
|
href = parent()->fileBase();
|
|
}
|
|
else {
|
|
href = fileBase();
|
|
}
|
|
if (!href.endsWith(".xml"))
|
|
href += ".xml";
|
|
return href + "#" + guid();
|
|
}
|
|
|
|
/*!
|
|
If this node is a QML class node, return a pointer to it.
|
|
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
|
|
{
|
|
if (isQmlNode()) {
|
|
const 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 0;
|
|
}
|
|
|
|
/*!
|
|
If this node is a QML node, find its QML class node,
|
|
and return a pointer to the C++ class node from the
|
|
QML class node. That pointer will be null if the QML
|
|
class node is a component. It will be non-null if
|
|
the QML class node is a QML element.
|
|
*/
|
|
const ClassNode* Node::declarativeCppNode() const
|
|
{
|
|
const QmlClassNode* qcn = qmlClassNode();
|
|
if (qcn)
|
|
return qcn->classNode();
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\class InnerNode
|
|
*/
|
|
|
|
/*!
|
|
The inner node destructor deletes the children and removes
|
|
this node from its related nodes.
|
|
*/
|
|
InnerNode::~InnerNode()
|
|
{
|
|
deleteChildren();
|
|
removeFromRelated();
|
|
}
|
|
|
|
/*!
|
|
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.
|
|
*/
|
|
Node *InnerNode::findNode(const QString& name)
|
|
{
|
|
Node *node = childMap.value(name);
|
|
if (node && node->subType() != QmlPropertyGroup)
|
|
return node;
|
|
if ((type() == Fake) && (subType() == QmlClass)) {
|
|
for (int i=0; i<children.size(); ++i) {
|
|
Node* n = children.at(i);
|
|
if (n->subType() == QmlPropertyGroup) {
|
|
node = static_cast<InnerNode*>(n)->findNode(name);
|
|
if (node)
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
return primaryFunctionMap.value(name);
|
|
}
|
|
|
|
/*!
|
|
Same as the other findNode(), but if the node with the
|
|
specified \a name is not of the specified \a type, return
|
|
0.
|
|
*/
|
|
Node *InnerNode::findNode(const QString& name, Type type)
|
|
{
|
|
if (type == Function) {
|
|
return primaryFunctionMap.value(name);
|
|
}
|
|
else {
|
|
Node *node = childMap.value(name);
|
|
if (node && node->type() == type) {
|
|
return node;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Find the function node in this node for the function named \a name.
|
|
*/
|
|
FunctionNode *InnerNode::findFunctionNode(const QString& name)
|
|
{
|
|
return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
|
|
}
|
|
|
|
/*!
|
|
Find the function node in this node that has the same name as \a clone.
|
|
*/
|
|
FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
|
|
{
|
|
QMap<QString, Node *>::ConstIterator c =
|
|
primaryFunctionMap.find(clone->name());
|
|
if (c != primaryFunctionMap.end()) {
|
|
if (isSameSignature(clone, (FunctionNode *) *c)) {
|
|
return (FunctionNode *) *c;
|
|
}
|
|
else if (secondaryFunctionMap.contains(clone->name())) {
|
|
const NodeList& secs = secondaryFunctionMap[clone->name()];
|
|
NodeList::ConstIterator s = secs.begin();
|
|
while (s != secs.end()) {
|
|
if (isSameSignature(clone, (FunctionNode *) *s))
|
|
return (FunctionNode *) *s;
|
|
++s;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
Returns the list of keys from the primary function map.
|
|
*/
|
|
QStringList InnerNode::primaryKeys()
|
|
{
|
|
QStringList t;
|
|
QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
|
|
while (i != primaryFunctionMap.end()) {
|
|
t.append(i.key());
|
|
++i;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/*!
|
|
Returns the list of keys from the secondary function map.
|
|
*/
|
|
QStringList InnerNode::secondaryKeys()
|
|
{
|
|
QStringList t;
|
|
QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
|
|
while (i != secondaryFunctionMap.end()) {
|
|
t.append(i.key());
|
|
++i;
|
|
}
|
|
return t;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::setOverload(const FunctionNode *func, bool overlode)
|
|
{
|
|
Node *node = (Node *) func;
|
|
Node *&primary = primaryFunctionMap[func->name()];
|
|
|
|
if (secondaryFunctionMap.contains(func->name())) {
|
|
NodeList& secs = secondaryFunctionMap[func->name()];
|
|
if (overlode) {
|
|
if (primary == node) {
|
|
primary = secs.first();
|
|
secs.erase(secs.begin());
|
|
secs.append(node);
|
|
}
|
|
else {
|
|
secs.removeAll(node);
|
|
secs.append(node);
|
|
}
|
|
}
|
|
else {
|
|
if (primary != node) {
|
|
secs.removeAll(node);
|
|
secs.prepend(primary);
|
|
primary = node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Mark all child nodes that have no documentation as having
|
|
private access and internal status. qdoc will then ignore
|
|
them for documentation purposes.
|
|
*/
|
|
void InnerNode::makeUndocumentedChildrenInternal()
|
|
{
|
|
foreach (Node *child, childNodes()) {
|
|
if (child->doc().isEmpty()) {
|
|
child->setAccess(Node::Private);
|
|
child->setStatus(Node::Internal);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::normalizeOverloads()
|
|
{
|
|
QMap<QString, Node *>::Iterator p1 = primaryFunctionMap.begin();
|
|
while (p1 != primaryFunctionMap.end()) {
|
|
FunctionNode *primaryFunc = (FunctionNode *) *p1;
|
|
if (secondaryFunctionMap.contains(primaryFunc->name()) &&
|
|
(primaryFunc->status() != Commendable ||
|
|
primaryFunc->access() == Private)) {
|
|
|
|
NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
|
|
NodeList::ConstIterator s = secs.begin();
|
|
while (s != secs.end()) {
|
|
FunctionNode *secondaryFunc = (FunctionNode *) *s;
|
|
|
|
// Any non-obsolete, non-compatibility, non-private functions
|
|
// (i.e, visible functions) are preferable to the primary
|
|
// function.
|
|
|
|
if (secondaryFunc->status() == Commendable &&
|
|
secondaryFunc->access() != Private) {
|
|
|
|
*p1 = secondaryFunc;
|
|
int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
|
|
secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
|
|
break;
|
|
}
|
|
++s;
|
|
}
|
|
}
|
|
++p1;
|
|
}
|
|
|
|
QMap<QString, Node *>::ConstIterator p = primaryFunctionMap.begin();
|
|
while (p != primaryFunctionMap.end()) {
|
|
FunctionNode *primaryFunc = (FunctionNode *) *p;
|
|
if (primaryFunc->isOverload())
|
|
primaryFunc->ove = false;
|
|
if (secondaryFunctionMap.contains(primaryFunc->name())) {
|
|
NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
|
|
NodeList::ConstIterator s = secs.begin();
|
|
while (s != secs.end()) {
|
|
FunctionNode *secondaryFunc = (FunctionNode *) *s;
|
|
if (!secondaryFunc->isOverload())
|
|
secondaryFunc->ove = true;
|
|
++s;
|
|
}
|
|
}
|
|
++p;
|
|
}
|
|
|
|
NodeList::ConstIterator c = childNodes().begin();
|
|
while (c != childNodes().end()) {
|
|
if ((*c)->isInnerNode())
|
|
((InnerNode *) *c)->normalizeOverloads();
|
|
++c;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::removeFromRelated()
|
|
{
|
|
while (!related.isEmpty()) {
|
|
Node *p = static_cast<Node *>(related.takeFirst());
|
|
|
|
if (p != 0 && p->relates() == this) p->clearRelated();
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::deleteChildren()
|
|
{
|
|
NodeList childrenCopy = children; // `children` will be changed in ~Node()
|
|
qDeleteAll(childrenCopy);
|
|
}
|
|
|
|
/*!
|
|
Returns true because this is an inner node.
|
|
*/
|
|
bool InnerNode::isInnerNode() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
const Node *InnerNode::findNode(const QString& name) const
|
|
{
|
|
InnerNode *that = (InnerNode *) this;
|
|
return that->findNode(name);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
const Node *InnerNode::findNode(const QString& name, Type type) const
|
|
{
|
|
InnerNode *that = (InnerNode *) this;
|
|
return that->findNode(name, type);
|
|
}
|
|
|
|
/*!
|
|
Find the function node in this node that has the given \a name.
|
|
*/
|
|
const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
|
|
{
|
|
InnerNode *that = (InnerNode *) this;
|
|
return that->findFunctionNode(name);
|
|
}
|
|
|
|
/*!
|
|
Find the function node in this node that has the same name as \a clone.
|
|
*/
|
|
const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
|
|
{
|
|
InnerNode *that = (InnerNode *) this;
|
|
return that->findFunctionNode(clone);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
|
|
{
|
|
foreach (const Node *node, enumChildren) {
|
|
const EnumNode *enume = static_cast<const EnumNode *>(node);
|
|
if (enume->hasItem(enumValue))
|
|
return enume;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
Returnds the sequence number of the function node \a func
|
|
in the list of overloaded functions for a class, such that
|
|
all the functions have the same name as the \a func.
|
|
*/
|
|
int InnerNode::overloadNumber(const FunctionNode *func) const
|
|
{
|
|
Node *node = (Node *) func;
|
|
if (primaryFunctionMap[func->name()] == node) {
|
|
return 1;
|
|
}
|
|
else {
|
|
return secondaryFunctionMap[func->name()].indexOf(node) + 2;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Returns the number of member functions of a class such that
|
|
the functions are all named \a funcName.
|
|
*/
|
|
int InnerNode::numOverloads(const QString& funcName) const
|
|
{
|
|
if (primaryFunctionMap.contains(funcName)) {
|
|
return secondaryFunctionMap[funcName].count() + 1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Returns a node list containing all the member functions of
|
|
some class such that the functions overload the name \a funcName.
|
|
*/
|
|
NodeList InnerNode::overloads(const QString &funcName) const
|
|
{
|
|
NodeList result;
|
|
Node *primary = primaryFunctionMap.value(funcName);
|
|
if (primary) {
|
|
result << primary;
|
|
result += secondaryFunctionMap[funcName];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*!
|
|
Construct an inner node (i.e., not a leaf node) of the
|
|
given \a type and having the given \a parent and \a name.
|
|
*/
|
|
InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
|
|
: Node(type, parent, name)
|
|
{
|
|
switch (type) {
|
|
case Class:
|
|
case Namespace:
|
|
setPageType(ApiPage);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Appends an \a include file to the list of include files.
|
|
*/
|
|
void InnerNode::addInclude(const QString& include)
|
|
{
|
|
inc.append(include);
|
|
}
|
|
|
|
/*!
|
|
Sets the list of include files to \a includes.
|
|
*/
|
|
void InnerNode::setIncludes(const QStringList& includes)
|
|
{
|
|
inc = includes;
|
|
}
|
|
|
|
/*!
|
|
f1 is always the clone
|
|
*/
|
|
bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
|
|
{
|
|
if (f1->parameters().count() != f2->parameters().count())
|
|
return false;
|
|
if (f1->isConst() != f2->isConst())
|
|
return false;
|
|
|
|
QList<Parameter>::ConstIterator p1 = f1->parameters().begin();
|
|
QList<Parameter>::ConstIterator p2 = f2->parameters().begin();
|
|
while (p2 != f2->parameters().end()) {
|
|
if ((*p1).hasType() && (*p2).hasType()) {
|
|
if ((*p1).rightType() != (*p2).rightType())
|
|
return false;
|
|
|
|
QString t1 = p1->leftType();
|
|
QString t2 = p2->leftType();
|
|
|
|
if (t1.length() < t2.length())
|
|
qSwap(t1, t2);
|
|
|
|
/*
|
|
### hack for C++ to handle superfluous
|
|
"Foo::" prefixes gracefully
|
|
*/
|
|
if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
|
|
return false;
|
|
}
|
|
++p1;
|
|
++p2;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
Adds the \a child to this node's child list.
|
|
*/
|
|
void InnerNode::addChild(Node *child)
|
|
{
|
|
children.append(child);
|
|
if ((child->type() == Function) || (child->type() == QmlMethod)) {
|
|
FunctionNode *func = (FunctionNode *) child;
|
|
if (!primaryFunctionMap.contains(func->name())) {
|
|
primaryFunctionMap.insert(func->name(), func);
|
|
}
|
|
else {
|
|
NodeList &secs = secondaryFunctionMap[func->name()];
|
|
secs.append(func);
|
|
}
|
|
}
|
|
else {
|
|
if (child->type() == Enum)
|
|
enumChildren.append(child);
|
|
childMap.insert(child->name(), child);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::removeChild(Node *child)
|
|
{
|
|
children.removeAll(child);
|
|
enumChildren.removeAll(child);
|
|
if (child->type() == Function) {
|
|
QMap<QString, Node *>::Iterator prim =
|
|
primaryFunctionMap.find(child->name());
|
|
NodeList& secs = secondaryFunctionMap[child->name()];
|
|
if (prim != primaryFunctionMap.end() && *prim == child) {
|
|
if (secs.isEmpty()) {
|
|
primaryFunctionMap.remove(child->name());
|
|
}
|
|
else {
|
|
primaryFunctionMap.insert(child->name(), secs.takeFirst());
|
|
}
|
|
}
|
|
else {
|
|
secs.removeAll(child);
|
|
}
|
|
QMap<QString, Node *>::Iterator ent = childMap.find( child->name() );
|
|
if (ent != childMap.end() && *ent == child)
|
|
childMap.erase( ent );
|
|
}
|
|
else {
|
|
QMap<QString, Node *>::Iterator ent = childMap.find(child->name());
|
|
if (ent != childMap.end() && *ent == child)
|
|
childMap.erase(ent);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Find the module (QtCore, QtGui, etc.) to which the class belongs.
|
|
We do this by obtaining the full path to the header file's location
|
|
and examine everything between "src/" and the filename. This is
|
|
semi-dirty because we are assuming a particular directory structure.
|
|
|
|
This function is only really useful if the class's module has not
|
|
been defined in the header file with a QT_MODULE macro or with an
|
|
\inmodule command in the documentation.
|
|
*/
|
|
QString Node::moduleName() const
|
|
{
|
|
if (!mod.isEmpty())
|
|
return mod;
|
|
|
|
QString path = location().filePath();
|
|
QString pattern = QString("src") + QDir::separator();
|
|
int start = path.lastIndexOf(pattern);
|
|
|
|
if (start == -1)
|
|
return "";
|
|
|
|
QString moduleDir = path.mid(start + pattern.size());
|
|
int finish = moduleDir.indexOf(QDir::separator());
|
|
|
|
if (finish == -1)
|
|
return "";
|
|
|
|
QString moduleName = moduleDir.left(finish);
|
|
|
|
if (moduleName == "corelib")
|
|
return "QtCore";
|
|
else if (moduleName == "uitools")
|
|
return "QtUiTools";
|
|
else if (moduleName == "gui")
|
|
return "QtGui";
|
|
else if (moduleName == "network")
|
|
return "QtNetwork";
|
|
else if (moduleName == "opengl")
|
|
return "QtOpenGL";
|
|
else if (moduleName == "qt3support")
|
|
return "Qt3Support";
|
|
else if (moduleName == "svg")
|
|
return "QtSvg";
|
|
else if (moduleName == "sql")
|
|
return "QtSql";
|
|
else if (moduleName == "qtestlib")
|
|
return "QtTest";
|
|
else if (moduleDir.contains("webkit"))
|
|
return "QtWebKit";
|
|
else if (moduleName == "xml")
|
|
return "QtXml";
|
|
else
|
|
return "";
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void InnerNode::removeRelated(Node *pseudoChild)
|
|
{
|
|
related.removeAll(pseudoChild);
|
|
}
|
|
|
|
/*!
|
|
\class LeafNode
|
|
*/
|
|
|
|
/*!
|
|
Returns false because this is a LeafNode.
|
|
*/
|
|
bool LeafNode::isInnerNode() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
Constructs a leaf node named \a name of the specified
|
|
\a type. The new leaf node becomes a child of \a parent.
|
|
*/
|
|
LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
|
|
: Node(type, parent, name)
|
|
{
|
|
switch (type) {
|
|
case Enum:
|
|
case Function:
|
|
case Typedef:
|
|
case Variable:
|
|
case QmlProperty:
|
|
case QmlSignal:
|
|
case QmlMethod:
|
|
setPageType(ApiPage);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\class NamespaceNode
|
|
*/
|
|
|
|
/*!
|
|
Constructs a namespace node.
|
|
*/
|
|
NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
|
|
: InnerNode(Namespace, parent, name)
|
|
{
|
|
setPageType(ApiPage);
|
|
}
|
|
|
|
/*!
|
|
\class ClassNode
|
|
\brief This class represents a C++ class.
|
|
*/
|
|
|
|
/*!
|
|
Constructs a class node. A class node will generate an API page.
|
|
*/
|
|
ClassNode::ClassNode(InnerNode *parent, const QString& name)
|
|
: InnerNode(Class, parent, name)
|
|
{
|
|
hidden = false;
|
|
abstract = false;
|
|
setPageType(ApiPage);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void ClassNode::addBaseClass(Access access,
|
|
ClassNode *node,
|
|
const QString &dataTypeWithTemplateArgs)
|
|
{
|
|
bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
|
|
node->derived.append(RelatedClass(access, this));
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void ClassNode::fixBaseClasses()
|
|
{
|
|
int i;
|
|
i = 0;
|
|
while (i < bases.size()) {
|
|
ClassNode* bc = bases.at(i).node;
|
|
if (bc->access() == Node::Private) {
|
|
RelatedClass rc = bases.at(i);
|
|
bases.removeAt(i);
|
|
ignoredBases.append(rc);
|
|
const QList<RelatedClass> &bb = bc->baseClasses();
|
|
for (int j = bb.size() - 1; j >= 0; --j)
|
|
bases.insert(i, bb.at(j));
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
|
|
i = 0;
|
|
while (i < derived.size()) {
|
|
ClassNode* dc = derived.at(i).node;
|
|
if (dc->access() == Node::Private) {
|
|
derived.removeAt(i);
|
|
const QList<RelatedClass> &dd = dc->derivedClasses();
|
|
for (int j = dd.size() - 1; j >= 0; --j)
|
|
derived.insert(i, dd.at(j));
|
|
}
|
|
else {
|
|
++i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Search the child list to find the property node with the
|
|
specified \a name.
|
|
*/
|
|
const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
|
|
{
|
|
const Node *n = findNode(name, Node::Property);
|
|
|
|
if (n)
|
|
return static_cast<const PropertyNode*>(n);
|
|
|
|
const 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;
|
|
pn = cn->findPropertyNode(name);
|
|
if (pn)
|
|
break;
|
|
}
|
|
}
|
|
const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
|
|
if (!ignoredBases.isEmpty()) {
|
|
for (int i = 0; i < ignoredBases.size(); ++i) {
|
|
const ClassNode *cn = ignoredBases[i].node;
|
|
pn = cn->findPropertyNode(name);
|
|
if (pn)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pn;
|
|
}
|
|
|
|
/*!
|
|
\class FakeNode
|
|
*/
|
|
|
|
/*!
|
|
The type of a FakeNode is Fake, and it has a \a subtype,
|
|
which specifies the type of FakeNode. The page type for
|
|
the page index is set here.
|
|
*/
|
|
FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype)
|
|
: InnerNode(Fake, parent, name), sub(subtype)
|
|
{
|
|
switch (subtype) {
|
|
case Module:
|
|
case Page:
|
|
case Group:
|
|
setPageType(ArticlePage);
|
|
break;
|
|
case QmlClass:
|
|
case QmlBasicType:
|
|
setPageType(ApiPage);
|
|
break;
|
|
case Example:
|
|
setPageType(ExamplePage);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Returns the fake node's title. This is used for the page title.
|
|
*/
|
|
QString FakeNode::title() const
|
|
{
|
|
return tle;
|
|
}
|
|
|
|
/*!
|
|
Returns the fake node's full title, which is usually
|
|
just title(), but for some SubType values is different
|
|
from title()
|
|
*/
|
|
QString FakeNode::fullTitle() const
|
|
{
|
|
if (sub == File) {
|
|
if (title().isEmpty())
|
|
return name().mid(name().lastIndexOf('/') + 1) + " Example File";
|
|
else
|
|
return title();
|
|
}
|
|
else if (sub == Image) {
|
|
if (title().isEmpty())
|
|
return name().mid(name().lastIndexOf('/') + 1) + " Image File";
|
|
else
|
|
return title();
|
|
}
|
|
else if (sub == HeaderFile) {
|
|
if (title().isEmpty())
|
|
return name();
|
|
else
|
|
return name() + " - " + title();
|
|
}
|
|
else {
|
|
return title();
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Returns the subtitle.
|
|
*/
|
|
QString FakeNode::subTitle() const
|
|
{
|
|
if (!stle.isEmpty())
|
|
return stle;
|
|
|
|
if ((sub == File) || (sub == Image)) {
|
|
if (title().isEmpty() && name().contains("/"))
|
|
return name();
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
/*!
|
|
The constructor calls the FakeNode constructor with
|
|
\a parent, \a name, and Node::Example.
|
|
*/
|
|
ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
|
|
: FakeNode(parent, name, Node::Example)
|
|
{
|
|
// nothing
|
|
}
|
|
|
|
/*!
|
|
\class EnumNode
|
|
*/
|
|
|
|
/*!
|
|
The constructor for the node representing an enum type
|
|
has a \a parent class and an enum type \a name.
|
|
*/
|
|
EnumNode::EnumNode(InnerNode *parent, const QString& name)
|
|
: LeafNode(Enum, parent, name), ft(0)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
Add \a item to the enum type's item list.
|
|
*/
|
|
void EnumNode::addItem(const EnumItem& item)
|
|
{
|
|
itms.append(item);
|
|
names.insert(item.name());
|
|
}
|
|
|
|
/*!
|
|
Returns the access level of the enumeration item named \a name.
|
|
Apparently it is private if it has been omitted by qdoc's
|
|
omitvalue command. Otherwise it is public.
|
|
*/
|
|
Node::Access EnumNode::itemAccess(const QString &name) const
|
|
{
|
|
if (doc().omitEnumItemNames().contains(name))
|
|
return Private;
|
|
return Public;
|
|
}
|
|
|
|
/*!
|
|
Returns the enum value associated with the enum \a name.
|
|
*/
|
|
QString EnumNode::itemValue(const QString &name) const
|
|
{
|
|
foreach (const EnumItem &item, itms) {
|
|
if (item.name() == name)
|
|
return item.value();
|
|
}
|
|
return QString();
|
|
}
|
|
|
|
/*!
|
|
\class TypedefNode
|
|
*/
|
|
|
|
/*!
|
|
*/
|
|
TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
|
|
: LeafNode(Typedef, parent, name), ae(0)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void TypedefNode::setAssociatedEnum(const EnumNode *enume)
|
|
{
|
|
ae = enume;
|
|
}
|
|
|
|
/*!
|
|
\class Parameter
|
|
\brief The class Parameter contains one parameter.
|
|
|
|
A parameter can be a function parameter or a macro
|
|
parameter.
|
|
*/
|
|
|
|
/*!
|
|
Constructs this parameter from the left and right types
|
|
\a leftType and rightType, the parameter \a name, and the
|
|
\a defaultValue. In practice, \a rightType is not used,
|
|
and I don't know what is was meant for.
|
|
*/
|
|
Parameter::Parameter(const QString& leftType,
|
|
const QString& rightType,
|
|
const QString& name,
|
|
const QString& defaultValue)
|
|
: lef(leftType), rig(rightType), nam(name), def(defaultValue)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
The standard copy constructor copies the strings from \a p.
|
|
*/
|
|
Parameter::Parameter(const Parameter& p)
|
|
: lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
|
|
{
|
|
}
|
|
|
|
/*!
|
|
Assigning Parameter \a p to this Parameter copies the
|
|
strings across.
|
|
*/
|
|
Parameter& Parameter::operator=(const Parameter& p)
|
|
{
|
|
lef = p.lef;
|
|
rig = p.rig;
|
|
nam = p.nam;
|
|
def = p.def;
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
Reconstructs the text describing the parameter and
|
|
returns it. If \a value is true, the default value
|
|
will be included, if there is one.
|
|
*/
|
|
QString Parameter::reconstruct(bool value) const
|
|
{
|
|
QString p = lef + rig;
|
|
if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
|
|
p += " ";
|
|
p += nam;
|
|
if (value && !def.isEmpty())
|
|
p += " = " + def;
|
|
return p;
|
|
}
|
|
|
|
|
|
/*!
|
|
\class FunctionNode
|
|
*/
|
|
|
|
/*!
|
|
Construct a function node for a C++ function. It's parent
|
|
is \a parent, and it's name is \a name.
|
|
*/
|
|
FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
|
|
: LeafNode(Function, parent, name),
|
|
met(Plain),
|
|
vir(NonVirtual),
|
|
con(false),
|
|
sta(false),
|
|
ove(false),
|
|
att(false),
|
|
rf(0),
|
|
ap(0)
|
|
{
|
|
// nothing.
|
|
}
|
|
|
|
/*!
|
|
Construct a function node for a QML method or signal, specified
|
|
by \a type. It's parent is \a parent, and it's name is \a name.
|
|
If \a attached is true, it is an attached method or signal.
|
|
*/
|
|
FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
|
|
: LeafNode(type, parent, name),
|
|
met(Plain),
|
|
vir(NonVirtual),
|
|
con(false),
|
|
sta(false),
|
|
ove(false),
|
|
att(attached),
|
|
rf(0),
|
|
ap(0)
|
|
{
|
|
// nothing.
|
|
}
|
|
|
|
/*!
|
|
Sets the \a virtualness of this function. If the \a virtualness
|
|
is PureVirtual, and if the parent() is a ClassNode, set the parent's
|
|
\e abstract flag to true.
|
|
*/
|
|
void FunctionNode::setVirtualness(Virtualness virtualness)
|
|
{
|
|
vir = virtualness;
|
|
if ((virtualness == PureVirtual) && parent() &&
|
|
(parent()->type() == Node::Class))
|
|
parent()->setAbstract(true);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void FunctionNode::setOverload(bool overlode)
|
|
{
|
|
parent()->setOverload(this, overlode);
|
|
ove = overlode;
|
|
}
|
|
|
|
/*!
|
|
Sets the function node's reimplementation flag to \a r.
|
|
When \a r is true, it is supposed to mean that this function
|
|
is a reimplementation of a virtual function in a base class,
|
|
but it really just means the \e reimp command was seen in the
|
|
qdoc comment.
|
|
*/
|
|
void FunctionNode::setReimp(bool r)
|
|
{
|
|
reimp = r;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void FunctionNode::addParameter(const Parameter& parameter)
|
|
{
|
|
params.append(parameter);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void FunctionNode::borrowParameterNames(const FunctionNode *source)
|
|
{
|
|
QList<Parameter>::Iterator t = params.begin();
|
|
QList<Parameter>::ConstIterator s = source->params.begin();
|
|
while (s != source->params.end() && t != params.end()) {
|
|
if (!(*s).name().isEmpty())
|
|
(*t).setName((*s).name());
|
|
++s;
|
|
++t;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
If this function is a reimplementation, \a from points
|
|
to the FunctionNode of the function being reimplemented.
|
|
*/
|
|
void FunctionNode::setReimplementedFrom(FunctionNode *from)
|
|
{
|
|
rf = from;
|
|
from->rb.append(this);
|
|
}
|
|
|
|
/*!
|
|
Sets the "associated" property to \a property. The function
|
|
might be the setter or getter for a property, for example.
|
|
*/
|
|
void FunctionNode::setAssociatedProperty(PropertyNode *property)
|
|
{
|
|
ap = property;
|
|
}
|
|
|
|
/*!
|
|
Returns the overload number for this function obtained
|
|
from the parent.
|
|
*/
|
|
int FunctionNode::overloadNumber() const
|
|
{
|
|
return parent()->overloadNumber(this);
|
|
}
|
|
|
|
/*!
|
|
Returns the number of times this function name has been
|
|
overloaded, obtained from the parent.
|
|
*/
|
|
int FunctionNode::numOverloads() const
|
|
{
|
|
return parent()->numOverloads(name());
|
|
}
|
|
|
|
/*!
|
|
Returns the list of parameter names.
|
|
*/
|
|
QStringList FunctionNode::parameterNames() const
|
|
{
|
|
QStringList names;
|
|
QList<Parameter>::ConstIterator p = parameters().begin();
|
|
while (p != parameters().end()) {
|
|
names << (*p).name();
|
|
++p;
|
|
}
|
|
return names;
|
|
}
|
|
|
|
/*!
|
|
Returns a raw list of parameters. If \a names is true, the
|
|
names are included. If \a values is true, the default values
|
|
are included, if any are present.
|
|
*/
|
|
QString FunctionNode::rawParameters(bool names, bool values) const
|
|
{
|
|
QString raw;
|
|
foreach (const Parameter ¶meter, parameters()) {
|
|
raw += parameter.leftType() + parameter.rightType();
|
|
if (names)
|
|
raw += parameter.name();
|
|
if (values)
|
|
raw += parameter.defaultValue();
|
|
}
|
|
return raw;
|
|
}
|
|
|
|
/*!
|
|
Returns the list of reconstructed parameters. If \a values
|
|
is true, the default values are included, if any are present.
|
|
*/
|
|
QStringList FunctionNode::reconstructParams(bool values) const
|
|
{
|
|
QStringList params;
|
|
QList<Parameter>::ConstIterator p = parameters().begin();
|
|
while (p != parameters().end()) {
|
|
params << (*p).reconstruct(values);
|
|
++p;
|
|
}
|
|
return params;
|
|
}
|
|
|
|
/*!
|
|
Reconstructs and returns the function's signature. If \a values
|
|
is true, the default values of the parameters are included, if
|
|
present.
|
|
*/
|
|
QString FunctionNode::signature(bool values) const
|
|
{
|
|
QString s;
|
|
if (!returnType().isEmpty())
|
|
s = returnType() + " ";
|
|
s += name() + "(";
|
|
QStringList params = reconstructParams(values);
|
|
int p = params.size();
|
|
if (p > 0) {
|
|
for (int i=0; i<p; i++) {
|
|
s += params[i];
|
|
if (i < (p-1))
|
|
s += ", ";
|
|
}
|
|
}
|
|
s += ")";
|
|
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.
|
|
*/
|
|
void FunctionNode::debug() const
|
|
{
|
|
qDebug("QML METHOD %s rt %s pp %s",
|
|
qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
|
|
}
|
|
|
|
/*!
|
|
\class PropertyNode
|
|
|
|
This class describes one instance of using the Q_PROPERTY macro.
|
|
*/
|
|
|
|
/*!
|
|
The constructor sets the \a parent and the \a name, but
|
|
everything else is set to default values.
|
|
*/
|
|
PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
|
|
: LeafNode(Property, parent, name),
|
|
sto(Trool_Default),
|
|
des(Trool_Default),
|
|
scr(Trool_Default),
|
|
wri(Trool_Default),
|
|
usr(Trool_Default),
|
|
cst(false),
|
|
fnl(false),
|
|
rev(-1),
|
|
overrides(0)
|
|
{
|
|
// nothing.
|
|
}
|
|
|
|
/*!
|
|
Sets this property's \e {overridden from} property to
|
|
\a baseProperty, which indicates that this property
|
|
overrides \a baseProperty. To begin with, all the values
|
|
in this property are set to the corresponding values in
|
|
\a baseProperty.
|
|
|
|
We probably should ensure that the constant and final
|
|
attributes are not being overridden improperly.
|
|
*/
|
|
void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
|
|
{
|
|
for (int i = 0; i < NumFunctionRoles; ++i) {
|
|
if (funcs[i].isEmpty())
|
|
funcs[i] = baseProperty->funcs[i];
|
|
}
|
|
if (sto == Trool_Default)
|
|
sto = baseProperty->sto;
|
|
if (des == Trool_Default)
|
|
des = baseProperty->des;
|
|
if (scr == Trool_Default)
|
|
scr = baseProperty->scr;
|
|
if (wri == Trool_Default)
|
|
wri = baseProperty->wri;
|
|
if (usr == Trool_Default)
|
|
usr = baseProperty->usr;
|
|
overrides = baseProperty;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
QString PropertyNode::qualifiedDataType() const
|
|
{
|
|
if (setters().isEmpty() && resetters().isEmpty()) {
|
|
if (dt.contains("*") || dt.contains("&")) {
|
|
// 'QWidget *' becomes 'QWidget *' const
|
|
return dt + " const";
|
|
}
|
|
else {
|
|
/*
|
|
'int' becomes 'const int' ('int const' is
|
|
correct C++, but looks wrong)
|
|
*/
|
|
return "const " + dt;
|
|
}
|
|
}
|
|
else {
|
|
return dt;
|
|
}
|
|
}
|
|
|
|
/*! Converts the \a boolean value to an enum representation
|
|
of the boolean type, which includes an enum value for the
|
|
\e {default value} of the item, i.e. true, false, or default.
|
|
*/
|
|
PropertyNode::Trool PropertyNode::toTrool(bool boolean)
|
|
{
|
|
return boolean ? Trool_True : Trool_False;
|
|
}
|
|
|
|
/*!
|
|
Converts the enum \a troolean back to a boolean value.
|
|
If \a troolean is neither the true enum value nor the
|
|
false enum value, the boolean value returned is
|
|
\a defaultValue.
|
|
|
|
Note that runtimeDesignabilityFunction() should be called
|
|
first. If that function returns the name of a function, it
|
|
means the function must be called at runtime to determine
|
|
whether the property is Designable.
|
|
*/
|
|
bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
|
|
{
|
|
switch (troolean) {
|
|
case Trool_True:
|
|
return true;
|
|
case Trool_False:
|
|
return false;
|
|
default:
|
|
return 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;
|
|
}
|
|
|
|
#ifdef QDOC_QML
|
|
bool QmlClassNode::qmlOnly = false;
|
|
QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
|
|
|
|
/*!
|
|
Constructs a Qml class node (i.e. a Fake node with the
|
|
subtype QmlClass. The new node has the given \a parent
|
|
and \a name and is associated with the C++ class node
|
|
specified by \a cn which may be null if the the Qml
|
|
class node is not associated with a C++ class node.
|
|
*/
|
|
QmlClassNode::QmlClassNode(InnerNode *parent,
|
|
const QString& name,
|
|
const ClassNode* cn)
|
|
: FakeNode(parent, name, QmlClass), cnode(cn)
|
|
{
|
|
if (name.startsWith(QLatin1String("QML:")))
|
|
setTitle((qmlOnly ? QLatin1String("") : QLatin1String("QML ")) + name.mid(4) + QLatin1String(" Element"));
|
|
else
|
|
setTitle((qmlOnly ? QLatin1String("") : QLatin1String("QML ")) + name + QLatin1String(" Element"));
|
|
}
|
|
|
|
/*!
|
|
I made this so I could print a debug message here.
|
|
*/
|
|
QmlClassNode::~QmlClassNode()
|
|
{
|
|
#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
|
|
qDebug() << "Deleting QmlClassNode:" << name();
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
Clear the multimap so that subsequent runs don't try to use
|
|
nodes from a previous run.
|
|
*/
|
|
void QmlClassNode::clear()
|
|
{
|
|
inheritedBy.clear();
|
|
}
|
|
|
|
/*!
|
|
The base file name for this kind of node has "qml_"
|
|
prepended to it.
|
|
|
|
But not yet. Still testing.
|
|
*/
|
|
QString QmlClassNode::fileBase() const
|
|
{
|
|
return Node::fileBase();
|
|
}
|
|
|
|
/*!
|
|
Record the fact that QML class \a base is inherited by
|
|
QML class \a sub.
|
|
*/
|
|
void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
|
|
{
|
|
inheritedBy.insert(base,sub);
|
|
#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
|
|
qDebug() << "QmlClassNode::addInheritedBy(): insert" << base << sub->name() << inheritedBy.size();
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
Loads the list \a subs with the nodes of all the subclasses of \a base.
|
|
*/
|
|
void QmlClassNode::subclasses(const QString& base, NodeList& subs)
|
|
{
|
|
subs.clear();
|
|
if (inheritedBy.count(base) > 0) {
|
|
subs = inheritedBy.values(base);
|
|
#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
|
|
qDebug() << "QmlClassNode::subclasses():" << inheritedBy.count(base) << base
|
|
<< "subs:" << subs.size() << "total size:" << inheritedBy.size();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Constructs a Qml basic type node (i.e. a Fake node with
|
|
the subtype QmlBasicType. The new node has the given
|
|
\a parent and \a name.
|
|
*/
|
|
QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
|
|
const QString& name)
|
|
: FakeNode(parent, name, QmlBasicType)
|
|
{
|
|
setTitle(name);
|
|
}
|
|
|
|
/*!
|
|
Constructor for the Qml property group node. \a parent is
|
|
always a QmlClassNode.
|
|
*/
|
|
QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent,
|
|
const QString& name,
|
|
bool attached)
|
|
: FakeNode(parent, name, QmlPropertyGroup),
|
|
isdefault(false),
|
|
att(attached)
|
|
{
|
|
// nothing.
|
|
}
|
|
|
|
/*!
|
|
Constructor for the QML property node.
|
|
*/
|
|
QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
|
|
const QString& name,
|
|
const QString& type,
|
|
bool attached)
|
|
: LeafNode(QmlProperty, parent, name),
|
|
dt(type),
|
|
sto(Trool_Default),
|
|
des(Trool_Default),
|
|
att(attached)
|
|
{
|
|
setPageType(ApiPage);
|
|
}
|
|
|
|
/*!
|
|
I don't know what this is.
|
|
*/
|
|
QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
|
|
{
|
|
return boolean ? Trool_True : Trool_False;
|
|
}
|
|
|
|
/*!
|
|
I don't know what this is either.
|
|
*/
|
|
bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
|
|
{
|
|
switch (troolean) {
|
|
case Trool_True:
|
|
return true;
|
|
case Trool_False:
|
|
return false;
|
|
default:
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Returns true if a QML property or attached property is
|
|
read-only. The algorithm for figuring this out is long
|
|
amd tedious and almost certainly will break. It currently
|
|
doesn't work for qmlproperty bool PropertyChanges::explicit,
|
|
because the tokenizer gets confused on "explicit".
|
|
*/
|
|
bool QmlPropertyNode::isWritable(const Tree* tree) const
|
|
{
|
|
if (wri != Trool_Default)
|
|
return fromTrool(wri, false);
|
|
|
|
const PropertyNode *pn = correspondingProperty(tree);
|
|
if (pn)
|
|
return pn->isWritable();
|
|
else {
|
|
location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) const
|
|
{
|
|
const 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();
|
|
if (cn) {
|
|
QStringList dotSplit = name().split(QChar('.'));
|
|
pn = cn->findPropertyNode(dotSplit[0]);
|
|
if (pn) {
|
|
if (dotSplit.size() > 1) {
|
|
// Find the C++ property corresponding to the QML property in
|
|
// the property group, <group>.<property>.
|
|
|
|
QStringList path(extractClassName(pn->qualifiedDataType()));
|
|
const Node* nn = tree->findNode(path,Class);
|
|
if (nn) {
|
|
const ClassNode* cn = static_cast<const ClassNode*>(nn);
|
|
const PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
|
|
if (pn2)
|
|
return pn2; // Return the property for the QML property.
|
|
else
|
|
return pn; // Return the property for the QML group.
|
|
}
|
|
}
|
|
else
|
|
return pn;
|
|
}
|
|
else {
|
|
pn = cn->findPropertyNode(dotSplit[0]);
|
|
if (pn)
|
|
return pn;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
QT_END_NAMESPACE
|