summaryrefslogtreecommitdiff
path: root/src/location/declarativemaps/qdeclarativegeomap.cpp
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2018-05-07 16:46:12 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2018-07-27 08:18:38 +0000
commitfd6c6e9654a14788fc4eb7384c9dfa5de1f5ffde (patch)
treed15088fbdac71e31fc5ef8aa445df39b6fb4070d /src/location/declarativemaps/qdeclarativegeomap.cpp
parent6815fd10c51c72ea91bdbc18acddaee2302871f8 (diff)
downloadqtlocation-fd6c6e9654a14788fc4eb7384c9dfa5de1f5ffde.tar.gz
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 <alexander.blasche@qt.io>
Diffstat (limited to 'src/location/declarativemaps/qdeclarativegeomap.cpp')
-rw-r--r--src/location/declarativemaps/qdeclarativegeomap.cpp293
1 files changed, 184 insertions, 109 deletions
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<QQuickItem *> quickKids = g->childItems();
- for (auto c: quickKids) {
- QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(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<QDeclarativeGeoMapItemView *>(k);
- if (mapView) {
- m_mapViews.append(mapView);
- setupMapView(mapView);
- continue;
- }
- QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(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<QDeclarativeGeoMapItemGroup *>(k);
- if (itemGroup) {
- addMapItemGroup(itemGroup);
- continue;
- }
-
- QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(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<QQuickItem *> quickKids = g->childItems();
- for (auto c: quickKids) {
- QDeclarativeGeoMapItemBase *itemBase = qobject_cast<QDeclarativeGeoMapItemBase *>(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<QDeclarativeGeoMapItemView *>(child);
+ if (mapView)
+ return addMapItemView_real(mapView);
+
+ QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(child);
+ if (itemGroup) // addMapItemView calls addMapItemGroup
+ return addMapItemGroup_real(itemGroup);
+
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(child);
+ if (mapItem)
+ return addMapItem_real(mapItem);
+
+ QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(child);
+ if (mapObject)
+ addMapObject(mapObject); // this emits mapObjectsChanged, != mapItemsChanged
+ return false;
+}
+
+bool QDeclarativeGeoMap::removeMapChild(QObject *child)
+{
+ // dispatch items appropriately
+ QDeclarativeGeoMapItemView *mapView = qobject_cast<QDeclarativeGeoMapItemView *>(child);
+ if (mapView)
+ return removeMapItemView_real(mapView);
+
+ QDeclarativeGeoMapItemGroup *itemGroup = qobject_cast<QDeclarativeGeoMapItemGroup *>(child);
+ if (itemGroup) // removeMapItemView calls removeMapItemGroup for itself.
+ return removeMapItemGroup_real(itemGroup);
+
+ QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(child);
+ if (mapItem)
+ return removeMapItem_real(mapItem);
+
+ QGeoMapObject *mapObject = qobject_cast<QGeoMapObject *>(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<QDeclarativeGeoMapItemGroup *>(parent)
+ || qobject_cast<QDeclarativeGeoMapItemGroup *>(group->parentItem());
+}
+
qreal QDeclarativeGeoMap::zoomLevel() const
{
return m_cameraData.zoomLevel();
@@ -1708,39 +1729,6 @@ void QDeclarativeGeoMap::onAttachedCopyrightNoticeVisibilityChanged()
}
/*!
- \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<QDeclarativeGeoMapItemGroup *>(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)
Adds a MapParameter object to the map. The effect of this call is dependent
@@ -1920,6 +1908,45 @@ QList<QObject *> QDeclarativeGeoMap::mapItems()
}
/*!
+ \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<QDeclarativeGeoMapItemGroup *>(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)
Removes the given \a item from the Map (for example MapQuickItem, MapCircle). If
@@ -1930,18 +1957,25 @@ QList<QObject *> 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<QDeclarativeGeoMapItemBase> 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<QDeclarativeGeoMapItemView *>(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<QDeclarativeGeoMapItemGroup> g(itemGroup);
m_mapItemGroups.append(g);
- const QList<QQuickItem *> quickKids = g->childItems();
+
+ const QList<QQuickItem *> quickKids = itemGroup->childItems();
+ int count = 0;
for (auto c: quickKids) {
- QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
- if (mapItem)
- addMapItem(mapItem);
+ count += addMapChild(c); // this calls addMapItemGroup recursively, if needed
}
- itemGroup->setParentItem(this);
+ return count;
}
/*!
@@ -2007,21 +2058,28 @@ void QDeclarativeGeoMap::addMapItemGroup(QDeclarativeGeoMapItemGroup *itemGroup)
*/
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<QDeclarativeGeoMapItemGroup> g(itemGroup);
if (!m_mapItemGroups.removeOne(g))
- return;
+ return false;
const QList<QQuickItem *> quickKids = itemGroup->childItems();
+ int count = 0;
for (auto c: quickKids) {
- QDeclarativeGeoMapItemBase *mapItem = qobject_cast<QDeclarativeGeoMapItemBase *>(c);
- if (mapItem)
- removeMapItem(mapItem);
+ count += removeMapChild(c);
}
itemGroup->setQuickMap(nullptr);
- itemGroup->setParentItem(0);
+ if (itemGroup->parentItem() == this)
+ itemGroup->setParentItem(0);
+ return count;
}
/*!
@@ -2035,14 +2093,23 @@ void QDeclarativeGeoMap::removeMapItemGroup(QDeclarativeGeoMapItemGroup *itemGro
*/
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.
}
/*!
@@ -2056,13 +2123,21 @@ void QDeclarativeGeoMap::removeMapItemView(QDeclarativeGeoMapItemView *itemView)
*/
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;
}
/*!