abstractview.cpp 21.5 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
18 19 20 21 22
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
con's avatar
con committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
25 26 27 28 29 30

#include "abstractview.h"

#include "model.h"
#include "model_p.h"
#include "internalnode_p.h"
Marco Bubke's avatar
Marco Bubke committed
31
#include "nodeinstanceview.h"
32
#include <qmlstate.h>
33

34
#include <coreplugin/helpmanager.h>
35 36
#include <utils/qtcassert.h>

37 38 39 40 41 42
namespace QmlDesigner {


/*!
\class QmlDesigner::AbstractView
\ingroup CoreModel
43 44
\brief The AbstractView class provides an abstract interface that views and
editors can implement to be notified about model changes.
45

46
\sa QmlDesigner::WidgetQueryView(), QmlDesigner::NodeInstanceView()
47 48 49 50 51 52 53 54 55
*/

AbstractView::~AbstractView()
{
    if (m_model)
        m_model.data()->detachView(this, Model::DoNotNotifyView);
}

/*!
56 57 58 59
    Sets the view of a new \a model. This is handled automatically by
    AbstractView::modelAttached().

    \sa AbstractView::modelAttached()
60 61 62 63 64 65 66 67 68 69 70 71 72
*/
void AbstractView::setModel(Model *model)
{
    Q_ASSERT(model != 0);
    if (model == m_model.data())
        return;

    if (m_model)
        m_model.data()->detachView(this);

    m_model = model;
}

73
RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &identifier)
74
{
75
    return RewriterTransaction(this, identifier);
76 77
}

78
ModelNode AbstractView::createModelNode(const TypeName &typeName,
79 80
                            int majorVersion,
                            int minorVersion,
81 82
                            const QList<QPair<PropertyName, QVariant> > &propertyList,
                            const QList<QPair<PropertyName, QVariant> > &auxPropertyList,
83 84
                            const QString &nodeSource,
                            ModelNode::NodeSourceType nodeSourceType)
85
{
86
    return ModelNode(model()->d->createNode(typeName, majorVersion, minorVersion, propertyList, auxPropertyList, nodeSource, nodeSourceType), model(), this);
87 88 89
}


90 91
/*!
    Returns the constant root model node.
92 93 94 95 96
*/

const ModelNode AbstractView::rootModelNode() const
{
    Q_ASSERT(model());
hjk's avatar
hjk committed
97
    return ModelNode(model()->d->rootNode(), model(), const_cast<AbstractView*>(this));
98 99 100
}


101 102
/*!
    Returns the root model node.
103 104 105 106 107
*/

ModelNode AbstractView::rootModelNode()
{
    Q_ASSERT(model());
Thomas Hartmann's avatar
Thomas Hartmann committed
108
    return ModelNode(model()->d->rootNode(), model(), this);
109 110 111
}

/*!
112
    Sets the reference to a model to a null pointer.
113 114 115 116 117 118 119

*/
void AbstractView::removeModel()
{
    m_model.clear();
}

120
WidgetInfo AbstractView::createWidgetInfo(QWidget *widget,
121
                                          WidgetInfo::ToolBarWidgetFactoryInterface *toolBarWidgetFactory,
122 123 124 125 126 127 128 129
                                          const QString &uniqueId,
                                          WidgetInfo::PlacementHint placementHint,
                                          int placementPriority,
                                          const QString &tabName)
{
    WidgetInfo widgetInfo;

    widgetInfo.widget = widget;
130
    widgetInfo.toolBarWidgetFactory = toolBarWidgetFactory;
131 132 133 134 135 136 137 138
    widgetInfo.uniqueId = uniqueId;
    widgetInfo.placementHint = placementHint;
    widgetInfo.placementPriority = placementPriority;
    widgetInfo.tabName = tabName;

    return widgetInfo;
}

139
/*!
140
    Returns the model of the view.
141 142 143 144 145 146
*/
Model* AbstractView::model() const
{
    return m_model.data();
}

