OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / model / modelnode.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include <modelnode.h>
34 #include <abstractproperty.h>
35 #include <abstractview.h>
36 #include <model.h>
37 #include <metainfo.h>
38 #include "internalnode_p.h"
39 #include <QHash>
40 #include <QTextStream>
41 #include "invalidargumentexception.h"
42 #include "invalididexception.h"
43 #include "invalidmodelnodeexception.h"
44 #include "invalidpropertyexception.h"
45 #include "invalidslideindexexception.h"
46 #include "model_p.h"
47 #include "abstractview.h"
48 #include "abstractproperty.h"
49 #include "variantproperty.h"
50 #include "bindingproperty.h"
51 #include "nodeabstractproperty.h"
52 #include "nodelistproperty.h"
53 #include "nodeproperty.h"
54
55 namespace QmlDesigner {
56 using namespace QmlDesigner::Internal;
57
58 /*!
59 \class QmlDesigner::ModelNode
60 \ingroup CoreModel
61 \brief The central class to access the node which can represent a widget, layout
62             or other items. A Node is a part of a tree and has properties.
63
64 Conceptually ModelNode is an opaque handle to the internal data structures.
65
66 There is always a root model node in every QmlDesigner::Model:
67 \code
68 QmlDesigner::Model *model = QmlDesigner::Model::create();
69 QmlDesigner::ModelNode rootNode = model->rootNode();
70 \endcode
71
72 You can add a property to a node:
73 \code
74 childNode.addProperty("pos", QPoint(2, 12));
75 \endcode
76
77 All the manipulation functions are generating undo commands internally.
78 */
79
80
81
82 /*! \brief internal constructor
83
84 */
85 ModelNode::ModelNode(const InternalNodePointer &internalNode, Model *model, AbstractView *view):
86         m_internalNode(internalNode),
87         m_model(model),
88         m_view(view)
89 {
90     Q_ASSERT(!m_model || m_view);
91 }
92
93 ModelNode::ModelNode(const ModelNode modelNode, AbstractView *view)
94     : m_internalNode(modelNode.m_internalNode),
95       m_model(modelNode.model()),
96       m_view(view)
97 {
98
99 }
100
101 /*! \brief contructs a invalid model node
102 \return invalid node
103 \see invalid
104 */
105 ModelNode::ModelNode():
106         m_internalNode(new InternalNode)
107 {
108
109 }
110
111 ModelNode::ModelNode(const ModelNode &other):
112         m_internalNode(other.m_internalNode),
113         m_model(other.m_model),
114         m_view(other.m_view)
115 {
116 }
117
118 ModelNode& ModelNode::operator=(const ModelNode &other)
119 {
120     this->m_model = other.m_model;
121     this->m_internalNode = other.m_internalNode;
122     this->m_view = other.m_view;
123
124     return *this;
125 }
126
127 /*! \brief does nothing
128 */
129 ModelNode::~ModelNode()
130 {
131 }
132
133 QString ModelNode::generateNewId() const
134 {
135     int counter = 1;
136     QString newId = QString("%1%2").arg(simplifiedTypeName().toLower()).arg(counter);
137
138     while(view()->hasId(newId)) {
139         counter += 1;
140         newId = QString("%1%2").arg(simplifiedTypeName().toLower()).arg(counter);
141     }
142
143     return newId;
144 }
145
146 /*! \brief returns the name of node which is a short cut to a property like objectName
147 \return name of the node
148 */
149 QString ModelNode::id() const
150 {
151     if (!isValid()) {
152         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
153     }
154
155     return m_internalNode->id();
156 }
157
158 QString ModelNode::validId()
159 {
160     if (id().isEmpty())
161         setId(generateNewId());
162
163     return id();
164 }
165
166 static bool idIsQmlKeyWord(const QString& id)
167 {
168     QStringList keywords;
169     keywords << "import" << "as";
170
171     return keywords.contains(id);
172 }
173
174 static bool idContainsWrongLetter(const QString& id)
175 {
176     static QRegExp idExpr(QLatin1String("[a-z_][a-zA-Z0-9_]*"));
177     return !idExpr.exactMatch(id);
178 }
179
180 bool ModelNode::isValidId(const QString &id)
181 {
182     return id.isEmpty() || (!idContainsWrongLetter(id) && !idIsQmlKeyWord(id));
183 }
184
185 void ModelNode::setId(const QString& id)
186 {
187     Internal::WriteLocker locker(m_model.data());
188     if (!isValid()) {
189         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
190         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
191     }
192
193     if (!isValidId(id))
194         throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id, InvalidIdException::InvalidCharacters);
195
196     if (id == ModelNode::id())
197         return;
198
199     if (view()->hasId(id))
200         throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id, InvalidIdException::DuplicateId);
201
202     m_model.data()->m_d->changeNodeId(internalNode(), id);
203 }
204
205 /*! \brief the fully-qualified type name of the node is represented as string
206 \return type of the node as a string
207 */
208 QString ModelNode::type() const
209 {
210     if (!isValid()) {
211         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
212         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
213     }
214     return m_internalNode->type();
215 }
216
217 /*! \brief minor number of the QML type
218 \return minor number
219 */
220 int ModelNode::minorVersion() const
221 {
222     if (!isValid()) {
223         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
224         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
225     }
226     return m_internalNode->minorVersion();
227 }
228
229 /*! \brief major number of the QML type
230 \return major number
231 */
232 int ModelNode::majorVersion() const
233 {
234     if (!isValid()) {
235         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
236         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
237     }
238     return m_internalNode->majorVersion();
239 }
240
241
242 /*! \return the short-hand type name of the node. */
243 QString ModelNode::simplifiedTypeName() const
244 {
245     if (!isValid()) {
246         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
247         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
248     }
249
250     return type().split(QLatin1Char('.')).last();
251 }
252
253 /*! \brief Returns whether the node is valid
254
255 A node is valid if its model still exists, and contains this node.
256 Also, the current state must be a valid one.
257
258 A node might become invalid if e.g. it or one of its ancestors is deleted.
259
260 \return is a node valid(true) or invalid(false)
261 */
262 bool ModelNode::isValid() const
263 {
264     return !m_model.isNull() && !m_view.isNull() && m_internalNode &&m_internalNode->isValid() /*&& model()->metaInfo().hasNodeMetaInfo(m_internalNode->type(), m_internalNode->majorVersion(), m_internalNode->minorVersion())*/;
265 }
266
267 /*!
268   \brief Returns whether the root node of the model is one of the anchestors of this node.
269
270   Will return true also for the root node itself.
271   */
272 bool ModelNode::isInHierarchy() const
273 {
274     if (!isValid()) {
275         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
276         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
277     }
278     if (isRootNode())
279         return true;
280     if (!hasParentProperty())
281         return false;
282     return parentProperty().parentModelNode().isInHierarchy();
283 }
284
285 /*!
286   \brief Returns the property containing this node
287
288   The NodeAbstractProperty is invalid if this ModelNode has no parent.
289   NodeAbstractProperty can be a NodeProperty containing a single ModelNode, or
290   a NodeListProperty.
291
292   \return the property containing this ModelNode
293   */
294 NodeAbstractProperty ModelNode::parentProperty() const
295 {
296     if (!isValid()) {
297         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
298         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
299     }
300     if (m_internalNode->parentProperty().isNull())
301         return NodeAbstractProperty();
302
303     return NodeAbstractProperty(m_internalNode->parentProperty()->name(), m_internalNode->parentProperty()->propertyOwner(), m_model.data(), view());
304 }
305
306
307 /*! \brief the command id is used to compress the some commands together.
308 \param newParentNode parent of this node will be set to this node
309 \param commandId integer which is used to descripe commands which should compressed together to one command
310
311 For example:
312 \code
313 node.setParentNode(parentNode1);
314 node.setParentNode(parentNode2, 212);
315 node.setParentNode(parentNode3, 212);
316 model->undoStack()->undo();
317 ModelNode parentNode4 = node.parentProperty().parentModelNode();
318 parentNode4 == parentNode1; -> true
319 \endcode
320
321 \see parentNode childNodes hasChildNodes Model::undo
322
323 */
324
325 void ModelNode::setParentProperty(NodeAbstractProperty parent)
326 {
327     if (!isValid()) {
328         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
329         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
330     }
331
332     if (!parent.parentModelNode().isValid()) {
333         throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, "newParentNode");
334     }
335
336     if (*this == parent.parentModelNode()) {
337         Q_ASSERT_X(*this != parent.parentModelNode(), Q_FUNC_INFO, "cannot set parent to itself");
338         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
339     }
340
341     if (parent == parentProperty())
342         return;
343
344     parent.reparentHere(*this);
345 }
346
347 void ModelNode::setParentProperty(const ModelNode &newParentNode, const QString &propertyName)
348 {
349     setParentProperty(newParentNode.nodeAbstractProperty(propertyName));
350 }
351
352 /*! \brief test if there is a parent for this node
353 \return true is this node has a parent
354 \see childNodes parentNode setParentNode hasChildNodes Model::undo
355 */
356 bool ModelNode::hasParentProperty() const
357 {
358     if (!isValid()) {
359         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
360         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
361     }
362
363     if (m_internalNode->parentProperty().isNull())
364         return false;
365
366     return true;
367 }
368
369 /*!
370   \brief Returns a BindingProperty
371
372   Note that a valid BindingProperty is returned, if the ModelNode is valid,
373   even if this property does not exist or is not a BindingProperty.
374   Assigning an expression to this BindingProperty will create the property.
375
376   \return BindingProperty named name
377   */
378
379 BindingProperty ModelNode::bindingProperty(const QString &name) const
380 {
381     if (!isValid())
382         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
383
384     return BindingProperty(name, m_internalNode, model(), view());
385 }
386
387
388 /*!
389   \brief Returns a NodeProperty
390
391   Note that a valid NodeProperty is returned, if the ModelNode is valid,
392   even if this property does not exist or is not a NodeProperty.
393   Assigning a ModelNode to this NodeProperty will create the property.
394
395   \return NodeProperty named name
396   */
397
398 NodeProperty ModelNode::nodeProperty(const QString &name) const
399 {
400       if (!isValid())
401         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
402
403     return NodeProperty(name, m_internalNode, model(), view());
404 }
405
406
407 /*!
408   \brief Returns a NodeListProperty
409
410   Note that a valid NodeListProperty is returned, if the ModelNode is valid,
411   even if this property does not exist or is not a NodeListProperty.
412   Assigning a ModelNode to this NodeListProperty will create the property.
413
414   \return NodeListProperty named name
415   */
416
417 NodeListProperty ModelNode::nodeListProperty(const QString &name) const
418 {
419     if (!isValid())
420         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
421
422     return NodeListProperty(name, m_internalNode, model(), view());
423 }
424
425 NodeAbstractProperty ModelNode::nodeAbstractProperty(const QString &name) const
426 {
427      if (!isValid())
428         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
429
430     return NodeAbstractProperty(name, m_internalNode, model(), view());
431 }
432
433
434 /*!
435   \brief Returns a VariantProperty
436
437   Note that a valid VariantProperty is returned, if the ModelNode is valid,
438   even if this property does not exist or is not a VariantProperty.
439   Assigning a value to this VariantProperty will create the property.
440
441   \return VariantProperty named name
442   */
443
444 VariantProperty ModelNode::variantProperty(const QString &name) const
445 {
446     if (!isValid())
447         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
448
449     return VariantProperty(name, m_internalNode, model(), view());
450 }
451
452 AbstractProperty ModelNode::property(const QString &name) const
453 {
454     if (!isValid())
455         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
456
457     return AbstractProperty(name, m_internalNode, model(), view());
458 }
459
460 /*! \brief returns a property
461 \param name name of the property
462 \return returns a node property handle. If the property is not set yet, the node property is still valid (lazy reference).
463
464 It is searching only in the local Property.
465
466 \see addProperty changePropertyValue removeProperty properties hasProperties
467 */
468
469 /*! \brief returns a list of all properties
470 \return list of all properties
471
472 The list of properties
473
474 */
475 QList<AbstractProperty> ModelNode::properties() const
476 {
477     if (!isValid())
478         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
479
480     QList<AbstractProperty> propertyList;
481
482     foreach (const QString &propertyName, internalNode()->propertyNameList()) {
483         AbstractProperty property(propertyName, internalNode(), model(), view());
484         propertyList.append(property);
485     }
486
487     return propertyList;
488 }
489
490
491 /*! \brief returns a list of all VariantProperties
492 \return list of all VariantProperties
493
494 The list of all properties containing just an atomic value.
495
496 */
497 QList<VariantProperty> ModelNode::variantProperties() const
498 {
499     QList<VariantProperty> propertyList;
500
501     foreach (const AbstractProperty &abstractProperty, properties())
502         if (abstractProperty.isVariantProperty())
503             propertyList.append(abstractProperty.toVariantProperty());
504     return propertyList;
505 }
506
507 QList<NodeAbstractProperty> ModelNode::nodeAbstractProperties() const
508 {
509     QList<NodeAbstractProperty> propertyList;
510
511     foreach (const AbstractProperty &nodeAbstractProperty, properties())
512         if (nodeAbstractProperty.isNodeAbstractProperty())
513             propertyList.append(nodeAbstractProperty.toNodeAbstractProperty());
514     return propertyList;
515 }
516
517 QList<NodeProperty> ModelNode::nodeProperties() const
518 {
519     QList<NodeProperty> propertyList;
520
521     foreach (const AbstractProperty &nodeProperty, properties())
522         if (nodeProperty.isNodeProperty())
523             propertyList.append(nodeProperty.toNodeProperty());
524     return propertyList;
525 }
526
527 QList<NodeListProperty> ModelNode::nodeListProperties() const
528 {
529     QList<NodeListProperty> propertyList;
530
531     foreach (const AbstractProperty &nodeListProperty, properties())
532         if (nodeListProperty.isNodeListProperty())
533             propertyList.append(nodeListProperty.toNodeListProperty());
534     return propertyList;
535 }
536
537
538 /*! \brief returns a list of all BindingProperties
539 \return list of all BindingProperties
540
541 The list of all properties containing an expression.
542
543 */
544 QList<BindingProperty> ModelNode::bindingProperties() const
545 {
546     QList<BindingProperty> propertyList;
547
548     foreach (const AbstractProperty &bindingProperty, properties())
549         if (bindingProperty.isBindingProperty())
550             propertyList.append(bindingProperty.toBindingProperty());
551     return propertyList;
552 }
553
554 /*!
555 \brief removes a property from this node
556 \param name name of the property
557
558 Does nothing if the node state does not set this property.
559
560 \see addProperty property  properties hasProperties
561 */
562 void ModelNode::removeProperty(const QString &name)
563 {
564     if (!isValid())
565         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
566
567     model()->m_d->checkPropertyName(name);
568
569     if (internalNode()->hasProperty(name))
570         model()->m_d->removeProperty(internalNode()->property(name));
571 }
572
573
574 /*! \brief removes this node from the node tree
575 */
576
577 static QList<ModelNode> descendantNodes(const ModelNode &parent)
578 {
579     QList<ModelNode> descendants(parent.allDirectSubModelNodes());
580     foreach (const ModelNode &child, parent.allDirectSubModelNodes()) {
581         descendants += descendantNodes(child);
582     }
583     return descendants;
584 }
585
586 static void removeModelNodeFromSelection(const ModelNode &node)
587 {
588     { // remove nodes from the active selection:
589         QList<ModelNode> selectedList = node.view()->selectedModelNodes();
590
591         foreach (const ModelNode &childModelNode, descendantNodes(node))
592             selectedList.removeAll(childModelNode);
593         selectedList.removeAll(node);
594
595         node.view()->setSelectedModelNodes(selectedList);
596     }
597 }
598
599
600 /*! \brief complete removes this ModelNode from the Model
601
602 */
603 void ModelNode::destroy()
604 {
605     if (!isValid()) {
606         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
607         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
608     }
609
610     if (isRootNode()) {
611         throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, "rootNode");
612     }
613
614     removeModelNodeFromSelection(*this);
615     model()->m_d->removeNode(internalNode());
616 }
617 //\}
618
619 /*! \name Property Manipulation
620  *  This methodes interact with properties.
621  */
622
623
624 /*!
625   \brief Returns if the the two nodes reference the same entity in the same model
626   */
627 bool operator ==(const ModelNode &firstNode, const ModelNode &secondNode)
628 {
629     if (firstNode.m_internalNode.isNull() || secondNode.m_internalNode.isNull()) {
630         Q_ASSERT_X(0, Q_FUNC_INFO, "model node is invalid");
631         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
632     }
633
634     return firstNode.internalId() == secondNode.internalId();
635 }
636
637 /*!
638   \brief Returns if the the two nodes do not reference the same entity in the same model
639   */
640 bool operator !=(const ModelNode &firstNode, const ModelNode &secondNode)
641 {
642     if (firstNode.m_internalNode.isNull() || secondNode.m_internalNode.isNull()) {
643         Q_ASSERT_X(0, Q_FUNC_INFO, "model node is invalid");
644         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
645     }
646
647     return firstNode.internalId() != secondNode.internalId();
648 }
649
650 bool operator <(const ModelNode &firstNode, const ModelNode &secondNode)
651 {
652     if (firstNode.m_internalNode.isNull() || secondNode.m_internalNode.isNull()) {
653         Q_ASSERT_X(0, Q_FUNC_INFO, "model node is invalid");
654         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
655     }
656
657     return firstNode.internalId() < secondNode.internalId();
658 }
659
660
661 Internal::InternalNodePointer ModelNode::internalNode() const
662 {
663     if (!isValid()) {
664         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
665         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
666     }
667     return m_internalNode;
668 }
669
670
671 uint qHash(const ModelNode &node)
672 {
673 //    if (!node.isValid()) {
674 //        Q_ASSERT_X(node.isValid(), Q_FUNC_INFO, "model node is invalid");
675 //        throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
676 //    }
677     return ::qHash(node.internalId());
678 }
679
680 /*!
681 \brief returns the model of the node
682 \return returns the model of the node
683 */
684 Model *ModelNode::model() const
685 {
686     return m_model.data();
687 }
688
689 /*!
690 \brief returns the view of the node
691 Each ModelNode belongs to one specific view.
692 \return view of the node
693 */
694 AbstractView *ModelNode::view() const
695 {
696     return m_view.data();
697 }
698
699
700 /*!
701 \brief returns all ModelNodes that are direct children of this ModelNode
702 The list contains every ModelNode that belongs to one of this ModelNodes
703 properties.
704 \return a list of all ModelNodes that are direct children
705 */
706 const QList<ModelNode> ModelNode::allDirectSubModelNodes() const
707 {
708     return toModelNodeList(internalNode()->allDirectSubNodes(), view());
709 }
710
711
712 /*!
713 \brief returns all ModelNodes that are direct or indirect children of this ModelNode
714 The list contains every ModelNode that is a direct or indirect child of this ModelNode.
715 All children in this list will be implicitly removed if this ModelNode is destroyed.
716 \return a list of all ModelNodes that are direct or indirect children
717 */
718
719 const QList<ModelNode> ModelNode::allSubModelNodes() const
720 {
721     return toModelNodeList(internalNode()->allSubNodes(), view());
722 }
723
724 /*!
725 \brief returns if this ModelNode has any child ModelNodes.
726
727 \return if this ModelNode has any child ModelNodes
728 */
729
730 bool ModelNode::hasAnySubModelNodes() const
731 {
732     return !nodeAbstractProperties().isEmpty();
733 }
734
735 const NodeMetaInfo ModelNode::metaInfo() const
736 {
737     if (!isValid()) {
738         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
739         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
740     }
741
742     return NodeMetaInfo(model()->metaInfoProxyModel(), type(), majorVersion(), minorVersion());
743 }
744
745 /*! \brief has a node the selection of the model
746 \return true if the node his selection
747 */
748 bool ModelNode::isSelected() const
749 {
750     if (!isValid()) {
751         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
752         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
753     }
754     return view()->selectedModelNodes().contains(ModelNode(m_internalNode, m_model.data(), view()));
755 }
756
757 /*! \briefis this node the root node of the model
758 \return true if it is the root node
759 */
760 bool ModelNode::isRootNode() const
761 {
762     if (!isValid()) {
763         Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
764         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
765     }
766     return view()->rootModelNode() == *this;
767 }
768
769 /*! \brief returns the list of all property names
770 \return list of all property names set in this state.
771
772 The list of properties set in this state.
773
774 \see addProperty property changePropertyValue removeProperty hasProperties
775 */
776 QStringList ModelNode::propertyNames() const
777 {
778     if (!isValid())
779         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
780     return internalNode()->propertyNameList();
781 }
782
783 /*! \brief test a if a property is set for this node
784 \return true if property a property ins this or a ancestor state exists
785 */
786 bool ModelNode::hasProperty(const QString &name) const
787 {
788     if (!isValid())
789         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
790
791     return internalNode()->hasProperty(name);
792 }
793
794 bool ModelNode::hasVariantProperty(const QString &name) const
795 {
796     return hasProperty(name) && internalNode()->property(name)->isVariantProperty();
797 }
798
799 bool ModelNode::hasBindingProperty(const QString &name) const
800 {
801     return hasProperty(name) && internalNode()->property(name)->isBindingProperty();
802 }
803
804 bool ModelNode::hasNodeAbstracProperty(const QString &name) const
805 {
806     return hasProperty(name) && internalNode()->property(name)->isNodeAbstractProperty();
807 }
808
809 bool ModelNode::hasNodeProperty(const QString &name) const
810 {
811     return hasProperty(name) && internalNode()->property(name)->isNodeProperty();
812 }
813
814 bool ModelNode::hasNodeListProperty(const QString &name) const
815 {
816     return hasProperty(name) && internalNode()->property(name)->isNodeListProperty();
817 }
818
819 static bool recursiveAncestor(const ModelNode &possibleAncestor, const ModelNode &node)
820 {
821     if (node.hasParentProperty()) {
822         if (node.parentProperty().parentModelNode() == possibleAncestor)
823            return true;
824         return recursiveAncestor(possibleAncestor, node.parentProperty().parentModelNode());
825     }
826
827     return false;
828 }
829
830 bool ModelNode::isAncestorOf(const ModelNode &node) const
831 {
832     return recursiveAncestor(*this, node);
833 }
834
835 QDebug operator<<(QDebug debug, const ModelNode &modelNode)
836 {
837     if (modelNode.isValid()) {
838         debug.nospace() << "ModelNode("
839                 << modelNode.internalId() << ", "
840                 << modelNode.type() << ", "
841                 << modelNode.id() << ')';
842     } else {
843         debug.nospace() << "ModelNode(invalid)";
844     }
845
846     return debug.space();
847 }
848
849 QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode)
850 {
851     if (modelNode.isValid()) {
852         stream << "ModelNode("
853                 << "type: " << modelNode.type() << ", "
854                 << "id: " << modelNode.id() << ')';
855     } else {
856         stream << "ModelNode(invalid)";
857     }
858
859     return stream;
860 }
861
862 void ModelNode::selectNode()
863 {
864     if (!isValid()) {
865             throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
866     }
867
868     QList<ModelNode> selectedNodeList;
869     selectedNodeList.append(*this);
870
871     view()->setSelectedModelNodes(selectedNodeList);
872 }
873
874 void ModelNode::deselectNode()
875 {
876     if (!isValid()) {
877             throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
878     }
879
880     QList<ModelNode> selectedNodeList(view()->selectedModelNodes());
881     selectedNodeList.removeAll(*this);
882
883     view()->setSelectedModelNodes(selectedNodeList);
884 }
885
886 int ModelNode::variantUserType()
887 {
888     return qMetaTypeId<ModelNode>();
889 }
890
891 QVariant ModelNode::toVariant() const
892 {
893     return QVariant::fromValue(*this);
894 }
895
896 QVariant ModelNode::auxiliaryData(const QString &name) const
897 {
898     if (!isValid()) {
899         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
900     }
901
902     return internalNode()->auxiliaryData(name);
903 }
904
905 void ModelNode::setAuxiliaryData(const QString &name, const QVariant &data)
906 {
907     Internal::WriteLocker locker(m_model.data());
908     m_model.data()->m_d->setAuxiliaryData(internalNode(), name, data);
909 }
910
911 bool ModelNode::hasAuxiliaryData(const QString &name) const
912 {
913     if (!isValid()) {
914         throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
915     }
916
917     return internalNode()->hasAuxiliaryData(name);
918 }
919
920 void  ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
921 {
922     model()->m_d->setScriptFunctions(internalNode(), scriptFunctionList);
923 }
924
925 QStringList  ModelNode::scriptFunctions() const
926 {
927     return internalNode()->scriptFunctions();
928 }
929
930 qint32 ModelNode::internalId() const
931 {
932     if (m_internalNode.isNull())
933         return -1;
934
935     return m_internalNode->internalId();
936 }
937
938 }