summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2018-01-19 18:53:24 +0100
committerBogDan Vatra <bogdan@kdab.com>2018-02-08 13:45:21 +0000
commit912e7eaf9a044941f7f351d8fe2dfdec71760f73 (patch)
treeeee52f5f70379a72eaf62d9e2b012208ee6c1b4e
parent538640b70f2062285415c3c324926bc06e814e9d (diff)
Introduce MapObjectView
This also adds addMapObject/removeMapObject to MapObjectView With this patch, MapObjectView becomes the intended way to programmatically populate a map with map objects. Objects can still be declared inside a Map{} element, but to programmatically add them it is necessary to add them to a MapObjectView that is added to the map. MapObjectView has then 3 ways to populate the map: via nested map objects, via a model, and via programmatically added map objects. All these 3 ways can be used simultaneously. Change-Id: Ic7712355fa5e5787a0b83d9547693e288cba1960 Reviewed-by: BogDan Vatra <bogdan@kdab.com>
-rw-r--r--src/imports/locationlabs/locationlabs.cpp4
-rw-r--r--src/locationlabs/qmapobjectview.cpp352
-rw-r--r--src/locationlabs/qmapobjectview_p.h111
-rw-r--r--src/locationlabs/qmapobjectview_p_p.h81
4 files changed, 546 insertions, 2 deletions
diff --git a/src/imports/locationlabs/locationlabs.cpp b/src/imports/locationlabs/locationlabs.cpp
index 0cdd7f84..4b77a2ae 100644
--- a/src/imports/locationlabs/locationlabs.cpp
+++ b/src/imports/locationlabs/locationlabs.cpp
@@ -35,7 +35,7 @@
****************************************************************************/
//#include <QtLocationLabs/private/qmapiconobject_p.h>
-//#include <QtLocationLabs/private/qmapobjectview_p.h>
+#include <QtLocationLabs/private/qmapobjectview_p.h>
#include <QtLocationLabs/private/qmaprouteobject_p.h>
//#include <QtLocationLabs/private/qdeclarativenavigator_p.h>
@@ -73,7 +73,7 @@ public:
// Register the 5.11 types
// qmlRegisterType<QDeclarativeNavigator>(uri, major, minor, "Navigator");
// qmlRegisterType<QMapIconObject>(uri, major, minor, "MapIconObject");
-// qmlRegisterType<QMapObjectView>(uri, major, minor, "MapObjectView");
+ qmlRegisterType<QMapObjectView>(uri, major, minor, "MapObjectView");
qmlRegisterType<QMapRouteObject>(uri, major, minor, "MapRouteObject");
// Register the latest Qt version as QML type version
diff --git a/src/locationlabs/qmapobjectview.cpp b/src/locationlabs/qmapobjectview.cpp
new file mode 100644
index 00000000..696b2bce
--- /dev/null
+++ b/src/locationlabs/qmapobjectview.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 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 "qmapobjectview_p.h"
+#include "qmapobjectview_p_p.h"
+#include <QtQml/private/qqmldelegatemodel_p.h>
+#include <QtLocation/private/qgeomap_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+
+ QGeoMapLayerPrivate
+
+*/
+
+
+QMapObjectViewPrivate::QMapObjectViewPrivate(QGeoMapObject *q)
+ : QGeoMapObjectPrivate(q)
+{
+}
+
+QMapObjectViewPrivate::~QMapObjectViewPrivate()
+{
+
+}
+
+QGeoMapObject::Type QMapObjectViewPrivate::type() const
+{
+ return QGeoMapObject::ViewType;
+}
+
+
+/*
+
+ QGeoMapLayerPrivateDefault
+
+*/
+
+
+QMapObjectViewPrivateDefault::QMapObjectViewPrivateDefault(const QMapObjectViewPrivate &other) : QMapObjectViewPrivate(other.q)
+{
+}
+
+QMapObjectViewPrivateDefault::~QMapObjectViewPrivateDefault()
+{
+
+}
+
+QMapObjectViewPrivateDefault::QMapObjectViewPrivateDefault(QGeoMapObject *q) : QMapObjectViewPrivate(q)
+{
+
+}
+
+QGeoMapObjectPrivate *QMapObjectViewPrivateDefault::clone()
+{
+ return new QMapObjectViewPrivateDefault(*this);
+}
+
+/*
+
+ QMapObjectView
+
+*/
+
+
+QMapObjectView::QMapObjectView(QObject *parent)
+ : QGeoMapObject(QExplicitlySharedDataPointer<QGeoMapObjectPrivate>(new QMapObjectViewPrivateDefault(this)), parent)
+{
+
+}
+
+QMapObjectView::~QMapObjectView()
+{
+ flushDelegateModel();
+ flushUserAddedMapObjects();
+}
+
+QList<QGeoMapObject *> QMapObjectView::geoMapObjectChildren() const
+{
+ auto kids = QGeoMapObject::geoMapObjectChildren();
+ auto size = m_instantiatedMapObjects.count();
+ for (int i = 0; i < size; ++i) {
+ auto obj = qobject_cast<QGeoMapObject*>(m_instantiatedMapObjects[i]);
+ if (obj)
+ kids << obj;
+ }
+ for (int i = 0; i < m_userAddedMapObjects.size(); ++i) {
+ auto obj = m_userAddedMapObjects.at(i);
+ if (obj)
+ kids << obj;
+ }
+ return kids;
+}
+
+void QMapObjectView::setMap(QGeoMap *map)
+{
+ QMapObjectViewPrivate *d = static_cast<QMapObjectViewPrivate *>(d_ptr.data());
+ if (d->m_map == map)
+ return;
+
+ QGeoMapObject::setMap(map); // This is where the specialized pimpl gets created and injected
+
+ for (int i = 0; i < m_userAddedMapObjects.size(); ++i) {
+ auto obj = m_userAddedMapObjects.at(i);
+ if (obj && obj->map() != map)
+ obj->setMap(map);
+ }
+
+ if (!map) {
+ // Map was set, now it has ben re-set to NULL
+ flushDelegateModel();
+ flushUserAddedMapObjects();
+ d_ptr = new QMapObjectViewPrivateDefault(*d);
+ } else if (d->m_componentCompleted) {
+ // Map was null, now it's set AND delegateModel is already complete.
+ // some delegates may have been incubated but not added to the map.
+ for (int i = 0; i < m_pendingMapObjects.size(); ++i) {
+ auto obj = m_pendingMapObjects.at(i);
+ if (obj && obj->map() != map)
+ obj->setMap(map);
+ }
+ m_pendingMapObjects.clear();
+ }
+}
+
+void QMapObjectView::classBegin()
+{
+ QQmlContext *ctx = qmlContext(this);
+ m_delegateModel = new QQmlDelegateModel(ctx, this);
+ m_delegateModel->classBegin();
+
+ QQmlInstanceModel *model = m_delegateModel;
+ connect(model, &QQmlInstanceModel::modelUpdated, this, &QMapObjectView::modelUpdated);
+ connect(model, &QQmlInstanceModel::createdItem, this, &QMapObjectView::createdItem);
+ connect(model, &QQmlInstanceModel::destroyingItem, this, &QMapObjectView::destroyingItem);
+ connect(model, &QQmlInstanceModel::initItem, this, &QMapObjectView::initItem);
+}
+
+void QMapObjectView::componentComplete()
+{
+ QGeoMapObject::componentComplete();
+ if (m_delegate)
+ m_delegateModel->setDelegate(m_delegate);
+ if (m_model.isValid())
+ m_delegateModel->setModel(m_model);
+ m_delegateModel->componentComplete();
+}
+
+QVariant QMapObjectView::model() const
+{
+ return m_model;
+}
+
+QQmlComponent *QMapObjectView::delegate() const
+{
+ return m_delegate;
+}
+
+void QMapObjectView::setModel(QVariant model)
+{
+ if (m_model == model)
+ return;
+ m_model = model;
+
+ if (d_ptr->m_componentCompleted)
+ m_delegateModel->setModel(model);
+
+ emit modelChanged(model);
+}
+
+void QMapObjectView::setDelegate(QQmlComponent *delegate)
+{
+ if (m_delegate == delegate)
+ return;
+ m_delegate = delegate;
+
+ if (d_ptr->m_componentCompleted)
+ m_delegateModel->setDelegate(delegate);
+
+ emit delegateChanged(delegate);
+}
+
+/*!
+ \qmlmethod void Qt.labs.location::MapObjectView::addMapObject(MapObject object)
+
+ Adds the given \a object to the MapObjectView (for example MapIconObject, MapRouteObject), and,
+ indirectly, to the underlying map. If the object already is on the MapObjectView, it will not be added again.
+
+ \sa removeMapObject
+*/
+void QMapObjectView::addMapObject(QGeoMapObject *object)
+{
+ if (m_userAddedMapObjects.indexOf(object) < 0)
+ m_userAddedMapObjects.append(object);
+ if (map() && object->map() != map())
+ object->setMap(map());
+}
+
+/*!
+ \qmlmethod void Qt.labs.location::MapObjectView::removeMapObject(MapObject object)
+
+ Removes the given \a object from the MapObjectView (for example MapIconObject, MapRouteObject), and,
+ indirectly, from the underlying map.
+
+ \sa addMapObject
+*/
+void QMapObjectView::removeMapObject(QGeoMapObject *object)
+{
+ int idx = m_userAddedMapObjects.indexOf(object);
+ if ( idx >= 0) {
+ object->setMap(nullptr);
+ m_userAddedMapObjects.remove(idx);
+ }
+}
+
+void QMapObjectView::destroyingItem(QObject */*object*/)
+{
+
+}
+
+void QMapObjectView::initItem(int /*index*/, QObject */*object*/)
+{
+
+}
+
+void QMapObjectView::modelUpdated(const QQmlChangeSet &changeSet, bool reset)
+{
+ // 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"
+ flushDelegateModel();
+ } else {
+ // Remove map objects 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)
+ removeMapObjectFromMap(idx);
+ }
+ }
+
+ for (const QQmlChangeSet::Change &c: changeSet.inserts()) {
+ for (int idx = c.start(); idx < c.end(); idx++) {
+ m_instantiatedMapObjects.insert(idx, nullptr);
+ QGeoMapObject *mo = qobject_cast<QGeoMapObject *>(m_delegateModel->object(idx, QQmlIncubator::Asynchronous));
+ if (mo) // if not, a createdItem signal will be emitted.
+ addMapObjectToMap(mo, idx);
+ }
+ }
+}
+
+void QMapObjectView::addMapObjectToMap(QGeoMapObject *object, int index)
+{
+ if (!object)
+ return;
+
+ m_instantiatedMapObjects[index] = object;
+ if (map())
+ object->setMap(map());
+ else
+ m_pendingMapObjects << object;
+
+ // ToDo:
+ // Figure out the proper way to replace "mo->setVisible(visible());". Options:
+ // - simply leave it to the user to set up a property binding
+ // - set up a property binding automatically
+ // - add a viewVisibility member to QGeoMapObject that gets combined at all times,
+ // and a connection for it.
+}
+
+void QMapObjectView::removeMapObjectFromMap(int index)
+{
+ if (index >= 0 && index < m_instantiatedMapObjects.size()) {
+ QGeoMapObject *mo = m_instantiatedMapObjects.takeAt(index);
+ if (!mo)
+ return;
+ mo->setMap(nullptr);
+ m_delegateModel->release(mo);
+ }
+}
+
+// See QObject *QQmlDelegateModel::object(int index, QQmlIncubator::IncubationMode incubationMode) doc
+// for explanation on when createdItem is emitted.
+void QMapObjectView::createdItem(int index, QObject *object)
+{
+ // According to the documentation above, object() should be called again for index.
+ // However, this seem to result in too many references for index, which will prevent destruction with
+ // one single release()
+ // QGeoMapObject *mo = qobject_cast<QGeoMapObject *>(m_delegateModel->object(index, QQmlIncubator::Asynchronous));
+ QGeoMapObject *mo = qobject_cast<QGeoMapObject *>(object);
+ if (mo)
+ addMapObjectToMap(mo, index);
+}
+
+
+void QMapObjectView::flushDelegateModel()
+{
+ // Backward as removeItemFromMap modifies m_instantiatedItems
+ for (int i = m_instantiatedMapObjects.size() -1; i >= 0 ; i--)
+ removeMapObjectFromMap(i);
+}
+
+void QMapObjectView::flushUserAddedMapObjects()
+{
+ for (int i = 0; i < m_userAddedMapObjects.size(); ++i) {
+ auto obj = m_userAddedMapObjects.at(i);
+ if (obj)
+ obj->setMap(nullptr); // obj parent might not be this. If so, it would not be destroyed by destroying this view.
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/locationlabs/qmapobjectview_p.h b/src/locationlabs/qmapobjectview_p.h
new file mode 100644
index 00000000..5477ca72
--- /dev/null
+++ b/src/locationlabs/qmapobjectview_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 QGEOMAPLAYER_P_H
+#define QGEOMAPLAYER_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 <QtLocation/private/qgeomapobject_p.h>
+#include <QQmlComponent>
+#include <QVector>
+
+class QQmlDelegateModel;
+class QMapObjectViewPrivate;
+class QQmlChangeSet;
+class Q_LOCATION_PRIVATE_EXPORT QMapObjectView : public QGeoMapObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_INTERFACES(QQmlParserStatus)
+public:
+ QMapObjectView(QObject *parent = nullptr);
+ ~QMapObjectView() override;
+
+ // QGeoMapObject interface
+ QList<QGeoMapObject *> geoMapObjectChildren() const override;
+ void setMap(QGeoMap *map) override;
+
+ // QQmlParserStatus interface
+ void classBegin() override;
+ void componentComplete() override;
+
+ QVariant model() const;
+ void setModel(QVariant model);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent * delegate);
+
+public Q_SLOTS:
+ // The dynamic API that matches Map.add/remove MapItem
+ void addMapObject(QGeoMapObject *object);
+ void removeMapObject(QGeoMapObject *object);
+
+signals:
+ void modelChanged(QVariant model);
+ void delegateChanged(QQmlComponent * delegate);
+
+protected Q_SLOTS:
+ void destroyingItem(QObject *object);
+ void initItem(int index, QObject *object);
+ void createdItem(int index, QObject *object);
+ void modelUpdated(const QQmlChangeSet &changeSet, bool reset);
+
+protected:
+ void addMapObjectToMap(QGeoMapObject *object, int index);
+ void removeMapObjectFromMap(int index);
+ void flushDelegateModel();
+ void flushUserAddedMapObjects();
+
+ QVariant m_model;
+ QQmlComponent *m_delegate = nullptr;
+ QQmlDelegateModel *m_delegateModel = nullptr;
+ QVector<QPointer<QGeoMapObject>> m_instantiatedMapObjects;
+ QVector<QPointer<QGeoMapObject>> m_pendingMapObjects;
+ QVector<QPointer<QGeoMapObject>> m_userAddedMapObjects; // A third list containing the objects dynamically added through addMapObject
+};
+
+#endif // QGEOMAPLAYER_P_H
diff --git a/src/locationlabs/qmapobjectview_p_p.h b/src/locationlabs/qmapobjectview_p_p.h
new file mode 100644
index 00000000..af6bdf8f
--- /dev/null
+++ b/src/locationlabs/qmapobjectview_p_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 QGEOMAPLAYER_P_P_H
+#define QGEOMAPLAYER_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 <QtLocation/private/qgeomapobject_p_p.h>
+#include <QPointer>
+#include <QVector>
+#include <QQmlComponent>
+
+class QQmlDelegateModel;
+class QGeoMap;
+class Q_LOCATION_PRIVATE_EXPORT QMapObjectViewPrivate : public QGeoMapObjectPrivate
+{
+public:
+ QMapObjectViewPrivate(QGeoMapObject *q);
+ ~QMapObjectViewPrivate() override;
+
+ virtual QGeoMapObject::Type type() const override final;
+};
+
+class Q_LOCATION_PRIVATE_EXPORT QMapObjectViewPrivateDefault : public QMapObjectViewPrivate
+{
+public:
+ QMapObjectViewPrivateDefault(QGeoMapObject *q);
+ QMapObjectViewPrivateDefault(const QMapObjectViewPrivate &other);
+ ~QMapObjectViewPrivateDefault() override;
+
+
+ // QGeoMapObjectPrivate interface
+public:
+ QGeoMapObjectPrivate *clone() override;
+};
+
+#endif // QGEOMAPLAYER_P_P_H