From fd6c6e9654a14788fc4eb7384c9dfa5de1f5ffde Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Mon, 7 May 2018 16:46:12 +0200 Subject: Enable nested MapItemViews This change allows MapItemView to use a MapItem, MapItemGroup or MapItemView as delegate. To achieve this, MapItemView base class also changes from QObject to MapItemGroup, effectively making MapItemView a MapItemGroup. Note, though, that MapItemGroup API in Map should be avoided, when dealing with a MapItemView, and only MapItemView-specific API should be used. Tests and example coming after [ChangeLog][QtLocation] Enabled nesting of MapItemView. This required a behavioral change, as MapItemView is now a MapItemGroup, not anymore a plain QObject. Due to a bug, MapItemView was previously not a Qt Quick Item, making it possible to create it as a child of any QObject. This has now been fixed, so if you happen to have a MapItemView in your scene which is not a child of a Qt Quick Item, you will get an error message. Task-number: QTBUG-62683 Task-number: QTBUG-62397 Change-Id: Id97e480429e7f952a541fe88df5c01317afeac18 Reviewed-by: Alex Blasche --- src/location/declarativemaps/declarativemaps.pri | 109 ++++---- .../declarativemaps/qdeclarativegeomap.cpp | 293 +++++++++++++-------- .../declarativemaps/qdeclarativegeomap_p.h | 10 + .../declarativemaps/qdeclarativegeomapitembase.cpp | 90 +------ .../declarativemaps/qdeclarativegeomapitembase_p.h | 37 +-- .../qdeclarativegeomapitemgroup.cpp | 63 ++++- .../qdeclarativegeomapitemgroup_p.h | 23 ++ .../qdeclarativegeomapitemtransitionmanager.cpp | 81 ++++++ .../qdeclarativegeomapitemtransitionmanager_p.h | 120 +++++++++ .../declarativemaps/qdeclarativegeomapitemview.cpp | 226 +++++++++++++--- .../declarativemaps/qdeclarativegeomapitemview_p.h | 29 +- tests/auto/declarative_ui/tst_map_itemview.qml | 12 +- 12 files changed, 768 insertions(+), 325 deletions(-) create mode 100644 src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp create mode 100644 src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h diff --git a/src/location/declarativemaps/declarativemaps.pri b/src/location/declarativemaps/declarativemaps.pri index 3cd7a529..28001f99 100644 --- a/src/location/declarativemaps/declarativemaps.pri +++ b/src/location/declarativemaps/declarativemaps.pri @@ -3,61 +3,64 @@ QT += quick-private network positioning-private qml-private core-private gui-pri INCLUDEPATH += declarativemaps PRIVATE_HEADERS += \ - declarativemaps/error_messages_p.h \ - declarativemaps/qdeclarativegeomapitemview_p.h \ - declarativemaps/qdeclarativegeoserviceprovider_p.h \ - declarativemaps/qdeclarativegeocodemodel_p.h \ - declarativemaps/qdeclarativegeoroutemodel_p.h \ - declarativemaps/qdeclarativegeoroute_p.h \ - declarativemaps/qdeclarativegeoroutesegment_p.h \ - declarativemaps/qdeclarativegeomaneuver_p.h \ - declarativemaps/qdeclarativegeomap_p.h \ - declarativemaps/qdeclarativegeomaptype_p.h \ - declarativemaps/qdeclarativegeomapitembase_p.h \ - declarativemaps/qdeclarativegeomapquickitem_p.h \ - declarativemaps/qdeclarativecirclemapitem_p.h \ - declarativemaps/qdeclarativerectanglemapitem_p.h \ - declarativemaps/qdeclarativepolygonmapitem_p.h \ - declarativemaps/qdeclarativepolylinemapitem_p.h \ - declarativemaps/qdeclarativeroutemapitem_p.h \ - declarativemaps/qdeclarativegeomapparameter_p.h \ - declarativemaps/qgeomapitemgeometry_p.h \ - declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h \ - declarativemaps/locationvaluetypehelper_p.h \ - declarativemaps/qquickgeomapgesturearea_p.h \ - declarativemaps/qdeclarativegeomapitemgroup_p.h \ - declarativemaps/qparameterizableobject_p.h \ - declarativemaps/qgeomapobject_p.h \ - declarativemaps/qgeomapobject_p_p.h \ - ../imports/positioning/qquickgeocoordinateanimation_p.h + declarativemaps/error_messages_p.h \ + declarativemaps/locationvaluetypehelper_p.h \ + declarativemaps/mapitemviewdelegateincubator_p.h \ + declarativemaps/qdeclarativecirclemapitem_p.h \ + declarativemaps/qdeclarativegeocodemodel_p.h \ + declarativemaps/qdeclarativegeomaneuver_p.h \ + declarativemaps/qdeclarativegeomapcopyrightsnotice_p.h \ + declarativemaps/qdeclarativegeomapitembase_p.h \ + declarativemaps/qdeclarativegeomapitemgroup_p.h \ + declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h \ + declarativemaps/qdeclarativegeomapitemview_p.h \ + declarativemaps/qdeclarativegeomapparameter_p.h \ + declarativemaps/qdeclarativegeomap_p.h \ + declarativemaps/qdeclarativegeomapquickitem_p.h \ + declarativemaps/qdeclarativegeomaptype_p.h \ + declarativemaps/qdeclarativegeoroutemodel_p.h \ + declarativemaps/qdeclarativegeoroute_p.h \ + declarativemaps/qdeclarativegeoroutesegment_p.h \ + declarativemaps/qdeclarativegeoserviceprovider_p.h \ + declarativemaps/qdeclarativepolygonmapitem_p.h \ + declarativemaps/qdeclarativepolylinemapitem_p.h \ + declarativemaps/qdeclarativerectanglemapitem_p.h \ + declarativemaps/qdeclarativeroutemapitem_p.h \ + declarativemaps/qgeomapitemgeometry_p.h \ + declarativemaps/qgeomapobject_p.h \ + declarativemaps/qgeomapobject_p_p.h \ + declarativemaps/qparameterizableobject_p.h \ + declarativemaps/qquickgeomapgesturearea_p.h \ + ../imports/positioning/qquickgeocoordinateanimation_p.h SOURCES += \ - declarativemaps/qdeclarativegeomapitemview.cpp \ - declarativemaps/qdeclarativegeoserviceprovider.cpp \ - declarativemaps/qdeclarativegeocodemodel.cpp \ - declarativemaps/qdeclarativegeoroutemodel.cpp \ - declarativemaps/qdeclarativegeoroute.cpp \ - declarativemaps/qdeclarativegeoroutesegment.cpp \ - declarativemaps/qdeclarativegeomaneuver.cpp \ - declarativemaps/qdeclarativegeomap.cpp \ - declarativemaps/qdeclarativegeomaptype.cpp \ - declarativemaps/qdeclarativegeomapitembase.cpp \ - declarativemaps/qdeclarativegeomapquickitem.cpp \ - declarativemaps/qdeclarativecirclemapitem.cpp \ - declarativemaps/qdeclarativerectanglemapitem.cpp \ - declarativemaps/qdeclarativepolygonmapitem.cpp \ - declarativemaps/qdeclarativepolylinemapitem.cpp \ - declarativemaps/qdeclarativeroutemapitem.cpp \ - declarativemaps/qdeclarativegeomapparameter.cpp \ - declarativemaps/qgeomapitemgeometry.cpp \ - declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \ - declarativemaps/error_messages.cpp \ - declarativemaps/locationvaluetypehelper.cpp \ - declarativemaps/qquickgeomapgesturearea.cpp \ - declarativemaps/qparameterizableobject.cpp \ - declarativemaps/qdeclarativegeomapitemgroup.cpp \ - declarativemaps/qgeomapobject.cpp \ - ../imports/positioning/qquickgeocoordinateanimation.cpp + declarativemaps/error_messages.cpp \ + declarativemaps/locationvaluetypehelper.cpp \ + declarativemaps/qdeclarativecirclemapitem.cpp \ + declarativemaps/qdeclarativegeocodemodel.cpp \ + declarativemaps/qdeclarativegeomaneuver.cpp \ + declarativemaps/qdeclarativegeomapcopyrightsnotice.cpp \ + declarativemaps/qdeclarativegeomap.cpp \ + declarativemaps/qdeclarativegeomapitembase.cpp \ + declarativemaps/qdeclarativegeomapitemgroup.cpp \ + declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp \ + declarativemaps/qdeclarativegeomapitemview.cpp \ + declarativemaps/qdeclarativegeomapparameter.cpp \ + declarativemaps/qdeclarativegeomapquickitem.cpp \ + declarativemaps/qdeclarativegeomaptype.cpp \ + declarativemaps/qdeclarativegeoroute.cpp \ + declarativemaps/qdeclarativegeoroutemodel.cpp \ + declarativemaps/qdeclarativegeoroutesegment.cpp \ + declarativemaps/qdeclarativegeoserviceprovider.cpp \ + declarativemaps/qdeclarativepolygonmapitem.cpp \ + declarativemaps/qdeclarativepolylinemapitem.cpp \ + declarativemaps/qdeclarativerectanglemapitem.cpp \ + declarativemaps/qdeclarativeroutemapitem.cpp \ + declarativemaps/qgeomapitemgeometry.cpp \ + declarativemaps/qgeomapobject.cpp \ + declarativemaps/qparameterizableobject.cpp \ + declarativemaps/qquickgeomapgesturearea.cpp \ + ../imports/positioning/qquickgeocoordinateanimation.cpp load(qt_build_paths) LIBS_PRIVATE += -L$$MODULE_BASE_OUTDIR/lib -lpoly2tri$$qtPlatformTargetSuffix() -lclip2tri$$qtPlatformTargetSuffix() diff --git a/src/location/declarativemaps/qdeclarativegeomap.cpp b/src/location/declarativemaps/qdeclarativegeomap.cpp index d201b6ab..00643ea1 100644 --- a/src/location/declarativemaps/qdeclarativegeomap.cpp +++ b/src/location/declarativemaps/qdeclarativegeomap.cpp @@ -240,10 +240,13 @@ QDeclarativeGeoMap::~QDeclarativeGeoMap() for (QDeclarativeGeoMapItemView *v : qAsConst(m_mapViews)) { if (!v) continue; - if (v->parent() == this) + if (v->parent() == this) { delete v; - else - v->removeInstantiatedItems(); + } else { + // FIXME: removeInstantiatedItems should abort, as well as exit transitions terminated + v->removeInstantiatedItems(false); + v->m_map = nullptr; + } } } // remove any map items associations @@ -251,19 +254,12 @@ QDeclarativeGeoMap::~QDeclarativeGeoMap() if (m_mapItems.at(i)) m_mapItems.at(i).data()->setMap(0,0); } - m_mapItems.clear(); - for (auto g: qAsConst(m_mapItemGroups)) { - if (!g) - continue; - const QList quickKids = g->childItems(); - for (auto c: quickKids) { - QDeclarativeGeoMapItemBase *itemBase = qobject_cast(c); - if (itemBase) - itemBase->setMap(0,0); - } + // remove any map item groups associations + for (int i = 0; i < m_mapItemGroups.count(); ++i) { + if (m_mapItemGroups.at(i)) + m_mapItemGroups.at(i).data()->setQuickMap(nullptr); } - m_mapItemGroups.clear(); if (m_copyrights.data()) delete m_copyrights.data(); @@ -470,28 +466,7 @@ void QDeclarativeGeoMap::populateMap() kids.insert(ite); for (QObject *k : qAsConst(kids)) { - // dispatch items appropriately - QDeclarativeGeoMapItemView *mapView = qobject_cast(k); - if (mapView) { - m_mapViews.append(mapView); - setupMapView(mapView); - continue; - } - QDeclarativeGeoMapItemBase *mapItem = qobject_cast(k); - if (mapItem) { - addMapItem(mapItem); - continue; - } - // Allow to add to the map Map items contained inside a parent QQuickItem, but only those at one level of nesting. - QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast(k); - if (itemGroup) { - addMapItemGroup(itemGroup); - continue; - } - - QGeoMapObject *mapObject = qobject_cast(k); - if (mapObject) - addMapObject(mapObject); + addMapChild(k); } } @@ -751,15 +726,9 @@ void QDeclarativeGeoMap::mappingManagerInitialized() } // Any map item groups that were added before the plugin was ready - // need to have setMap called again on their children map items - for (auto g: qAsConst(m_mapItemGroups)) { - const QList quickKids = g->childItems(); - for (auto c: quickKids) { - QDeclarativeGeoMapItemBase *itemBase = qobject_cast(c); - if (itemBase) - itemBase->setMap(this, m_map); - } - } + // DO NOT need to have setMap called again on their children map items + // because they have been added to m_mapItems, which is processed right above. + // All map parameters that were added before the plugin was ready // need to be added to m_map @@ -943,6 +912,58 @@ void QDeclarativeGeoMap::setZoomLevel(qreal zoomLevel, bool overzoom) emit zoomLevelChanged(m_cameraData.zoomLevel()); } +bool QDeclarativeGeoMap::addMapChild(QObject *child) +{ + // dispatch items appropriately + QDeclarativeGeoMapItemView *mapView = qobject_cast(child); + if (mapView) + return addMapItemView_real(mapView); + + QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast(child); + if (itemGroup) // addMapItemView calls addMapItemGroup + return addMapItemGroup_real(itemGroup); + + QDeclarativeGeoMapItemBase *mapItem = qobject_cast(child); + if (mapItem) + return addMapItem_real(mapItem); + + QGeoMapObject *mapObject = qobject_cast(child); + if (mapObject) + addMapObject(mapObject); // this emits mapObjectsChanged, != mapItemsChanged + return false; +} + +bool QDeclarativeGeoMap::removeMapChild(QObject *child) +{ + // dispatch items appropriately + QDeclarativeGeoMapItemView *mapView = qobject_cast(child); + if (mapView) + return removeMapItemView_real(mapView); + + QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast(child); + if (itemGroup) // removeMapItemView calls removeMapItemGroup for itself. + return removeMapItemGroup_real(itemGroup); + + QDeclarativeGeoMapItemBase *mapItem = qobject_cast(child); + if (mapItem) + return removeMapItem_real(mapItem); + + QGeoMapObject *mapObject = qobject_cast(child); + if (mapObject) + removeMapObject(mapObject); // this emits mapObjectsChanged, != mapItemsChanged + return false; +} + +bool QDeclarativeGeoMap::isGroupNested(QDeclarativeGeoMapItemGroup *group) +{ + QObject *parent = group->parent(); + // Nested groups have parent set in parent's componentComplete() + // Those instantiated by MapItemView's delegateModel, however, do not, + // but have setParentItem set. + return qobject_cast(parent) + || qobject_cast(group->parentItem()); +} + qreal QDeclarativeGeoMap::zoomLevel() const { return m_cameraData.zoomLevel(); @@ -1707,39 +1728,6 @@ void QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged() m_map->setCopyrightVisible(m_copyNoticesVisible > 0); } -/*! - \qmlmethod void QtLocation::Map::addMapItem(MapItem item) - - Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object - already is on the Map, it will not be added again. - - As an example, consider the case where you have a MapCircle representing your current position: - - \snippet declarative/maps.qml QtQuick import - \snippet declarative/maps.qml QtLocation import - \codeline - \snippet declarative/maps.qml Map addMapItem MapCircle at current position - - \note MapItemViews cannot be added with this method. - - \sa mapItems, removeMapItem, clearMapItems -*/ - -void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item) -{ - if (!item || item->quickMap()) - return; - // If the item comes from a MapItemGroup, do not reparent it. - if (!qobject_cast(item->parentItem())) - item->setParentItem(this); - m_mapItems.append(item); - if (m_map) { - item->setMap(this, m_map); - m_map->addMapItem(item); - } - emit mapItemsChanged(); -} - /*! \qmlmethod void QtLocation::Map::addMapParameter(MapParameter parameter) @@ -1919,6 +1907,45 @@ QList QDeclarativeGeoMap::mapItems() return ret; } +/*! + \qmlmethod void QtLocation::Map::addMapItem(MapItem item) + + Adds the given \a item to the Map (for example MapQuickItem, MapCircle). If the object + already is on the Map, it will not be added again. + + As an example, consider the case where you have a MapCircle representing your current position: + + \snippet declarative/maps.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/maps.qml Map addMapItem MapCircle at current position + + \note MapItemViews cannot be added with this method. + + \sa mapItems, removeMapItem, clearMapItems +*/ + +void QDeclarativeGeoMap::addMapItem(QDeclarativeGeoMapItemBase *item) +{ + if (addMapItem_real(item)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::addMapItem_real(QDeclarativeGeoMapItemBase *item) +{ + if (!item || item->quickMap()) + return false; + // If the item comes from a MapItemGroup, do not reparent it. + if (!qobject_cast(item->parentItem())) + item->setParentItem(this); + m_mapItems.append(item); + if (m_map) { + item->setMap(this, m_map); + m_map->addMapItem(item); + } + return true; +} + /*! \qmlmethod void QtLocation::Map::removeMapItem(MapItem item) @@ -1930,18 +1957,25 @@ QList QDeclarativeGeoMap::mapItems() */ void QDeclarativeGeoMap::removeMapItem(QDeclarativeGeoMapItemBase *ptr) { - if (!ptr || !m_map) - return; - m_map->removeMapItem(ptr); + if (removeMapItem_real(ptr)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::removeMapItem_real(QDeclarativeGeoMapItemBase *ptr) +{ + if (!ptr) + return false; QPointer item(ptr); if (!m_mapItems.contains(item)) - return; + return false; + if (m_map) + m_map->removeMapItem(ptr); if (item->parentItem() == this) item->setParentItem(0); item->setMap(0, 0); // these can be optimized for perf, as we already check the 'contains' above m_mapItems.removeOne(item); - emit mapItemsChanged(); + return true; } /*! @@ -1955,18 +1989,25 @@ void QDeclarativeGeoMap::clearMapItems() { if (m_mapItems.isEmpty()) return; - if (m_map) - m_map->clearMapItems(); - for (auto i : qAsConst(m_mapItems)) { - if (i) { - i->setMap(0, 0); - if (i->parentItem() == this) - i->setParentItem(0); - } + + int removed = 0; + for (auto i : qAsConst(m_mapItemGroups)) { + // Processing only top-level groups (!views) + QDeclarativeGeoMapItemView *view = qobject_cast(i); + if (view) + continue; + + if (i->parentItem() != this) + continue; + + removed += removeMapItemGroup_real(i); } - m_mapItems.clear(); - m_mapItemGroups.clear(); - emit mapItemsChanged(); + + for (auto i : qAsConst(m_mapItems)) + removed += removeMapItem_real(i); + + if (removed) + emit mapItemsChanged(); } /*! @@ -1981,19 +2022,29 @@ void QDeclarativeGeoMap::clearMapItems() */ void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) { - if (!itemGroup || itemGroup->quickMap()) // || Already added to some map - return; + if (addMapItemGroup_real(itemGroup)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::addMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) +{ + if (!itemGroup || itemGroup->quickMap()) // Already added to some map + return false; itemGroup->setQuickMap(this); + + if (!isGroupNested(itemGroup)) + itemGroup->setParentItem(this); + QPointer g(itemGroup); m_mapItemGroups.append(g); - const QList quickKids = g->childItems(); + + const QList quickKids = itemGroup->childItems(); + int count = 0; for (auto c: quickKids) { - QDeclarativeGeoMapItemBase *mapItem = qobject_cast(c); - if (mapItem) - addMapItem(mapItem); + count += addMapChild(c); // this calls addMapItemGroup recursively, if needed } - itemGroup->setParentItem(this); + return count; } /*! @@ -2006,22 +2057,29 @@ void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) \since 5.9 */ void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup) +{ + if (removeMapItemGroup_real(itemGroup)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup) { if (!itemGroup || itemGroup->quickMap() != this) // cant remove an itemGroup added to another map - return; + return false; QPointer g(itemGroup); if (!m_mapItemGroups.removeOne(g)) - return; + return false; const QList quickKids = itemGroup->childItems(); + int count = 0; for (auto c: quickKids) { - QDeclarativeGeoMapItemBase *mapItem = qobject_cast(c); - if (mapItem) - removeMapItem(mapItem); + count += removeMapChild(c); } itemGroup->setQuickMap(nullptr); - itemGroup->setParentItem(0); + if (itemGroup->parentItem() == this) + itemGroup->setParentItem(0); + return count; } /*! @@ -2034,15 +2092,24 @@ void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGro \since 5.10 */ void QDeclarativeGeoMap::removeMapItemView(QDeclarativeGeoMapItemView *itemView) +{ + if (removeMapItemView_real(itemView)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::removeMapItemView_real(QDeclarativeGeoMapItemView *itemView) { if (!itemView || itemView->m_map != this) // can't remove a view that is already added to another map - return; + return false; + // Leaving this as void since the removal is async (potentially transitioned) + // && the delegates *could* be empty mapItemGroups. itemView->removeInstantiatedItems(); itemView->m_map = 0; // it can be removed from the list at this point, since no operations that require a Map have to be done // anymore on destruction. m_mapViews.removeOne(itemView); + return removeMapItemGroup_real(itemView); // at this point, delegate instances have been removed. } /*! @@ -2055,14 +2122,22 @@ void QDeclarativeGeoMap::removeMapItemView(QDeclarativeGeoMapItemView *itemView) \since 5.10 */ void QDeclarativeGeoMap::addMapItemView(QDeclarativeGeoMapItemView *itemView) +{ + if (addMapItemView_real(itemView)) + emit mapItemsChanged(); +} + +bool QDeclarativeGeoMap::addMapItemView_real(QDeclarativeGeoMapItemView *itemView) { if (!itemView || itemView->m_map) // can't add a view twice - return; + return false; + int count = addMapItemGroup_real(itemView); // at this point, delegates aren't yet incubated. // Not appending it to m_mapViews because it seems unnecessary even if the // itemView is a child of this (in which case it would be destroyed m_mapViews.append(itemView); setupMapView(itemView); + return count; } /*! diff --git a/src/location/declarativemaps/qdeclarativegeomap_p.h b/src/location/declarativemaps/qdeclarativegeomap_p.h index 6948b15b..02379411 100644 --- a/src/location/declarativemaps/qdeclarativegeomap_p.h +++ b/src/location/declarativemaps/qdeclarativegeomap_p.h @@ -254,6 +254,16 @@ protected: void setError(QGeoServiceProvider::Error error, const QString &errorString); void initialize(); void setZoomLevel(qreal zoomLevel, bool overzoom); + bool addMapChild(QObject *child); + bool removeMapChild(QObject *child); + bool isGroupNested(QDeclarativeGeoMapItemGroup *group); + + bool addMapItem_real(QDeclarativeGeoMapItemBase *item); + bool removeMapItem_real(QDeclarativeGeoMapItemBase *item); + bool addMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup); + bool removeMapItemGroup_real(QDeclarativeGeoMapItemGroup *itemGroup); + bool addMapItemView_real(QDeclarativeGeoMapItemView *itemView); + bool removeMapItemView_real(QDeclarativeGeoMapItemView *itemView); private Q_SLOTS: void mappingManagerInitialized(); diff --git a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp index 366992ed..7de6afb5 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitembase.cpp @@ -85,10 +85,6 @@ QDeclarativeGeoMapItemBase::QDeclarativeGeoMapItemBase(QQuickItem *parent) // Changing opacity on a mapItemGroup should affect also the opacity on the children. // This must be notified to plugins, if they are to render the item. connect(this, &QQuickItem::opacityChanged, this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); - parentGroup_ = qobject_cast(parent); - if (parentGroup_) - connect(qobject_cast(parent), &QQuickItem::opacityChanged, - this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); } QDeclarativeGeoMapItemBase::~QDeclarativeGeoMapItemBase() @@ -285,49 +281,26 @@ QSGNode *QDeclarativeGeoMapItemBase::updateMapItemPaintNode(QSGNode *oldNode, Up return 0; } +/*! + \internal + + The actual combined opacity of the item. Needed by custom renderer to look like + the scene-graph one. +*/ qreal QDeclarativeGeoMapItemBase::mapItemOpacity() const { if (parentGroup_) - return parentGroup_->opacity() * opacity(); + return parentGroup_->mapItemOpacity() * opacity(); 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() +void QDeclarativeGeoMapItemBase::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup) { - 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; + parentGroup_ = &parentGroup; + if (parentGroup_) { + connect(parentGroup_, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged, + this, &QDeclarativeGeoMapItemBase::mapItemOpacityChanged); } - 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 @@ -341,43 +314,4 @@ 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 4a2f9282..f884c13e 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitembase_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitembase_p.h @@ -56,12 +56,11 @@ #include #include #include -#include +#include #include QT_BEGIN_NAMESPACE -class QDeclarativeGeoMapItemTransitionManager; -class QDeclarativeGeoMapItemBase; + class Q_LOCATION_PRIVATE_EXPORT QGeoMapViewportChangeEvent { public: @@ -80,29 +79,6 @@ 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 enterActions; - QList exitActions; - TransitionState m_transitionState = NoTransition; -}; - class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemBase : public QQuickItem { Q_OBJECT @@ -125,15 +101,12 @@ public: virtual QGeoMap::ItemType itemType() const = 0; qreal mapItemOpacity() const; - virtual bool prepareEnterTransition(); - virtual bool prepareExitTransition(); - virtual void finalizeEnterTransition(); - virtual void finalizeExitTransition(); + void setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup); Q_SIGNALS: void mapItemOpacityChanged(); - Q_REVISION(11) void enterTransitionFinished(); - Q_REVISION(11) void exitTransitionFinished(); + Q_REVISION(12) void addTransitionFinished(); + Q_REVISION(12) void removeTransitionFinished(); protected Q_SLOTS: virtual void afterChildrenChanged(); diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp index b4d214ad..a51dcb31 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup.cpp @@ -35,6 +35,8 @@ ****************************************************************************/ #include "qdeclarativegeomapitemgroup_p.h" +#include "qdeclarativegeomapitembase_p.h" +#include "qdeclarativegeomap_p.h" QT_BEGIN_NAMESPACE @@ -135,9 +137,11 @@ QT_BEGIN_NAMESPACE \image api-mapitemgroup.png */ -QDeclarativeGeoMapItemGroup::QDeclarativeGeoMapItemGroup(QQuickItem *parent): QQuickItem(parent), m_quickMap(nullptr) +QDeclarativeGeoMapItemGroup::QDeclarativeGeoMapItemGroup(QQuickItem *parent) +: QQuickItem(parent), m_quickMap(nullptr) { - + connect(this, &QQuickItem::opacityChanged, + this, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged); } QDeclarativeGeoMapItemGroup::~QDeclarativeGeoMapItemGroup() @@ -145,9 +149,23 @@ QDeclarativeGeoMapItemGroup::~QDeclarativeGeoMapItemGroup() } +void QDeclarativeGeoMapItemGroup::setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup) +{ + m_parentGroup = &parentGroup; + connect(m_parentGroup, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged, + this, &QDeclarativeGeoMapItemGroup::mapItemOpacityChanged); +} + void QDeclarativeGeoMapItemGroup::setQuickMap(QDeclarativeGeoMap *quickMap) { + if (!quickMap && m_quickMap) + m_quickMap->disconnect(this); m_quickMap = quickMap; + if (m_quickMap) { + onMapSizeChanged(); + connect(m_quickMap, &QQuickItem::widthChanged, this, &QDeclarativeGeoMapItemGroup::onMapSizeChanged); + connect(m_quickMap, &QQuickItem::heightChanged, this, &QDeclarativeGeoMapItemGroup::onMapSizeChanged); + } } QDeclarativeGeoMap *QDeclarativeGeoMapItemGroup::quickMap() const @@ -155,4 +173,45 @@ QDeclarativeGeoMap *QDeclarativeGeoMapItemGroup::quickMap() const return m_quickMap; } +qreal QDeclarativeGeoMapItemGroup::mapItemOpacity() const +{ + return ((m_parentGroup) ? m_parentGroup->mapItemOpacity() : 1.0) * opacity(); +} + +void QDeclarativeGeoMapItemGroup::classBegin() +{ + QQuickItem::classBegin(); +} + +void QDeclarativeGeoMapItemGroup::componentComplete() +{ + QQuickItem::componentComplete(); + + // In certain cases the parent won't be set via the constructor, but rather later on + // during the instantiation/incubation process. + // Therefore calling setParentGroup here, when the parent is known. + // The childrenChanged use case to handle dynamically-added items is currently unsupported. + const QList &quickKids = childItems(); + for (QQuickItem *k : quickKids) { + QDeclarativeGeoMapItemGroup *childGroup + = qobject_cast(k); + if (childGroup) { + childGroup->setParentGroup(*this); + continue; + } + QDeclarativeGeoMapItemBase *childItem + = qobject_cast(k); + if (childItem) { + childItem->setParentGroup(*this); + continue; + } + } +} + +void QDeclarativeGeoMapItemGroup::onMapSizeChanged() +{ + setWidth(m_quickMap->width()); + setHeight(m_quickMap->height()); +} + QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h index f91d291c..395e74a1 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitemgroup_p.h @@ -49,6 +49,7 @@ // #include +#include #include QT_BEGIN_NAMESPACE @@ -61,10 +62,32 @@ public: explicit QDeclarativeGeoMapItemGroup(QQuickItem *parent = 0); virtual ~QDeclarativeGeoMapItemGroup(); + void setParentGroup(QDeclarativeGeoMapItemGroup &parentGroup); void setQuickMap(QDeclarativeGeoMap *quickMap); QDeclarativeGeoMap *quickMap() const; + + qreal mapItemOpacity() const; + +Q_SIGNALS: + void mapItemOpacityChanged(); + void addTransitionFinished(); + void removeTransitionFinished(); + +protected: + // QQmlParserStatus interface + void classBegin() override; + void componentComplete() override; + +protected slots: + void onMapSizeChanged(); + private: QDeclarativeGeoMap *m_quickMap; + QDeclarativeGeoMapItemGroup *m_parentGroup = nullptr; + QScopedPointer m_transitionManager; + + friend class QDeclarativeGeoMapItemView; + friend class QDeclarativeGeoMapItemTransitionManager; }; QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp new file mode 100644 index 00000000..549ab2cb --- /dev/null +++ b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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$ +** +****************************************************************************/ + +#include "qdeclarativegeomapitemtransitionmanager_p.h" +#include "qdeclarativegeomapitemview_p.h" + +QT_BEGIN_NAMESPACE + +QDeclarativeGeoMapItemTransitionManager::QDeclarativeGeoMapItemTransitionManager(QObject *mapItem) + : QQuickTransitionManager(), m_mapItem(mapItem) +{ +} + +void QDeclarativeGeoMapItemTransitionManager::transitionEnter() +{ + if (m_transitionState == ExitTransition) + cancel(); + + if (!prepareEnterTransition()) + return; + + if (m_view && m_view->m_enter) + transition(enterActions, m_view->m_enter, m_mapItem); + else + finished(); +} + +void QDeclarativeGeoMapItemTransitionManager::transitionExit() +{ + if (!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) + finalizeEnterTransition(); + else if (m_transitionState == ExitTransition) + finalizeExitTransition(); +} + + +QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h new file mode 100644 index 00000000..0a83fe39 --- /dev/null +++ b/src/location/declarativemaps/qdeclarativegeomapitemtransitionmanager_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QDECLARATIVEGEOMAPITEMTRANSITIONMANAGER_H +#define QDECLARATIVEGEOMAPITEMTRANSITIONMANAGER_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 +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeclarativeGeoMapItemView; + +class QDeclarativeGeoMapItemTransitionManager : public QQuickTransitionManager +{ +public: + enum TransitionState { + NoTransition, EnterTransition, ExitTransition + }; + + QDeclarativeGeoMapItemTransitionManager(QObject *mapItem); + + void transitionEnter(); + void transitionExit(); + + bool prepareEnterTransition() + { + if (m_transitionState == QDeclarativeGeoMapItemTransitionManager::EnterTransition + && isRunning()) + return false; + + if (m_transitionState != QDeclarativeGeoMapItemTransitionManager::EnterTransition) { + // setVisible(true); + m_transitionState = QDeclarativeGeoMapItemTransitionManager::EnterTransition; + } + return true; + } + bool prepareExitTransition() + { + if (m_transitionState == QDeclarativeGeoMapItemTransitionManager::ExitTransition + && isRunning()) + return false; + + if (m_transitionState != QDeclarativeGeoMapItemTransitionManager::ExitTransition) { + m_transitionState = QDeclarativeGeoMapItemTransitionManager::ExitTransition; + } + return true; + } + void finalizeEnterTransition() + { + m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; + // use invokeMethod since this is used on both QDeclarativeGeoMapItemBase and QDeclarativeGeoMapItemGroup + QMetaObject::invokeMethod(m_mapItem, QByteArrayLiteral("addTransitionFinished").constData(), Qt::DirectConnection); + } + void finalizeExitTransition() + { +// setVisible(false); + m_transitionState = QDeclarativeGeoMapItemTransitionManager::NoTransition; + QMetaObject::invokeMethod(m_mapItem, QByteArrayLiteral("removeTransitionFinished").constData(), Qt::DirectConnection); + } + +protected: + void finished() override; + +public: + QObject *m_mapItem; + QDeclarativeGeoMapItemView *m_view = nullptr; + QList enterActions; + QList exitActions; + TransitionState m_transitionState = NoTransition; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp index dca92269..415eecb3 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview.cpp +++ b/src/location/declarativemaps/qdeclarativegeomapitemview.cpp @@ -94,7 +94,7 @@ QT_BEGIN_NAMESPACE */ QDeclarativeGeoMapItemView::QDeclarativeGeoMapItemView(QQuickItem *parent) - : QObject(parent), m_componentCompleted(false), m_delegate(0), + : QDeclarativeGeoMapItemGroup(parent), m_componentCompleted(false), m_delegate(0), m_map(0), m_fitViewport(false), m_delegateModel(0) { m_exit = new QQuickTransition(this); @@ -116,6 +116,7 @@ QDeclarativeGeoMapItemView::~QDeclarativeGeoMapItemView() */ void QDeclarativeGeoMapItemView::componentComplete() { + QDeclarativeGeoMapItemGroup::componentComplete(); m_componentCompleted = true; if (!m_itemModel.isNull()) m_delegateModel->setModel(m_itemModel); @@ -128,6 +129,7 @@ void QDeclarativeGeoMapItemView::componentComplete() void QDeclarativeGeoMapItemView::classBegin() { + QDeclarativeGeoMapItemGroup::classBegin(); QQmlContext *ctx = qmlContext(this); m_delegateModel = new QQmlDelegateModel(ctx, this); m_delegateModel->classBegin(); @@ -154,10 +156,15 @@ void QDeclarativeGeoMapItemView::createdItem(int index, QObject */*object*/) return; // 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(m_delegateModel->object(index, QQmlIncubator::Asynchronous)); + + if (m_incubationMode == QQmlIncubator::Synchronous) { + qWarning() << "createdItem invoked on Synchronous incubation"; + return; + } + + QQuickItem *item = qobject_cast(m_delegateModel->object(index, m_incubationMode)); if (item) - addItemToMap(item, index); + addDelegateToMap(item, index); else qWarning() << "createdItem for " << index << " produced a null item"; } @@ -179,16 +186,13 @@ void QDeclarativeGeoMapItemView::modelUpdated(const QQmlChangeSet &changeSet, bo 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); + removeDelegateFromMap(idx); } } for (const QQmlChangeSet::Change &c: changeSet.inserts()) { - for (int idx = c.start(); idx < c.end(); idx++) { - QDeclarativeGeoMapItemBase *item = - qobject_cast(m_delegateModel->object(idx, QQmlIncubator::Asynchronous)); - addItemToMap(item, idx); // if not item, a createdItem signal will be emitted. - } + for (int idx = c.start(); idx < c.end(); idx++) + addDelegateToMap(qobject_cast(m_delegateModel->object(idx, m_incubationMode)), idx); } fitViewport(); @@ -290,14 +294,15 @@ void QDeclarativeGeoMapItemView::setMap(QDeclarativeGeoMap *map) /*! \internal */ -void QDeclarativeGeoMapItemView::removeInstantiatedItems() +void QDeclarativeGeoMapItemView::removeInstantiatedItems(bool transition) { if (!m_map) return; + // FIXME: removeInstantiatedItems should abort, as well as exit transitions terminated QTBUG-69195 // Backward as removeItemFromMap modifies m_instantiatedItems for (int i = m_instantiatedItems.size() -1; i >= 0 ; i--) - removeItemFromMap(i); + removeDelegateFromMap(i, transition); } /*! @@ -312,19 +317,36 @@ void QDeclarativeGeoMapItemView::instantiateAllItems() return; // 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(m_delegateModel->object(i, QQmlIncubator::Asynchronous)); - addItemToMap(item, i); // if not item, createdItem will be emitted. - } + for (int i = 0; i < m_delegateModel->count(); i++) + addDelegateToMap(qobject_cast(m_delegateModel->object(i, m_incubationMode)), i); fitViewport(); } -void QDeclarativeGeoMapItemView::removeItemFromMap(int index) +void QDeclarativeGeoMapItemView::setIncubateDelegates(bool useIncubators) +{ + const QQmlIncubator::IncubationMode incubationMode = + (useIncubators) ? QQmlIncubator::Asynchronous : QQmlIncubator::Synchronous; + if (m_incubationMode == incubationMode) + return; + m_incubationMode = incubationMode; + emit incubateDelegatesChanged(); +} + +bool QDeclarativeGeoMapItemView::incubateDelegates() const +{ + return m_incubationMode == QQmlIncubator::Asynchronous; +} + +QList QDeclarativeGeoMapItemView::mapItems() +{ + return m_instantiatedItems; +} + +void QDeclarativeGeoMapItemView::removeDelegateFromMap(int index, bool transition) { if (index >= 0 && index < m_instantiatedItems.size()) { - QDeclarativeGeoMapItemBase *item = m_instantiatedItems.takeAt(index); + QQuickItem *item = m_instantiatedItems.takeAt(index); if (!item) { if (m_incubatingItems.contains(index)) { // cancel request @@ -333,50 +355,106 @@ void QDeclarativeGeoMapItemView::removeItemFromMap(int index) } return; } - if (m_exit && m_map) { - if (!item->m_transitionManager) { - QScopedPointermanager(new QDeclarativeGeoMapItemTransitionManager(item)); - item->m_transitionManager.swap(manager); - item->m_transitionManager->m_view = this; - } - connect(item, &QDeclarativeGeoMapItemBase::exitTransitionFinished, - this, &QDeclarativeGeoMapItemView::exitTransitionFinished); - item->m_transitionManager->transitionExit(); + // item can be either a QDeclarativeGeoMapItemBase or a QDeclarativeGeoMapItemGroup + if (m_exit && m_map && transition) { + transitionItemOut(item); } else { disconnect(item, 0, this, 0); - if (m_map) - m_map->removeMapItem(item); + removeDelegateFromMap(item); + item->setParentItem(nullptr); // Needed because + item->setParent(nullptr); // m_delegateModel->release(item) does not destroy the item most of the times!! QQmlInstanceModel::ReleaseFlags releaseStatus = m_delegateModel->release(item); +#ifdef QT_DEBUG if (releaseStatus == QQmlInstanceModel::Referenced) - qWarning() << "item "<< index << " still referenced"; + qWarning() << "item "<< index << "(" << item << ") still referenced"; +#else + Q_UNUSED(releaseStatus) +#endif } } } +void QDeclarativeGeoMapItemView::removeDelegateFromMap(QQuickItem *o) +{ + if (!m_map) + return; + + QDeclarativeGeoMapItemBase *item = qobject_cast(o); + if (item) { + m_map->removeMapItem(item); + return; + } + QDeclarativeGeoMapItemView *view = qobject_cast(o); + if (view) { + m_map->removeMapItemView(view); + return; + } + QDeclarativeGeoMapItemGroup *group = qobject_cast(o); + if (group) { + m_map->removeMapItemGroup(group); + return; + } +} + +void QDeclarativeGeoMapItemView::transitionItemOut(QQuickItem *o) +{ + QDeclarativeGeoMapItemGroup *group = qobject_cast(o); + if (group) { + if (!group->m_transitionManager) { + QScopedPointermanager(new QDeclarativeGeoMapItemTransitionManager(group)); + group->m_transitionManager.swap(manager); + group->m_transitionManager->m_view = this; + } + connect(group, SIGNAL(removeTransitionFinished()), + this, SLOT(exitTransitionFinished())); + + group->m_transitionManager->transitionExit(); + return; + } + QDeclarativeGeoMapItemBase *item = qobject_cast(o); + if (item) { + if (!item->m_transitionManager) { + QScopedPointer manager(new QDeclarativeGeoMapItemTransitionManager(item)); + item->m_transitionManager.swap(manager); + item->m_transitionManager->m_view = this; + } + connect(item, SIGNAL(removeTransitionFinished()), + this, SLOT(exitTransitionFinished()) ); + + item->m_transitionManager->transitionExit(); + return; + } +} + void QDeclarativeGeoMapItemView::exitTransitionFinished() { - QDeclarativeGeoMapItemBase *item = static_cast(sender()); + QQuickItem *item = qobject_cast(sender()); + if (!item) + return; disconnect(item, 0, this, 0); - if (m_map) - m_map->removeMapItem(item); + removeDelegateFromMap(item); + item->setParentItem(nullptr); + item->setParent(nullptr); QQmlInstanceModel::ReleaseFlags releaseStatus = m_delegateModel->release(item); +#ifdef QT_DEBUG if (releaseStatus == QQmlInstanceModel::Referenced) qWarning() << "item "<quickMap() == m_map) // belonging to another map?? - return; - if (m_map) { - if (!item) { - m_incubatingItems.insert(index); - m_instantiatedItems.insert(index, nullptr); + if (m_map && item) { // belonging to another map?? + if (item->quickMap() == m_map) return; - } + } + if (m_map) { insertInstantiatedItem(index, item); + item->setParentItem(this); m_map->addMapItem(item); if (m_enter) { if (!item->m_transitionManager) { @@ -389,7 +467,7 @@ void QDeclarativeGeoMapItemView::addItemToMap(QDeclarativeGeoMapItemBase *item, } } -void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QDeclarativeGeoMapItemBase *o) +void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QQuickItem *o) { if (m_incubatingItems.contains(index)) { m_incubatingItems.remove(index); @@ -399,6 +477,70 @@ void QDeclarativeGeoMapItemView::insertInstantiatedItem(int index, QDeclarativeG } } +void QDeclarativeGeoMapItemView::addItemViewToMap(QDeclarativeGeoMapItemView *item, int index) +{ + if (!item || (m_map && item->quickMap() == m_map)) + return; + + if (m_map) { + insertInstantiatedItem(index, item); + item->setParentItem(this); + m_map->addMapItemView(item); + if (m_enter) { + if (!item->m_transitionManager) { + QScopedPointer manager(new QDeclarativeGeoMapItemTransitionManager(item)); + item->m_transitionManager.swap(manager); + } + item->m_transitionManager->m_view = this; + item->m_transitionManager->transitionEnter(); + } + } +} + +void QDeclarativeGeoMapItemView::addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index) +{ + if (!item || (m_map && item->quickMap() == m_map)) + return; + + if (m_map) { + insertInstantiatedItem(index, item); + item->setParentItem(this); + m_map->addMapItemGroup(item); + if (m_enter) { + if (!item->m_transitionManager) { + QScopedPointermanager(new QDeclarativeGeoMapItemTransitionManager(item)); + item->m_transitionManager.swap(manager); + } + item->m_transitionManager->m_view = this; + item->m_transitionManager->transitionEnter(); + } + } +} + +void QDeclarativeGeoMapItemView::addDelegateToMap(QQuickItem *object, int index) +{ + if (!object) { + m_incubatingItems.insert(index); + m_instantiatedItems.insert(index, nullptr); + return; + } + QDeclarativeGeoMapItemBase *item = qobject_cast(object); + if (item) { // else createdItem will be emitted. + addItemToMap(item, index); + return; + } + QDeclarativeGeoMapItemView *view = qobject_cast(object); + if (view) { + addItemViewToMap(view, index); + return; + } + QDeclarativeGeoMapItemGroup *group = qobject_cast(object); + if (group) { + addItemGroupToMap(group, index); + return; + } +} + QT_END_NAMESPACE diff --git a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h index 9e1bebad..58ef2835 100644 --- a/src/location/declarativemaps/qdeclarativegeomapitemview_p.h +++ b/src/location/declarativemaps/qdeclarativegeomapitemview_p.h @@ -58,6 +58,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -71,18 +72,19 @@ class QQmlOpenMetaObjectType; class MapItemViewDelegateIncubator; class QDeclarativeGeoMapItemViewItemData; class QDeclarativeGeoMapItemView; +class QDeclarativeGeoMapItemGroup; -class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QObject, public QQmlParserStatus +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeGeoMapItemView : public QDeclarativeGeoMapItemGroup { Q_OBJECT - Q_INTERFACES(QQmlParserStatus) - 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 *add MEMBER m_enter REVISION 12) Q_PROPERTY(QQuickTransition *remove MEMBER m_exit REVISION 12) + Q_PROPERTY(QList mapItems READ mapItems REVISION 12) + Q_PROPERTY(bool incubateDelegates READ incubateDelegates WRITE setIncubateDelegates NOTIFY incubateDelegatesChanged REVISION 12) public: explicit QDeclarativeGeoMapItemView(QQuickItem *parent = 0); @@ -98,9 +100,14 @@ public: void setAutoFitViewport(const bool &fit); void setMap(QDeclarativeGeoMap *); - void removeInstantiatedItems(); + void removeInstantiatedItems(bool transition = true); void instantiateAllItems(); + void setIncubateDelegates(bool useIncubators); + bool incubateDelegates() const; + + QList mapItems(); + // From QQmlParserStatus void componentComplete() override; void classBegin() override; @@ -109,6 +116,7 @@ Q_SIGNALS: void modelChanged(); void delegateChanged(); void autoFitViewportChanged(); + void incubateDelegatesChanged(); private Q_SLOTS: void destroyingItem(QObject *object); @@ -119,15 +127,22 @@ private Q_SLOTS: private: void fitViewport(); - void removeItemFromMap(int index); + void removeDelegateFromMap(int index, bool transition = true); + void removeDelegateFromMap(QQuickItem *o); + void transitionItemOut(QQuickItem *o); + + void insertInstantiatedItem(int index, QQuickItem *o); void addItemToMap(QDeclarativeGeoMapItemBase *item, int index); - void insertInstantiatedItem(int index, QDeclarativeGeoMapItemBase *o); + void addItemViewToMap(QDeclarativeGeoMapItemView *item, int index); + void addItemGroupToMap(QDeclarativeGeoMapItemGroup *item, int index); + void addDelegateToMap(QQuickItem *object, int index); bool m_componentCompleted; + QQmlIncubator::IncubationMode m_incubationMode = QQmlIncubator::Asynchronous; QQmlComponent *m_delegate; QVariant m_itemModel; QDeclarativeGeoMap *m_map; - QList m_instantiatedItems; + QList m_instantiatedItems; QSet m_incubatingItems; bool m_fitViewport; QQmlDelegateModel *m_delegateModel; diff --git a/tests/auto/declarative_ui/tst_map_itemview.qml b/tests/auto/declarative_ui/tst_map_itemview.qml index 097212ca..0ab9d494 100644 --- a/tests/auto/declarative_ui/tst_map_itemview.qml +++ b/tests/auto/declarative_ui/tst_map_itemview.qml @@ -28,7 +28,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtLocation 5.6 +import QtLocation 5.12 import QtPositioning 5.5 import QtLocation.Test 5.5 @@ -49,6 +49,7 @@ Item { MapItemView { id: routeItemViewExtra model: routeModel + incubateDelegates: false delegate: Component { MapRoute { route: routeData @@ -58,6 +59,10 @@ Item { MapItemView { id: listModelItemViewExtra + objectName: "listModelItemViewExtra" + incubateDelegates: false + add: null + remove: null model: ListModel { id: testingListModelExtra ListElement { lat: 11; lon: 31 } @@ -252,6 +257,9 @@ Item { MapItemView { id: listModelItemView + incubateDelegates: false + add: null + remove: null model: ListModel { id: testingListModel ListElement { lat: 11; lon: 31 } @@ -487,7 +495,7 @@ Item { testingListModelExtra.clear() tryCompare(mapForTestingListModel, "mapItemsLength", 0) mapForTestingListModel.removeMapItemView(listModelItemViewExtra) - + tryCompare(mapForTestingListModel, "mapItemsLength", 0) mapForTestingListModel.addMapItemView(listModelItemView) tryCompare(mapForTestingListModel, "mapItemsLength", 3) -- cgit v1.2.1