Marco Bubke's avatar
Marco Bubke committed
147 148 149 150 151
bool AbstractView::isAttached() const
{
    return model();
}

152
/*!
153
Called if a view is being attached to \a model.
154
The default implementation is setting the reference of the model to the view.
155
\sa Model::attachView()
156 157 158 159 160 161 162
*/
void AbstractView::modelAttached(Model *model)
{
    setModel(model);
}

/*!
163
Called before a view is detached from \a model.
164

165 166
This function is not called if Model::detachViewWithOutNotification is used.
The default implementation
167 168
is removing the reference to the model from the view.

169
\sa Model::detachView()
170 171 172 173 174 175 176
*/
void AbstractView::modelAboutToBeDetached(Model *)
{
    removeModel();
}

/*!
177
    \enum QmlDesigner::AbstractView::PropertyChangeFlag
178

179
    Notifies about changes in the abstract properties of a node:
180

181 182
    \value  NoAdditionalChanges
            No changes were made.
183

184 185 186 187 188
    \value  PropertiesAdded
            Some properties were added.

    \value  EmptyPropertiesRemoved
            Empty properties were removed.
189 190
*/

191
void AbstractView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &/*propertyList*/)
192 193 194
{
}

195
void AbstractView::instanceInformationsChanged(const QMultiHash<ModelNode, InformationName> &/*informationChangeHash*/)
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
{
}

void AbstractView::instancesRenderImageChanged(const QVector<ModelNode> &/*nodeList*/)
{
}

void AbstractView::instancesPreviewImageChanged(const QVector<ModelNode> &/*nodeList*/)
{
}

void AbstractView::instancesChildrenChanged(const QVector<ModelNode> &/*nodeList*/)
{
}

void AbstractView::instancesToken(const QString &/*tokenName*/, int /*tokenNumber*/, const QVector<ModelNode> &/*nodeVector*/)
{
}

void AbstractView::nodeSourceChanged(const ModelNode &/*modelNode*/, const QString &/*newNodeSource*/)
{
}

void AbstractView::rewriterBeginTransaction()
{
}

void AbstractView::rewriterEndTransaction()
{
}
226

227
void AbstractView::instanceErrorChanged(const QVector<ModelNode> &/*errorNodeList*/)
228 229 230
{
}

231 232 233 234
void AbstractView::instancesCompleted(const QVector<ModelNode> &/*completedNodeList*/)
{
}

235
// Node related functions
236 237

/*!
238 239
\fn void AbstractView::nodeCreated(const ModelNode &createdNode)
Called when the new node \a createdNode is created.
240
*/
241 242 243 244 245 246 247
void AbstractView::nodeCreated(const ModelNode &/*createdNode*/)
{
}

void AbstractView::currentStateChanged(const ModelNode &/*node*/)
{
}
248 249

/*!
250 251
Called when the file URL (that is needed to resolve relative paths against,
for example) is changed form \a oldUrl to \a newUrl.
252 253 254 255 256
*/
void AbstractView::fileUrlChanged(const QUrl &/*oldUrl*/, const QUrl &/*newUrl*/)
{
}

257 258 259 260
void AbstractView::nodeOrderChanged(const NodeListProperty &/*listProperty*/, const ModelNode &/*movedNode*/, int /*oldIndex*/)
{
}

261
/*!
262 263
\fn void AbstractView::nodeAboutToBeRemoved(const ModelNode &removedNode)
Called when the node specified by \a removedNode will be removed.
264
*/
265 266 267 268 269 270 271 272 273 274 275
void AbstractView::nodeAboutToBeRemoved(const ModelNode &/*removedNode*/)
{
}

void AbstractView::nodeRemoved(const ModelNode &/*removedNode*/, const NodeAbstractProperty &/*parentProperty*/, PropertyChangeFlags /*propertyChange*/)
{
}

void AbstractView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& /*propertyList*/)
{
}
276 277

/*!
278
Called when the properties specified by \a propertyList are removed.
279 280 281 282 283 284
*/
void AbstractView::propertiesRemoved(const QList<AbstractProperty>& /*propertyList*/)
{
}

