diff options
author | Paolo Angelelli <paolo.angelelli@qt.io> | 2017-12-22 18:17:19 +0100 |
---|---|---|
committer | Paolo Angelelli <paolo.angelelli@qt.io> | 2018-07-05 06:09:56 +0000 |
commit | f8df5799b68fcb8690462b6dce226e6ce9bac282 (patch) | |
tree | c88fbdc8b4bd28662cfe3c14d665c4744fc29057 | |
parent | 5ccc595db4e9282f6a58f8712550eda935a6eecb (diff) | |
download | qtlocation-f8df5799b68fcb8690462b6dce226e6ce9bac282.tar.gz |
Enable incremental updates in PlaceSearchModel
This way pages can be changed without resetting the model.
To achieve this, new members into QPlaceSearchRequestPrivate
are introduced, to keep the relationship between a request
for one page, and the previous or the next page.
In this way sparse population of the model becomes possible.
Change-Id: Ic8db0281408f3500ba83f78c7e152ee0b68cd099
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
-rw-r--r-- | src/imports/location/location.cpp | 1 | ||||
-rw-r--r-- | src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp | 80 | ||||
-rw-r--r-- | src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h | 8 | ||||
-rw-r--r-- | src/location/places/places.pri | 1 | ||||
-rw-r--r-- | src/location/places/qplacesearchrequest.cpp | 44 | ||||
-rw-r--r-- | src/location/places/qplacesearchrequest.h | 2 | ||||
-rw-r--r-- | src/location/places/qplacesearchrequest_p.h | 79 | ||||
-rw-r--r-- | src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp | 10 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qplacemanagerengineosm.cpp | 2 | ||||
-rw-r--r-- | src/plugins/geoservices/osm/qplacesearchreplyosm.cpp | 7 |
10 files changed, 203 insertions, 31 deletions
diff --git a/src/imports/location/location.cpp b/src/imports/location/location.cpp index fc2b62c3..b632836f 100644 --- a/src/imports/location/location.cpp +++ b/src/imports/location/location.cpp @@ -189,6 +189,7 @@ public: // Register the 5.12 types minor = 12; qmlRegisterType<QDeclarativeGeoMapItemView, 12>(uri, major, minor, "MapItemView"); + qmlRegisterType<QDeclarativeSearchResultModel, 12>(uri, major, minor, "PlaceSearchModel"); // Register the latest Qt version as QML type version qmlRegisterModule(uri, QT_VERSION_MAJOR, QT_VERSION_MINOR); diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp index ed99da1c..73e43240 100644 --- a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp @@ -47,6 +47,7 @@ #include <QtLocation/QPlaceMatchReply> #include <QtLocation/QPlaceResult> #include <QtLocation/QPlaceProposedSearchResult> +#include <QtLocation/private/qplacesearchrequest_p.h> QT_BEGIN_NAMESPACE @@ -260,6 +261,18 @@ QT_BEGIN_NAMESPACE */ /*! + \qmlproperty bool PlaceSearchModel::incremental + + This property controls how paging will affect the PlaceSearchModel. + If true, calling \l previousPage or \l nextPage will not reset the model, + but new results will instead be appended to the model. + Default is false. + + \since QtLocation 5.12 +*/ + + +/*! \qmlmethod void PlaceSearchModel::update() Updates the model based on the provided query parameters. The model will be populated with a @@ -733,6 +746,9 @@ void QDeclarativeSearchResultModel::queryFinished() return; QPlaceReply *reply = m_reply; m_reply = 0; + if (!m_incremental) + m_pages.clear(); + if (reply->error() != QPlaceReply::NoError) { m_resultsBuffer.clear(); updateLayout(); @@ -745,7 +761,14 @@ void QDeclarativeSearchResultModel::queryFinished() QPlaceSearchReply *searchReply = qobject_cast<QPlaceSearchReply *>(reply); Q_ASSERT(searchReply); + const QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(searchReply->request()); + if (!rpimpl->related || !m_incremental) + m_pages.clear(); m_resultsBuffer = searchReply->results(); + bool alreadyLoaded = false; + if (m_pages.contains(rpimpl->page) && m_resultsBuffer == m_pages.value(rpimpl->page)) + alreadyLoaded = true; + m_pages.insert(rpimpl->page, m_resultsBuffer); setPreviousPageRequest(searchReply->previousPageRequest()); setNextPageRequest(searchReply->nextPageRequest()); @@ -785,6 +808,8 @@ void QDeclarativeSearchResultModel::queryFinished() } request.setResults(m_resultsBuffer); + if (alreadyLoaded) + m_resultsBuffer.clear(); m_reply = favoritesManager->matchingPlaces(request); connect(m_reply, SIGNAL(finished()), this, SLOT(queryFinished())); } @@ -823,14 +848,24 @@ void QDeclarativeSearchResultModel::queryFinished() */ void QDeclarativeSearchResultModel::updateLayout(const QList<QPlace> &favoritePlaces) { - int oldRowCount = rowCount(); + const int oldRowCount = rowCount(); + int start = 0; - beginResetModel(); - clearData(true); - m_results = m_resultsBuffer; - m_resultsBuffer.clear(); + if (m_incremental) { + if (!m_resultsBuffer.size()) + return; + + beginInsertRows(QModelIndex(), oldRowCount , oldRowCount + m_resultsBuffer.size() - 1); + m_results = resultsFromPages(); + start = oldRowCount; + } else { + beginResetModel(); + clearData(true); + m_results = m_resultsBuffer; + } - for (int i = 0; i < m_results.count(); ++i) { + m_resultsBuffer.clear(); + for (int i = start; i < m_results.count(); ++i) { const QPlaceSearchResult &result = m_results.at(i); if (result.type() == QPlaceSearchResult::PlaceResult) { @@ -851,7 +886,10 @@ void QDeclarativeSearchResultModel::updateLayout(const QList<QPlace> &favoritePl m_icons.append(icon); } - endResetModel(); + if (m_incremental) + endInsertRows(); + else + endResetModel(); if (m_results.count() != oldRowCount) emit rowCountChanged(); } @@ -882,11 +920,39 @@ void QDeclarativeSearchResultModel::placeRemoved(const QString &placeId) delete m_places.at(row); m_places.removeAt(row); m_results.removeAt(row); + removePageRow(row); endRemoveRows(); emit rowCountChanged(); } +QList<QPlaceSearchResult> QDeclarativeSearchResultModel::resultsFromPages() const +{ + QList<QPlaceSearchResult> res; + QMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); + while (i.hasNext()) { + i.next(); + res.append(i.value()); + } + return res; +} + +void QDeclarativeSearchResultModel::removePageRow(int row) +{ + QMapIterator<int, QList<QPlaceSearchResult>> i(m_pages); + int scanned = 0; + while (i.hasNext()) { + i.next(); + QList<QPlaceSearchResult> page = i.value(); + scanned += page.size(); + if (row >= scanned) + continue; + page.removeAt(row - scanned + page.size()); + m_pages.insert(i.key(), page); + return; + } +} + /*! \internal */ diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h index 77526fd0..037b91ad 100644 --- a/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h @@ -72,6 +72,8 @@ class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchResultModel : public QDeclarat Q_PROPERTY(QDeclarativeGeoServiceProvider *favoritesPlugin READ favoritesPlugin WRITE setFavoritesPlugin NOTIFY favoritesPluginChanged) Q_PROPERTY(QVariantMap favoritesMatchParameters READ favoritesMatchParameters WRITE setFavoritesMatchParameters NOTIFY favoritesMatchParametersChanged) + Q_PROPERTY(bool incremental MEMBER m_incremental NOTIFY incrementalChanged REVISION 12) + Q_ENUMS(SearchResultType RelevanceHint) public: @@ -137,6 +139,7 @@ Q_SIGNALS: void favoritesPluginChanged(); void favoritesMatchParametersChanged(); void dataChanged(); + void incrementalChanged(); protected: QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request); @@ -162,9 +165,13 @@ private: }; int getRow(const QString &placeId) const; + QList<QPlaceSearchResult> resultsFromPages() const; + void removePageRow(int row); + QList<QDeclarativeCategory *> m_categories; QLocation::VisibilityScope m_visibilityScope; + QMap<int, QList<QPlaceSearchResult>> m_pages; QList<QPlaceSearchResult> m_results; QList<QPlaceSearchResult> m_resultsBuffer; QList<QDeclarativePlace *> m_places; @@ -172,6 +179,7 @@ private: QDeclarativeGeoServiceProvider *m_favoritesPlugin; QVariantMap m_matchParameters; + bool m_incremental = false; }; QT_END_NAMESPACE diff --git a/src/location/places/places.pri b/src/location/places/places.pri index 1a3796fc..5a766b61 100644 --- a/src/location/places/places.pri +++ b/src/location/places/places.pri @@ -24,6 +24,7 @@ PUBLIC_HEADERS += \ places/qplacecontentrequest.h \ places/qplacematchrequest.h \ places/qplacesearchrequest.h \ + places/qplacesearchrequest_p.h \ #reply classes places/qplacereply.h \ places/qplacedetailsreply.h \ diff --git a/src/location/places/qplacesearchrequest.cpp b/src/location/places/qplacesearchrequest.cpp index c2d993e3..49e782c5 100644 --- a/src/location/places/qplacesearchrequest.cpp +++ b/src/location/places/qplacesearchrequest.cpp @@ -35,37 +35,17 @@ ****************************************************************************/ #include "qplacesearchrequest.h" +#include "qplacesearchrequest_p.h" #include "qgeocoordinate.h" #include "qgeoshape.h" #include <QtCore/QSharedData> #include <QtCore/QList> #include <QtCore/QVariant> +#include <QDebug> QT_BEGIN_NAMESPACE -class QPlaceSearchRequestPrivate : public QSharedData -{ -public: - QPlaceSearchRequestPrivate(); - QPlaceSearchRequestPrivate(const QPlaceSearchRequestPrivate &other); - ~QPlaceSearchRequestPrivate(); - - QPlaceSearchRequestPrivate &operator=(const QPlaceSearchRequestPrivate &other); - bool operator==(const QPlaceSearchRequestPrivate &other) const; - - void clear(); - - QString searchTerm; - QList<QPlaceCategory> categories; - QGeoShape searchArea; - QString recommendationId; - QLocation::VisibilityScope visibilityScope; - QPlaceSearchRequest::RelevanceHint relevanceHint; - int limit; - QVariant searchContext; -}; - QPlaceSearchRequestPrivate::QPlaceSearchRequestPrivate() : QSharedData(), visibilityScope(QLocation::UnspecifiedVisibility), @@ -83,7 +63,9 @@ QPlaceSearchRequestPrivate::QPlaceSearchRequestPrivate(const QPlaceSearchRequest visibilityScope(other.visibilityScope), relevanceHint(other.relevanceHint), limit(other.limit), - searchContext(other.searchContext) + searchContext(other.searchContext), + related(other.related), + page(other.page) { } @@ -102,6 +84,8 @@ QPlaceSearchRequestPrivate &QPlaceSearchRequestPrivate::operator=(const QPlaceSe relevanceHint = other.relevanceHint; limit = other.limit; searchContext = other.searchContext; + related = other.related; + page = other.page; } return *this; @@ -117,6 +101,8 @@ bool QPlaceSearchRequestPrivate::operator==(const QPlaceSearchRequestPrivate &ot relevanceHint == other.relevanceHint && limit == other.limit && searchContext == other.searchContext; + + // deliberately not testing related and page. comparing only the content. } void QPlaceSearchRequestPrivate::clear() @@ -129,6 +115,18 @@ void QPlaceSearchRequestPrivate::clear() visibilityScope = QLocation::UnspecifiedVisibility; relevanceHint = QPlaceSearchRequest::UnspecifiedHint; searchContext.clear(); + related = false; + page = 0; +} + +const QPlaceSearchRequestPrivate *QPlaceSearchRequestPrivate::get(const QPlaceSearchRequest &request) +{ + return request.d_ptr.constData(); +} + +QPlaceSearchRequestPrivate *QPlaceSearchRequestPrivate::get(QPlaceSearchRequest &request) +{ + return request.d_ptr.data(); } /*! diff --git a/src/location/places/qplacesearchrequest.h b/src/location/places/qplacesearchrequest.h index 09654503..d6611017 100644 --- a/src/location/places/qplacesearchrequest.h +++ b/src/location/places/qplacesearchrequest.h @@ -98,6 +98,8 @@ private: QSharedDataPointer<QPlaceSearchRequestPrivate> d_ptr; inline QPlaceSearchRequestPrivate *d_func(); inline const QPlaceSearchRequestPrivate *d_func() const; + + friend class QPlaceSearchRequestPrivate; }; QT_END_NAMESPACE diff --git a/src/location/places/qplacesearchrequest_p.h b/src/location/places/qplacesearchrequest_p.h new file mode 100644 index 00000000..98a747b0 --- /dev/null +++ b/src/location/places/qplacesearchrequest_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 QPLACESEARCHREQUEST_P_H +#define QPLACESEARCHREQUEST_P_H + +#include "qplacesearchrequest.h" +#include "qgeocoordinate.h" +#include "qgeoshape.h" + +#include <QtCore/QSharedData> +#include <QtCore/QList> +#include <QtLocation/private/qlocationglobal_p.h> +#include <QtCore/QVariant> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QPlaceSearchRequestPrivate : public QSharedData +{ +public: + QPlaceSearchRequestPrivate(); + QPlaceSearchRequestPrivate(const QPlaceSearchRequestPrivate &other); + ~QPlaceSearchRequestPrivate(); + + QPlaceSearchRequestPrivate &operator=(const QPlaceSearchRequestPrivate &other); + bool operator==(const QPlaceSearchRequestPrivate &other) const; + + void clear(); + static const QPlaceSearchRequestPrivate *get(const QPlaceSearchRequest &request); + static QPlaceSearchRequestPrivate *get(QPlaceSearchRequest &request); + + QString searchTerm; + QList<QPlaceCategory> categories; + QGeoShape searchArea; + QString recommendationId; + QLocation::VisibilityScope visibilityScope; + QPlaceSearchRequest::RelevanceHint relevanceHint; + int limit; + QVariant searchContext; + bool related = false; + int page = 0; +}; + +QT_END_NAMESPACE + +#endif // QPLACESEARCHREQUEST_P_H diff --git a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp index 9808b539..28aa930f 100644 --- a/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp +++ b/src/plugins/geoservices/nokia/placesv2/qplacesearchreplyhere.cpp @@ -46,6 +46,7 @@ #include <QtLocation/QPlaceIcon> #include <QtLocation/QPlaceResult> #include <QtLocation/QPlaceProposedSearchResult> +#include <QtLocation/private/qplacesearchrequest_p.h> #include <QtCore/QDebug> @@ -113,15 +114,24 @@ void QPlaceSearchReplyHere::replyFinished() results.append(parseSearchResult(item)); } + QPlaceSearchRequest r_orig = request(); + QPlaceSearchRequestPrivate *rpimpl_orig = QPlaceSearchRequestPrivate::get(r_orig); + if (resultsObject.contains(QStringLiteral("next"))) { QPlaceSearchRequest request; request.setSearchContext(QUrl(resultsObject.value(QStringLiteral("next")).toString())); + QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(request); + rpimpl->related = true; + rpimpl->page = rpimpl_orig->page + 1; setNextPageRequest(request); } if (resultsObject.contains(QStringLiteral("previous"))) { QPlaceSearchRequest request; request.setSearchContext(QUrl(resultsObject.value(QStringLiteral("previous")).toString())); + QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(request); + rpimpl->related = true; + rpimpl->page = rpimpl_orig->page - 1; setPreviousPageRequest(request); } diff --git a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp index 3c201e41..be66414f 100644 --- a/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qplacemanagerengineosm.cpp @@ -191,7 +191,7 @@ QPlaceSearchReply *QPlaceManagerEngineOsm::search(const QPlaceSearchRequest &req this, SLOT(replyError(QPlaceReply::Error,QString))); if (m_debugQuery) - reply->requestUrl = requestUrl.toString(); + reply->requestUrl = requestUrl.url(QUrl::None); return reply; } diff --git a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp index 0228a975..80c50d1b 100644 --- a/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp +++ b/src/plugins/geoservices/osm/qplacesearchreplyosm.cpp @@ -48,6 +48,7 @@ #include <QtPositioning/QGeoRectangle> #include <QtLocation/QPlaceResult> #include <QtLocation/QPlaceSearchRequest> +#include <QtLocation/private/qplacesearchrequest_p.h> QT_BEGIN_NAMESPACE @@ -135,6 +136,9 @@ void QPlaceSearchReplyOsm::replyFinished() parameters.insert(QStringLiteral("ExcludePlaceIds"), epi); r.setSearchContext(parameters); + QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(r); + rpimpl->related = true; + rpimpl->page--; setPreviousPageRequest(r); } @@ -147,6 +151,9 @@ void QPlaceSearchReplyOsm::replyFinished() parameters.insert(QStringLiteral("ExcludePlaceIds"), epi); r.setSearchContext(parameters); + QPlaceSearchRequestPrivate *rpimpl = QPlaceSearchRequestPrivate::get(r); + rpimpl->related = true; + rpimpl->page++; setNextPageRequest(r); } |