source: trunk/tools/qdoc3/node.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 45.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*
43 node.cpp
44*/
45
46#include "node.h"
47#include "tree.h"
48#include "codemarker.h"
49#include <qdebug.h>
50
51QT_BEGIN_NAMESPACE
52
53/*!
54 \class Node
55 \brief The Node class is a node in the Tree.
56
57 A Node represents a class or function or something else
58 from the source code..
59 */
60
61/*!
62 When this Node is destroyed, if it has a parent Node, it
63 removes itself from the parent node's child list.
64 */
65Node::~Node()
66{
67 if (par)
68 par->removeChild(this);
69 if (rel)
70 rel->removeRelated(this);
71}
72
73/*!
74 Sets this Node's Doc to \a doc. If \a replace is false and
75 this Node already has a Doc, a warning is reported that the
76 Doc is being overridden, and it reports where the previous
77 Doc was found. If \a replace is true, the Doc is replaced
78 silently.
79 */
80void Node::setDoc(const Doc& doc, bool replace)
81{
82 if (!d.isEmpty() && !replace) {
83 doc.location().warning(tr("Overrides a previous doc"));
84 d.location().warning(tr("(The previous doc is here)"));
85 }
86 d = doc;
87}
88
89/*!
90 Construct a node with the given \a type and having the
91 given \a parent and \a name. The new node is added to the
92 parent's child list.
93 */
94Node::Node(Type type, InnerNode *parent, const QString& name)
95 : typ(type),
96 acc(Public),
97 saf(UnspecifiedSafeness),
98 pageTyp(NoPageType),
99 sta(Commendable),
100 par(parent),
101 rel(0),
102 nam(name)
103{
104 if (par)
105 par->addChild(this);
106 //uuid = QUuid::createUuid();
107}
108
109/*!
110 Returns the node's URL.
111 */
112QString Node::url() const
113{
114 return u;
115}
116
117/*!
118 Sets the node's URL to \a url
119 */
120void Node::setUrl(const QString &url)
121{
122 u = url;
123}
124
125void Node::setPageType(const QString& t)
126{
127 if ((t == "API") || (t == "api"))
128 pageTyp = ApiPage;
129 else if (t == "article")
130 pageTyp = ArticlePage;
131 else if (t == "example")
132 pageTyp = ExamplePage;
133}
134
135/*!
136 Sets the pointer to the node that this node relates to.
137 */
138void Node::setRelates(InnerNode *pseudoParent)
139{
140 if (rel)
141 rel->removeRelated(this);
142 rel = pseudoParent;
143 pseudoParent->related.append(this);
144}
145
146/*!
147 This function creates a pair that describes a link.
148 The pair is composed from \a link and \a desc. The
149 \a linkType is the map index the pair is filed under.
150 */
151void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
152{
153 QPair<QString,QString> linkPair;
154 linkPair.first = link;
155 linkPair.second = desc;
156 linkMap[linkType] = linkPair;
157}
158
159/*!
160 Returns a string representing the access specifier.
161 */
162QString Node::accessString() const
163{
164 switch (acc) {
165 case Protected:
166 return "protected";
167 case Private:
168 return "private";
169 case Public:
170 default:
171 break;
172 }
173 return "public";
174}
175
176/*!
177 Extract a class name from the type \a string and return it.
178 */
179QString Node::extractClassName(const QString &string) const
180{
181 QString result;
182 for (int i=0; i<=string.size(); ++i) {
183 QChar ch;
184 if (i != string.size())
185 ch = string.at(i);
186
187 QChar lower = ch.toLower();
188 if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
189 ch.digitValue() >= 0 ||
190 ch == QLatin1Char('_') ||
191 ch == QLatin1Char(':')) {
192 result += ch;
193 }
194 else if (!result.isEmpty()) {
195 if (result != QLatin1String("const"))
196 return result;
197 result.clear();
198 }
199 }
200 return result;
201}
202
203/*!
204 Returns a string representing the access specifier.
205 */
206QString RelatedClass::accessString() const
207{
208 switch (access) {
209 case Node::Protected:
210 return "protected";
211 case Node::Private:
212 return "private";
213 case Node::Public:
214 default:
215 break;
216 }
217 return "public";
218}
219
220/*!
221 */
222Node::Status Node::inheritedStatus() const
223{
224 Status parentStatus = Commendable;
225 if (par)
226 parentStatus = par->inheritedStatus();
227 return (Status)qMin((int)sta, (int)parentStatus);
228}
229
230/*!
231 Returns the thread safeness value for whatever this node
232 represents. But if this node has a parent and the thread
233 safeness value of the parent is the same as the thread
234 safeness value of this node, what is returned is the
235 value \c{UnspecifiedSafeness}. Why?
236 */
237Node::ThreadSafeness Node::threadSafeness() const
238{
239 if (par && saf == par->inheritedThreadSafeness())
240 return UnspecifiedSafeness;
241 return saf;
242}
243
244/*!
245 If this node has a parent, the parent's thread safeness
246 value is returned. Otherwise, this node's thread safeness
247 value is returned. Why?
248 */
249Node::ThreadSafeness Node::inheritedThreadSafeness() const
250{
251 if (par && saf == UnspecifiedSafeness)
252 return par->inheritedThreadSafeness();
253 return saf;
254}
255
256/*!
257 Returns the sanitized file name without the path.
258 If the the file is an html file, the html suffix
259 is removed. Why?
260 */
261QString Node::fileBase() const
262{
263 QString base = name();
264 if (base.endsWith(".html"))
265 base.chop(5);
266 base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
267 base = base.trimmed();
268 base.replace(" ", "-");
269 return base.toLower();
270}
271
272/*!
273 Returns this node's Universally Unique IDentifier.
274 If its UUID has not yet been created, it is created
275 first.
276 */
277QUuid Node::guid() const
278{
279 if (uuid.isNull())
280 uuid = QUuid::createUuid();
281 return uuid;
282}
283
284/*!
285 Composes a string to be used as an href attribute in DITA
286 XML. It is composed of the file name and the UUID separated
287 by a '#'. If this node is a class node, the file name is
288 taken from this node; if this node is a function node, the
289 file name is taken from the parent node of this node.
290 */
291QString Node::ditaXmlHref()
292{
293 QString href;
294 if ((type() == Function) ||
295 (type() == Property) ||
296 (type() == Variable)) {
297 href = parent()->fileBase();
298 }
299 else {
300 href = fileBase();
301 }
302 if (!href.endsWith(".xml"))
303 href += ".xml";
304 return href + "#" + guid();
305}
306
307/*!
308 \class InnerNode
309 */
310
311/*!
312 The inner node destructor deletes the children and removes
313 this node from its related nodes.
314 */
315InnerNode::~InnerNode()
316{
317 deleteChildren();
318 removeFromRelated();
319}
320
321/*!
322 Find the node in this node's children that has the
323 given \a name. If this node is a QML class node, be
324 sure to also look in the children of its property
325 group nodes. Return the matching node or 0.
326 */
327Node *InnerNode::findNode(const QString& name)
328{
329 Node *node = childMap.value(name);
330 if (node && node->subType() != QmlPropertyGroup)
331 return node;
332 if ((type() == Fake) && (subType() == QmlClass)) {
333 for (int i=0; i<children.size(); ++i) {
334 Node* n = children.at(i);
335 if (n->subType() == QmlPropertyGroup) {
336 node = static_cast<InnerNode*>(n)->findNode(name);
337 if (node)
338 return node;
339 }
340 }
341 }
342 return primaryFunctionMap.value(name);
343}
344
345/*!
346 Same as the other findNode(), but if the node with the
347 specified \a name is not of the specified \a type, return
348 0.
349 */
350Node *InnerNode::findNode(const QString& name, Type type)
351{
352 if (type == Function) {
353 return primaryFunctionMap.value(name);
354 }
355 else {
356 Node *node = childMap.value(name);
357 if (node && node->type() == type) {
358 return node;
359 }
360 else {
361 return 0;
362 }
363 }
364}
365
366/*!
367 Find the function node in this node for the function named \a name.
368 */
369FunctionNode *InnerNode::findFunctionNode(const QString& name)
370{
371 return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
372}
373
374/*!
375 Find the function node in this node that has the same name as \a clone.
376 */
377FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
378{
379 QMap<QString, Node *>::ConstIterator c =
380 primaryFunctionMap.find(clone->name());
381 if (c != primaryFunctionMap.end()) {
382 if (isSameSignature(clone, (FunctionNode *) *c)) {
383 return (FunctionNode *) *c;
384 }
385 else if (secondaryFunctionMap.contains(clone->name())) {
386 const NodeList& secs = secondaryFunctionMap[clone->name()];
387 NodeList::ConstIterator s = secs.begin();
388 while (s != secs.end()) {
389 if (isSameSignature(clone, (FunctionNode *) *s))
390 return (FunctionNode *) *s;
391 ++s;
392 }
393 }
394 }
395 return 0;
396}
397
398/*!
399 Returns the list of keys from the primary function map.
400 */
401QStringList InnerNode::primaryKeys()
402{
403 QStringList t;
404 QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
405 while (i != primaryFunctionMap.end()) {
406 t.append(i.key());
407 ++i;
408 }
409 return t;
410}
411
412/*!
413 Returns the list of keys from the secondary function map.
414 */
415QStringList InnerNode::secondaryKeys()
416{
417 QStringList t;
418 QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
419 while (i != secondaryFunctionMap.end()) {
420 t.append(i.key());
421 ++i;
422 }
423 return t;
424}
425
426/*!
427 */
428void InnerNode::setOverload(const FunctionNode *func, bool overlode)
429{
430 Node *node = (Node *) func;
431 Node *&primary = primaryFunctionMap[func->name()];
432
433 if (secondaryFunctionMap.contains(func->name())) {
434 NodeList& secs = secondaryFunctionMap[func->name()];
435 if (overlode) {
436 if (primary == node) {
437 primary = secs.first();
438 secs.erase(secs.begin());
439 secs.append(node);
440 }
441 else {
442 secs.removeAll(node);
443 secs.append(node);
444 }
445 }
446 else {
447 if (primary != node) {
448 secs.removeAll(node);
449 secs.prepend(primary);
450 primary = node;
451 }
452 }
453 }
454}
455
456/*!
457 Mark all child nodes that have no documentation as having
458 private access and internal status. qdoc will then ignore
459 them for documentation purposes.
460 */
461void InnerNode::makeUndocumentedChildrenInternal()
462{
463 foreach (Node *child, childNodes()) {
464 if (child->doc().isEmpty()) {
465 child->setAccess(Node::Private);
466 child->setStatus(Node::Internal);
467 }
468 }
469}
470
471/*!
472 */
473void InnerNode::normalizeOverloads()
474{
475 QMap<QString, Node *>::Iterator p1 = primaryFunctionMap.begin();
476 while (p1 != primaryFunctionMap.end()) {
477 FunctionNode *primaryFunc = (FunctionNode *) *p1;
478 if (secondaryFunctionMap.contains(primaryFunc->name()) &&
479 (primaryFunc->status() != Commendable ||
480 primaryFunc->access() == Private)) {
481
482 NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
483 NodeList::ConstIterator s = secs.begin();
484 while (s != secs.end()) {
485 FunctionNode *secondaryFunc = (FunctionNode *) *s;
486
487 // Any non-obsolete, non-compatibility, non-private functions
488 // (i.e, visible functions) are preferable to the primary
489 // function.
490
491 if (secondaryFunc->status() == Commendable &&
492 secondaryFunc->access() != Private) {
493
494 *p1 = secondaryFunc;
495 int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
496 secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
497 break;
498 }
499 ++s;
500 }
501 }
502 ++p1;
503 }
504
505 QMap<QString, Node *>::ConstIterator p = primaryFunctionMap.begin();
506 while (p != primaryFunctionMap.end()) {
507 FunctionNode *primaryFunc = (FunctionNode *) *p;
508 if (primaryFunc->isOverload())
509 primaryFunc->ove = false;
510 if (secondaryFunctionMap.contains(primaryFunc->name())) {
511 NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
512 NodeList::ConstIterator s = secs.begin();
513 while (s != secs.end()) {
514 FunctionNode *secondaryFunc = (FunctionNode *) *s;
515 if (!secondaryFunc->isOverload())
516 secondaryFunc->ove = true;
517 ++s;
518 }
519 }
520 ++p;
521 }
522
523 NodeList::ConstIterator c = childNodes().begin();
524 while (c != childNodes().end()) {
525 if ((*c)->isInnerNode())
526 ((InnerNode *) *c)->normalizeOverloads();
527 ++c;
528 }
529}
530
531/*!
532 */
533void InnerNode::removeFromRelated()
534{
535 while (!related.isEmpty()) {
536 Node *p = static_cast<Node *>(related.takeFirst());
537
538 if (p != 0 && p->relates() == this) p->clearRelated();
539 }
540}
541
542/*!
543 */
544void InnerNode::deleteChildren()
545{
546 qDeleteAll(children);
547}
548
549/*!
550 Returns true because this is an inner node.
551 */
552bool InnerNode::isInnerNode() const
553{
554 return true;
555}
556
557/*!
558 */
559const Node *InnerNode::findNode(const QString& name) const
560{
561 InnerNode *that = (InnerNode *) this;
562 return that->findNode(name);
563}
564
565/*!
566 */
567const Node *InnerNode::findNode(const QString& name, Type type) const
568{
569 InnerNode *that = (InnerNode *) this;
570 return that->findNode(name, type);
571}
572
573/*!
574 Find the function node in this node that has the given \a name.
575 */
576const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
577{
578 InnerNode *that = (InnerNode *) this;
579 return that->findFunctionNode(name);
580}
581
582/*!
583 Find the function node in this node that has the same name as \a clone.
584 */
585const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
586{
587 InnerNode *that = (InnerNode *) this;
588 return that->findFunctionNode(clone);
589}
590
591/*!
592 */
593const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
594{
595 foreach (const Node *node, enumChildren) {
596 const EnumNode *enume = static_cast<const EnumNode *>(node);
597 if (enume->hasItem(enumValue))
598 return enume;
599 }
600 return 0;
601}
602
603/*!
604 Returnds the sequence number of the function node \a func
605 in the list of overloaded functions for a class, such that
606 all the functions have the same name as the \a func.
607 */
608int InnerNode::overloadNumber(const FunctionNode *func) const
609{
610 Node *node = (Node *) func;
611 if (primaryFunctionMap[func->name()] == node) {
612 return 1;
613 }
614 else {
615 return secondaryFunctionMap[func->name()].indexOf(node) + 2;
616 }
617}
618
619/*!
620 Returns the number of member functions of a class such that
621 the functions are all named \a funcName.
622 */
623int InnerNode::numOverloads(const QString& funcName) const
624{
625 if (primaryFunctionMap.contains(funcName)) {
626 return secondaryFunctionMap[funcName].count() + 1;
627 }
628 else {
629 return 0;
630 }
631}
632
633/*!
634 Returns a node list containing all the member functions of
635 some class such that the functions overload the name \a funcName.
636 */
637NodeList InnerNode::overloads(const QString &funcName) const
638{
639 NodeList result;
640 Node *primary = primaryFunctionMap.value(funcName);
641 if (primary) {
642 result << primary;
643 result += secondaryFunctionMap[funcName];
644 }
645 return result;
646}
647
648/*!
649 Construct an inner node (i.e., not a leaf node) of the
650 given \a type and having the given \a parent and \a name.
651 */
652InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
653 : Node(type, parent, name)
654{
655 switch (type) {
656 case Class:
657 case Namespace:
658 setPageType(ApiPage);
659 break;
660 default:
661 break;
662 }
663}
664
665/*!
666 Appends an \a include file to the list of include files.
667 */
668void InnerNode::addInclude(const QString& include)
669{
670 inc.append(include);
671}
672
673/*!
674 Sets the list of include files to \a includes.
675 */
676void InnerNode::setIncludes(const QStringList& includes)
677{
678 inc = includes;
679}
680
681/*!
682 f1 is always the clone
683 */
684bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
685{
686 if (f1->parameters().count() != f2->parameters().count())
687 return false;
688 if (f1->isConst() != f2->isConst())
689 return false;
690
691 QList<Parameter>::ConstIterator p1 = f1->parameters().begin();
692 QList<Parameter>::ConstIterator p2 = f2->parameters().begin();
693 while (p2 != f2->parameters().end()) {
694 if ((*p1).hasType() && (*p2).hasType()) {
695 if ((*p1).rightType() != (*p2).rightType())
696 return false;
697
698 QString t1 = p1->leftType();
699 QString t2 = p2->leftType();
700
701 if (t1.length() < t2.length())
702 qSwap(t1, t2);
703
704 /*
705 ### hack for C++ to handle superfluous
706 "Foo::" prefixes gracefully
707 */
708 if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
709 return false;
710 }
711 ++p1;
712 ++p2;
713 }
714 return true;
715}
716
717/*!
718 Adds the \a child to this node's child list.
719 */
720void InnerNode::addChild(Node *child)
721{
722 children.append(child);
723 if ((child->type() == Function) || (child->type() == QmlMethod)) {
724 FunctionNode *func = (FunctionNode *) child;
725 if (!primaryFunctionMap.contains(func->name())) {
726 primaryFunctionMap.insert(func->name(), func);
727 }
728 else {
729 NodeList &secs = secondaryFunctionMap[func->name()];
730 secs.append(func);
731 }
732 }
733 else {
734 if (child->type() == Enum)
735 enumChildren.append(child);
736 childMap.insert(child->name(), child);
737 }
738}
739
740/*!
741 */
742void InnerNode::removeChild(Node *child)
743{
744 children.removeAll(child);
745 enumChildren.removeAll(child);
746 if (child->type() == Function) {
747 QMap<QString, Node *>::Iterator prim =
748 primaryFunctionMap.find(child->name());
749 NodeList& secs = secondaryFunctionMap[child->name()];
750 if (prim != primaryFunctionMap.end() && *prim == child) {
751 if (secs.isEmpty()) {
752 primaryFunctionMap.remove(child->name());
753 }
754 else {
755 primaryFunctionMap.insert(child->name(), secs.takeFirst());
756 }
757 }
758 else {
759 secs.removeAll(child);
760 }
761 QMap<QString, Node *>::Iterator ent = childMap.find( child->name() );
762 if (ent != childMap.end() && *ent == child)
763 childMap.erase( ent );
764 }
765 else {
766 QMap<QString, Node *>::Iterator ent = childMap.find(child->name());
767 if (ent != childMap.end() && *ent == child)
768 childMap.erase(ent);
769 }
770}
771
772/*!
773 Find the module (QtCore, QtGui, etc.) to which the class belongs.
774 We do this by obtaining the full path to the header file's location
775 and examine everything between "src/" and the filename. This is
776 semi-dirty because we are assuming a particular directory structure.
777
778 This function is only really useful if the class's module has not
779 been defined in the header file with a QT_MODULE macro or with an
780 \inmodule command in the documentation.
781*/
782QString Node::moduleName() const
783{
784 if (!mod.isEmpty())
785 return mod;
786
787 QString path = location().filePath();
788 QString pattern = QString("src") + QDir::separator();
789 int start = path.lastIndexOf(pattern);
790
791 if (start == -1)
792 return "";
793
794 QString moduleDir = path.mid(start + pattern.size());
795 int finish = moduleDir.indexOf(QDir::separator());
796
797 if (finish == -1)
798 return "";
799
800 QString moduleName = moduleDir.left(finish);
801
802 if (moduleName == "corelib")
803 return "QtCore";
804 else if (moduleName == "uitools")
805 return "QtUiTools";
806 else if (moduleName == "gui")
807 return "QtGui";
808 else if (moduleName == "network")
809 return "QtNetwork";
810 else if (moduleName == "opengl")
811 return "QtOpenGL";
812 else if (moduleName == "qt3support")
813 return "Qt3Support";
814 else if (moduleName == "svg")
815 return "QtSvg";
816 else if (moduleName == "sql")
817 return "QtSql";
818 else if (moduleName == "qtestlib")
819 return "QtTest";
820 else if (moduleDir.contains("webkit"))
821 return "QtWebKit";
822 else if (moduleName == "xml")
823 return "QtXml";
824 else
825 return "";
826}
827
828/*!
829 */
830void InnerNode::removeRelated(Node *pseudoChild)
831{
832 related.removeAll(pseudoChild);
833}
834
835/*!
836 \class LeafNode
837 */
838
839/*!
840 Returns false because this is a LeafNode.
841 */
842bool LeafNode::isInnerNode() const
843{
844 return false;
845}
846
847/*!
848 Constructs a leaf node named \a name of the specified
849 \a type. The new leaf node becomes a child of \a parent.
850 */
851LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
852 : Node(type, parent, name)
853{
854 switch (type) {
855 case Enum:
856 case Function:
857 case Typedef:
858 case Variable:
859 case QmlProperty:
860 case QmlSignal:
861 case QmlMethod:
862 setPageType(ApiPage);
863 break;
864 default:
865 break;
866 }
867}
868
869/*!
870 \class NamespaceNode
871 */
872
873/*!
874 Constructs a namespace node.
875 */
876NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
877 : InnerNode(Namespace, parent, name)
878{
879 setPageType(ApiPage);
880}
881
882/*!
883 \class ClassNode
884 \brief This class represents a C++ class.
885 */
886
887/*!
888 Constructs a class node. A class node will generate an API page.
889 */
890ClassNode::ClassNode(InnerNode *parent, const QString& name)
891 : InnerNode(Class, parent, name)
892{
893 hidden = false;
894 abstract = false;
895 setPageType(ApiPage);
896}
897
898/*!
899 */
900void ClassNode::addBaseClass(Access access,
901 ClassNode *node,
902 const QString &dataTypeWithTemplateArgs)
903{
904 bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
905 node->derived.append(RelatedClass(access, this));
906}
907
908/*!
909 */
910void ClassNode::fixBaseClasses()
911{
912 int i;
913 i = 0;
914 while (i < bases.size()) {
915 ClassNode* bc = bases.at(i).node;
916 if (bc->access() == Node::Private) {
917 RelatedClass rc = bases.at(i);
918 bases.removeAt(i);
919 ignoredBases.append(rc);
920 const QList<RelatedClass> &bb = bc->baseClasses();
921 for (int j = bb.size() - 1; j >= 0; --j)
922 bases.insert(i, bb.at(j));
923 }
924 else {
925 ++i;
926 }
927 }
928
929 i = 0;
930 while (i < derived.size()) {
931 ClassNode* dc = derived.at(i).node;
932 if (dc->access() == Node::Private) {
933 derived.removeAt(i);
934 const QList<RelatedClass> &dd = dc->derivedClasses();
935 for (int j = dd.size() - 1; j >= 0; --j)
936 derived.insert(i, dd.at(j));
937 }
938 else {
939 ++i;
940 }
941 }
942}
943
944/*!
945 Search the child list to find the property node with the
946 specified \a name.
947 */
948const PropertyNode* ClassNode::findPropertyNode(const QString& name) const
949{
950 const Node* n = findNode(name,Node::Property);
951 return (n ? static_cast<const PropertyNode*>(n) : 0);
952}
953
954/*!
955 \class FakeNode
956 */
957
958/*!
959 The type of a FakeNode is Fake, and it has a \a subtype,
960 which specifies the type of FakeNode. The page type for
961 the page index is set here.
962 */
963FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype)
964 : InnerNode(Fake, parent, name), sub(subtype)
965{
966 switch (subtype) {
967 case Module:
968 case Page:
969 case Group:
970 setPageType(ArticlePage);
971 break;
972 case QmlClass:
973 case QmlBasicType:
974 setPageType(ApiPage);
975 break;
976 case Example:
977 setPageType(ExamplePage);
978 break;
979 default:
980 break;
981 }
982}
983
984/*!
985 Returns the fake node's title. This is used for the page title.
986*/
987QString FakeNode::title() const
988{
989 return tle;
990}
991
992/*!
993 Returns the fake node's full title, which is usually
994 just title(), but for some SubType values is different
995 from title()
996 */
997QString FakeNode::fullTitle() const
998{
999 if (sub == File) {
1000 if (title().isEmpty())
1001 return name().mid(name().lastIndexOf('/') + 1) + " Example File";
1002 else
1003 return title();
1004 }
1005 else if (sub == Image) {
1006 if (title().isEmpty())
1007 return name().mid(name().lastIndexOf('/') + 1) + " Image File";
1008 else
1009 return title();
1010 }
1011 else if (sub == HeaderFile) {
1012 if (title().isEmpty())
1013 return name();
1014 else
1015 return name() + " - " + title();
1016 }
1017 else {
1018 return title();
1019 }
1020}
1021
1022/*!
1023 Returns the subtitle.
1024 */
1025QString FakeNode::subTitle() const
1026{
1027 if (!stle.isEmpty())
1028 return stle;
1029
1030 if ((sub == File) || (sub == Image)) {
1031 if (title().isEmpty() && name().contains("/"))
1032 return name();
1033 }
1034 return QString();
1035}
1036
1037/*!
1038 \class EnumNode
1039 */
1040
1041/*!
1042 The constructor for the node representing an enum type
1043 has a \a parent class and an enum type \a name.
1044 */
1045EnumNode::EnumNode(InnerNode *parent, const QString& name)
1046 : LeafNode(Enum, parent, name), ft(0)
1047{
1048}
1049
1050/*!
1051 Add \a item to the enum type's item list.
1052 */
1053void EnumNode::addItem(const EnumItem& item)
1054{
1055 itms.append(item);
1056 names.insert(item.name());
1057}
1058
1059/*!
1060 Returns the access level of the enumeration item named \a name.
1061 Apparently it is private if it has been omitted by qdoc's
1062 omitvalue command. Otherwise it is public.
1063 */
1064Node::Access EnumNode::itemAccess(const QString &name) const
1065{
1066 if (doc().omitEnumItemNames().contains(name))
1067 return Private;
1068 return Public;
1069}
1070
1071/*!
1072 Returns the enum value associated with the enum \a name.
1073 */
1074QString EnumNode::itemValue(const QString &name) const
1075{
1076 foreach (const EnumItem &item, itms) {
1077 if (item.name() == name)
1078 return item.value();
1079 }
1080 return QString();
1081}
1082
1083/*!
1084 \class TypedefNode
1085 */
1086
1087/*!
1088 */
1089TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
1090 : LeafNode(Typedef, parent, name), ae(0)
1091{
1092}
1093
1094/*!
1095 */
1096void TypedefNode::setAssociatedEnum(const EnumNode *enume)
1097{
1098 ae = enume;
1099}
1100
1101/*!
1102 \class Parameter
1103 \brief The class Parameter contains one parameter.
1104
1105 A parameter can be a function parameter or a macro
1106 parameter.
1107 */
1108
1109/*!
1110 Constructs this parameter from the left and right types
1111 \a leftType and rightType, the parameter \a name, and the
1112 \a defaultValue. In practice, \a rightType is not used,
1113 and I don't know what is was meant for.
1114 */
1115Parameter::Parameter(const QString& leftType,
1116 const QString& rightType,
1117 const QString& name,
1118 const QString& defaultValue)
1119 : lef(leftType), rig(rightType), nam(name), def(defaultValue)
1120{
1121}
1122
1123/*!
1124 The standard copy constructor copies the strings from \a p.
1125 */
1126Parameter::Parameter(const Parameter& p)
1127 : lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
1128{
1129}
1130
1131/*!
1132 Assigning Parameter \a p to this Parameter copies the
1133 strings across.
1134 */
1135Parameter& Parameter::operator=(const Parameter& p)
1136{
1137 lef = p.lef;
1138 rig = p.rig;
1139 nam = p.nam;
1140 def = p.def;
1141 return *this;
1142}
1143
1144/*!
1145 Reconstructs the text describing the parameter and
1146 returns it. If \a value is true, the default value
1147 will be included, if there is one.
1148 */
1149QString Parameter::reconstruct(bool value) const
1150{
1151 QString p = lef + rig;
1152 if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
1153 p += " ";
1154 p += nam;
1155 if (value)
1156 p += def;
1157 return p;
1158}
1159
1160
1161/*!
1162 \class FunctionNode
1163 */
1164
1165/*!
1166 Construct a function node for a C++ function. It's parent
1167 is \a parent, and it's name is \a name.
1168 */
1169FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
1170 : LeafNode(Function, parent, name),
1171 met(Plain),
1172 vir(NonVirtual),
1173 con(false),
1174 sta(false),
1175 ove(false),
1176 att(false),
1177 rf(0),
1178 ap(0)
1179{
1180 // nothing.
1181}
1182
1183/*!
1184 Construct a function node for a QML method or signal, specified
1185 by \a type. It's parent is \a parent, and it's name is \a name.
1186 If \a attached is true, it is an attached method or signal.
1187 */
1188FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
1189 : LeafNode(type, parent, name),
1190 met(Plain),
1191 vir(NonVirtual),
1192 con(false),
1193 sta(false),
1194 ove(false),
1195 att(attached),
1196 rf(0),
1197 ap(0)
1198{
1199 // nothing.
1200}
1201
1202/*!
1203 Sets the \a virtualness of this function. If the \a virtualness
1204 is PureVirtual, and if the parent() is a ClassNode, set the parent's
1205 \e abstract flag to true.
1206 */
1207void FunctionNode::setVirtualness(Virtualness virtualness)
1208{
1209 vir = virtualness;
1210 if ((virtualness == PureVirtual) && parent() &&
1211 (parent()->type() == Node::Class))
1212 parent()->setAbstract(true);
1213}
1214
1215/*!
1216 */
1217void FunctionNode::setOverload(bool overlode)
1218{
1219 parent()->setOverload(this, overlode);
1220 ove = overlode;
1221}
1222
1223/*!
1224 Sets the function node's reimplementation flag to \a r.
1225 When \a r is true, it is supposed to mean that this function
1226 is a reimplementation of a virtual function in a base class,
1227 but it really just means the \e reimp command was seen in the
1228 qdoc comment.
1229 */
1230void FunctionNode::setReimp(bool r)
1231{
1232 reimp = r;
1233}
1234
1235/*!
1236 */
1237void FunctionNode::addParameter(const Parameter& parameter)
1238{
1239 params.append(parameter);
1240}
1241
1242/*!
1243 */
1244void FunctionNode::borrowParameterNames(const FunctionNode *source)
1245{
1246 QList<Parameter>::Iterator t = params.begin();
1247 QList<Parameter>::ConstIterator s = source->params.begin();
1248 while (s != source->params.end() && t != params.end()) {
1249 if (!(*s).name().isEmpty())
1250 (*t).setName((*s).name());
1251 ++s;
1252 ++t;
1253 }
1254}
1255
1256/*!
1257 If this function is a reimplementation, \a from points
1258 to the FunctionNode of the function being reimplemented.
1259 */
1260void FunctionNode::setReimplementedFrom(FunctionNode *from)
1261{
1262 rf = from;
1263 from->rb.append(this);
1264}
1265
1266/*!
1267 Sets the "associated" property to \a property. The function
1268 might be the setter or getter for a property, for example.
1269 */
1270void FunctionNode::setAssociatedProperty(PropertyNode *property)
1271{
1272 ap = property;
1273}
1274
1275/*!
1276 Returns the overload number for this function obtained
1277 from the parent.
1278 */
1279int FunctionNode::overloadNumber() const
1280{
1281 return parent()->overloadNumber(this);
1282}
1283
1284/*!
1285 Returns the number of times this function name has been
1286 overloaded, obtained from the parent.
1287 */
1288int FunctionNode::numOverloads() const
1289{
1290 return parent()->numOverloads(name());
1291}
1292
1293/*!
1294 Returns the list of parameter names.
1295 */
1296QStringList FunctionNode::parameterNames() const
1297{
1298 QStringList names;
1299 QList<Parameter>::ConstIterator p = parameters().begin();
1300 while (p != parameters().end()) {
1301 names << (*p).name();
1302 ++p;
1303 }
1304 return names;
1305}
1306
1307/*!
1308 Returns a raw list of parameters. If \a names is true, the
1309 names are included. If \a values is true, the default values
1310 are included, if any are present.
1311 */
1312QString FunctionNode::rawParameters(bool names, bool values) const
1313{
1314 QString raw;
1315 foreach (const Parameter &parameter, parameters()) {
1316 raw += parameter.leftType() + parameter.rightType();
1317 if (names)
1318 raw += parameter.name();
1319 if (values)
1320 raw += parameter.defaultValue();
1321 }
1322 return raw;
1323}
1324
1325/*!
1326 Returns the list of reconstructed parameters. If \a values
1327 is true, the default values are included, if any are present.
1328 */
1329QStringList FunctionNode::reconstructParams(bool values) const
1330{
1331 QStringList params;
1332 QList<Parameter>::ConstIterator p = parameters().begin();
1333 while (p != parameters().end()) {
1334 params << (*p).reconstruct(values);
1335 ++p;
1336 }
1337 return params;
1338}
1339
1340/*!
1341 Reconstructs and returns the function's signature. If \a values
1342 is true, the default values of the parameters are included, if
1343 present.
1344 */
1345QString FunctionNode::signature(bool values) const
1346{
1347 QString s;
1348 if (!returnType().isEmpty())
1349 s = returnType() + " ";
1350 s += name() + "(";
1351 QStringList params = reconstructParams(values);
1352 int p = params.size();
1353 if (p > 0) {
1354 for (int i=0; i<p; i++) {
1355 s += params[i];
1356 if (i < (p-1))
1357 s += ", ";
1358 }
1359 }
1360 s += ")";
1361 return s;
1362}
1363
1364/*!
1365 Print some debugging stuff.
1366 */
1367void FunctionNode::debug() const
1368{
1369 qDebug("QML METHOD %s rt %s pp %s",
1370 qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
1371}
1372
1373/*!
1374 \class PropertyNode
1375
1376 This class describes one instance of using the Q_PROPERTY macro.
1377 */
1378
1379/*!
1380 The constructor sets the \a parent and the \a name, but
1381 everything else is set to default values.
1382 */
1383PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
1384 : LeafNode(Property, parent, name),
1385 sto(Trool_Default),
1386 des(Trool_Default),
1387 scr(Trool_Default),
1388 wri(Trool_Default),
1389 usr(Trool_Default),
1390 cst(false),
1391 fnl(false),
1392 overrides(0)
1393{
1394 // nothing.
1395}
1396
1397/*!
1398 Sets this property's \e {overridden from} property to
1399 \a baseProperty, which indicates that this property
1400 overrides \a baseProperty. To begin with, all the values
1401 in this property are set to the corresponding values in
1402 \a baseProperty.
1403
1404 We probably should ensure that the constant and final
1405 attributes are not being overridden improperly.
1406 */
1407void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
1408{
1409 for (int i = 0; i < NumFunctionRoles; ++i) {
1410 if (funcs[i].isEmpty())
1411 funcs[i] = baseProperty->funcs[i];
1412 }
1413 if (sto == Trool_Default)
1414 sto = baseProperty->sto;
1415 if (des == Trool_Default)
1416 des = baseProperty->des;
1417 if (scr == Trool_Default)
1418 scr = baseProperty->scr;
1419 if (wri == Trool_Default)
1420 wri = baseProperty->wri;
1421 if (usr == Trool_Default)
1422 usr = baseProperty->usr;
1423 overrides = baseProperty;
1424}
1425
1426/*!
1427 */
1428QString PropertyNode::qualifiedDataType() const
1429{
1430 if (setters().isEmpty() && resetters().isEmpty()) {
1431 if (dt.contains("*") || dt.contains("&")) {
1432 // 'QWidget *' becomes 'QWidget *' const
1433 return dt + " const";
1434 }
1435 else {
1436 /*
1437 'int' becomes 'const int' ('int const' is
1438 correct C++, but looks wrong)
1439 */
1440 return "const " + dt;
1441 }
1442 }
1443 else {
1444 return dt;
1445 }
1446}
1447
1448/*! Converts the \a boolean value to an enum representation
1449 of the boolean type, which includes an enum value for the
1450 \e {default value} of the item, i.e. true, false, or default.
1451 */
1452PropertyNode::Trool PropertyNode::toTrool(bool boolean)
1453{
1454 return boolean ? Trool_True : Trool_False;
1455}
1456
1457/*!
1458 Converts the enum \a troolean back to a boolean value.
1459 If \a troolean is neither the true enum value nor the
1460 false enum value, the boolean value returned is
1461 \a defaultValue.
1462
1463 Note that runtimeDesignabilityFunction() should be called
1464 first. If that function returns the name of a function, it
1465 means the function must be called at runtime to determine
1466 whether the property is Designable.
1467 */
1468bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
1469{
1470 switch (troolean) {
1471 case Trool_True:
1472 return true;
1473 case Trool_False:
1474 return false;
1475 default:
1476 return defaultValue;
1477 }
1478}
1479
1480/*!
1481 \class TargetNode
1482 */
1483
1484/*!
1485 */
1486TargetNode::TargetNode(InnerNode *parent, const QString& name)
1487 : LeafNode(Target, parent, name)
1488{
1489}
1490
1491/*!
1492 Returns false because this is a TargetNode.
1493 */
1494bool TargetNode::isInnerNode() const
1495{
1496 return false;
1497}
1498
1499#ifdef QDOC_QML
1500bool QmlClassNode::qmlOnly = false;
1501QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
1502
1503/*!
1504 Constructs a Qml class node (i.e. a Fake node with the
1505 subtype QmlClass. The new node has the given \a parent
1506 and \a name and is associated with the C++ class node
1507 specified by \a cn which may be null if the the Qml
1508 class node is not associated with a C++ class node.
1509 */
1510QmlClassNode::QmlClassNode(InnerNode *parent,
1511 const QString& name,
1512 const ClassNode* cn)
1513 : FakeNode(parent, name, QmlClass), cnode(cn)
1514{
1515 if (name.startsWith(QLatin1String("QML:")))
1516 setTitle((qmlOnly ? QLatin1String("") : QLatin1String("QML ")) + name.mid(4) + QLatin1String(" Element"));
1517 else
1518 setTitle((qmlOnly ? QLatin1String("") : QLatin1String("QML ")) + name + QLatin1String(" Element"));
1519}
1520
1521/*!
1522 I made this so I could print a debug message here.
1523 */
1524QmlClassNode::~QmlClassNode()
1525{
1526#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
1527 qDebug() << "Deleting QmlClassNode:" << name();
1528#endif
1529}
1530
1531/*!
1532 Clear the multimap so that subsequent runs don't try to use
1533 nodes from a previous run.
1534 */
1535void QmlClassNode::clear()
1536{
1537 inheritedBy.clear();
1538}
1539
1540/*!
1541 The base file name for this kind of node has "qml_"
1542 prepended to it.
1543
1544 But not yet. Still testing.
1545 */
1546QString QmlClassNode::fileBase() const
1547{
1548#if 0
1549 if (Node::fileBase() == "item")
1550 qDebug() << "FILEBASE: qmlitem" << name();
1551 return "qml_" + Node::fileBase();
1552#endif
1553 return Node::fileBase();
1554}
1555
1556/*!
1557 Record the fact that QML class \a base is inherited by
1558 QML class \a sub.
1559 */
1560void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
1561{
1562 inheritedBy.insert(base,sub);
1563#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
1564 qDebug() << "QmlClassNode::addInheritedBy(): insert" << base << sub->name() << inheritedBy.size();
1565#endif
1566}
1567
1568/*!
1569 Loads the list \a subs with the nodes of all the subclasses of \a base.
1570 */
1571void QmlClassNode::subclasses(const QString& base, NodeList& subs)
1572{
1573 subs.clear();
1574 if (inheritedBy.count(base) > 0) {
1575 subs = inheritedBy.values(base);
1576#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
1577 qDebug() << "QmlClassNode::subclasses():" << inheritedBy.count(base) << base
1578 << "subs:" << subs.size() << "total size:" << inheritedBy.size();
1579#endif
1580 }
1581}
1582
1583/*!
1584 Constructs a Qml basic type node (i.e. a Fake node with
1585 the subtype QmlBasicType. The new node has the given
1586 \a parent and \a name.
1587 */
1588QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
1589 const QString& name)
1590 : FakeNode(parent, name, QmlBasicType)
1591{
1592 setTitle(name);
1593}
1594
1595/*!
1596 Constructor for the Qml property group node. \a parent is
1597 always a QmlClassNode.
1598 */
1599QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent,
1600 const QString& name,
1601 bool attached)
1602 : FakeNode(parent, name, QmlPropertyGroup),
1603 isdefault(false),
1604 att(attached)
1605{
1606 // nothing.
1607}
1608
1609/*!
1610 Constructor for the QML property node.
1611 */
1612QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
1613 const QString& name,
1614 const QString& type,
1615 bool attached)
1616 : LeafNode(QmlProperty, parent, name),
1617 dt(type),
1618 sto(Trool_Default),
1619 des(Trool_Default),
1620 att(attached)
1621{
1622 setPageType(ApiPage);
1623}
1624
1625/*!
1626 I don't know what this is.
1627 */
1628QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
1629{
1630 return boolean ? Trool_True : Trool_False;
1631}
1632
1633/*!
1634 I don't know what this is either.
1635 */
1636bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
1637{
1638 switch (troolean) {
1639 case Trool_True:
1640 return true;
1641 case Trool_False:
1642 return false;
1643 default:
1644 return defaultValue;
1645 }
1646}
1647
1648static QString valueType(const QString& n)
1649{
1650 if (n == "QPoint")
1651 return "QDeclarativePointValueType";
1652 if (n == "QPointF")
1653 return "QDeclarativePointFValueType";
1654 if (n == "QSize")
1655 return "QDeclarativeSizeValueType";
1656 if (n == "QSizeF")
1657 return "QDeclarativeSizeFValueType";
1658 if (n == "QRect")
1659 return "QDeclarativeRectValueType";
1660 if (n == "QRectF")
1661 return "QDeclarativeRectFValueType";
1662 if (n == "QVector2D")
1663 return "QDeclarativeVector2DValueType";
1664 if (n == "QVector3D")
1665 return "QDeclarativeVector3DValueType";
1666 if (n == "QVector4D")
1667 return "QDeclarativeVector4DValueType";
1668 if (n == "QQuaternion")
1669 return "QDeclarativeQuaternionValueType";
1670 if (n == "QMatrix4x4")
1671 return "QDeclarativeMatrix4x4ValueType";
1672 if (n == "QEasingCurve")
1673 return "QDeclarativeEasingValueType";
1674 if (n == "QFont")
1675 return "QDeclarativeFontValueType";
1676 return QString();
1677}
1678
1679/*!
1680 Returns true if a QML property or attached property is
1681 read-only. The algorithm for figuring this out is long
1682 amd tedious and almost certainly will break. It currently
1683 doesn't work for qmlproperty bool PropertyChanges::explicit,
1684 because the tokenized gets confused on "explicit" .
1685 */
1686bool QmlPropertyNode::isWritable(const Tree* tree) const
1687{
1688 Node* n = parent();
1689 while (n && n->subType() != Node::QmlClass)
1690 n = n->parent();
1691 if (n) {
1692 const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
1693 const ClassNode* cn = qcn->classNode();
1694 if (cn) {
1695 QStringList dotSplit = name().split(QChar('.'));
1696 const PropertyNode* pn = cn->findPropertyNode(dotSplit[0]);
1697 if (pn) {
1698 if (dotSplit.size() > 1) {
1699 QStringList path(extractClassName(pn->qualifiedDataType()));
1700 const Node* nn = tree->findNode(path,Class);
1701 if (nn) {
1702 const ClassNode* cn = static_cast<const ClassNode*>(nn);
1703 pn = cn->findPropertyNode(dotSplit[1]);
1704 if (pn) {
1705 return pn->isWritable();
1706 }
1707 else {
1708 const QList<RelatedClass>& bases = cn->baseClasses();
1709 if (!bases.isEmpty()) {
1710 for (int i=0; i<bases.size(); ++i) {
1711 const ClassNode* cn = bases[i].node;
1712 pn = cn->findPropertyNode(dotSplit[1]);
1713 if (pn) {
1714 return pn->isWritable();
1715 }
1716 }
1717 }
1718 const QList<RelatedClass>& ignoredBases = cn->ignoredBaseClasses();
1719 if (!ignoredBases.isEmpty()) {
1720 for (int i=0; i<ignoredBases.size(); ++i) {
1721 const ClassNode* cn = ignoredBases[i].node;
1722 pn = cn->findPropertyNode(dotSplit[1]);
1723 if (pn) {
1724 return pn->isWritable();
1725 }
1726 }
1727 }
1728 QString vt = valueType(cn->name());
1729 if (!vt.isEmpty()) {
1730 QStringList path(vt);
1731 const Node* vtn = tree->findNode(path,Class);
1732 if (vtn) {
1733 const ClassNode* cn = static_cast<const ClassNode*>(vtn);
1734 pn = cn->findPropertyNode(dotSplit[1]);
1735 if (pn) {
1736 return pn->isWritable();
1737 }
1738 }
1739 }
1740 }
1741 }
1742 }
1743 else {
1744 return pn->isWritable();
1745 }
1746 }
1747 else {
1748 const QList<RelatedClass>& bases = cn->baseClasses();
1749 if (!bases.isEmpty()) {
1750 for (int i=0; i<bases.size(); ++i) {
1751 const ClassNode* cn = bases[i].node;
1752 pn = cn->findPropertyNode(dotSplit[0]);
1753 if (pn) {
1754 return pn->isWritable();
1755 }
1756 }
1757 }
1758 const QList<RelatedClass>& ignoredBases = cn->ignoredBaseClasses();
1759 if (!ignoredBases.isEmpty()) {
1760 for (int i=0; i<ignoredBases.size(); ++i) {
1761 const ClassNode* cn = ignoredBases[i].node;
1762 pn = cn->findPropertyNode(dotSplit[0]);
1763 if (pn) {
1764 return pn->isWritable();
1765 }
1766 }
1767 }
1768 if (isAttached()) {
1769 QString classNameAttached = cn->name() + "Attached";
1770 QStringList path(classNameAttached);
1771 const Node* nn = tree->findNode(path,Class);
1772 const ClassNode* acn = static_cast<const ClassNode*>(nn);
1773 pn = acn->findPropertyNode(dotSplit[0]);
1774 if (pn) {
1775 return pn->isWritable();
1776 }
1777 }
1778 }
1779 }
1780 }
1781 location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
1782 return true;
1783}
1784
1785#endif
1786
1787QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.