/*!
285 286 287
\fn void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange)
Called when the parent of \a node will be changed from \a oldPropertyParent to
\a newPropertyParent.
288 289 290
*/

/*!
291 292 293 294
\fn void QmlDesigner::AbstractView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
                                                         const QList<ModelNode> &lastSelectedNodeList)
Called when the selection is changed from \a lastSelectedNodeList to
\a selectedNodeList.
295
*/
296 297 298
void AbstractView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/)
{
}
299

300
void AbstractView::nodeAboutToBeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
301
{
302
}
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
void AbstractView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
{
}

void AbstractView::nodeIdChanged(const ModelNode& /*node*/, const QString& /*newId*/, const QString& /*oldId*/)
{
}

void AbstractView::variantPropertiesChanged(const QList<VariantProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
{
}

void AbstractView::bindingPropertiesChanged(const QList<BindingProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
{
}

void AbstractView::signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& /*propertyList*/, PropertyChangeFlags /*propertyChange*/)
{
}

void AbstractView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/)
{
}

328 329 330 331 332
void AbstractView::nodeTypeChanged(const ModelNode & /*node*/, const TypeName & /*type*/, int /*majorVersion*/, int /*minorVersion*/)
{

}

333 334 335 336 337 338
void AbstractView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
{
}

void AbstractView::auxiliaryDataChanged(const ModelNode &/*node*/, const PropertyName &/*name*/, const QVariant &/*data*/)
{
339 340 341 342 343 344
}

void AbstractView::customNotification(const AbstractView * /*view*/, const QString & /*identifier*/, const QList<ModelNode> & /*nodeList*/, const QList<QVariant> & /*data*/)
{
}

345 346 347 348
void AbstractView::scriptFunctionsChanged(const ModelNode &/*node*/, const QStringList &/*scriptFunctionList*/)
{
}

349 350 351 352 353 354 355 356
QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList) const
{
    return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this));
}

QList<ModelNode> toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList, AbstractView *view)
{
    QList<ModelNode> newNodeList;
357
    foreach (const Internal::InternalNode::Pointer &node, nodeList)
358 359 360 361 362 363 364 365
        newNodeList.append(ModelNode(node, view->model(), view));

    return newNodeList;
}

QList<Internal::InternalNode::Pointer> toInternalNodeList(const QList<ModelNode> &nodeList)
{
    QList<Internal::InternalNode::Pointer> newNodeList;
366
    foreach (const ModelNode &node, nodeList)
367 368 369 370 371 372
        newNodeList.append(node.internalNode());

    return newNodeList;
}

/*!
373 374
    Sets the list of nodes to the actual selected nodes specified by
    \a selectedNodeList.
375 376 377
*/
void AbstractView::setSelectedModelNodes(const QList<ModelNode> &selectedNodeList)
{
hjk's avatar
hjk committed
378
    model()->d->setSelectedNodes(toInternalNodeList(selectedNodeList));
379 380
}

381 382 383 384 385
void AbstractView::setSelectedModelNode(const ModelNode &modelNode)
{
    setSelectedModelNodes(QList<ModelNode>() << modelNode);
}

386
/*!
387
    Clears the selection.
388 389 390
*/
void AbstractView::clearSelectedModelNodes()
{
hjk's avatar
hjk committed
391
    model()->d->clearSelectedNodes();
392 393
}

394 395 396 397 398 399 400 401 402 403
bool AbstractView::hasSelectedModelNodes() const
{
    return !model()->d->selectedNodes().isEmpty();
}

bool AbstractView::hasSingleSelectedModelNode() const
{
    return model()->d->selectedNodes().count() == 1;
}

404 405 406 407 408
bool AbstractView::isSelectedModelNode(const ModelNode &modelNode) const
{
    return model()->d->selectedNodes().contains(modelNode.internalNode());
}

