1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "qmlobjectnode.h"
27 #include "qmlitemnode.h"
28 #include "qmlstate.h"
29 #include "qmltimelinekeyframegroup.h"
30 #include "qmlvisualnode.h"
31 #include "qml3dnode.h"
32 #include "variantproperty.h"
33 #include "nodeproperty.h"
34 #include <invalidmodelnodeexception.h>
35 #include "abstractview.h"
36 #include "nodeinstance.h"
37 #include "nodemetainfo.h"
38 #include "bindingproperty.h"
39 #include "nodelistproperty.h"
40 #include "nodeinstanceview.h"
41 
42 #include <qmltimeline.h>
43 
44 #ifndef QMLDESIGNER_TEST
45 #include <qmldesignerplugin.h>
46 #endif
47 
48 #include <utils/qtcassert.h>
49 
50 #include <QRegularExpression>
51 
52 namespace QmlDesigner {
53 
setVariantProperty(const PropertyName & name,const QVariant & value)54 void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant &value)
55 {
56     if (!isValid())
57         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
58 
59     if (timelineIsActive() && currentTimeline().isRecording()) {
60         modelNode().validId();
61 
62         QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name));
63 
64         Q_ASSERT(timelineFrames.isValid());
65 
66         qreal frame = currentTimeline().modelNode().auxiliaryData("currentFrame@NodeInstance").toReal();
67         timelineFrames.setValue(value, frame);
68 
69         return;
70     } else if (modelNode().hasId() && timelineIsActive() && currentTimeline().hasKeyframeGroup(modelNode(), name)) {
71         QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name));
72 
73         Q_ASSERT(timelineFrames.isValid());
74 
75         if (timelineFrames.isRecording()) {
76             qreal frame = currentTimeline().modelNode().auxiliaryData("currentFrame@NodeInstance").toReal();
77             timelineFrames.setValue(value, frame);
78 
79             return;
80         }
81     }
82 
83     if (isInBaseState()) {
84         modelNode().variantProperty(name).setValue(value); //basestate
85     } else {
86         modelNode().validId();
87 
88         QmlPropertyChanges changeSet(currentState().propertyChanges(modelNode()));
89         Q_ASSERT(changeSet.isValid());
90         changeSet.modelNode().variantProperty(name).setValue(value);
91     }
92 }
93 
setBindingProperty(const PropertyName & name,const QString & expression)94 void QmlObjectNode::setBindingProperty(const PropertyName &name, const QString &expression)
95 {
96     if (!isValid())
97         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
98 
99     if (isInBaseState()) {
100         modelNode().bindingProperty(name).setExpression(expression); //basestate
101     } else {
102         modelNode().validId();
103 
104         QmlPropertyChanges changeSet(currentState().propertyChanges(modelNode()));
105         Q_ASSERT(changeSet.isValid());
106         changeSet.modelNode().bindingProperty(name).setExpression(expression);
107     }
108 }
109 
currentState() const110 QmlModelState QmlObjectNode::currentState() const
111 {
112     if (isValid())
113         return QmlModelState(view()->currentStateNode());
114     else
115         return QmlModelState();
116 }
117 
currentTimeline() const118 QmlTimeline QmlObjectNode::currentTimeline() const
119 {
120     if (isValid())
121         return view()->currentTimeline();
122     else
123         return QmlTimeline();
124 }
125 
isRootModelNode() const126 bool QmlObjectNode::isRootModelNode() const
127 {
128     return modelNode().isRootNode();
129 }
130 
131 
132 /*!
133     Returns the value of the property specified by \name that is based on an
134     actual instance. The return value is not the value in the model, but the
135     value of a real instantiated instance of this object.
136 */
instanceValue(const PropertyName & name) const137 QVariant  QmlObjectNode::instanceValue(const PropertyName &name) const
138 {
139     return nodeInstance().property(name);
140 }
141 
142 
hasProperty(const PropertyName & name) const143 bool QmlObjectNode::hasProperty(const PropertyName &name) const
144 {
145     if (!isValid())
146         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
147 
148     if (currentState().hasPropertyChanges(modelNode())) {
149         QmlPropertyChanges propertyChanges = currentState().propertyChanges(modelNode());
150         if (propertyChanges.modelNode().hasProperty(name))
151             return true;
152     }
153 
154     return modelNode().hasProperty(name);
155 }
156 
hasBindingProperty(const PropertyName & name) const157 bool QmlObjectNode::hasBindingProperty(const PropertyName &name) const
158 {
159     if (!isValid())
160         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
161 
162     if (currentState().hasPropertyChanges(modelNode())) {
163         QmlPropertyChanges propertyChanges = currentState().propertyChanges(modelNode());
164         if (propertyChanges.modelNode().hasBindingProperty(name))
165             return true;
166     }
167 
168     return modelNode().hasBindingProperty(name);
169 }
170 
nodeAbstractProperty(const PropertyName & name) const171 NodeAbstractProperty QmlObjectNode::nodeAbstractProperty(const PropertyName &name) const
172 {
173     return modelNode().nodeAbstractProperty(name);
174 }
175 
defaultNodeAbstractProperty() const176 NodeAbstractProperty QmlObjectNode::defaultNodeAbstractProperty() const
177 {
178     return modelNode().defaultNodeAbstractProperty();
179 }
180 
nodeProperty(const PropertyName & name) const181 NodeProperty QmlObjectNode::nodeProperty(const PropertyName &name) const
182 {
183     return modelNode().nodeProperty(name);
184 }
185 
nodeListProperty(const PropertyName & name) const186 NodeListProperty QmlObjectNode::nodeListProperty(const PropertyName &name) const
187 {
188     return modelNode().nodeListProperty(name);
189 }
190 
instanceHasValue(const PropertyName & name) const191 bool QmlObjectNode::instanceHasValue(const PropertyName &name) const
192 {
193     return nodeInstance().hasProperty(name);
194 }
195 
propertyAffectedByCurrentState(const PropertyName & name) const196 bool QmlObjectNode::propertyAffectedByCurrentState(const PropertyName &name) const
197 {
198     if (!isValid())
199         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
200 
201     if (currentState().isBaseState())
202         return modelNode().hasProperty(name);
203 
204     if (timelineIsActive() && currentTimeline().hasTimeline(modelNode(), name))
205         return true;
206 
207     if (!currentState().hasPropertyChanges(modelNode()))
208         return false;
209 
210     return currentState().propertyChanges(modelNode()).modelNode().hasProperty(name);
211 }
212 
modelValue(const PropertyName & name) const213 QVariant QmlObjectNode::modelValue(const PropertyName &name) const
214 {
215     if (!isValid())
216         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
217 
218     if (timelineIsActive() && currentTimeline().hasTimeline(modelNode(), name)) {
219         QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name));
220 
221         Q_ASSERT(timelineFrames.isValid());
222 
223         qreal frame = currentTimeline().modelNode().auxiliaryData("currentFrame@NodeInstance").toReal();
224 
225         QVariant value = timelineFrames.value(frame);
226 
227         if (!value.isValid()) //interpolation is not done in the model
228             value = instanceValue(name);
229 
230         return value;
231     }
232 
233     if (currentState().isBaseState())
234         return modelNode().variantProperty(name).value();
235 
236     if (!currentState().hasPropertyChanges(modelNode()))
237         return modelNode().variantProperty(name).value();
238 
239     QmlPropertyChanges propertyChanges(currentState().propertyChanges(modelNode()));
240 
241     if (!propertyChanges.modelNode().hasProperty(name))
242         return modelNode().variantProperty(name).value();
243 
244     return propertyChanges.modelNode().variantProperty(name).value();
245 }
246 
isTranslatableText(const PropertyName & name) const247 bool QmlObjectNode::isTranslatableText(const PropertyName &name) const
248 {
249     if (modelNode().metaInfo().isValid() && modelNode().metaInfo().hasProperty(name))
250         if (modelNode().metaInfo().propertyTypeName(name) == "QString" || modelNode().metaInfo().propertyTypeName(name) == "string") {
251             if (modelNode().hasBindingProperty(name)) {
252                 static QRegularExpression regularExpressionPattern(
253                             QLatin1String("^qsTr(|Id|anslate)\\(\".*\"\\)$"));
254                 return modelNode().bindingProperty(name).expression().contains(regularExpressionPattern);
255             }
256 
257             return false;
258         }
259 
260     return false;
261 }
262 
stripedTranslatableText(const PropertyName & name) const263 QString QmlObjectNode::stripedTranslatableText(const PropertyName &name) const
264 {
265     if (modelNode().hasBindingProperty(name)) {
266         static QRegularExpression regularExpressionPattern(
267                     QLatin1String("^qsTr(|Id|anslate)\\(\"(.*)\"\\)$"));
268         const QRegularExpressionMatch match = regularExpressionPattern.match(
269                     modelNode().bindingProperty(name).expression());
270         if (match.hasMatch())
271             return match.captured(2);
272         return instanceValue(name).toString();
273     }
274     return instanceValue(name).toString();
275 }
276 
expression(const PropertyName & name) const277 QString QmlObjectNode::expression(const PropertyName &name) const
278 {
279     if (!isValid())
280         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
281 
282     if (currentState().isBaseState())
283         return modelNode().bindingProperty(name).expression();
284 
285     if (!currentState().hasPropertyChanges(modelNode()))
286         return modelNode().bindingProperty(name).expression();
287 
288     QmlPropertyChanges propertyChanges(currentState().propertyChanges(modelNode()));
289 
290     if (!propertyChanges.modelNode().hasProperty(name))
291         return modelNode().bindingProperty(name).expression();
292 
293     return propertyChanges.modelNode().bindingProperty(name).expression();
294 }
295 
296 /*!
297     Returns \c true if the ObjectNode is in the BaseState.
298 */
isInBaseState() const299 bool QmlObjectNode::isInBaseState() const
300 {
301     return currentState().isBaseState();
302 }
303 
timelineIsActive() const304 bool QmlObjectNode::timelineIsActive() const
305 {
306     return currentTimeline().isValid();
307 }
308 
instanceCanReparent() const309 bool QmlObjectNode::instanceCanReparent() const
310 {
311     return isInBaseState();
312 }
313 
propertyChangeForCurrentState() const314 QmlPropertyChanges QmlObjectNode::propertyChangeForCurrentState() const
315 {
316     if (!isValid())
317         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
318 
319      if (currentState().isBaseState())
320          return QmlPropertyChanges();
321 
322      if (!currentState().hasPropertyChanges(modelNode()))
323          return QmlPropertyChanges();
324 
325      return currentState().propertyChanges(modelNode());
326 }
327 
removeStateOperationsForChildren(const QmlObjectNode & node)328 static void removeStateOperationsForChildren(const QmlObjectNode &node)
329 {
330     if (node.isValid()) {
331         foreach (QmlModelStateOperation stateOperation, node.allAffectingStatesOperations()) {
332             stateOperation.modelNode().destroy(); //remove of belonging StatesOperations
333         }
334 
335         foreach (const QmlObjectNode &childNode, node.modelNode().directSubModelNodes()) {
336             removeStateOperationsForChildren(childNode);
337         }
338     }
339 }
340 
removeAliasExports(const QmlObjectNode & node)341 static void removeAliasExports(const QmlObjectNode &node)
342 {
343 
344     PropertyName propertyName = node.id().toUtf8();
345 
346     ModelNode rootNode = node.view()->rootModelNode();
347     bool hasAliasExport = !propertyName.isEmpty()
348             && rootNode.isValid()
349             && rootNode.hasBindingProperty(propertyName)
350             && rootNode.bindingProperty(propertyName).isAliasExport();
351 
352     if (hasAliasExport)
353         rootNode.removeProperty(propertyName);
354 
355     foreach (const ModelNode &childNode, node.modelNode().directSubModelNodes()) {
356         removeAliasExports(childNode);
357     }
358 
359 }
360 
removeLayerEnabled(const ModelNode & node)361 static void removeLayerEnabled(const ModelNode &node)
362 {
363     QTC_ASSERT(node.isValid(), return );
364     if (node.parentProperty().isValid() && node.parentProperty().name() == "layer.effect") {
365         ModelNode parent = node.parentProperty().parentModelNode();
366         if (parent.isValid() && parent.hasProperty("layer.enabled"))
367             parent.removeProperty("layer.enabled");
368     }
369 }
370 
371 /*!
372     Deletes this object's node and its dependencies from the model.
373     Everything that belongs to this Object, the ModelNode, and ChangeOperations
374     is deleted from the model.
375 */
destroy()376 void QmlObjectNode::destroy()
377 {
378     if (!isValid())
379         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
380 
381     removeLayerEnabled(modelNode());
382     removeAliasExports(modelNode());
383 
384     for (QmlModelStateOperation stateOperation : allAffectingStatesOperations()) {
385         stateOperation.modelNode().destroy(); //remove of belonging StatesOperations
386     }
387 
388     QVector<ModelNode> timelineNodes;
389     const auto allNodes = view()->allModelNodes();
390     for (const auto &timelineNode : allNodes) {
391         if (QmlTimeline::isValidQmlTimeline(timelineNode))
392             timelineNodes.append(timelineNode);
393     }
394 
395     const auto subNodes = modelNode().allSubModelNodesAndThisNode();
396     for (auto &timelineNode : qAsConst(timelineNodes)) {
397         QmlTimeline timeline(timelineNode);
398         for (const auto &subNode : subNodes)
399             timeline.destroyKeyframesForTarget(subNode);
400     }
401 
402     bool wasFlowEditorTarget = false;
403     if (QmlFlowTargetNode::isFlowEditorTarget(modelNode())) {
404         QmlFlowTargetNode(modelNode()).destroyTargets();
405         wasFlowEditorTarget = true;
406     }
407 
408     removeStateOperationsForChildren(modelNode());
409     BindingProperty::deleteAllReferencesTo(modelNode());
410 
411     QmlFlowViewNode root(view()->rootModelNode());
412 
413     modelNode().destroy();
414 
415     if (wasFlowEditorTarget && root.isValid())
416         root.removeDanglingTransitions();
417 }
418 
ensureAliasExport()419 void QmlObjectNode::ensureAliasExport()
420 {
421     if (!isValid())
422         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
423 
424     if (!isAliasExported()) {
425         modelNode().validId();
426         ModelNode rootModelNode = view()->rootModelNode();
427         rootModelNode.bindingProperty(modelNode().id().toUtf8()).
428             setDynamicTypeNameAndExpression("alias", modelNode().id());
429     }
430 }
431 
isAliasExported() const432 bool QmlObjectNode::isAliasExported() const
433 {
434 
435     if (modelNode().isValid() && !modelNode().id().isEmpty()) {
436          PropertyName modelNodeId = modelNode().id().toUtf8();
437          ModelNode rootModelNode = view()->rootModelNode();
438          Q_ASSERT(rootModelNode.isValid());
439          if (rootModelNode.hasBindingProperty(modelNodeId)
440                  && rootModelNode.bindingProperty(modelNodeId).isDynamic()
441                  && rootModelNode.bindingProperty(modelNodeId).expression() == modelNode().id())
442              return true;
443     }
444 
445     return false;
446 }
447 
448 /*!
449     Returns a list of states the affect this object.
450 */
451 
allAffectingStates() const452 QList<QmlModelState> QmlObjectNode::allAffectingStates() const
453 {
454     if (!isValid())
455         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
456 
457     QList<QmlModelState> returnList;
458 
459     foreach (const QmlModelState &state, allDefinedStates()) {
460         if (state.affectsModelNode(modelNode()))
461             returnList.append(state);
462     }
463     return returnList;
464 }
465 
466 /*!
467     Returns a list of all state operations that affect this object.
468 */
469 
allAffectingStatesOperations() const470 QList<QmlModelStateOperation> QmlObjectNode::allAffectingStatesOperations() const
471 {
472     if (!isValid())
473         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
474 
475     QList<QmlModelStateOperation> returnList;
476     foreach (const QmlModelState &state, allDefinedStates()) {
477         if (state.affectsModelNode(modelNode()))
478             returnList.append(state.stateOperations(modelNode()));
479     }
480 
481     return returnList;
482 }
483 
allQmlVisualNodesRecursive(const QmlItemNode & qmlItemNode)484 static QList<QmlVisualNode> allQmlVisualNodesRecursive(const QmlItemNode &qmlItemNode)
485 {
486     QList<QmlVisualNode> qmlVisualNodeList;
487 
488     if (qmlItemNode.isValid()) {
489         qmlVisualNodeList.append(qmlItemNode);
490 
491         foreach (const ModelNode &modelNode, qmlItemNode.modelNode().directSubModelNodes()) {
492             if (QmlVisualNode::isValidQmlVisualNode(modelNode))
493                 qmlVisualNodeList.append(allQmlVisualNodesRecursive(modelNode));
494         }
495     }
496 
497     return qmlVisualNodeList;
498 }
499 
allDefinedStates() const500 QList<QmlModelState> QmlObjectNode::allDefinedStates() const
501 {
502     if (!isValid())
503         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
504 
505     QList<QmlModelState> returnList;
506 
507     QList<QmlVisualNode> allVisualNodes;
508 
509     if (QmlVisualNode::isValidQmlVisualNode(view()->rootModelNode()))
510         allVisualNodes.append(allQmlVisualNodesRecursive(view()->rootModelNode()));
511 
512     for (const QmlVisualNode &node : qAsConst(allVisualNodes))
513         returnList.append(node.states().allStates());
514 
515     return returnList;
516 }
517 
518 
519 /*!
520     Removes a variant property of the object specified by \a name from the
521     model.
522 */
523 
removeProperty(const PropertyName & name)524 void  QmlObjectNode::removeProperty(const PropertyName &name)
525 {
526     if (!isValid())
527         throw new InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
528 
529     if (isInBaseState()) {
530         modelNode().removeProperty(name); //basestate
531     } else {
532         QmlPropertyChanges changeSet(currentState().propertyChanges(modelNode()));
533         Q_ASSERT(changeSet.isValid());
534         changeSet.removeProperty(name);
535     }
536 }
537 
toModelNodeList(const QList<QmlObjectNode> & qmlObjectNodeList)538 QList<ModelNode> toModelNodeList(const QList<QmlObjectNode> &qmlObjectNodeList)
539 {
540     QList<ModelNode> modelNodeList;
541 
542     foreach (const QmlObjectNode &qmlObjectNode, qmlObjectNodeList)
543         modelNodeList.append(qmlObjectNode.modelNode());
544 
545     return modelNodeList;
546 }
547 
toQmlObjectNodeList(const QList<ModelNode> & modelNodeList)548 QList<QmlObjectNode> toQmlObjectNodeList(const QList<ModelNode> &modelNodeList)
549 {
550     QList<QmlObjectNode> qmlObjectNodeList;
551 
552     foreach (const ModelNode &modelNode, modelNodeList) {
553         if (QmlObjectNode::isValidQmlObjectNode(modelNode))
554              qmlObjectNodeList.append(modelNode);
555     }
556 
557     return qmlObjectNodeList;
558 }
559 
isAncestorOf(const QmlObjectNode & objectNode) const560 bool QmlObjectNode::isAncestorOf(const QmlObjectNode &objectNode) const
561 {
562     return modelNode().isAncestorOf(objectNode.modelNode());
563 }
564 
instanceValue(const ModelNode & modelNode,const PropertyName & name)565 QVariant QmlObjectNode::instanceValue(const ModelNode &modelNode, const PropertyName &name)
566 {
567     Q_ASSERT(modelNode.view()->nodeInstanceView()->hasInstanceForModelNode(modelNode));
568     return modelNode.view()->nodeInstanceView()->instanceForModelNode(modelNode).property(name);
569 }
570 
generateTranslatableText(const QString & text)571 QString QmlObjectNode::generateTranslatableText(const QString &text)
572 {
573 #ifndef QMLDESIGNER_TEST
574 
575     if (QmlDesignerPlugin::instance()->settings().value(
576             DesignerSettingsKey::TYPE_OF_QSTR_FUNCTION).toInt())
577 
578         switch (QmlDesignerPlugin::instance()->settings().value(
579                     DesignerSettingsKey::TYPE_OF_QSTR_FUNCTION).toInt()) {
580         case 0: return QString(QStringLiteral("qsTr(\"%1\")")).arg(text);
581         case 1: return QString(QStringLiteral("qsTrId(\"%1\")")).arg(text);
582         case 2: return QString(QStringLiteral("qsTranslate(\"\"\"%1\")")).arg(text);
583         default:
584             break;
585 
586         }
587     return QString(QStringLiteral("qsTr(\"%1\")")).arg(text);
588 #else
589     Q_UNUSED(text)
590     return QString();
591 #endif
592 }
593 
instanceType(const PropertyName & name) const594 TypeName QmlObjectNode::instanceType(const PropertyName &name) const
595 {
596     return nodeInstance().instanceType(name);
597 }
598 
instanceHasBinding(const PropertyName & name) const599 bool QmlObjectNode::instanceHasBinding(const PropertyName &name) const
600 {
601     return nodeInstance().hasBindingForProperty(name);
602 }
603 
nodeInstance() const604 NodeInstance QmlObjectNode::nodeInstance() const
605 {
606     return nodeInstanceView()->instanceForModelNode(modelNode());
607 }
608 
nodeForInstance(const NodeInstance & instance) const609 QmlObjectNode QmlObjectNode::nodeForInstance(const NodeInstance &instance) const
610 {
611     return QmlObjectNode(ModelNode(instance.modelNode(), view()));
612 }
613 
itemForInstance(const NodeInstance & instance) const614 QmlItemNode QmlObjectNode::itemForInstance(const NodeInstance &instance) const
615 {
616     return QmlItemNode(ModelNode(instance.modelNode(), view()));
617 }
618 
QmlObjectNode()619 QmlObjectNode::QmlObjectNode()
620 {
621 }
622 
QmlObjectNode(const ModelNode & modelNode)623 QmlObjectNode::QmlObjectNode(const ModelNode &modelNode)
624     : QmlModelNodeFacade(modelNode)
625 {
626 }
627 
isValidQmlObjectNode(const ModelNode & modelNode)628 bool QmlObjectNode::isValidQmlObjectNode(const ModelNode &modelNode)
629 {
630     return isValidQmlModelNodeFacade(modelNode);
631 }
632 
isValid() const633 bool QmlObjectNode::isValid() const
634 {
635     return isValidQmlObjectNode(modelNode());
636 }
637 
hasError() const638 bool QmlObjectNode::hasError() const
639 {
640     if (isValid())
641         return nodeInstance().hasError();
642     else
643         qDebug() << "called hasError() on an invalid QmlObjectNode";
644     return false;
645 }
646 
error() const647 QString QmlObjectNode::error() const
648 {
649     if (hasError())
650         return nodeInstance().error();
651     return QString();
652 }
653 
hasNodeParent() const654 bool QmlObjectNode::hasNodeParent() const
655 {
656     return modelNode().hasParentProperty();
657 }
658 
hasInstanceParent() const659 bool QmlObjectNode::hasInstanceParent() const
660 {
661     return nodeInstance().parentId() >= 0 && nodeInstanceView()->hasInstanceForId(nodeInstance().parentId());
662 }
663 
hasInstanceParentItem() const664 bool QmlObjectNode::hasInstanceParentItem() const
665 {
666     return isValid()
667            && nodeInstance().parentId() >= 0
668            && nodeInstanceView()->hasInstanceForId(nodeInstance().parentId())
669            && QmlItemNode::isItemOrWindow(view()->modelNodeForInternalId(nodeInstance().parentId()));
670 }
671 
672 
setParentProperty(const NodeAbstractProperty & parentProeprty)673 void QmlObjectNode::setParentProperty(const NodeAbstractProperty &parentProeprty)
674 {
675     return modelNode().setParentProperty(parentProeprty);
676 }
677 
instanceParent() const678 QmlObjectNode QmlObjectNode::instanceParent() const
679 {
680     if (hasInstanceParent())
681         return nodeForInstance(nodeInstanceView()->instanceForId(nodeInstance().parentId()));
682 
683     return QmlObjectNode();
684 }
685 
instanceParentItem() const686 QmlItemNode QmlObjectNode::instanceParentItem() const
687 {
688     if (hasInstanceParentItem())
689         return itemForInstance(nodeInstanceView()->instanceForId(nodeInstance().parentId()));
690 
691     return QmlItemNode();
692 }
693 
modelParentItem() const694 QmlItemNode QmlObjectNode::modelParentItem() const
695 {
696     return modelNode().parentProperty().parentModelNode();
697 }
698 
setId(const QString & id)699 void QmlObjectNode::setId(const QString &id)
700 {
701     modelNode().setIdWithRefactoring(id);
702 }
703 
id() const704 QString QmlObjectNode::id() const
705 {
706     return modelNode().id();
707 }
708 
validId()709 QString QmlObjectNode::validId()
710 {
711     return modelNode().validId();
712 }
713 
hasDefaultPropertyName() const714 bool QmlObjectNode::hasDefaultPropertyName() const
715 {
716     return modelNode().metaInfo().hasDefaultProperty();
717 }
718 
defaultPropertyName() const719 PropertyName QmlObjectNode::defaultPropertyName() const
720 {
721     return modelNode().metaInfo().defaultPropertyName();
722 }
723 
setParent(const QmlObjectNode & newParent)724 void QmlObjectNode::setParent(const QmlObjectNode &newParent)
725 {
726     if (newParent.hasDefaultPropertyName())
727         newParent.modelNode().defaultNodeAbstractProperty().reparentHere(modelNode());
728 }
729 
toQmlItemNode() const730 QmlItemNode QmlObjectNode::toQmlItemNode() const
731 {
732     return QmlItemNode(modelNode());
733 }
734 
toQmlVisualNode() const735 QmlVisualNode QmlObjectNode::toQmlVisualNode() const
736 {
737      return QmlVisualNode(modelNode());
738 }
739 
qHash(const QmlObjectNode & node)740 uint qHash(const QmlObjectNode &node)
741 {
742     return qHash(node.modelNode());
743 }
744 
simplifiedTypeName() const745 QString QmlObjectNode::simplifiedTypeName() const
746 {
747     return modelNode().simplifiedTypeName();
748 }
749 
allStateNames() const750 QStringList QmlObjectNode::allStateNames() const
751 {
752     return nodeInstance().allStateNames();
753 }
754 
getQmlObjectNodeOfCorrectType(const ModelNode & modelNode)755 QmlObjectNode *QmlObjectNode::getQmlObjectNodeOfCorrectType(const ModelNode &modelNode)
756 {
757     // Create QmlObjectNode of correct type for the modelNode
758     // Note: Currently we are only interested in differentiating 3D nodes, so no check for
759     // visual nodes is done for efficiency reasons
760     if (modelNode.isValid() && modelNode.isSubclassOf("QtQuick3D.Node"))
761         return new Qml3DNode(modelNode);
762     return new QmlObjectNode(modelNode);
763 }
764 
isBlocked(const PropertyName & propName) const765 bool QmlObjectNode::isBlocked(const PropertyName &propName) const
766 {
767     Q_UNUSED(propName)
768     return false;
769 }
770 
771 } //QmlDesigner
772