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