409
/*!
410 411
    Sets the list of nodes to the actual selected nodes. Returns a list of the
    selected nodes.
412 413 414
*/
QList<ModelNode> AbstractView::selectedModelNodes() const
{
hjk's avatar
hjk committed
415
    return toModelNodeList(model()->d->selectedNodes());
416 417
}

418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
ModelNode AbstractView::firstSelectedModelNode() const
{
    if (hasSelectedModelNodes())
        return ModelNode(model()->d->selectedNodes().first(), model(), this);

    return ModelNode();
}

ModelNode AbstractView::singleSelectedModelNode() const
{
    if (hasSingleSelectedModelNode())
        return ModelNode(model()->d->selectedNodes().first(), model(), this);

    return ModelNode();
}

434
/*!
435
    Adds \a node to the selection list.
436
*/
437
void AbstractView::selectModelNode(const ModelNode &modelNode)
438
{
439 440
    QTC_ASSERT(modelNode.isInHierarchy(), return);
    model()->d->selectNode(modelNode.internalNode());
441 442 443
}

/*!
444
    Removes \a node from the selection list.
445 446 447
*/
void AbstractView::deselectModelNode(const ModelNode &node)
{
hjk's avatar
hjk committed
448
    model()->d->deselectNode(node.internalNode());
449 450 451 452
}

ModelNode AbstractView::modelNodeForId(const QString &id)
{
hjk's avatar
hjk committed
453
    return ModelNode(model()->d->nodeForId(id), model(), this);
454 455 456 457
}

bool AbstractView::hasId(const QString &id) const
{
hjk's avatar
hjk committed
458
    return model()->d->hasId(id);
459 460
}

461
QString firstCharToLower(const QString &string)
Thomas Hartmann's avatar
Thomas Hartmann committed
462 463 464 465 466 467 468 469 470
{
    QString resultString = string;

    if (!resultString.isEmpty())
        resultString[0] = resultString.at(0).toLower();

    return resultString;
}

471
QString AbstractView::generateNewId(const QString &prefixName) const
472 473 474
{
    int counter = 1;

475 476 477 478 479 480 481 482
    /* First try just the prefixName without number as postfix, then continue with 2 and further as postfix
     * until id does not already exist.
     * Properties of the root node are not allowed for ids, because they are available in the complete context
     * without qualification.
     * The id "item" is explicitly not allowed, because it is too likely to clash.
    */

    QString newId = QString(QStringLiteral("%1")).arg(firstCharToLower(prefixName));
483
    newId.remove(QRegExp(QStringLiteral("[^a-zA-Z0-9_]")));
484

485
    while (!ModelNode::isValidId(newId) || hasId(newId) || rootModelNode().hasProperty(newId.toUtf8()) || newId == "item") {
486
        counter += 1;
487
        newId = QString(QStringLiteral("%1%2")).arg(firstCharToLower(prefixName)).arg(counter - 1);
488
        newId.remove(QRegExp(QStringLiteral("[^a-zA-Z0-9_]")));
489 490 491 492 493
    }

    return newId;
}

494
ModelNode AbstractView::modelNodeForInternalId(qint32 internalId) const
495
{
hjk's avatar
hjk committed
496
     return ModelNode(model()->d->nodeForInternalId(internalId), model(), this);
497 498
}

499
bool AbstractView::hasModelNodeForInternalId(qint32 internalId) const
500
{
hjk's avatar
hjk committed
501
    return model()->d->hasNodeForInternalId(internalId);
502 503
}

504 505
NodeInstanceView *AbstractView::nodeInstanceView() const
{
506
    if (model())
hjk's avatar
hjk committed
507
        return model()->d->nodeInstanceView();
508
    else
509 510 511
        return 0;
}

512 513
RewriterView *AbstractView::rewriterView() const
{
514
    if (model())
hjk's avatar
hjk committed
515
        return model()->d->rewriterView();
516
    else
517 518 519
        return 0;
}

520 521 522 523 524 525 526 527 528 529
void AbstractView::resetView()
{
    if (!model())
        return;
    Model *currentModel = model();

    currentModel->detachView(this);
    currentModel->attachView(this);
}

