1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include <modelnode.h>
34 #include <abstractproperty.h>
35 #include <abstractview.h>
38 #include "internalnode_p.h"
40 #include <QTextStream>
41 #include "invalidargumentexception.h"
42 #include "invalididexception.h"
43 #include "invalidmodelnodeexception.h"
44 #include "invalidpropertyexception.h"
45 #include "invalidslideindexexception.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"
55 namespace QmlDesigner {
56 using namespace QmlDesigner::Internal;
59 \class QmlDesigner::ModelNode
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.
64 Conceptually ModelNode is an opaque handle to the internal data structures.
66 There is always a root model node in every QmlDesigner::Model:
68 QmlDesigner::Model *model = QmlDesigner::Model::create();
69 QmlDesigner::ModelNode rootNode = model->rootNode();
72 You can add a property to a node:
74 childNode.addProperty("pos", QPoint(2, 12));
77 All the manipulation functions are generating undo commands internally.
82 /*! \brief internal constructor
85 ModelNode::ModelNode(const InternalNodePointer &internalNode, Model *model, AbstractView *view):
86 m_internalNode(internalNode),
90 Q_ASSERT(!m_model || m_view);
93 ModelNode::ModelNode(const ModelNode modelNode, AbstractView *view)
94 : m_internalNode(modelNode.m_internalNode),
95 m_model(modelNode.model()),
101 /*! \brief contructs a invalid model node
105 ModelNode::ModelNode():
106 m_internalNode(new InternalNode)
111 ModelNode::ModelNode(const ModelNode &other):
112 m_internalNode(other.m_internalNode),
113 m_model(other.m_model),
118 ModelNode& ModelNode::operator=(const ModelNode &other)
120 this->m_model = other.m_model;
121 this->m_internalNode = other.m_internalNode;
122 this->m_view = other.m_view;
127 /*! \brief does nothing
129 ModelNode::~ModelNode()
133 QString ModelNode::generateNewId() const
136 QString newId = QString("%1%2").arg(simplifiedTypeName().toLower()).arg(counter);
138 while(view()->hasId(newId)) {
140 newId = QString("%1%2").arg(simplifiedTypeName().toLower()).arg(counter);
146 /*! \brief returns the name of node which is a short cut to a property like objectName
147 \return name of the node
149 QString ModelNode::id() const
152 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
155 return m_internalNode->id();
158 QString ModelNode::validId()
161 setId(generateNewId());
166 static bool idIsQmlKeyWord(const QString& id)
168 QStringList keywords;
169 keywords << "import" << "as";
171 return keywords.contains(id);
174 static bool idContainsWrongLetter(const QString& id)
176 static QRegExp idExpr(QLatin1String("[a-z_][a-zA-Z0-9_]*"));
177 return !idExpr.exactMatch(id);
180 bool ModelNode::isValidId(const QString &id)
182 return id.isEmpty() || (!idContainsWrongLetter(id) && !idIsQmlKeyWord(id));
185 void ModelNode::setId(const QString& id)
187 Internal::WriteLocker locker(m_model.data());
189 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
190 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
194 throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id, InvalidIdException::InvalidCharacters);
196 if (id == ModelNode::id())
199 if (view()->hasId(id))
200 throw InvalidIdException(__LINE__, __FUNCTION__, __FILE__, id, InvalidIdException::DuplicateId);
202 m_model.data()->m_d->changeNodeId(internalNode(), id);
205 /*! \brief the fully-qualified type name of the node is represented as string
206 \return type of the node as a string
208 QString ModelNode::type() const
211 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
212 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
214 return m_internalNode->type();
217 /*! \brief minor number of the QML type
220 int ModelNode::minorVersion() const
223 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
224 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
226 return m_internalNode->minorVersion();
229 /*! \brief major number of the QML type
232 int ModelNode::majorVersion() const
235 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
236 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
238 return m_internalNode->majorVersion();
242 /*! \return the short-hand type name of the node. */
243 QString ModelNode::simplifiedTypeName() const
246 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
247 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
250 return type().split(QLatin1Char('.')).last();
253 /*! \brief Returns whether the node is valid
255 A node is valid if its model still exists, and contains this node.
256 Also, the current state must be a valid one.
258 A node might become invalid if e.g. it or one of its ancestors is deleted.
260 \return is a node valid(true) or invalid(false)
262 bool ModelNode::isValid() const
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())*/;
268 \brief Returns whether the root node of the model is one of the anchestors of this node.
270 Will return true also for the root node itself.
272 bool ModelNode::isInHierarchy() const
275 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
276 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
280 if (!hasParentProperty())
282 return parentProperty().parentModelNode().isInHierarchy();
286 \brief Returns the property containing this node
288 The NodeAbstractProperty is invalid if this ModelNode has no parent.
289 NodeAbstractProperty can be a NodeProperty containing a single ModelNode, or
292 \return the property containing this ModelNode
294 NodeAbstractProperty ModelNode::parentProperty() const
297 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
298 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
300 if (m_internalNode->parentProperty().isNull())
301 return NodeAbstractProperty();
303 return NodeAbstractProperty(m_internalNode->parentProperty()->name(), m_internalNode->parentProperty()->propertyOwner(), m_model.data(), view());
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
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
321 \see parentNode childNodes hasChildNodes Model::undo
325 void ModelNode::setParentProperty(NodeAbstractProperty parent)
328 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
329 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
332 if (!parent.parentModelNode().isValid()) {
333 throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, "newParentNode");
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__);
341 if (parent == parentProperty())
344 parent.reparentHere(*this);
347 void ModelNode::setParentProperty(const ModelNode &newParentNode, const QString &propertyName)
349 setParentProperty(newParentNode.nodeAbstractProperty(propertyName));
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
356 bool ModelNode::hasParentProperty() const
359 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
360 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
363 if (m_internalNode->parentProperty().isNull())
370 \brief Returns a BindingProperty
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.
376 \return BindingProperty named name
379 BindingProperty ModelNode::bindingProperty(const QString &name) const
382 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
384 return BindingProperty(name, m_internalNode, model(), view());
389 \brief Returns a NodeProperty
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.
395 \return NodeProperty named name
398 NodeProperty ModelNode::nodeProperty(const QString &name) const
401 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
403 return NodeProperty(name, m_internalNode, model(), view());
408 \brief Returns a NodeListProperty
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.
414 \return NodeListProperty named name
417 NodeListProperty ModelNode::nodeListProperty(const QString &name) const
420 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
422 return NodeListProperty(name, m_internalNode, model(), view());
425 NodeAbstractProperty ModelNode::nodeAbstractProperty(const QString &name) const
428 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
430 return NodeAbstractProperty(name, m_internalNode, model(), view());
435 \brief Returns a VariantProperty
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.
441 \return VariantProperty named name
444 VariantProperty ModelNode::variantProperty(const QString &name) const
447 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
449 return VariantProperty(name, m_internalNode, model(), view());
452 AbstractProperty ModelNode::property(const QString &name) const
455 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
457 return AbstractProperty(name, m_internalNode, model(), view());
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).
464 It is searching only in the local Property.
466 \see addProperty changePropertyValue removeProperty properties hasProperties
469 /*! \brief returns a list of all properties
470 \return list of all properties
472 The list of properties
475 QList<AbstractProperty> ModelNode::properties() const
478 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
480 QList<AbstractProperty> propertyList;
482 foreach (const QString &propertyName, internalNode()->propertyNameList()) {
483 AbstractProperty property(propertyName, internalNode(), model(), view());
484 propertyList.append(property);
491 /*! \brief returns a list of all VariantProperties
492 \return list of all VariantProperties
494 The list of all properties containing just an atomic value.
497 QList<VariantProperty> ModelNode::variantProperties() const
499 QList<VariantProperty> propertyList;
501 foreach (const AbstractProperty &abstractProperty, properties())
502 if (abstractProperty.isVariantProperty())
503 propertyList.append(abstractProperty.toVariantProperty());
507 QList<NodeAbstractProperty> ModelNode::nodeAbstractProperties() const
509 QList<NodeAbstractProperty> propertyList;
511 foreach (const AbstractProperty &nodeAbstractProperty, properties())
512 if (nodeAbstractProperty.isNodeAbstractProperty())
513 propertyList.append(nodeAbstractProperty.toNodeAbstractProperty());
517 QList<NodeProperty> ModelNode::nodeProperties() const
519 QList<NodeProperty> propertyList;
521 foreach (const AbstractProperty &nodeProperty, properties())
522 if (nodeProperty.isNodeProperty())
523 propertyList.append(nodeProperty.toNodeProperty());
527 QList<NodeListProperty> ModelNode::nodeListProperties() const
529 QList<NodeListProperty> propertyList;
531 foreach (const AbstractProperty &nodeListProperty, properties())
532 if (nodeListProperty.isNodeListProperty())
533 propertyList.append(nodeListProperty.toNodeListProperty());
538 /*! \brief returns a list of all BindingProperties
539 \return list of all BindingProperties
541 The list of all properties containing an expression.
544 QList<BindingProperty> ModelNode::bindingProperties() const
546 QList<BindingProperty> propertyList;
548 foreach (const AbstractProperty &bindingProperty, properties())
549 if (bindingProperty.isBindingProperty())
550 propertyList.append(bindingProperty.toBindingProperty());
555 \brief removes a property from this node
556 \param name name of the property
558 Does nothing if the node state does not set this property.
560 \see addProperty property properties hasProperties
562 void ModelNode::removeProperty(const QString &name)
565 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
567 model()->m_d->checkPropertyName(name);
569 if (internalNode()->hasProperty(name))
570 model()->m_d->removeProperty(internalNode()->property(name));
574 /*! \brief removes this node from the node tree
577 static QList<ModelNode> descendantNodes(const ModelNode &parent)
579 QList<ModelNode> descendants(parent.allDirectSubModelNodes());
580 foreach (const ModelNode &child, parent.allDirectSubModelNodes()) {
581 descendants += descendantNodes(child);
586 static void removeModelNodeFromSelection(const ModelNode &node)
588 { // remove nodes from the active selection:
589 QList<ModelNode> selectedList = node.view()->selectedModelNodes();
591 foreach (const ModelNode &childModelNode, descendantNodes(node))
592 selectedList.removeAll(childModelNode);
593 selectedList.removeAll(node);
595 node.view()->setSelectedModelNodes(selectedList);
600 /*! \brief complete removes this ModelNode from the Model
603 void ModelNode::destroy()
606 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
607 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
611 throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, "rootNode");
614 removeModelNodeFromSelection(*this);
615 model()->m_d->removeNode(internalNode());
619 /*! \name Property Manipulation
620 * This methodes interact with properties.
625 \brief Returns if the the two nodes reference the same entity in the same model
627 bool operator ==(const ModelNode &firstNode, const ModelNode &secondNode)
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__);
634 return firstNode.internalId() == secondNode.internalId();
638 \brief Returns if the the two nodes do not reference the same entity in the same model
640 bool operator !=(const ModelNode &firstNode, const ModelNode &secondNode)
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__);
647 return firstNode.internalId() != secondNode.internalId();
650 bool operator <(const ModelNode &firstNode, const ModelNode &secondNode)
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__);
657 return firstNode.internalId() < secondNode.internalId();
661 Internal::InternalNodePointer ModelNode::internalNode() const
664 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
665 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
667 return m_internalNode;
671 uint qHash(const ModelNode &node)
673 // if (!node.isValid()) {
674 // Q_ASSERT_X(node.isValid(), Q_FUNC_INFO, "model node is invalid");
675 // throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
677 return ::qHash(node.internalId());
681 \brief returns the model of the node
682 \return returns the model of the node
684 Model *ModelNode::model() const
686 return m_model.data();
690 \brief returns the view of the node
691 Each ModelNode belongs to one specific view.
692 \return view of the node
694 AbstractView *ModelNode::view() const
696 return m_view.data();
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
704 \return a list of all ModelNodes that are direct children
706 const QList<ModelNode> ModelNode::allDirectSubModelNodes() const
708 return toModelNodeList(internalNode()->allDirectSubNodes(), view());
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
719 const QList<ModelNode> ModelNode::allSubModelNodes() const
721 return toModelNodeList(internalNode()->allSubNodes(), view());
725 \brief returns if this ModelNode has any child ModelNodes.
727 \return if this ModelNode has any child ModelNodes
730 bool ModelNode::hasAnySubModelNodes() const
732 return !nodeAbstractProperties().isEmpty();
735 const NodeMetaInfo ModelNode::metaInfo() const
738 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
739 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
742 return NodeMetaInfo(model()->metaInfoProxyModel(), type(), majorVersion(), minorVersion());
745 /*! \brief has a node the selection of the model
746 \return true if the node his selection
748 bool ModelNode::isSelected() const
751 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
752 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
754 return view()->selectedModelNodes().contains(ModelNode(m_internalNode, m_model.data(), view()));
757 /*! \briefis this node the root node of the model
758 \return true if it is the root node
760 bool ModelNode::isRootNode() const
763 Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
764 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
766 return view()->rootModelNode() == *this;
769 /*! \brief returns the list of all property names
770 \return list of all property names set in this state.
772 The list of properties set in this state.
774 \see addProperty property changePropertyValue removeProperty hasProperties
776 QStringList ModelNode::propertyNames() const
779 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
780 return internalNode()->propertyNameList();
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
786 bool ModelNode::hasProperty(const QString &name) const
789 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
791 return internalNode()->hasProperty(name);
794 bool ModelNode::hasVariantProperty(const QString &name) const
796 return hasProperty(name) && internalNode()->property(name)->isVariantProperty();
799 bool ModelNode::hasBindingProperty(const QString &name) const
801 return hasProperty(name) && internalNode()->property(name)->isBindingProperty();
804 bool ModelNode::hasNodeAbstracProperty(const QString &name) const
806 return hasProperty(name) && internalNode()->property(name)->isNodeAbstractProperty();
809 bool ModelNode::hasNodeProperty(const QString &name) const
811 return hasProperty(name) && internalNode()->property(name)->isNodeProperty();
814 bool ModelNode::hasNodeListProperty(const QString &name) const
816 return hasProperty(name) && internalNode()->property(name)->isNodeListProperty();
819 static bool recursiveAncestor(const ModelNode &possibleAncestor, const ModelNode &node)
821 if (node.hasParentProperty()) {
822 if (node.parentProperty().parentModelNode() == possibleAncestor)
824 return recursiveAncestor(possibleAncestor, node.parentProperty().parentModelNode());
830 bool ModelNode::isAncestorOf(const ModelNode &node) const
832 return recursiveAncestor(*this, node);
835 QDebug operator<<(QDebug debug, const ModelNode &modelNode)
837 if (modelNode.isValid()) {
838 debug.nospace() << "ModelNode("
839 << modelNode.internalId() << ", "
840 << modelNode.type() << ", "
841 << modelNode.id() << ')';
843 debug.nospace() << "ModelNode(invalid)";
846 return debug.space();
849 QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode)
851 if (modelNode.isValid()) {
852 stream << "ModelNode("
853 << "type: " << modelNode.type() << ", "
854 << "id: " << modelNode.id() << ')';
856 stream << "ModelNode(invalid)";
862 void ModelNode::selectNode()
865 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
868 QList<ModelNode> selectedNodeList;
869 selectedNodeList.append(*this);
871 view()->setSelectedModelNodes(selectedNodeList);
874 void ModelNode::deselectNode()
877 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
880 QList<ModelNode> selectedNodeList(view()->selectedModelNodes());
881 selectedNodeList.removeAll(*this);
883 view()->setSelectedModelNodes(selectedNodeList);
886 int ModelNode::variantUserType()
888 return qMetaTypeId<ModelNode>();
891 QVariant ModelNode::toVariant() const
893 return QVariant::fromValue(*this);
896 QVariant ModelNode::auxiliaryData(const QString &name) const
899 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
902 return internalNode()->auxiliaryData(name);
905 void ModelNode::setAuxiliaryData(const QString &name, const QVariant &data)
907 Internal::WriteLocker locker(m_model.data());
908 m_model.data()->m_d->setAuxiliaryData(internalNode(), name, data);
911 bool ModelNode::hasAuxiliaryData(const QString &name) const
914 throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
917 return internalNode()->hasAuxiliaryData(name);
920 void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList)
922 model()->m_d->setScriptFunctions(internalNode(), scriptFunctionList);
925 QStringList ModelNode::scriptFunctions() const
927 return internalNode()->scriptFunctions();
930 qint32 ModelNode::internalId() const
932 if (m_internalNode.isNull())
935 return m_internalNode->internalId();