diff options
Diffstat (limited to 'src')
8 files changed, 272 insertions, 498 deletions
diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri index 335dc55a..3cd7a529 100644 --- a/src/location/declarativemaps/declarativemaps.pri +++ b/src/location/declarativemaps/declarativemaps.pri @@ -5,7 +5,6 @@ INCLUDEPATH += declarativemaps PRIVATE_HEADERS += \ declarativemaps/error_messages_p.h \ declarativemaps/qdeclarativegeomapitemview_p.h \ - declarativemaps/qdeclarativegeomapitemview_p_p.h \ declarativemaps/qdeclarativegeoserviceprovider_p.h \ declarativemaps/qdeclarativegeocodemodel_p.h \ declarativemaps/qdeclarativegeoroutemodel_p.h \ @@ -28,7 +27,6 @@ PRIVATE_HEADERS += \ declarativemaps/qquickgeomapgesturearea_p.h \ declarativemaps/qdeclarativegeomapitemgroup_p.h \ declarativemaps/qparameterizableobject_p.h \ - declarativemaps/mapitemviewdelegateincubator_p.h \ declarativemaps/qgeomapobject_p.h \ declarativemaps/qgeomapobject_p_p.h \ ../imports/positioning/qquickgeocoordinateanimation_p.h @@ -58,7 +56,6 @@ SOURCES += \ declarativemaps/qquickgeomapgesturearea.cpp \ declarativemaps/qparameterizableobject.cpp \ declarativemaps/qdeclarativegeomapitemgroup.cpp \ - declarativemaps/mapitemviewdelegateincubator.cpp \ declarativemaps/qgeomapobject.cpp \ ../imports/positioning/qquickgeocoordinateanimation.cpp diff --git a/src/location/declarativemaps/mapitemviewdelegateincubator.cpp b/src/location/declarativemaps/mapitemviewdelegateincubator.cpp deleted file mode 100644 index c8500e4b..00000000 --- a/src/location/declarativemaps/mapitemviewdelegateincubator.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Copyright (C) 2015 Jolla Ltd, author: Aaron McCarthy <aaron.mccarthy@jollamobile.com> -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mapitemviewdelegateincubator_p.h" -#include "qdeclarativegeomapitemview_p.h" -#include "qdeclarativegeomapitemview_p_p.h" - -QT_BEGIN_NAMESPACE - -MapItemViewDelegateIncubator::MapItemViewDelegateIncubator(QDeclarativeGeoMapItemView *view, QDeclarativeGeoMapItemViewItemData *itemData, bool batched) -: m_view(view), m_itemData(itemData), m_batched(batched) -{ -} - -void MapItemViewDelegateIncubator::statusChanged(QQmlIncubator::Status status) -{ - m_view->incubatorStatusChanged(this, status, m_batched); -} - -QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index f8218604..09f9d01c 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -503,9 +503,7 @@ void QDeclarativeGeoMap::populateParameters() */ void QDeclarativeGeoMap::setupMapView(QDeclarativeGeoMapItemView *view) { - Q_UNUSED(view) view->setMap(this); - view->repopulate(); } /*! diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp index 7b3950db..faa06fef 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp @@ -283,6 +283,44 @@ qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const return opacity(); } +bool QDeclarativeGeoMapItemBase::prepareEnterTransition() +{ + if (m_transitionManager->m_transitionState == QDeclarativeGeoMapItemTransitionManager::EnterTransition + && m_transitionManager->isRunning()) + return false; + + if (m_transitionManager->m_transitionState != QDeclarativeGeoMapItemTransitionManager::EnterTransition) { + setVisible(true); + m_transitionManager->m_transitionState = QDeclarativeGeoMapItemTransitionManager::EnterTransition; + } + return true; +} + +bool QDeclarativeGeoMapItemBase::prepareExitTransition() +{ + if (m_transitionManager->m_transitionState == QDeclarativeGeoMapItemTransitionManager::ExitTransition + && m_transitionManager->isRunning()) + return false; + + if (m_transitionManager->m_transitionState != QDeclarativeGeoMapItemTransitionManager::ExitTransition) { + m_transitionManager->m_transitionState = QDeclarativeGeoMapItemTransitionManager::ExitTransition; + } + return true; +} + +void QDeclarativeGeoMapItemBase::finalizeEnterTransition() +{ + m_transitionManager->m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; + emit enterTransitionFinished(); +} + +void QDeclarativeGeoMapItemBase::finalizeExitTransition() +{ + setVisible(false); + m_transitionManager->m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; + emit exitTransitionFinished(); +} + bool QDeclarativeGeoMapItemBase::isPolishScheduled() const { return QQuickItemPrivate::get(this)->polishScheduled; @@ -294,4 +332,43 @@ void QDeclarativeGeoMapItemBase::polishAndUpdate() update(); } +QDeclarativeGeoMapItemTransitionManager::QDeclarativeGeoMapItemTransitionManager(QDeclarativeGeoMapItemBase *mapItem) + : QQuickTransitionManager(), m_mapItem(mapItem) +{ +} + +void QDeclarativeGeoMapItemTransitionManager::transitionEnter() +{ + if (m_transitionState == ExitTransition) + cancel(); + + if (!m_mapItem->prepareEnterTransition()) + return; + + if (m_view && m_view->m_enter) + transition(enterActions, m_view->m_enter, m_mapItem); + else + finished(); +} + +void QDeclarativeGeoMapItemTransitionManager::transitionExit() +{ + if (!m_mapItem->prepareExitTransition()) + return; + + if (m_view && m_view->m_exit) + transition(exitActions, m_view->m_exit, m_mapItem); + else + finished(); +} + +void QDeclarativeGeoMapItemTransitionManager::finished() +{ + if (m_transitionState == EnterTransition) + m_mapItem->finalizeEnterTransition(); + else if (m_transitionState == ExitTransition) + m_mapItem->finalizeExitTransition(); +} + + QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h index edb97c10..162c6d71 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h @@ -56,9 +56,12 @@ #include <QtLocation/private/qdeclarativegeomap_p.h> #include <QtLocation/private/qlocationglobal_p.h> #include <QtLocation/private/qgeomap_p.h> +#include <QtQuick/private/qquicktransitionmanager_p_p.h> +#include <QScopedPointer> QT_BEGIN_NAMESPACE - +class QDeclarativeGeoMapItemTransitionManager; +class QDeclarativeGeoMapItemBase; class Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent { public: @@ -77,6 +80,29 @@ public: bool rollChanged; }; +class QDeclarativeGeoMapItemTransitionManager : public QQuickTransitionManager +{ +public: + enum TransitionState { + NoTransition, EnterTransition, ExitTransition + }; + + QDeclarativeGeoMapItemTransitionManager(QDeclarativeGeoMapItemBase *mapItem); + + void transitionEnter(); + void transitionExit(); + +protected: + void finished() override; + +public: + QDeclarativeGeoMapItemBase *m_mapItem; + QDeclarativeGeoMapItemView *m_view = nullptr; + QList<QQuickStateAction> enterActions; + QList<QQuickStateAction> exitActions; + TransitionState m_transitionState = NoTransition; +}; + class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem { Q_OBJECT @@ -99,8 +125,15 @@ public: virtual QGeoMap::ItemType itemType() const = 0; qreal mapItemOpacity() const; + virtual bool prepareEnterTransition(); + virtual bool prepareExitTransition(); + virtual void finalizeEnterTransition(); + virtual void finalizeExitTransition(); + Q_SIGNALS: void mapItemOpacityChanged(); + void enterTransitionFinished(); + void exitTransitionFinished(); protected Q_SLOTS: virtual void afterChildrenChanged(); @@ -124,7 +157,11 @@ private: QDeclarativeGeoMapItemGroup *parentGroup_; + QScopedPointer<QDeclarativeGeoMapItemTransitionManager> m_transitionManager; + friend class QDeclarativeGeoMap; + friend class QDeclarativeGeoMapItemView; + friend class QDeclarativeGeoMapItemTransitionManager; }; QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp index ce7b4946..b49e675c 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp @@ -37,15 +37,16 @@ ****************************************************************************/ #include "qdeclarativegeomapitemview_p.h" -#include "qdeclarativegeomapitemview_p_p.h" #include "qdeclarativegeomap_p.h" #include "qdeclarativegeomapitembase_p.h" #include "mapitemviewdelegateincubator_p.h" #include <QtCore/QAbstractItemModel> #include <QtQml/QQmlContext> -#include <QtQml/QQmlIncubator> +#include <QtQml/private/qqmldelegatemodel_p.h> #include <QtQml/private/qqmlopenmetaobject_p.h> +#include <QtQuick/private/qquickanimation_p.h> +#include <QtQml/QQmlListProperty> QT_BEGIN_NAMESPACE @@ -76,16 +77,20 @@ QT_BEGIN_NAMESPACE QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent) : QObject(parent), m_componentCompleted(false), m_delegate(0), - m_itemModel(0), m_map(0), m_fitViewport(false), m_metaObjectType(0), - m_readyIncubators(0), m_repopulating(false) + m_map(0), m_fitViewport(false), m_delegateModel(0) { + m_exit = new QQuickTransition(this); + QQmlListProperty<QQuickAbstractAnimation> anims = m_exit->animations(); + QQuickNumberAnimation *ani = new QQuickNumberAnimation(m_exit); + ani->setProperty(QStringLiteral("opacity")); + ani->setTo(0.0); + ani->setDuration(300.0); + anims.append(&anims, ani); } QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView() { removeInstantiatedItems(); - if (m_metaObjectType) - m_metaObjectType->release(); } /*! @@ -94,239 +99,103 @@ QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView() void QDeclarativeGeoMapItemView::componentComplete() { m_componentCompleted = true; -} + if (!m_itemModel.isNull()) + m_delegateModel->setModel(m_itemModel); -void QDeclarativeGeoMapItemView::incubatorStatusChanged(MapItemViewDelegateIncubator *incubator, - QQmlIncubator::Status status, - bool batched) -{ - if (status == QQmlIncubator::Loading) - return; + if (m_delegate) + m_delegateModel->setDelegate(m_delegate); - QDeclarativeGeoMapItemViewItemData *itemData = incubator->m_itemData; - if (!itemData) { - // Should never get here - qWarning() << "MapItemViewDelegateIncubator incubating invalid itemData"; - return; - } - - switch (status) { - case QQmlIncubator::Ready: - { - QDeclarativeGeoMapItemBase *item = qobject_cast<QDeclarativeGeoMapItemBase *>(incubator->object()); - if (!item) - break; - itemData->item = item; - if (!itemData->item) { - qWarning() << "QDeclarativeGeoMapItemView map item delegate is of unsupported type."; - delete incubator->object(); - } else { - if (!batched) { - m_map->addMapItem(itemData->item); - fitViewport(); - } else { - ++m_readyIncubators; // QSemaphore not needed as multiple threads not involved - - if (m_readyIncubators == m_itemDataBatched.size()) { - - // Clearing stuff older than the reset - foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemData) - removeItemData(i); - m_itemData.clear(); - - // Adding everthing created after reset was issued - foreach (QDeclarativeGeoMapItemViewItemData *i, m_itemDataBatched) { - m_map->addMapItem(i->item); - } - m_itemData = m_itemDataBatched; - m_itemDataBatched.clear(); - - m_readyIncubators = 0; - m_repopulating = false; - - fitViewport(); - } - } - } - delete itemData->incubator; - itemData->incubator = 0; - break; - } - case QQmlIncubator::Null: - // Should never get here - delete itemData->incubator; - itemData->incubator = 0; - break; - case QQmlIncubator::Error: - qWarning() << "QDeclarativeGeoMapItemView map item creation failed."; - delete itemData->incubator; - itemData->incubator = 0; - break; - default: - ; - } + m_delegateModel->componentComplete(); } -/*! - \qmlproperty model QtLocation::MapItemView::model - - This property holds the model that provides data used for creating the map items defined by the - delegate. Only QAbstractItemModel based models are supported. -*/ -QVariant QDeclarativeGeoMapItemView::model() const +void QDeclarativeGeoMapItemView::classBegin() { - return QVariant::fromValue(m_itemModel); + QQmlContext *ctx = qmlContext(this); + m_delegateModel = new QQmlDelegateModel(ctx, this); + m_delegateModel->classBegin(); + + connect(m_delegateModel, &QQmlInstanceModel::modelUpdated, this, &QDeclarativeGeoMapItemView::modelUpdated); + connect(m_delegateModel, &QQmlInstanceModel::createdItem, this, &QDeclarativeGeoMapItemView::createdItem); + connect(m_delegateModel, &QQmlInstanceModel::destroyingItem, this, &QDeclarativeGeoMapItemView::destroyingItem); + connect(m_delegateModel, &QQmlInstanceModel::initItem, this, &QDeclarativeGeoMapItemView::initItem); } -void QDeclarativeGeoMapItemView::setModel(const QVariant &model) +void QDeclarativeGeoMapItemView::destroyingItem(QObject */*object*/) { - QAbstractItemModel *itemModel = model.value<QAbstractItemModel *>(); - if (itemModel == m_itemModel) - return; - - if (m_itemModel) { - disconnect(m_itemModel, SIGNAL(modelReset()), this, SLOT(itemModelReset())); - disconnect(m_itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(itemModelRowsRemoved(QModelIndex,int,int))); - disconnect(m_itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(itemModelRowsInserted(QModelIndex,int,int))); - disconnect(m_itemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int))); - disconnect(m_itemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), - this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>))); - - removeInstantiatedItems(); // this also terminates ongong repopulations. - m_metaObjectType->release(); - m_metaObjectType = 0; - - m_itemModel = 0; - } - - if (itemModel) { - m_itemModel = itemModel; - connect(m_itemModel, SIGNAL(modelReset()), this, SLOT(itemModelReset())); - connect(m_itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), - this, SLOT(itemModelRowsRemoved(QModelIndex,int,int))); - connect(m_itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), - this, SLOT(itemModelRowsInserted(QModelIndex,int,int))); - connect(m_itemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - this, SLOT(itemModelRowsMoved(QModelIndex,int,int,QModelIndex,int))); - connect(m_itemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)), - this, SLOT(itemModelDataChanged(QModelIndex,QModelIndex,QVector<int>))); - - m_metaObjectType = new QQmlOpenMetaObjectType(&QObject::staticMetaObject, 0); - foreach (const QByteArray &name, m_itemModel->roleNames()) - m_metaObjectType->createProperty(name); - - instantiateAllItems(); - } - emit modelChanged(); } -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::itemModelReset() +void QDeclarativeGeoMapItemView::initItem(int /*index*/, QObject */*object*/) { - repopulate(); + } -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::itemModelRowsInserted(const QModelIndex &index, int start, int end) +void QDeclarativeGeoMapItemView::createdItem(int index, QObject */*object*/) { - Q_UNUSED(index) - - if (!m_componentCompleted || !m_map || !m_delegate || !m_itemModel) + if (!m_map) return; - - for (int i = start; i <= end; ++i) { - const QModelIndex insertedIndex = m_itemModel->index(i, 0, index); - // If ran inside a qquickwidget which forces incubators to be synchronous, this call won't happen - // with m_repopulating == true while incubators from a model reset are still incubating. - // Note that having the model in a different thread is not supported in general. - createItemForIndex(insertedIndex, m_repopulating); - } - - fitViewport(); + // createdItem is emitted on asynchronous creation. In which case, object has to be invoked again. + // See QQmlDelegateModel::object for further info. + QDeclarativeGeoMapItemBase *item = + qobject_cast<QDeclarativeGeoMapItemBase *>(m_delegateModel->object(index, QQmlIncubator::Asynchronous)); + if (item) + addItemToMap(item, index); } -/*! - \internal -*/ -void QDeclarativeGeoMapItemView::itemModelRowsRemoved(const QModelIndex &index, int start, int end) +void QDeclarativeGeoMapItemView::modelUpdated(const QQmlChangeSet &changeSet, bool reset) { - Q_UNUSED(index) - - if (!m_componentCompleted || !m_map || !m_delegate || !m_itemModel) - return; + // move changes are expressed as one remove + one insert, with the same moveId. + // For simplicity, they will be treated as remove + insert. + // Changes will be also ignored, as they represent only data changes, not layout changes + if (reset) { // Assuming this means "remove everything already instantiated" + removeInstantiatedItems(); + } else { + // Remove items from the back to the front to retain the mapping to what is received from the changesets + const QVector<QQmlChangeSet::Change> &removes = changeSet.removes(); + std::map<int, int> mapRemoves; + for (int i = 0; i < removes.size(); i++) + mapRemoves.insert(std::pair<int, int>(removes.at(i).start(), i)); + + for (auto rit = mapRemoves.rbegin(); rit != mapRemoves.rend(); ++rit) { + const QQmlChangeSet::Change &c = removes.at(rit->second); + for (int idx = c.end() - 1; idx >= c.start(); --idx) + removeItemFromMap(idx); + } + } - for (int i = end; i >= start; --i) { - if (m_repopulating) { - QDeclarativeGeoMapItemViewItemData *itemData = m_itemDataBatched.takeAt(i); - if (!itemData) - continue; - if (itemData->incubator) { - if (itemData->incubator->isReady()) { - --m_readyIncubators; - delete itemData->incubator->object(); - } - itemData->incubator->clear(); - } - delete itemData; - } else { - QDeclarativeGeoMapItemViewItemData *itemData = m_itemData.takeAt(i); - removeItemData(itemData); + for (const QQmlChangeSet::Change &c: changeSet.inserts()) { + for (int idx = c.start(); idx < c.end(); idx++) { + QDeclarativeGeoMapItemBase *item = + qobject_cast<QDeclarativeGeoMapItemBase *>(m_delegateModel->object(idx, QQmlIncubator::Asynchronous)); + if (item) // if not, a createdItem signal will be emitted. + addItemToMap(item, idx); } } fitViewport(); } -void QDeclarativeGeoMapItemView::itemModelRowsMoved(const QModelIndex &parent, int start, int end, - const QModelIndex &destination, int row) -{ - Q_UNUSED(parent) - Q_UNUSED(start) - Q_UNUSED(end) - Q_UNUSED(destination) - Q_UNUSED(row) +/*! + \qmlproperty model QtLocation::MapItemView::model - qWarning() << "QDeclarativeGeoMapItemView does not support models that move rows."; + This property holds the model that provides data used for creating the map items defined by the + delegate. Only QAbstractItemModel based models are supported. +*/ +QVariant QDeclarativeGeoMapItemView::model() const +{ + return m_itemModel; } -void QDeclarativeGeoMapItemView::itemModelDataChanged(const QModelIndex &topLeft, - const QModelIndex &bottomRight, - const QVector<int> &roles) +void QDeclarativeGeoMapItemView::setModel(const QVariant &model) { - Q_UNUSED(roles) - - if (!m_itemData.count() || (m_repopulating && !m_itemDataBatched.count()) ) + if (model == m_itemModel) return; - for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { - const QModelIndex index = m_itemModel->index(i, 0); - QDeclarativeGeoMapItemViewItemData *itemData; - if (m_repopulating) - itemData= m_itemDataBatched.at(i); - else - itemData= m_itemData.at(i); - - QHashIterator<int, QByteArray> iterator(m_itemModel->roleNames()); - while (iterator.hasNext()) { - iterator.next(); - - QVariant modelData = m_itemModel->data(index, iterator.key()); - if (!modelData.isValid()) - continue; - - itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()), - modelData); - itemData->modelDataMeta->setValue(iterator.value(), modelData); - } - } + m_itemModel = model; + if (m_componentCompleted) + m_delegateModel->setModel(m_itemModel); + + emit modelChanged(); } /*! @@ -347,8 +216,9 @@ void QDeclarativeGeoMapItemView::setDelegate(QQmlComponent *delegate) return; m_delegate = delegate; + if (m_componentCompleted) + m_delegateModel->setDelegate(m_delegate); - repopulate(); emit delegateChanged(); } @@ -365,11 +235,12 @@ bool QDeclarativeGeoMapItemView::autoFitViewport() const return m_fitViewport; } -void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fitViewport) +void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fit) { - if (fitViewport == m_fitViewport) + if (fit == m_fitViewport) return; - m_fitViewport = fitViewport; + m_fitViewport = fit; + fitViewport(); emit autoFitViewportChanged(); } @@ -378,7 +249,8 @@ void QDeclarativeGeoMapItemView::setAutoFitViewport(const bool &fitViewport) */ void QDeclarativeGeoMapItemView::fitViewport() { - if (!m_map || !m_map->mapReady() || !m_fitViewport || m_repopulating) + + if (!m_map || !m_map->mapReady() || !m_fitViewport) return; if (m_map->mapItems().size() > 0) @@ -393,6 +265,7 @@ void QDeclarativeGeoMapItemView::setMap(QDeclarativeGeoMap *map) if (!map || m_map) // changing map on the fly not supported return; m_map = map; + instantiateAllItems(); } /*! @@ -403,10 +276,9 @@ void QDeclarativeGeoMapItemView::removeInstantiatedItems() if (!m_map) return; - terminateOngoingRepopulation(); - foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemData) - removeItemData(itemData); - m_itemData.clear(); + // Backward as removeItemFromMap modifies m_instantiatedItems + for (int i = m_instantiatedItems.size() -1; i >= 0 ; i--) + removeItemFromMap(i); } /*! @@ -416,127 +288,70 @@ void QDeclarativeGeoMapItemView::removeInstantiatedItems() */ void QDeclarativeGeoMapItemView::instantiateAllItems() { - if (!m_componentCompleted || !m_map || !m_delegate || !m_itemModel) + // The assumption is that if m_instantiatedItems isn't empty, instantiated items have been already added + if (!m_componentCompleted || !m_map || !m_delegate || m_itemModel.isNull() || !m_instantiatedItems.isEmpty()) return; - Q_ASSERT(!m_itemDataBatched.size()); - m_repopulating = true; - - // QQuickWidget forces incubators to synchronous mode. Thus itemDataChanged gets called during the for loop below. - m_itemDataBatched.resize(m_itemModel->rowCount()); - for (int i = 0; i < m_itemModel->rowCount(); ++i) { - const QModelIndex index = m_itemModel->index(i, 0); - createItemForIndex(index, true); + + // If here, m_delegateModel may contain data, but QQmlInstanceModel::object for each row hasn't been called yet. + for (int i = 0; i < m_delegateModel->count(); i++) { + QDeclarativeGeoMapItemBase *item = + qobject_cast<QDeclarativeGeoMapItemBase *>(m_delegateModel->object(i, QQmlIncubator::Asynchronous)); + if (item) // else createdItem will be emitted. + addItemToMap(item, i); } fitViewport(); } -/* - * used internally -*/ -void QDeclarativeGeoMapItemView::removeItemData(QDeclarativeGeoMapItemViewItemData *itemData) +void QDeclarativeGeoMapItemView::removeItemFromMap(int index) { - if (!itemData) - return; - if (itemData->incubator) { - if (itemData->incubator->isReady()) { - if (itemData->incubator->object() == itemData->item) { - m_map->removeMapItem(itemData->item); // removeMapItem checks whether the item is in the map, so it's safe to call. - itemData->item = 0; + if (index >= 0 && index < m_instantiatedItems.size()) { + QDeclarativeGeoMapItemBase *item = m_instantiatedItems.takeAt(index); + if (m_exit && m_map) { + if (!item->m_transitionManager) { + QScopedPointer<QDeclarativeGeoMapItemTransitionManager>manager(new QDeclarativeGeoMapItemTransitionManager(item)); + item->m_transitionManager.swap(manager); + item->m_transitionManager->m_view = this; } - delete itemData->incubator->object(); + connect(item, &QDeclarativeGeoMapItemBase::exitTransitionFinished, + this, &QDeclarativeGeoMapItemView::exitTransitionFinished); + item->m_transitionManager->transitionExit(); + } else { + if (m_map) + m_map->removeMapItem(item); + m_delegateModel->release(item); } - itemData->incubator->clear(); // stops ongoing incubation } - if (itemData->item) - m_map->removeMapItem(itemData->item); - delete itemData; // destroys the ->item too. } -void QDeclarativeGeoMapItemView::terminateOngoingRepopulation() -{ - if (m_repopulating) { - // Terminate the previous resetting task. Not all incubators finished, but - // QQmlIncubatorController operates in the same thread, so it is safe - // to check, here, whether incubators are ready or not, without having - // to race with them. - - foreach (QDeclarativeGeoMapItemViewItemData *itemData, m_itemDataBatched) - removeItemData(itemData); - - m_itemDataBatched.clear(); - m_readyIncubators = 0; - m_repopulating = false; - } -} - -/*! - \internal - Removes and repopulates all items. -*/ -void QDeclarativeGeoMapItemView::repopulate() +void QDeclarativeGeoMapItemView::exitTransitionFinished() { - if (!m_itemModel || !m_itemModel->rowCount()) { - removeInstantiatedItems(); - } else { - terminateOngoingRepopulation(); - instantiateAllItems(); // removal of instantiated item done at incubation completion - } + QDeclarativeGeoMapItemBase *item = static_cast<QDeclarativeGeoMapItemBase *>(sender()); + disconnect(item, 0, this, 0); + if (m_map) + m_map->removeMapItem(item); + m_delegateModel->release(item); } -/*! - \internal - - Note: this call is async. that is returns to the event loop before returning to the caller. - May also trigger incubatorStatusChanged() before returning to the caller if the incubator is fast enough. -*/ -void QDeclarativeGeoMapItemView::createItemForIndex(const QModelIndex &index, bool batched) +void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, int index) { - // Expected to be already tested by caller. - Q_ASSERT(m_delegate); - Q_ASSERT(m_itemModel); - - QDeclarativeGeoMapItemViewItemData *itemData = new QDeclarativeGeoMapItemViewItemData; - - itemData->modelData = new QObject; - itemData->modelDataMeta = new QQmlOpenMetaObject(itemData->modelData, m_metaObjectType, false); - itemData->context = new QQmlContext(qmlContext(this)); - - QHashIterator<int, QByteArray> iterator(m_itemModel->roleNames()); - while (iterator.hasNext()) { - iterator.next(); - - QVariant modelData = m_itemModel->data(index, iterator.key()); - if (!modelData.isValid()) - continue; - - itemData->context->setContextProperty(QString::fromLatin1(iterator.value().constData()), - modelData); + if (!item || (m_map && item->quickMap() == m_map)) + return; - itemData->modelDataMeta->setValue(iterator.value(), modelData); + if (m_map) { + m_instantiatedItems.insert(index, item); + m_map->addMapItem(item); + if (m_enter) { + if (!item->m_transitionManager) { + QScopedPointer<QDeclarativeGeoMapItemTransitionManager>manager(new QDeclarativeGeoMapItemTransitionManager(item)); + item->m_transitionManager.swap(manager); + } + item->m_transitionManager->m_view = this; + item->m_transitionManager->transitionEnter(); + } } - - itemData->context->setContextProperty(QLatin1String("model"), itemData->modelData); - itemData->context->setContextProperty(QLatin1String("index"), index.row()); - - if (batched || m_repopulating) { - if (index.row() < m_itemDataBatched.size()) - m_itemDataBatched.replace(index.row(), itemData); - else - m_itemDataBatched.insert(index.row(), itemData); - } else - m_itemData.insert(index.row(), itemData); - itemData->incubator = new MapItemViewDelegateIncubator(this, itemData, batched || m_repopulating); - - m_delegate->create(*itemData->incubator, itemData->context); -} - -QDeclarativeGeoMapItemViewItemData::~QDeclarativeGeoMapItemViewItemData() -{ - delete incubator; - delete item; - delete context; - delete modelData; } QT_END_NAMESPACE + + diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h index e1132025..a3bf8596 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h @@ -51,11 +51,13 @@ // #include <QtLocation/private/qlocationglobal_p.h> - +#include <map> #include <QtCore/QModelIndex> #include <QtQml/QQmlParserStatus> #include <QtQml/QQmlIncubator> #include <QtQml/qqml.h> +#include <QtQml/private/qqmldelegatemodel_p.h> +#include <QtQuick/private/qquicktransition_p.h> QT_BEGIN_NAMESPACE @@ -68,6 +70,7 @@ class QQmlOpenMetaObject; class QQmlOpenMetaObjectType; class MapItemViewDelegateIncubator; class QDeclarativeGeoMapItemViewItemData; +class QDeclarativeGeoMapItemView; class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus { @@ -78,6 +81,8 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, pub Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(bool autoFitViewport READ autoFitViewport WRITE setAutoFitViewport NOTIFY autoFitViewportChanged) +// Q_PROPERTY(QQuickTransition *enter MEMBER m_enter) +// Q_PROPERTY(QQuickTransition *exit MEMBER m_exit) public: explicit QDeclarativeGeoMapItemView(QQuickItem *parent = 0); @@ -90,60 +95,46 @@ public: void setDelegate(QQmlComponent *); bool autoFitViewport() const; - void setAutoFitViewport(const bool &); + void setAutoFitViewport(const bool &fit); void setMap(QDeclarativeGeoMap *); - void repopulate(); void removeInstantiatedItems(); void instantiateAllItems(); - qreal zValue(); - void setZValue(qreal zValue); - // From QQmlParserStatus - virtual void componentComplete(); - void classBegin() {} + void componentComplete() override; + void classBegin() override; Q_SIGNALS: void modelChanged(); void delegateChanged(); void autoFitViewportChanged(); -protected: - void incubatorStatusChanged(MapItemViewDelegateIncubator *incubator, - QQmlIncubator::Status status, - bool batched); - private Q_SLOTS: - void itemModelReset(); - void itemModelRowsInserted(const QModelIndex &index, int start, int end); - void itemModelRowsRemoved(const QModelIndex &index, int start, int end); - void itemModelRowsMoved(const QModelIndex &parent, int start, int end, - const QModelIndex &destination, int row); - void itemModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector<int> &roles); + void destroyingItem(QObject *object); + void initItem(int index, QObject *object); + void createdItem(int index, QObject *object); + void modelUpdated(const QQmlChangeSet &changeSet, bool reset); + void exitTransitionFinished(); private: - void createItemForIndex(const QModelIndex &index, bool batched = false); void fitViewport(); - void terminateOngoingRepopulation(); - void removeItemData(QDeclarativeGeoMapItemViewItemData *itemData); + void removeItemFromMap(int index); + void addItemToMap(QDeclarativeGeoMapItemBase *item, int index); bool m_componentCompleted; QQmlComponent *m_delegate; - QAbstractItemModel *m_itemModel; + QVariant m_itemModel; QDeclarativeGeoMap *m_map; - QVector<QDeclarativeGeoMapItemViewItemData *> m_itemData; - QVector<QDeclarativeGeoMapItemViewItemData *> m_itemDataBatched; + QList<QDeclarativeGeoMapItemBase *> m_instantiatedItems; bool m_fitViewport; - - QQmlOpenMetaObjectType *m_metaObjectType; - int m_readyIncubators; - bool m_repopulating; + QQmlDelegateModel *m_delegateModel; + QQuickTransition *m_enter = nullptr; + QQuickTransition *m_exit = nullptr; friend class QDeclarativeGeoMap; - friend class QDeclarativeGeoMapItemViewItemData; - friend class MapItemViewDelegateIncubator; + friend class QDeclarativeGeoMapItemBase; + friend class QDeclarativeGeoMapItemTransitionManager; }; QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h deleted file mode 100644 index 3ad3ceb4..00000000 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtLocation module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPLv3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEGEOMAPITEMVIEW_P_P_H -#define QDECLARATIVEGEOMAPITEMVIEW_P_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/QModelIndex> -#include <QtQml/QQmlParserStatus> -#include <QtQml/QQmlIncubator> -#include <QtQml/qqml.h> -#include <QtQml/private/qqmlopenmetaobject_p.h> - -QT_BEGIN_NAMESPACE - -class MapItemViewDelegateIncubator; -class QDeclarativeGeoMapItemView; -class QDeclarativeGeoMapItemBase; - -class QDeclarativeGeoMapItemViewItemData -{ -public: - QDeclarativeGeoMapItemViewItemData() - : incubator(0), item(0), context(0), modelData(0), modelDataMeta(0) - { - } - - ~QDeclarativeGeoMapItemViewItemData(); - - MapItemViewDelegateIncubator *incubator; - QDeclarativeGeoMapItemBase *item; - QQmlContext *context; - QObject *modelData; - QQmlOpenMetaObject *modelDataMeta; - - friend class MapItemViewDelegateIncubator; - friend class QDeclarativeGeoMapItemView; -}; - -Q_DECLARE_TYPEINFO(QDeclarativeGeoMapItemViewItemData, Q_MOVABLE_TYPE); - -QT_END_NAMESPACE - -#endif // QDECLARATIVEGEOMAPITEMVIEW_P_P_H |