530 531 532 533 534
void AbstractView::resetPuppet()
{
    emitCustomNotification(QStringLiteral("reset QmlPuppet"));
}

535 536 537 538 539 540 541 542 543 544
bool AbstractView::hasWidget() const
{
    return false;
}

WidgetInfo AbstractView::widgetInfo()
{
    return createWidgetInfo();
}

Marco Bubke's avatar
Marco Bubke committed
545 546 547 548 549
QString AbstractView::contextHelpId() const
{
    QString helpId;

    if (hasSelectedModelNodes()) {
550 551 552 553 554 555 556 557 558 559 560 561
        QString className = firstSelectedModelNode().simplifiedTypeName();
        helpId = QStringLiteral("QML.") + className;
        if (Core::HelpManager::linksForIdentifier(helpId).isEmpty() && firstSelectedModelNode().metaInfo().isValid()) {

            foreach (className, firstSelectedModelNode().metaInfo().superClassNames()) {
                helpId = QStringLiteral("QML.") + className;
                if (Core::HelpManager::linksForIdentifier(helpId).isEmpty())
                    helpId = QString();
                else
                    break;
            }
        }
Marco Bubke's avatar
Marco Bubke committed
562 563 564 565 566
    }

    return helpId;
}

Marco Bubke's avatar
Marco Bubke committed
567
QList<ModelNode> AbstractView::allModelNodes() const
568
{
hjk's avatar
hjk committed
569
   return toModelNodeList(model()->d->allNodes());
570 571 572 573 574 575 576 577 578 579 580 581 582 583
}

void AbstractView::emitCustomNotification(const QString &identifier)
{
    emitCustomNotification(identifier, QList<ModelNode>());
}

void AbstractView::emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList)
{
    emitCustomNotification(identifier, nodeList, QList<QVariant>());
}

void AbstractView::emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
hjk's avatar
hjk committed
584
    model()->d->notifyCustomNotification(this, identifier, nodeList, data);
585 586
}

587
void AbstractView::emitInstancePropertyChange(const QList<QPair<ModelNode, PropertyName> > &propertyList)
588
{
589
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
590
        model()->d->notifyInstancePropertyChange(propertyList);
591 592
}

593 594 595 596 597 598
void AbstractView::emitInstanceErrorChange(const QVector<qint32> &instanceIds)
{
    if (model() && nodeInstanceView() == this)
        model()->d->notifyInstanceErrorChange(instanceIds);
}

599 600 601
void AbstractView::emitInstancesCompleted(const QVector<ModelNode> &nodeVector)
{
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
602
        model()->d->notifyInstancesCompleted(nodeVector);
603 604
}

605
void AbstractView::emitInstanceInformationsChange(const QMultiHash<ModelNode, InformationName> &informationChangeHash)
606 607
{
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
608
        model()->d->notifyInstancesInformationsChange(informationChangeHash);
609 610 611 612 613
}

void AbstractView::emitInstancesRenderImageChanged(const QVector<ModelNode> &nodeVector)
{
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
614
        model()->d->notifyInstancesRenderImageChanged(nodeVector);
615 616 617 618 619
}

void AbstractView::emitInstancesPreviewImageChanged(const QVector<ModelNode> &nodeVector)
{
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
620
        model()->d->notifyInstancesPreviewImageChanged(nodeVector);
621 622 623 624 625
}

void AbstractView::emitInstancesChildrenChanged(const QVector<ModelNode> &nodeVector)
{
    if (model() && nodeInstanceView() == this)
hjk's avatar
hjk committed
626
        model()->d->notifyInstancesChildrenChanged(nodeVector);
627 628 629 630 631
}

void AbstractView::emitRewriterBeginTransaction()
{
    if (model())
hjk's avatar
hjk committed
632
        model()->d->notifyRewriterBeginTransaction();
633 634
}

635 636 637 638 639 640 641 642 643
void AbstractView::sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector)
{
    if (nodeInstanceView())
        nodeInstanceView()->sendToken(token, number, nodeVector);
}

void AbstractView::emitInstanceToken(const QString &token, int number, const QVector<ModelNode> &nodeVector)
{
    if (nodeInstanceView())
hjk's avatar
hjk committed
644
        model()->d->notifyInstanceToken(token, number, nodeVector);
645 646
}

647 648 649
void AbstractView::emitRewriterEndTransaction()
{
    if (model())
hjk's avatar
hjk committed
650
        model()->d->notifyRewriterEndTransaction();
651 652
}

653
void AbstractView::setCurrentStateNode(const ModelNode &node)
654
{
Marco Bubke's avatar
Marco Bubke committed
655
    Internal::WriteLocker locker(m_model.data());
656
    if (model())
657
        model()->d->notifyCurrentStateChanged(node);
658 659
}

660
void AbstractView::changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion)
661 662 663
{
    Internal::WriteLocker locker(m_model.data());

hjk's avatar
hjk committed
664
    m_model.data()->d->changeRootNodeType(type, majorVersion, minorVersion);
665 666
}

667
ModelNode AbstractView::currentStateNode() const
Marco Bubke's avatar
Marco Bubke committed
668
{
669
    if (model())
670
        return ModelNode(m_model.data()->d->currentStateNode(), m_model.data(), const_cast<AbstractView*>(this));
671 672

    return ModelNode();
Marco Bubke's avatar
Marco Bubke committed
673 674
}

675 676 677 678 679
QmlModelState AbstractView::currentState() const
{
    return QmlModelState(currentStateNode());
}

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
static int getMinorVersionFromImport(const Model *model)
{
    foreach (const Import &import, model->imports()) {
        if (import.isLibraryImport() && import.url() == "QtQuick") {
            const QString versionString = import.version();
            if (versionString.contains(".")) {
                const QString minorVersionString = versionString.split(".").last();
                return minorVersionString.toInt();
            }
        }
    }

    return -1;
}

695 696 697
static int getMajorVersionFromImport(const Model *model)
{
    foreach (const Import &import, model->imports()) {
698
        if (import.isLibraryImport() && import.url() == QStringLiteral("QtQuick")) {
699
            const QString versionString = import.version();
700 701
            if (versionString.contains(QStringLiteral("."))) {
                const QString majorVersionString = versionString.split(QStringLiteral(".")).first();
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
                return majorVersionString.toInt();
            }
        }
    }

    return -1;
}

static int getMajorVersionFromNode(const ModelNode &modelNode)
{
    if (modelNode.metaInfo().isValid()) {
        if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item")
            return modelNode.majorVersion();

        foreach (const NodeMetaInfo &superClass,  modelNode.metaInfo().superClasses()) {
            if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item")
                return superClass.majorVersion();
        }
    }

    return 1; //default
}

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
static int getMinorVersionFromNode(const ModelNode &modelNode)
{
    if (modelNode.metaInfo().isValid()) {
        if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item")
            return modelNode.minorVersion();

        foreach (const NodeMetaInfo &superClass,  modelNode.metaInfo().superClasses()) {
            if (modelNode.type() == "QtQuick.QtObject" || modelNode.type() == "QtQuick.Item")
                return superClass.minorVersion();
        }
    }

    return 1; //default
}

740 741 742 743 744 745 746 747 748
int AbstractView::majorQtQuickVersion() const
{
    int majorVersionFromImport = getMajorVersionFromImport(model());
    if (majorVersionFromImport >= 0)
        return majorVersionFromImport;

    return getMajorVersionFromNode(rootModelNode());
}

749 750 751 752 753 754 755 756 757 758
int AbstractView::minorQtQuickVersion() const
{
    int minorVersionFromImport = getMinorVersionFromImport(model());
    if (minorVersionFromImport >= 0)
        return minorVersionFromImport;

    return getMinorVersionFromNode(rootModelNode());
}


759
} // namespace QmlDesigner