diff options
Diffstat (limited to 'src/location/declarativeplaces')
34 files changed, 8246 insertions, 0 deletions
diff --git a/src/location/declarativeplaces/declarativeplaces.pri b/src/location/declarativeplaces/declarativeplaces.pri new file mode 100644 index 00000000..82f60c23 --- /dev/null +++ b/src/location/declarativeplaces/declarativeplaces.pri @@ -0,0 +1,51 @@ +INCLUDEPATH += declarativeplaces + +SOURCES += \ +#models + declarativeplaces/qdeclarativeplacecontentmodel.cpp \ + declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp \ + declarativeplaces/qdeclarativesearchsuggestionmodel.cpp \ + declarativeplaces/qdeclarativesearchresultmodel.cpp \ + declarativeplaces/qdeclarativereviewmodel.cpp \ + declarativeplaces/qdeclarativeplaceimagemodel.cpp \ + declarativeplaces/qdeclarativeplaceeditorialmodel.cpp \ +#data + declarativeplaces/qdeclarativecontactdetail.cpp \ + declarativeplaces/qdeclarativecategory.cpp \ + declarativeplaces/qdeclarativeplace.cpp \ + declarativeplaces/qdeclarativeplaceattribute.cpp \ + declarativeplaces/qdeclarativeplaceicon.cpp \ + declarativeplaces/qdeclarativeplaceuser.cpp \ + declarativeplaces/qdeclarativeratings.cpp \ + declarativeplaces/qdeclarativesupplier.cpp \ + declarativeplaces/qdeclarativesearchmodelbase.cpp + +PRIVATE_HEADERS += \ +#models + declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h \ + declarativeplaces/qdeclarativesearchsuggestionmodel_p.h \ + declarativeplaces/qdeclarativesearchresultmodel_p.h \ + declarativeplaces/qdeclarativereviewmodel_p.h \ + declarativeplaces/qdeclarativeplaceimagemodel_p.h \ +#data + declarativeplaces/qdeclarativecontactdetail_p.h \ + declarativeplaces/qdeclarativecategory_p.h \ + declarativeplaces/qdeclarativeplace_p.h \ + declarativeplaces/qdeclarativeplaceattribute_p.h \ + declarativeplaces/qdeclarativeplaceicon_p.h \ + declarativeplaces/qdeclarativeplaceuser_p.h \ + declarativeplaces/qdeclarativeratings_p.h \ + declarativeplaces/qdeclarativesupplier_p.h \ + declarativeplaces/qdeclarativesearchmodelbase_p.h \ + declarativeplaces/qdeclarativeplacecontentmodel_p.h \ + declarativeplaces/qdeclarativeplaceeditorialmodel_p.h + + + + + + + + + + diff --git a/src/location/declarativeplaces/qdeclarativecategory.cpp b/src/location/declarativeplaces/qdeclarativecategory.cpp new file mode 100644 index 00000000..c58ec3a2 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativecategory.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** 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 "qdeclarativecategory_p.h" +#include "qdeclarativeplaceicon_p.h" +#include "qdeclarativegeoserviceprovider_p.h" +#include "error_messages.h" + +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceManager> +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Category + \instantiates QDeclarativeCategory + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + + \since Qt Location 5.5 + + \brief The Category type represents a category that a \l Place can be associated with. + + Categories are used to search for places based on the categories they are associated with. The + list of available categories can be obtained from the \l CategoryModel. The + \l PlaceSearchModel has a \l {PlaceSearchModel::categories}{categories} property that is used + to limit the search results to places with the specified categories. + + If the \l Plugin supports it, categories can be created or removed. To create a new category + construct a new Category object and set its properties, then invoke the \l save() method. + + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml Category + \dots 0 + \snippet declarative/places.qml Category save + + To remove a category ensure that the \l plugin and categoryId properties are set and call the + \l remove() method. + + \sa CategoryModel +*/ + +QDeclarativeCategory::QDeclarativeCategory(QObject *parent) +: QObject(parent), m_icon(0), m_plugin(0), m_reply(0), m_complete(false), m_status(Ready) +{ +} + +QDeclarativeCategory::QDeclarativeCategory(const QPlaceCategory &category, + QDeclarativeGeoServiceProvider *plugin, + QObject *parent) +: QObject(parent), m_category(category), m_icon(0), m_plugin(plugin), m_reply(0), + m_complete(false), m_status(Ready) +{ + setCategory(category); +} + +QDeclarativeCategory::~QDeclarativeCategory() {} + +// From QQmlParserStatus +void QDeclarativeCategory::componentComplete() +{ + // delayed instantiation of QObject based properties. + if (!m_icon) { + m_icon = new QDeclarativePlaceIcon(this); + m_icon->setPlugin(m_plugin); + } + + m_complete = true; +} + +/*! + \qmlproperty Plugin Category::plugin + + This property holds the location based service to which the category belongs. +*/ +void QDeclarativeCategory::setPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_plugin == plugin) + return; + + m_plugin = plugin; + if (m_complete) + emit pluginChanged(); + + if (m_icon && m_icon->parent() == this && !m_icon->plugin()) + m_icon->setPlugin(m_plugin); + + if (!m_plugin) + return; + + if (m_plugin->isAttached()) { + pluginReady(); + } else { + connect(m_plugin, SIGNAL(attached()), + this, SLOT(pluginReady())); + } +} + +QDeclarativeGeoServiceProvider *QDeclarativeCategory::plugin() const +{ + return m_plugin; +} + +/*! + \internal +*/ +void QDeclarativeCategory::pluginReady() +{ + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return; + } +} + + +/*! + \qmlproperty QPlaceCategory Category::category + \keyword Category::category + + For details on how to use this property to interface between C++ and QML see + "\l {Category - QPlaceCategory} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativeCategory::setCategory(const QPlaceCategory &category) +{ + QPlaceCategory previous = m_category; + m_category = category; + + if (category.name() != previous.name()) + emit nameChanged(); + + if (category.categoryId() != previous.categoryId()) + emit categoryIdChanged(); + + if (m_icon && m_icon->parent() == this) { + m_icon->setPlugin(m_plugin); + m_icon->setIcon(m_category.icon()); + } else if (!m_icon || m_icon->parent() != this) { + m_icon = new QDeclarativePlaceIcon(m_category.icon(), m_plugin, this); + emit iconChanged(); + } +} + +QPlaceCategory QDeclarativeCategory::category() +{ + m_category.setIcon(m_icon ? m_icon->icon() : QPlaceIcon()); + return m_category; +} + +/*! + \qmlproperty string Category::categoryId + + This property holds the identifier of the category. The categoryId is a string which uniquely + identifies this category within the categories \l plugin. +*/ +void QDeclarativeCategory::setCategoryId(const QString &id) +{ + if (m_category.categoryId() != id) { + m_category.setCategoryId(id); + emit categoryIdChanged(); + } +} + +QString QDeclarativeCategory::categoryId() const +{ + return m_category.categoryId(); +} + +/*! + \qmlproperty string Category::name + + This property holds string based name of the category. +*/ +void QDeclarativeCategory::setName(const QString &name) +{ + if (m_category.name() != name) { + m_category.setName(name); + emit nameChanged(); + } +} + +QString QDeclarativeCategory::name() const +{ + return m_category.name(); +} + +/*! + \qmlproperty enumeration Category::visibility + + This property holds the visibility of the category. It can be one of: + + \table + \row + \li Category.UnspecifiedVisibility + \li The visibility of the category is unspecified. If saving a category, the + plugin will automatically set a default visibility to the category saved in the backend. + This default is dependent on the plugin implementation. + \row + \li Category.DeviceVisibility + \li The category is limited to the current device. The category will not be transferred + off of the device. + \row + \li Category.PrivateVisibility + \li The category is private to the current user. The category may be transferred to an + online service but is only ever visible to the current user. + \row + \li Category.PublicVisibility + \li The category is public. + \endtable + + Note that visibility does not affect how \l{Place}s associated with + the category are displayed in the user-interface of an application + on the device. Instead, it defines the sharing semantics of the + category. +*/ +QDeclarativeCategory::Visibility QDeclarativeCategory::visibility() const +{ + return static_cast<QDeclarativeCategory::Visibility>(m_category.visibility()); +} + +void QDeclarativeCategory::setVisibility(Visibility visibility) +{ + if (static_cast<QDeclarativeCategory::Visibility>(m_category.visibility()) == visibility) + return; + + m_category.setVisibility(static_cast<QLocation::Visibility>(visibility)); + emit visibilityChanged(); +} + +/*! + \qmlproperty PlaceIcon Category::icon + + This property holds the image source associated with the category. To display the icon you can use + the \l Image type. +*/ +QDeclarativePlaceIcon *QDeclarativeCategory::icon() const +{ + return m_icon; +} + +void QDeclarativeCategory::setIcon(QDeclarativePlaceIcon *icon) +{ + if (m_icon == icon) + return; + + if (m_icon && m_icon->parent() == this) + delete m_icon; + + m_icon = icon; + emit iconChanged(); +} + +/*! + \qmlmethod string Category::errorString() + + Returns a string description of the error of the last operation. + If the last operation completed successfully then the string is empty. +*/ +QString QDeclarativeCategory::errorString() const +{ + return m_errorString; +} + +void QDeclarativeCategory::setStatus(Status status, const QString &errorString) +{ + Status originalStatus = m_status; + m_status = status; + m_errorString = errorString; + + if (originalStatus != m_status) + emit statusChanged(); +} + +/*! + \qmlproperty enumeration Category::status + + This property holds the status of the category. It can be one of: + + \table + \row + \li Category.Ready + \li No error occurred during the last operation, further operations may be performed on + the category. + \row + \li Category.Saving + \li The category is currently being saved, no other operations may be performed until the + current operation completes. + \row + \li Category.Removing + \li The category is currently being removed, no other operations can be performed until + the current operation completes. + \row + \li Category.Error + \li An error occurred during the last operation, further operations can still be + performed on the category. + \endtable +*/ +QDeclarativeCategory::Status QDeclarativeCategory::status() const +{ + return m_status; +} + +/*! + \qmlmethod void Category::save() + + This method saves the category to the backend service. +*/ +void QDeclarativeCategory::save(const QString &parentId) +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + m_reply = placeManager->saveCategory(category(), parentId); + connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished())); + setStatus(QDeclarativeCategory::Saving); +} + +/*! + \qmlmethod void Category::remove() + + This method permanently removes the category from the backend service. +*/ +void QDeclarativeCategory::remove() +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + m_reply = placeManager->removeCategory(m_category.categoryId()); + connect(m_reply, SIGNAL(finished()), this, SLOT(replyFinished())); + setStatus(QDeclarativeCategory::Removing); +} + +/*! + \internal +*/ +void QDeclarativeCategory::replyFinished() +{ + if (!m_reply) + return; + + if (m_reply->error() == QPlaceReply::NoError) { + switch (m_reply->type()) { + case (QPlaceReply::IdReply) : { + QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(m_reply); + + switch (idReply->operationType()) { + case QPlaceIdReply::SaveCategory: + setCategoryId(idReply->id()); + break; + case QPlaceIdReply::RemoveCategory: + setCategoryId(QString()); + break; + default: + //Other operation types shouldn't ever be received. + break; + } + break; + } + default: + //other types of replies shouldn't ever be received. + break; + } + + m_errorString.clear(); + + m_reply->deleteLater(); + m_reply = 0; + + setStatus(QDeclarativeCategory::Ready); + } else { + QString errorString = m_reply->errorString(); + + m_reply->deleteLater(); + m_reply = 0; + + setStatus(QDeclarativeCategory::Error, errorString); + } +} + +/*! + \internal + Helper function to return the manager, this manager is intended to be used to perform the next + operation. Sets status to Error and an appropriate m_errorString if the manager cannot be + obtained. +*/ +QPlaceManager *QDeclarativeCategory::manager() +{ + if (m_status != QDeclarativeCategory::Ready && m_status != QDeclarativeCategory::Error) + return 0; + + if (m_reply) { + m_reply->abort(); + m_reply->deleteLater(); + m_reply = 0; + } + + if (!m_plugin) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET)); + return 0; + } + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_NOT_VALID)); + return 0; + } + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return 0; + } + + return placeManager; +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativecategory_p.h b/src/location/declarativeplaces/qdeclarativecategory_p.h new file mode 100644 index 00000000..c32072f4 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativecategory_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECATEGORY_P_H +#define QDECLARATIVECATEGORY_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/qlocationglobal_p.h> +#include <QtQml/qqml.h> +#include <QtQml/QQmlParserStatus> +#include <QObject> + +#include <QtLocation/qplacecategory.h> + +#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativePlaceIcon; +class QPlaceReply; +class QPlaceManager; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeCategory : public QObject, public QQmlParserStatus +{ + Q_OBJECT + + Q_ENUMS(Status Visibility) + + + Q_PROPERTY(QPlaceCategory category READ category WRITE setCategory) + Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) + Q_PROPERTY(QString categoryId READ categoryId WRITE setCategoryId NOTIFY categoryIdChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged) + Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + + Q_INTERFACES(QQmlParserStatus) + +public: + explicit QDeclarativeCategory(QObject *parent = 0); + QDeclarativeCategory(const QPlaceCategory &category, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0); + ~QDeclarativeCategory(); + + enum Visibility { + UnspecifiedVisibility = QLocation::UnspecifiedVisibility, + DeviceVisibility = QLocation::DeviceVisibility, + PrivateVisibility = QLocation::PrivateVisibility, + PublicVisibility = QLocation::PublicVisibility + }; + enum Status {Ready, Saving, Removing, Error}; + + //From QQmlParserStatus + virtual void classBegin() {} + virtual void componentComplete(); + + void setPlugin(QDeclarativeGeoServiceProvider *plugin); + QDeclarativeGeoServiceProvider *plugin() const; + + QPlaceCategory category(); + void setCategory(const QPlaceCategory &category); + + QString categoryId() const; + void setCategoryId(const QString &catID); + QString name() const; + void setName(const QString &name); + + Visibility visibility() const; + void setVisibility(Visibility visibility); + + QDeclarativePlaceIcon *icon() const; + void setIcon(QDeclarativePlaceIcon *icon); + + Q_INVOKABLE QString errorString() const; + + Status status() const; + void setStatus(Status status, const QString &errorString = QString()); + + Q_INVOKABLE void save(const QString &parentId = QString()); + Q_INVOKABLE void remove(); + +Q_SIGNALS: + void pluginChanged(); + void categoryIdChanged(); + void nameChanged(); + void visibilityChanged(); + void iconChanged(); + void statusChanged(); + +private Q_SLOTS: + void replyFinished(); + void pluginReady(); + +private: + QPlaceManager *manager(); + + QPlaceCategory m_category; + QDeclarativePlaceIcon *m_icon; + QDeclarativeGeoServiceProvider *m_plugin; + QPlaceReply *m_reply; + bool m_complete; + Status m_status; + QString m_errorString; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeCategory) + +#endif // QDECLARATIVECATEGORY_P_H diff --git a/src/location/declarativeplaces/qdeclarativecontactdetail.cpp b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp new file mode 100644 index 00000000..7a7a4c33 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativecontactdetail.cpp @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** 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 "qdeclarativecontactdetail_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ContactDetails + \instantiates QDeclarativeContactDetails + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The ContactDetails type holds contact details for a \l Place. + + The ContactDetails type is a map of \l {QtLocation::ContactDetail}{ContactDetail} objects. + To access contact details in the map use the \l keys() method to get the list of keys stored in + the map and then use the \c {[]} operator to access the + \l {QtLocation::ContactDetail}{ContactDetail} items. + + The following keys are defined in the API. \l Plugin implementations are free to define + additional keys. + + \list + \li phone + \li fax + \li email + \li website + \endlist + + ContactDetails instances are only ever used in the context of \l {Place}{Places}. It is not possible + to create a ContactDetails instance directly or re-assign ContactDetails instances to \l {Place}{Places}. + Modification of ContactDetails can only be accomplished via Javascript. + + \section1 Examples + + The following example shows how to access all \l {QtLocation::ContactDetail}{ContactDetails} + and print them to the console: + + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml ContactDetails read + + The returned list of contact details is an \l {QObjectList-based model}{object list} and so can be used directly as a data model. For example, the + following demonstrates how to display a list of contact phone numbers in a list view: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml ContactDetails phoneList + + The following example demonstrates how to assign a single phone number to a place in JavaScript: + \snippet declarative/places.qml ContactDetails write single + + The following demonstrates how to assign multiple phone numbers to a place in JavaScript: + \snippet declarative/places.qml ContactDetails write multiple +*/ + +/*! + \qmlmethod variant ContactDetails::keys() + + Returns an array of contact detail keys currently stored in the map. +*/ +QDeclarativeContactDetails::QDeclarativeContactDetails(QObject *parent) + : QQmlPropertyMap(parent) +{ +} + +QVariant QDeclarativeContactDetails::updateValue(const QString &, const QVariant &input) +{ + if (input.userType() == QMetaType::QObjectStar) { + QDeclarativeContactDetail *detail = + qobject_cast<QDeclarativeContactDetail *>(input.value<QObject *>()); + if (detail) { + QVariantList varList; + varList.append(input); + return varList; + } + } + + return input; +} + +/*! + \qmltype ContactDetail + \instantiates QDeclarativeContactDetail + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The ContactDetail type holds a contact detail such as a phone number or a website + address. + + The ContactDetail provides a single detail on how one could contact a \l Place. The + ContactDetail consists of a \l label, which is a localized string describing the contact + method, and a \l value representing the actual contact detail. + + \section1 Examples + + The following example demonstrates how to assign a single phone number to a place in JavaScript: + \snippet declarative/places.qml ContactDetails write single + + The following demonstrates how to assign multiple phone numbers to a place in JavaScript: + \snippet declarative/places.qml ContactDetails write multiple + + Note, due to limitations of the QQmlPropertyMap, it is not possible + to declaratively specify the contact details in QML, it can only be accomplished + via JavaScript. +*/ +QDeclarativeContactDetail::QDeclarativeContactDetail(QObject *parent) + : QObject(parent) +{ +} + +QDeclarativeContactDetail::QDeclarativeContactDetail(const QPlaceContactDetail &src, QObject *parent) + : QObject(parent), m_contactDetail(src) +{ +} + +QDeclarativeContactDetail::~QDeclarativeContactDetail() +{ +} + +/*! + \qmlproperty QPlaceContactDetail QtLocation::ContactDetail::contactDetail + + For details on how to use this property to interface between C++ and QML see + "\l {ContactDetail - QDeclarativeContactDetail} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativeContactDetail::setContactDetail(const QPlaceContactDetail &src) +{ + QPlaceContactDetail prevContactDetail = m_contactDetail; + m_contactDetail = src; + + if (m_contactDetail.label() != prevContactDetail.label()) + emit labelChanged(); + if (m_contactDetail.value() != prevContactDetail.value()) + emit valueChanged(); +} + +QPlaceContactDetail QDeclarativeContactDetail::contactDetail() const +{ + return m_contactDetail; +} + +/*! + \qmlproperty string QtLocation::ContactDetail::label + + This property holds a label describing the contact detail. + + The label can potentially be localized. The language is dependent on the entity that sets it, + typically this is the \l {Plugin}. The \l {Plugin::locales} property defines + what language is used. +*/ +QString QDeclarativeContactDetail::label() const +{ + return m_contactDetail.label(); +} + +void QDeclarativeContactDetail::setLabel(const QString &label) +{ + if (m_contactDetail.label() != label) { + m_contactDetail.setLabel(label); + emit labelChanged(); + } +} + +/*! + \qmlproperty string QtLocation::ContactDetail::value + + This property holds the value of the contact detail which may be a phone number, an email + address, a website url and so on. +*/ +QString QDeclarativeContactDetail::value() const +{ + return m_contactDetail.value(); +} + +void QDeclarativeContactDetail::setValue(const QString &value) +{ + if (m_contactDetail.value() != value) { + m_contactDetail.setValue(value); + emit valueChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativecontactdetail_p.h b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h new file mode 100644 index 00000000..ad60c3b5 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativecontactdetail_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVECONTACTDETAIL_P_H +#define QDECLARATIVECONTACTDETAIL_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/qlocationglobal_p.h> +#include <QtCore/QObject> +#include <QtLocation/QPlaceContactDetail> +#include <QtQml/QQmlPropertyMap> +#include <QtQml/qqml.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetails : public QQmlPropertyMap +{ + Q_OBJECT + +public: + explicit QDeclarativeContactDetails(QObject *parent = 0); + virtual QVariant updateValue(const QString &key, const QVariant &input); +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeContactDetail : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPlaceContactDetail contactDetail READ contactDetail WRITE setContactDetail) + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged) + +public: + explicit QDeclarativeContactDetail(QObject *parent = 0); + explicit QDeclarativeContactDetail(const QPlaceContactDetail &src, QObject *parent = 0); + ~QDeclarativeContactDetail(); + + QPlaceContactDetail contactDetail() const; + void setContactDetail(const QPlaceContactDetail &contactDetail); + + QString label() const; + void setLabel(const QString &label); + + QString value() const; + void setValue(const QString &value); + +Q_SIGNALS: + void labelChanged(); + void valueChanged(); + +private: + QPlaceContactDetail m_contactDetail; + +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeContactDetail) +QML_DECLARE_TYPE(QDeclarativeContactDetails) + +#endif diff --git a/src/location/declarativeplaces/qdeclarativeperiod_p.h b/src/location/declarativeplaces/qdeclarativeperiod_p.h new file mode 100644 index 00000000..3ded0109 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeperiod_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPERIOD_P_H +#define QDECLARATIVEPERIOD_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 <qplaceperiod.h> +#include <QtQml/qqml.h> + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class QDeclarativePeriod : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QDate startDate READ startDate WRITE setStartDate NOTIFY startDateChanged) + Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged) + Q_PROPERTY(QDate endDate READ endDate WRITE setEndDate NOTIFY endDateChanged) + Q_PROPERTY(QTime endTime READ endTime WRITE setEndTime NOTIFY endTimeChanged) + +public: + explicit QDeclarativePeriod(QObject *parent = 0); + explicit QDeclarativePeriod(const QPlacePeriod &period, QObject *parent = 0); + ~QDeclarativePeriod(); + + QPlacePeriod period() const; + void setPeriod(const QPlacePeriod &period); + + QDate startDate() const; + void setStartDate(const QDate &data); + QTime startTime() const; + void setStartTime(const QTime &data); + QDate endDate() const; + void setEndDate(const QDate &data); + QTime endTime() const; + void setEndTime(const QTime &data); + +Q_SIGNALS: + void startDateChanged(); + void startTimeChanged(); + void endDateChanged(); + void endTimeChanged(); + +private: + QPlacePeriod m_period; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QT_PREPEND_NAMESPACE(QDeclarativePeriod)); + +#endif // QDECLARATIVEPERIOD_P_H diff --git a/src/location/declarativeplaces/qdeclarativeplace.cpp b/src/location/declarativeplaces/qdeclarativeplace.cpp new file mode 100644 index 00000000..91ef2026 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplace.cpp @@ -0,0 +1,1229 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplace_p.h" +#include "qdeclarativecontactdetail_p.h" +#include "qdeclarativegeoserviceprovider_p.h" +#include "qdeclarativeplaceattribute_p.h" +#include "qdeclarativeplaceicon_p.h" +#include "error_messages.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QMetaObject> +#include <QtQml/QQmlEngine> +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceManager> +#include <QtLocation/QPlaceDetailsReply> +#include <QtLocation/QPlaceReply> +#include <QtLocation/QPlaceIdReply> +#include <QtLocation/QPlaceContactDetail> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Place + \instantiates QDeclarativePlace + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The Place type represents a location that is a position of interest. + + The Place type represents a physical location with additional metadata describing that + location. Contrasted with \l Location, \l Address, and + \l {coordinate} type which are used to describe where a location is. + The basic properties of a Place are its \l name and \l location. + + Place objects are typically obtained from a search model and will generally only have their + basic properties set. The \l detailsFetched property can be used to test if further property + values need to be fetched from the \l Plugin. This can be done by invoking the \l getDetails() + method. Progress of the fetching operation can be monitored with the \l status property, which + will be set to Place.Fetching when the details are being fetched. + + The Place type has many properties holding information about the location. Details on how to + contact the place are available from the \l contactDetails property. Convenience properties + for obtaining the primary \l {primaryPhone}{phone}, \l {primaryFax}{fax}, + \l {primaryEmail}{email} and \l {primaryWebsite}{website} are also available. + + Each place is assigned zero or more \l categories. Categories are typically used when + searching for a particular kind of place, such as a restaurant or hotel. Some places have a + \l ratings object, which gives an indication of the quality of the place. + + Place metadata is provided by a \l supplier who may require that an \l attribution message be + displayed to the user when the place details are viewed. + + Places have an associated \l icon which can be used to represent a place on a map or to + decorate a delegate in a view. + + Places may have additional rich content associated with them. The currently supported rich + content include editorial descriptions, reviews and images. These are exposed as a set of + models for retrieving the content. Editorial descriptions of the place are available from the + \l editorialModel property. Reviews of the place are available from the \l reviewModel + property. A gallery of pictures of the place can be accessed using the \l imageModel property. + + Places may have additional attributes which are not covered in the formal API. The + \l extendedAttributes property provides access to these. The type of extended attributes + available is specific to each \l Plugin. + + A Place is almost always tied to a \l plugin. The \l plugin property must be set before it is + possible to call \l save(), \l remove() or \l getDetails(). The \l reviewModel, \l imageModel + and \l editorialModel are only valid then the \l plugin property is set. + + \section2 Saving a Place + + If the \l Plugin supports it, the Place type can be used to save a place. First create a new + Place and set its properties: + + \snippet declarative/places.qml Place savePlace def + + Then invoke the \l save() method: + + \snippet declarative/places.qml Place savePlace + + The \l status property will change to Place.Saving and then to Place.Ready if the save was + successful or to Place.Error if an error occurs. + + If the \l placeId property is set, the backend will update an existing place otherwise it will + create a new place. On success the \l placeId property will be updated with the identifier of the newly + saved place. + + \section3 Caveats + \input place-caveats.qdocinc + + \section3 Saving Between Plugins + When saving places between plugins, there are a few things to be aware of. + Some fields of a place such as the id, categories and icons are plugin specific entities. For example + the categories in one manager may not be recognised in another. + Therefore trying to save a place directly from one plugin to another is not possible. + + It is generally recommended that saving across plugins be handled as saving \l {Favorites}{favorites} + as explained in the Favorites section. However there is another approach which is to create a new place, + set its (destination) plugin and then use the \l copyFrom() method to copy the details of the original place. + Using \l copyFrom() only copies data that is supported by the destination plugin, + plugin specific data such as the place identifier is not copied over. Once the copy is done, + the place is in a suitable state to be saved. + + The following snippet provides an example of saving a place to a different plugin + using the \l copyFrom method: + + \snippet declarative/places.qml Place save to different plugin + + \section2 Removing a Place + + To remove a place, ensure that a Place object with a valid \l placeId property exists and call + its \l remove() method. The \l status property will change to Place.Removing and then to + Place.Ready if the save was successful or to Place.Error if an error occurs. + + \section2 Favorites + The Places API supports the concept of favorites. Favorites are generally implemented + by using two plugins, the first plugin is typically a read-only source of places (origin plugin) and a second + read/write plugin (destination plugin) is used to store places from the origin as favorites. + + Each Place has a favorite property which is intended to contain the corresponding place + from the destination plugin (the place itself is sourced from the origin plugin). Because both the original + place and favorite instances are available, the developer can choose which + properties to show to the user. For example the favorite may have a modified name which should + be displayed rather than the original name. + + \snippet declarative/places.qml Place favorite + + The following demonstrates how to save a new favorite instance. A call is made + to create/initialize the favorite instance and then the instance is saved. + + \snippet declarative/places.qml Place saveFavorite + + The following demonstrates favorite removal: + + \snippet declarative/places.qml Place removeFavorite 1 + \dots + \snippet declarative/places.qml Place removeFavorite 2 + + The PlaceSearchModel has a favoritesPlugin property. If the property is set, any places found + during a search are checked against the favoritesPlugin to see if there is a corresponding + favorite place. If so, the favorite property of the Place is set, otherwise the favorite + property is remains null. + + \sa PlaceSearchModel +*/ + +QDeclarativePlace::QDeclarativePlace(QObject *parent) +: QObject(parent), m_location(0), m_ratings(0), m_supplier(0), m_icon(0), + m_reviewModel(0), m_imageModel(0), m_editorialModel(0), + m_extendedAttributes(new QQmlPropertyMap(this)), + m_contactDetails(new QDeclarativeContactDetails(this)), m_reply(0), m_plugin(0), + m_complete(false), m_favorite(0), m_status(QDeclarativePlace::Ready) +{ + connect(m_contactDetails, SIGNAL(valueChanged(QString,QVariant)), + this, SLOT(contactsModified(QString,QVariant))); + + setPlace(QPlace()); +} + +QDeclarativePlace::QDeclarativePlace(const QPlace &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent) +: QObject(parent), m_location(0), m_ratings(0), m_supplier(0), m_icon(0), + m_reviewModel(0), m_imageModel(0), m_editorialModel(0), + m_extendedAttributes(new QQmlPropertyMap(this)), + m_contactDetails(new QDeclarativeContactDetails(this)), m_reply(0), m_plugin(plugin), + m_complete(false), m_favorite(0), m_status(QDeclarativePlace::Ready) +{ + Q_ASSERT(plugin); + + connect(m_contactDetails, SIGNAL(valueChanged(QString,QVariant)), + this, SLOT(contactsModified(QString,QVariant))); + + setPlace(src); +} + +QDeclarativePlace::~QDeclarativePlace() +{ +} + +// From QQmlParserStatus +void QDeclarativePlace::componentComplete() +{ + m_complete = true; +} + +/*! + \qmlproperty Plugin Place::plugin + + This property holds the \l Plugin that provided this place which can be used to retrieve more information about the service. +*/ +void QDeclarativePlace::setPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_plugin == plugin) + return; + + m_plugin = plugin; + if (m_complete) + emit pluginChanged(); + + if (m_plugin->isAttached()) { + pluginReady(); + } else { + connect(m_plugin, SIGNAL(attached()), + this, SLOT(pluginReady())); + } +} + +void QDeclarativePlace::pluginReady() +{ + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return; + } +} + +QDeclarativeGeoServiceProvider *QDeclarativePlace::plugin() const +{ + return m_plugin; +} + +/*! + \qmlproperty ReviewModel Place::reviewModel + + This property holds a model which can be used to retrieve reviews about the place. +*/ +QDeclarativeReviewModel *QDeclarativePlace::reviewModel() +{ + if (!m_reviewModel) { + m_reviewModel = new QDeclarativeReviewModel(this); + m_reviewModel->setPlace(this); + } + + return m_reviewModel; +} + +/*! + \qmlproperty ImageModel Place::imageModel + + This property holds a model which can be used to retrieve images of the place. +*/ +QDeclarativePlaceImageModel *QDeclarativePlace::imageModel() +{ + if (!m_imageModel) { + m_imageModel = new QDeclarativePlaceImageModel(this); + m_imageModel->setPlace(this); + } + + return m_imageModel; +} + +/*! + \qmlproperty EditorialModel Place::editorialModel + + This property holds a model which can be used to retrieve editorial descriptions of the place. +*/ +QDeclarativePlaceEditorialModel *QDeclarativePlace::editorialModel() +{ + if (!m_editorialModel) { + m_editorialModel = new QDeclarativePlaceEditorialModel(this); + m_editorialModel->setPlace(this); + } + + return m_editorialModel; +} + +/*! + \qmlproperty QPlace Place::place + + For details on how to use this property to interface between C++ and QML see + "\l {Place - QPlace} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativePlace::setPlace(const QPlace &src) +{ + QPlace previous = m_src; + m_src = src; + + if (previous.categories() != m_src.categories()) { + synchronizeCategories(); + emit categoriesChanged(); + } + + if (m_location && m_location->parent() == this) { + m_location->setLocation(m_src.location()); + } else if (!m_location || m_location->parent() != this) { + m_location = new QDeclarativeGeoLocation(m_src.location(), this); + emit locationChanged(); + } + + if (m_ratings && m_ratings->parent() == this) { + m_ratings->setRatings(m_src.ratings()); + } else if (!m_ratings || m_ratings->parent() != this) { + m_ratings = new QDeclarativeRatings(m_src.ratings(), this); + emit ratingsChanged(); + } + + if (m_supplier && m_supplier->parent() == this) { + m_supplier->setSupplier(m_src.supplier(), m_plugin); + } else if (!m_supplier || m_supplier->parent() != this) { + m_supplier = new QDeclarativeSupplier(m_src.supplier(), m_plugin, this); + emit supplierChanged(); + } + + if (m_icon && m_icon->parent() == this) { + m_icon->setPlugin(m_plugin); + m_icon->setIcon(m_src.icon()); + } else if (!m_icon || m_icon->parent() != this) { + m_icon = new QDeclarativePlaceIcon(m_src.icon(), m_plugin, this); + emit iconChanged(); + } + + if (previous.name() != m_src.name()) { + emit nameChanged(); + } + if (previous.placeId() != m_src.placeId()) { + emit placeIdChanged(); + } + if (previous.attribution() != m_src.attribution()) { + emit attributionChanged(); + } + if (previous.detailsFetched() != m_src.detailsFetched()) { + emit detailsFetchedChanged(); + } + if (previous.primaryPhone() != m_src.primaryPhone()) { + emit primaryPhoneChanged(); + } + if (previous.primaryFax() != m_src.primaryFax()) { + emit primaryFaxChanged(); + } + if (previous.primaryEmail() != m_src.primaryEmail()) { + emit primaryEmailChanged(); + } + if (previous.primaryWebsite() != m_src.primaryWebsite()) { + emit primaryWebsiteChanged(); + } + + if (m_reviewModel && m_src.totalContentCount(QPlaceContent::ReviewType) >= 0) { + m_reviewModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ReviewType), + m_src.content(QPlaceContent::ReviewType)); + } + if (m_imageModel && m_src.totalContentCount(QPlaceContent::ImageType) >= 0) { + m_imageModel->initializeCollection(m_src.totalContentCount(QPlaceContent::ImageType), + m_src.content(QPlaceContent::ImageType)); + } + if (m_editorialModel && m_src.totalContentCount(QPlaceContent::EditorialType) >= 0) { + m_editorialModel->initializeCollection(m_src.totalContentCount(QPlaceContent::EditorialType), + m_src.content(QPlaceContent::EditorialType)); + } + + synchronizeExtendedAttributes(); + synchronizeContacts(); +} + +QPlace QDeclarativePlace::place() +{ + // The following properties are not stored in m_src but instead stored in QDeclarative* objects + + QPlace result = m_src; + + // Categories + QList<QPlaceCategory> categories; + foreach (QDeclarativeCategory *value, m_categories) + categories.append(value->category()); + + result.setCategories(categories); + + // Location + result.setLocation(m_location ? m_location->location() : QGeoLocation()); + + // Rating + result.setRatings(m_ratings ? m_ratings->ratings() : QPlaceRatings()); + + // Supplier + result.setSupplier(m_supplier ? m_supplier->supplier() : QPlaceSupplier()); + + // Icon + result.setIcon(m_icon ? m_icon->icon() : QPlaceIcon()); + + //contact details + QList<QPlaceContactDetail> cppDetails; + foreach (const QString &key, m_contactDetails->keys()) { + cppDetails.clear(); + if (m_contactDetails->value(key).type() == QVariant::List) { + QVariantList detailsVarList = m_contactDetails->value(key).toList(); + foreach (const QVariant &detailVar, detailsVarList) { + QDeclarativeContactDetail *detail = qobject_cast<QDeclarativeContactDetail *>(detailVar.value<QObject *>()); + if (detail) + cppDetails.append(detail->contactDetail()); + } + } else { + QDeclarativeContactDetail *detail = qobject_cast<QDeclarativeContactDetail *>(m_contactDetails->value(key).value<QObject *>()); + if (detail) + cppDetails.append(detail->contactDetail()); + } + result.setContactDetails(key, cppDetails); + } + + return result; +} + +/*! + \qmlproperty QtPositioning::Location Place::location + + This property holds the location of the place which can be used to retrieve the coordinate, + address and the bounding box. +*/ +void QDeclarativePlace::setLocation(QDeclarativeGeoLocation *location) +{ + if (m_location == location) + return; + + if (m_location && m_location->parent() == this) + delete m_location; + + m_location = location; + emit locationChanged(); +} + +QDeclarativeGeoLocation *QDeclarativePlace::location() +{ + return m_location; +} + +/*! + \qmlproperty Ratings Place::ratings + + This property holds ratings of the place. The ratings provide an indication of the quality of a + place. +*/ +void QDeclarativePlace::setRatings(QDeclarativeRatings *rating) +{ + if (m_ratings == rating) + return; + + if (m_ratings && m_ratings->parent() == this) + delete m_ratings; + + m_ratings = rating; + emit ratingsChanged(); +} + +QDeclarativeRatings *QDeclarativePlace::ratings() +{ + + return m_ratings; +} + +/*! + \qmlproperty Supplier Place::supplier + + This property holds the supplier of the place data. + The supplier is typically a business or organization that collected the data about the place. +*/ +void QDeclarativePlace::setSupplier(QDeclarativeSupplier *supplier) +{ + if (m_supplier == supplier) + return; + + if (m_supplier && m_supplier->parent() == this) + delete m_supplier; + + m_supplier = supplier; + emit supplierChanged(); +} + +QDeclarativeSupplier *QDeclarativePlace::supplier() const +{ + return m_supplier; +} + +/*! + \qmlproperty Icon Place::icon + + This property holds a graphical icon which can be used to represent the place. +*/ +QDeclarativePlaceIcon *QDeclarativePlace::icon() const +{ + return m_icon; +} + +void QDeclarativePlace::setIcon(QDeclarativePlaceIcon *icon) +{ + if (m_icon == icon) + return; + + if (m_icon && m_icon->parent() == this) + delete m_icon; + + m_icon = icon; + emit iconChanged(); +} + +/*! + \qmlproperty string Place::name + + This property holds the name of the place which can be used to represent the place. +*/ +void QDeclarativePlace::setName(const QString &name) +{ + if (m_src.name() != name) { + m_src.setName(name); + emit nameChanged(); + } +} + +QString QDeclarativePlace::name() const +{ + return m_src.name(); +} + +/*! + \qmlproperty string Place::placeId + + This property holds the unique identifier of the place. The place identifier is only meaningful to the + \l Plugin that generated it and is not transferable between \l {Plugin}{Plugins}. The place id + is not guaranteed to be universally unique, but unique within the \l Plugin that generated it. + + If only the place identifier is known, all other place data can fetched from the \l Plugin. + + \snippet declarative/places.qml Place placeId +*/ +void QDeclarativePlace::setPlaceId(const QString &placeId) +{ + if (m_src.placeId() != placeId) { + m_src.setPlaceId(placeId); + emit placeIdChanged(); + } +} + +QString QDeclarativePlace::placeId() const +{ + return m_src.placeId(); +} + +/*! + \qmlproperty string Place::attribution + + This property holds a rich text attribution string for the place. + Some providers may require that the attribution be shown to the user + whenever a place is displayed. The contents of this property should + be shown to the user if it is not empty. +*/ +void QDeclarativePlace::setAttribution(const QString &attribution) +{ + if (m_src.attribution() != attribution) { + m_src.setAttribution(attribution); + emit attributionChanged(); + } +} + +QString QDeclarativePlace::attribution() const +{ + return m_src.attribution(); +} + +/*! + \qmlproperty bool Place::detailsFetched + + This property indicates whether the details of the place have been fetched. If this property + is false, the place details have not yet been fetched. Fetching can be done by invoking the + \l getDetails() method. + + \sa getDetails() +*/ +bool QDeclarativePlace::detailsFetched() const +{ + return m_src.detailsFetched(); +} + +/*! + \qmlproperty enumeration Place::status + + This property holds the status of the place. It can be one of: + + \table + \row + \li Place.Ready + \li No error occurred during the last operation, further operations may be performed on + the place. + \row + \li Place.Saving + \li The place is currently being saved, no other operation may be performed until + complete. + \row + \li Place.Fetching + \li The place details are currently being fetched, no other operations may be performed + until complete. + \row + \li Place.Removing + \li The place is currently being removed, no other operations can be performed until + complete. + \row + \li Place.Error + \li An error occurred during the last operation, further operations can still be + performed on the place. + \endtable + + The status of a place can be checked by connecting the status property + to a handler function, and then have the handler function process the change + in status. + + \snippet declarative/places.qml Place checkStatus + \dots + \snippet declarative/places.qml Place checkStatus handler + +*/ +void QDeclarativePlace::setStatus(Status status, const QString &errorString) +{ + Status originalStatus = m_status; + m_status = status; + m_errorString = errorString; + + if (originalStatus != m_status) + emit statusChanged(); +} + +QDeclarativePlace::Status QDeclarativePlace::status() const +{ + return m_status; +} + +/*! + \internal +*/ +void QDeclarativePlace::finished() +{ + if (!m_reply) + return; + + if (m_reply->error() == QPlaceReply::NoError) { + switch (m_reply->type()) { + case (QPlaceReply::IdReply) : { + QPlaceIdReply *idReply = qobject_cast<QPlaceIdReply *>(m_reply); + + switch (idReply->operationType()) { + case QPlaceIdReply::SavePlace: + setPlaceId(idReply->id()); + break; + case QPlaceIdReply::RemovePlace: + break; + default: + //Other operation types shouldn't ever be received. + break; + } + break; + } + case (QPlaceReply::DetailsReply): { + QPlaceDetailsReply *detailsReply = qobject_cast<QPlaceDetailsReply *>(m_reply); + setPlace(detailsReply->place()); + break; + } + default: + //other types of replies shouldn't ever be received. + break; + } + + m_errorString.clear(); + + m_reply->deleteLater(); + m_reply = 0; + + setStatus(QDeclarativePlace::Ready); + } else { + QString errorString = m_reply->errorString(); + + m_reply->deleteLater(); + m_reply = 0; + + setStatus(QDeclarativePlace::Error, errorString); + } +} + +/*! + \internal +*/ +void QDeclarativePlace::contactsModified(const QString &key, const QVariant &) +{ + primarySignalsEmission(key); +} + +/*! + \internal +*/ +void QDeclarativePlace::cleanupDeletedCategories() +{ + foreach (QDeclarativeCategory * category, m_categoriesToBeDeleted) { + if (category->parent() == this) + delete category; + } + m_categoriesToBeDeleted.clear(); +} + +/*! + \qmlmethod void Place::getDetails() + + This method starts fetching place details. + + The \l status property will change to Place.Fetching while the fetch is in progress. On + success the object's properties will be updated, \l status will be set to Place.Ready and + \l detailsFetched will be set to true. On error \l status will be set to Place.Error. The + \l errorString() method can be used to get the details of the error. +*/ +void QDeclarativePlace::getDetails() +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + m_reply = placeManager->getPlaceDetails(placeId()); + connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + setStatus(QDeclarativePlace::Fetching); +} + +/*! + \qmlmethod void Place::save() + + This method performs a save operation on the place. + + The \l status property will change to Place.Saving while the save operation is in progress. On + success the \l status will be set to Place.Ready. On error \l status will be set to Place.Error. + The \l errorString() method can be used to get the details of the error. + + If the \l placeId property was previously empty, it will be assigned a valid value automatically + during a successful save operation. + + Note that a \l PlaceSearchModel will call Place::getDetails on any place that it detects an update + on. A consequence of this is that whenever a Place from a \l PlaceSearchModel is successfully saved, + it will be followed by a fetch of place details, leading to a sequence of state changes + of \c Saving, \c Ready, \c Fetching, \c Ready. + +*/ +void QDeclarativePlace::save() +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + m_reply = placeManager->savePlace(place()); + connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + setStatus(QDeclarativePlace::Saving); +} + +/*! + \qmlmethod void Place::remove() + + This method performs a remove operation on the place. + + The \l status property will change to Place.Removing while the save operation is in progress. + On success \l status will be set to Place.Ready. On error \l status will be set to + Place.Error. The \l errorString() method can be used to get the details of the error. +*/ +void QDeclarativePlace::remove() +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + m_reply = placeManager->removePlace(place().placeId()); + connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + setStatus(QDeclarativePlace::Removing); +} + +/*! + \qmlmethod string Place::errorString() + + Returns a string description of the error of the last operation. If the last operation + completed successfully then the string is empty. +*/ +QString QDeclarativePlace::errorString() const +{ + return m_errorString; +} + +/*! + \qmlproperty string Place::primaryPhone + + This property holds the primary phone number of the place. If no "phone" contact detail is + defined for this place, this property will be an empty string. It is equivalent to: + + + \snippet declarative/places.qml Place primaryPhone +*/ +QString QDeclarativePlace::primaryPhone() const +{ + return primaryValue(QPlaceContactDetail::Phone); +} + +/*! + \qmlproperty string Place::primaryFax + + This property holds the primary fax number of the place. If no "fax" contact detail is + defined for this place this property will be an empty string. It is equivalent to + + \snippet declarative/places.qml Place primaryFax +*/ +QString QDeclarativePlace::primaryFax() const +{ + return primaryValue(QPlaceContactDetail::Fax); +} + +/*! + \qmlproperty string Place::primaryEmail + + This property holds the primary email address of the place. If no "email" contact detail is + defined for this place this property will be an empty string. It is equivalent to + + \snippet declarative/places.qml Place primaryEmail +*/ +QString QDeclarativePlace::primaryEmail() const +{ + return primaryValue(QPlaceContactDetail::Email); +} + +/*! + \qmlproperty string Place::primaryWebsite + + This property holds the primary website url of the place. If no "website" contact detail is + defined for this place this property will be an empty string. It is equivalent to + + \snippet declarative/places.qml Place primaryWebsite +*/ + +QUrl QDeclarativePlace::primaryWebsite() const +{ + return QUrl(primaryValue(QPlaceContactDetail::Website)); +} + +/*! + \qmlproperty ExtendedAttributes Place::extendedAttributes + + This property holds the extended attributes of a place. Extended attributes are additional + information about a place not covered by the place's properties. +*/ +QQmlPropertyMap *QDeclarativePlace::extendedAttributes() const +{ + return m_extendedAttributes; +} + +/*! + \qmlproperty ContactDetails Place::contactDetails + + This property holds the contact information for this place, for example a phone number or + a website URL. This property is a map of \l ContactDetail objects. +*/ +QDeclarativeContactDetails *QDeclarativePlace::contactDetails() const +{ + return m_contactDetails; +} + +/*! + \qmlproperty list<Category> Place::categories + + This property holds the list of categories this place is a member of. The categories that can + be assigned to a place are specific to each \l plugin. +*/ +QQmlListProperty<QDeclarativeCategory> QDeclarativePlace::categories() +{ + return QQmlListProperty<QDeclarativeCategory>(this, + 0, // opaque data parameter + category_append, + category_count, + category_at, + category_clear); +} + +/*! + \internal +*/ +void QDeclarativePlace::category_append(QQmlListProperty<QDeclarativeCategory> *prop, + QDeclarativeCategory *value) +{ + QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object); + + if (object->m_categoriesToBeDeleted.contains(value)) + object->m_categoriesToBeDeleted.removeAll(value); + + if (!object->m_categories.contains(value)) { + object->m_categories.append(value); + QList<QPlaceCategory> list = object->m_src.categories(); + list.append(value->category()); + object->m_src.setCategories(list); + + emit object->categoriesChanged(); + } +} + +/*! + \internal +*/ +int QDeclarativePlace::category_count(QQmlListProperty<QDeclarativeCategory> *prop) +{ + return static_cast<QDeclarativePlace *>(prop->object)->m_categories.count(); +} + +/*! + \internal +*/ +QDeclarativeCategory *QDeclarativePlace::category_at(QQmlListProperty<QDeclarativeCategory> *prop, + int index) +{ + QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object); + QDeclarativeCategory *res = NULL; + if (object->m_categories.count() > index && index > -1) { + res = object->m_categories[index]; + } + return res; +} + +/*! + \internal +*/ +void QDeclarativePlace::category_clear(QQmlListProperty<QDeclarativeCategory> *prop) +{ + QDeclarativePlace *object = static_cast<QDeclarativePlace *>(prop->object); + if (object->m_categories.isEmpty()) + return; + + for (int i = 0; i < object->m_categories.count(); ++i) { + if (object->m_categories.at(i)->parent() == object) + object->m_categoriesToBeDeleted.append(object->m_categories.at(i)); + } + + object->m_categories.clear(); + object->m_src.setCategories(QList<QPlaceCategory>()); + emit object->categoriesChanged(); + QMetaObject::invokeMethod(object, "cleanupDeletedCategories", Qt::QueuedConnection); +} + +/*! + \internal +*/ +void QDeclarativePlace::synchronizeCategories() +{ + qDeleteAll(m_categories); + m_categories.clear(); + foreach (const QPlaceCategory &value, m_src.categories()) { + QDeclarativeCategory *declarativeValue = new QDeclarativeCategory(value, m_plugin, this); + m_categories.append(declarativeValue); + } +} + +/*! + \qmlproperty enumeration Place::visibility + + This property holds the visibility of the place. It can be one of: + + \table + \row + \li Place.UnspecifiedVisibility + \li The visibility of the place is unspecified, the default visibility of the \l Plugin + will be used. + \row + \li Place.DeviceVisibility + \li The place is limited to the current device. The place will not be transferred off + of the device. + \row + \li Place.PrivateVisibility + \li The place is private to the current user. The place may be transferred to an online + service but is only ever visible to the current user. + \row + \li Place.PublicVisibility + \li The place is public. + \endtable + + Note that visibility does not affect how the place is displayed + in the user-interface of an application on the device. Instead, + it defines the sharing semantics of the place. +*/ +QDeclarativePlace::Visibility QDeclarativePlace::visibility() const +{ + return static_cast<QDeclarativePlace::Visibility>(m_src.visibility()); +} + +void QDeclarativePlace::setVisibility(Visibility visibility) +{ + if (static_cast<QDeclarativePlace::Visibility>(m_src.visibility()) == visibility) + return; + + m_src.setVisibility(static_cast<QLocation::Visibility>(visibility)); + emit visibilityChanged(); +} + +/*! + \qmlproperty Place Place::favorite + + This property holds the favorite instance of a place. +*/ +QDeclarativePlace *QDeclarativePlace::favorite() const +{ + return m_favorite; +} + +void QDeclarativePlace::setFavorite(QDeclarativePlace *favorite) +{ + + if (m_favorite == favorite) + return; + + if (m_favorite && m_favorite->parent() == this) + delete m_favorite; + + m_favorite = favorite; + emit favoriteChanged(); +} + +/*! + \qmlmethod void Place::copyFrom(Place original) + + Copies data from an \a original place into this place. Only data that is supported by this + place's plugin is copied over and plugin specific data such as place identifier is not copied over. +*/ +void QDeclarativePlace::copyFrom(QDeclarativePlace *original) +{ + QPlaceManager *placeManager = manager(); + if (!placeManager) + return; + + setPlace(placeManager->compatiblePlace(original->place())); +} + +/*! + \qmlmethod void Place::initializeFavorite(Plugin destinationPlugin) + + Creates a favorite instance for the place which is to be saved into the + \a destination plugin. This method does nothing if the favorite property is + not null. +*/ +void QDeclarativePlace::initializeFavorite(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_favorite == 0) { + QDeclarativePlace *place = new QDeclarativePlace(this); + place->setPlugin(plugin); + place->copyFrom(this); + setFavorite(place); + } +} + +/*! + \internal +*/ +void QDeclarativePlace::synchronizeExtendedAttributes() +{ + QStringList keys = m_extendedAttributes->keys(); + foreach (const QString &key, keys) + m_extendedAttributes->clear(key); + + QStringList attributeTypes = m_src.extendedAttributeTypes(); + foreach (const QString &attributeType, attributeTypes) { + m_extendedAttributes->insert(attributeType, + qVariantFromValue(new QDeclarativePlaceAttribute(m_src.extendedAttribute(attributeType)))); + } + + emit extendedAttributesChanged(); +} + +/*! + \internal +*/ +void QDeclarativePlace::synchronizeContacts() +{ + //clear out contact data + foreach (const QString &contactType, m_contactDetails->keys()) { + QList<QVariant> contacts = m_contactDetails->value(contactType).toList(); + foreach (const QVariant &var, contacts) { + QObject *obj = var.value<QObject *>(); + if (obj->parent() == this) + delete obj; + } + m_contactDetails->insert(contactType, QVariantList()); + } + + //insert new contact data from source place + foreach (const QString &contactType, m_src.contactTypes()) { + QList<QPlaceContactDetail> sourceContacts = m_src.contactDetails(contactType); + QVariantList declContacts; + foreach (const QPlaceContactDetail &sourceContact, sourceContacts) { + QDeclarativeContactDetail *declContact = new QDeclarativeContactDetail(this); + declContact->setContactDetail(sourceContact); + declContacts.append(QVariant::fromValue(qobject_cast<QObject *>(declContact))); + } + m_contactDetails->insert(contactType, declContacts); + } + primarySignalsEmission(); +} + +/*! + \internal + Helper function to emit the signals for the primary___() + fields. It is expected that the values of the primary___() + functions have already been modified to new values. +*/ +void QDeclarativePlace::primarySignalsEmission(const QString &type) +{ + if (type.isEmpty() || type == QPlaceContactDetail::Phone) { + if (m_prevPrimaryPhone != primaryPhone()) { + m_prevPrimaryPhone = primaryPhone(); + emit primaryPhoneChanged(); + } + if (!type.isEmpty()) + return; + } + + if (type.isEmpty() || type == QPlaceContactDetail::Email) { + if (m_prevPrimaryEmail != primaryEmail()) { + m_prevPrimaryEmail = primaryEmail(); + emit primaryEmailChanged(); + } + if (!type.isEmpty()) + return; + } + + if (type.isEmpty() || type == QPlaceContactDetail::Website) { + if (m_prevPrimaryWebsite != primaryWebsite()) { + m_prevPrimaryWebsite = primaryWebsite(); + emit primaryWebsiteChanged(); + } + if (!type.isEmpty()) + return; + } + + if (type.isEmpty() || type == QPlaceContactDetail::Fax) { + if (m_prevPrimaryFax != primaryFax()) { + m_prevPrimaryFax = primaryFax(); + emit primaryFaxChanged(); + } + } +} + +/*! + \internal + Helper function to return the manager, this manager is intended to be used + to perform the next operation. If a an operation is currently underway + then return a null pointer. +*/ +QPlaceManager *QDeclarativePlace::manager() +{ + if (m_status != QDeclarativePlace::Ready && m_status != QDeclarativePlace::Error) + return 0; + + if (m_reply) { + m_reply->abort(); + m_reply->deleteLater(); + m_reply = 0; + } + + if (!m_plugin) { + qmlWarning(this) << QStringLiteral("Plugin is not assigned to place."); + return 0; + } + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider) + return 0; + + QPlaceManager *placeManager = serviceProvider->placeManager(); + + if (!placeManager) { + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return 0; + } + + return placeManager; +} + +/*! + \internal +*/ +QString QDeclarativePlace::primaryValue(const QString &contactType) const +{ + QVariant value = m_contactDetails->value(contactType); + if (value.userType() == qMetaTypeId<QJSValue>()) + value = value.value<QJSValue>().toVariant(); + + if (value.userType() == QVariant::List) { + QVariantList detailList = m_contactDetails->value(contactType).toList(); + if (!detailList.isEmpty()) { + QDeclarativeContactDetail *primaryDetail = qobject_cast<QDeclarativeContactDetail *>(detailList.at(0).value<QObject *>()); + if (primaryDetail) + return primaryDetail->value(); + } + } else if (value.userType() == QMetaType::QObjectStar) { + QDeclarativeContactDetail *primaryDetail = qobject_cast<QDeclarativeContactDetail *>(m_contactDetails->value(contactType).value<QObject *>()); + if (primaryDetail) + return primaryDetail->value(); + } + + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplace_p.h b/src/location/declarativeplaces/qdeclarativeplace_p.h new file mode 100644 index 00000000..5a1470fe --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplace_p.h @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACE_P_H +#define QDECLARATIVEPLACE_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/qlocationglobal_p.h> +#include <QtCore/QObject> +#include <QtQml/QQmlListProperty> +#include <QtQml/QQmlParserStatus> +#include <QtQml/QQmlPropertyMap> +#include <QtLocation/QPlace> + +#include <QtPositioning/private/qdeclarativegeolocation_p.h> +#include <QtLocation/private/qdeclarativecategory_p.h> +#include <QtLocation/private/qdeclarativecontactdetail_p.h> +#include <QtLocation/private/qdeclarativesupplier_p.h> +#include <QtLocation/private/qdeclarativeratings_p.h> +#include <QtLocation/private/qdeclarativereviewmodel_p.h> +#include <QtLocation/private/qdeclarativeplaceimagemodel_p.h> +#include <QtLocation/private/qdeclarativeplaceeditorialmodel_p.h> + +QT_BEGIN_NAMESPACE + +class QPlaceReply; + +class QPlaceManager; +class QDeclarativePlaceIcon; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlace : public QObject, public QQmlParserStatus +{ + Q_OBJECT + + Q_ENUMS(Status Visibility) + + Q_PROPERTY(QPlace place READ place WRITE setPlace) + Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) + Q_PROPERTY(QQmlListProperty<QDeclarativeCategory> categories READ categories NOTIFY categoriesChanged) + Q_PROPERTY(QDeclarativeGeoLocation *location READ location WRITE setLocation NOTIFY locationChanged) + Q_PROPERTY(QDeclarativeRatings *ratings READ ratings WRITE setRatings NOTIFY ratingsChanged) + Q_PROPERTY(QDeclarativeSupplier *supplier READ supplier WRITE setSupplier NOTIFY supplierChanged) + Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString placeId READ placeId WRITE setPlaceId NOTIFY placeIdChanged) + Q_PROPERTY(QString attribution READ attribution WRITE setAttribution NOTIFY attributionChanged) + + Q_PROPERTY(QDeclarativeReviewModel *reviewModel READ reviewModel NOTIFY reviewModelChanged) + Q_PROPERTY(QDeclarativePlaceImageModel *imageModel READ imageModel NOTIFY imageModelChanged) + Q_PROPERTY(QDeclarativePlaceEditorialModel *editorialModel READ editorialModel NOTIFY editorialModelChanged) + + Q_PROPERTY(QObject *extendedAttributes READ extendedAttributes NOTIFY extendedAttributesChanged) + Q_PROPERTY(QObject *contactDetails READ contactDetails NOTIFY contactDetailsChanged) + Q_PROPERTY(bool detailsFetched READ detailsFetched NOTIFY detailsFetchedChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + + Q_PROPERTY(QString primaryPhone READ primaryPhone NOTIFY primaryPhoneChanged) + Q_PROPERTY(QString primaryFax READ primaryFax NOTIFY primaryFaxChanged) + Q_PROPERTY(QString primaryEmail READ primaryEmail NOTIFY primaryEmailChanged) + Q_PROPERTY(QUrl primaryWebsite READ primaryWebsite NOTIFY primaryWebsiteChanged) + + Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged) + Q_PROPERTY(QDeclarativePlace *favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged) + + Q_INTERFACES(QQmlParserStatus) + +public: + explicit QDeclarativePlace(QObject *parent = 0); + QDeclarativePlace(const QPlace &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0); + ~QDeclarativePlace(); + + enum Status {Ready, Saving, Fetching, Removing, Error}; + enum Visibility { + UnspecifiedVisibility = QLocation::UnspecifiedVisibility, + DeviceVisibility = QLocation::DeviceVisibility, + PrivateVisibility = QLocation::PrivateVisibility, + PublicVisibility = QLocation::PublicVisibility + }; + + //From QQmlParserStatus + virtual void classBegin() {} + virtual void componentComplete(); + + void setPlugin(QDeclarativeGeoServiceProvider *plugin); + QDeclarativeGeoServiceProvider *plugin() const; + + QDeclarativeReviewModel *reviewModel(); + QDeclarativePlaceImageModel *imageModel(); + QDeclarativePlaceEditorialModel *editorialModel(); + + QPlace place(); + void setPlace(const QPlace &src); + + QQmlListProperty<QDeclarativeCategory> categories(); + static void category_append(QQmlListProperty<QDeclarativeCategory> *prop, + QDeclarativeCategory *value); + static int category_count(QQmlListProperty<QDeclarativeCategory> *prop); + static QDeclarativeCategory *category_at(QQmlListProperty<QDeclarativeCategory> *prop, int index); + static void category_clear(QQmlListProperty<QDeclarativeCategory> *prop); + + QDeclarativeGeoLocation *location(); + void setLocation(QDeclarativeGeoLocation *location); + QDeclarativeRatings *ratings(); + void setRatings(QDeclarativeRatings *ratings); + QDeclarativeSupplier *supplier() const; + void setSupplier(QDeclarativeSupplier *supplier); + QDeclarativePlaceIcon *icon() const; + void setIcon(QDeclarativePlaceIcon *icon); + QString name() const; + void setName(const QString &name); + QString placeId() const; + void setPlaceId(const QString &placeId); + QString attribution() const; + void setAttribution(const QString &attribution); + bool detailsFetched() const; + + Status status() const; + void setStatus(Status status, const QString &errorString = QString()); + + Q_INVOKABLE void getDetails(); + Q_INVOKABLE void save(); + Q_INVOKABLE void remove(); + Q_INVOKABLE QString errorString() const; + + QString primaryPhone() const; + QString primaryFax() const; + QString primaryEmail() const; + QUrl primaryWebsite() const; + + QQmlPropertyMap *extendedAttributes() const; + + QDeclarativeContactDetails *contactDetails() const; + + Visibility visibility() const; + void setVisibility(Visibility visibility); + + QDeclarativePlace *favorite() const; + void setFavorite(QDeclarativePlace *favorite); + + Q_INVOKABLE void copyFrom(QDeclarativePlace *original); + Q_INVOKABLE void initializeFavorite(QDeclarativeGeoServiceProvider *plugin); + +Q_SIGNALS: + void pluginChanged(); + void categoriesChanged(); + void locationChanged(); + void ratingsChanged(); + void supplierChanged(); + void iconChanged(); + void nameChanged(); + void placeIdChanged(); + void attributionChanged(); + void detailsFetchedChanged(); + void reviewModelChanged(); + void imageModelChanged(); + void editorialModelChanged(); + + void primaryPhoneChanged(); + void primaryFaxChanged(); + void primaryEmailChanged(); + void primaryWebsiteChanged(); + + void extendedAttributesChanged(); + void contactDetailsChanged(); + void statusChanged(); + void visibilityChanged(); + void favoriteChanged(); + +private Q_SLOTS: + void finished(); + void contactsModified(const QString &, const QVariant &); + void pluginReady(); + void cleanupDeletedCategories(); +private: + void synchronizeCategories(); + void synchronizeExtendedAttributes(); + void synchronizeContacts(); + void primarySignalsEmission(const QString &type = QString()); + QString primaryValue(const QString &contactType) const; + +private: + QPlaceManager *manager(); + + QList<QDeclarativeCategory *> m_categories; + QDeclarativeGeoLocation *m_location; + QDeclarativeRatings *m_ratings; + QDeclarativeSupplier *m_supplier; + QDeclarativePlaceIcon *m_icon; + QDeclarativeReviewModel *m_reviewModel; + QDeclarativePlaceImageModel *m_imageModel; + QDeclarativePlaceEditorialModel *m_editorialModel; + QQmlPropertyMap *m_extendedAttributes; + QDeclarativeContactDetails *m_contactDetails; + + QPlace m_src; + + QPlaceReply *m_reply; + + QDeclarativeGeoServiceProvider *m_plugin; + bool m_complete; + + QString m_prevPrimaryPhone; + QString m_prevPrimaryEmail; + QString m_prevPrimaryFax; + QUrl m_prevPrimaryWebsite; + + QDeclarativePlace *m_favorite; + + Status m_status; + QString m_errorString; + + QList<QDeclarativeCategory *>m_categoriesToBeDeleted; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativePlace) + +#endif // QDECLARATIVEPLACE_P_H diff --git a/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp new file mode 100644 index 00000000..20adbafb --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceattribute.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplaceattribute_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ExtendedAttributes + \instantiates QQmlPropertyMap + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The ExtendedAttributes type holds additional data about a \l Place. + + The ExtendedAttributes type is a map of \l {PlaceAttribute}{PlaceAttributes}. To access + attributes in the map use the \l keys() method to get the list of keys stored in the map and + use the \c {[]} operator to access the \l PlaceAttribute items. + + The following are standard keys that are defined by the API. \l Plugin + implementations are free to define additional keys. Custom keys should + be qualified by a unique prefix to avoid clashes. + \table + \header + \li key + \li description + \row + \li openingHours + \li The trading hours of the place + \row + \li payment + \li The types of payment the place accepts, for example visa, mastercard. + \row + \li x_provider + \li The name of the provider that a place is sourced from + \row + \li x_id_<provider> (for example x_id_here) + \li An alternative identifier which identifies the place from the + perspective of the specified provider. + \endtable + + Some plugins may not support attributes at all, others may only support a + certain set, others still may support a dynamically changing set of attributes + over time or even allow attributes to be arbitrarily defined by the client + application. The attributes could also vary on a place by place basis, + for example one place may have opening hours while another does not. + Consult the \l {Plugin References and Parameters}{plugin + references} for details. + + Some attributes may not be intended to be readable by end users, the label field + of such attributes is empty to indicate this fact. + + \note ExtendedAttributes instances are only ever used in the context of \l {Place}s. It is not + possible to create an ExtendedAttributes instance directly or re-assign a \l {Place}'s + ExtendedAttributes property. Modification of ExtendedAttributes can only be accomplished + via Javascript. + + The following example shows how to access all \l {PlaceAttribute}{PlaceAttributes} and print + them to the console: + + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml ExtendedAttributes read + + The following example shows how to assign and modify an attribute: + \snippet declarative/places.qml ExtendedAttributes write + + \sa PlaceAttribute, QQmlPropertyMap +*/ + +/*! + \qmlmethod variant ExtendedAttributes::keys() + + Returns an array of place attribute keys currently stored in the map. +*/ + +/*! + \qmlsignal void ExtendedAttributes::valueChanged(string key, variant value) + + This signal is emitted when the set of attributes changes. \a key is the key + corresponding to the \a value that was changed. + + The corresponding handler is \c onValueChanged. +*/ + +/*! + \qmltype PlaceAttribute + \instantiates QDeclarativePlaceAttribute + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The PlaceAttribute type holds generic place attribute information. + + A place attribute stores an additional piece of information about a \l Place that is not + otherwise exposed through the \l Place type. A PlaceAttribute is a textual piece of data, + accessible through the \l text property, and a \l label. Both the \l text and \l label + properties are intended to be displayed to the user. PlaceAttributes are stored in an + \l ExtendedAttributes map with a unique key. + + The following example shows how to display all attributes in a list: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml ExtendedAttributes + + The following example shows how to assign and modify an attribute: + \snippet declarative/places.qml ExtendedAttributes write +*/ + +QDeclarativePlaceAttribute::QDeclarativePlaceAttribute(QObject *parent) + : QObject(parent) +{ +} + +QDeclarativePlaceAttribute::QDeclarativePlaceAttribute(const QPlaceAttribute &src, QObject *parent) + : QObject(parent),m_attribute(src) +{ +} + +QDeclarativePlaceAttribute::~QDeclarativePlaceAttribute() +{ +} + +/*! + \qmlproperty QPlaceAttribute PlaceAttribute::attribute + + For details on how to use this property to interface between C++ and QML see + "\l {PlaceAttribute - QPlaceAttribute} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativePlaceAttribute::setAttribute(const QPlaceAttribute &src) +{ + QPlaceAttribute prevAttribute = m_attribute; + m_attribute = src; + + if (m_attribute.label() != prevAttribute.label()) + emit labelChanged(); + if (m_attribute.text() != prevAttribute.text()) + emit textChanged(); +} + +QPlaceAttribute QDeclarativePlaceAttribute::attribute() const +{ + return m_attribute; +} + +/*! + \qmlproperty string PlaceAttribute::label + + This property holds the attribute label which is a user visible string + describing the attribute. +*/ +void QDeclarativePlaceAttribute::setLabel(const QString &label) +{ + if (m_attribute.label() != label) { + m_attribute.setLabel(label); + emit labelChanged(); + } +} + +QString QDeclarativePlaceAttribute::label() const +{ + return m_attribute.label(); +} + +/*! + \qmlproperty string PlaceAttribute::text + + This property holds the attribute text which can be used to show additional information about the place. +*/ +void QDeclarativePlaceAttribute::setText(const QString &text) +{ + if (m_attribute.text() != text) { + m_attribute.setText(text); + emit textChanged(); + } +} + +QString QDeclarativePlaceAttribute::text() const +{ + return m_attribute.text(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h new file mode 100644 index 00000000..8079df9c --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceattribute_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACEATTRIBUTE_P_H +#define QDECLARATIVEPLACEATTRIBUTE_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/qlocationglobal_p.h> +#include <QObject> +#include <QtQml/qqml.h> +#include <QString> + +#include <QtLocation/qplaceattribute.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceAttribute : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPlaceAttribute attribute READ attribute WRITE setAttribute) + Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged) + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + +public: + explicit QDeclarativePlaceAttribute(QObject *parent = 0); + explicit QDeclarativePlaceAttribute(const QPlaceAttribute &src, QObject *parent = 0); + ~QDeclarativePlaceAttribute(); + + QPlaceAttribute attribute() const; + void setAttribute(const QPlaceAttribute &place); + + QString text() const; + void setText(const QString &text); + + + QString label() const; + void setLabel(const QString &label); + +Q_SIGNALS: + void labelChanged(); + void textChanged(); + +private: + QPlaceAttribute m_attribute; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativePlaceAttribute) + +#endif diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp new file mode 100644 index 00000000..faf7e418 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel.cpp @@ -0,0 +1,397 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplacecontentmodel_p.h" +#include "qdeclarativeplace_p.h" +#include "qdeclarativegeoserviceprovider_p.h" +#include "qdeclarativeplaceuser_p.h" +#include "error_messages.h" + +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceManager> +#include <QtLocation/QPlaceContentRequest> + +QT_BEGIN_NAMESPACE + +QDeclarativePlaceContentModel::QDeclarativePlaceContentModel(QPlaceContent::Type type, + QObject *parent) +: QAbstractListModel(parent), m_place(0), m_type(type), m_batchSize(1), m_contentCount(-1), + m_reply(0), m_complete(false) +{ +} + +QDeclarativePlaceContentModel::~QDeclarativePlaceContentModel() +{ +} + +/*! + \internal +*/ +QDeclarativePlace *QDeclarativePlaceContentModel::place() const +{ + return m_place; +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::setPlace(QDeclarativePlace *place) +{ + if (m_place != place) { + beginResetModel(); + + int initialCount = m_contentCount; + clearData(); + m_place = place; + endResetModel(); + + emit placeChanged(); + if (initialCount != -1) + emit totalCountChanged(); + + fetchMore(QModelIndex()); + } +} + +/*! + \internal +*/ +int QDeclarativePlaceContentModel::batchSize() const +{ + return m_batchSize; +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::setBatchSize(int batchSize) +{ + if (m_batchSize != batchSize) { + m_batchSize = batchSize; + emit batchSizeChanged(); + } +} + +/*! + \internal +*/ +int QDeclarativePlaceContentModel::totalCount() const +{ + return m_contentCount; +} + +/*! + \internal + Clears the model data but does not reset it. +*/ +void QDeclarativePlaceContentModel::clearData() +{ + qDeleteAll(m_users); + m_users.clear(); + + qDeleteAll(m_suppliers); + m_suppliers.clear(); + + m_content.clear(); + + m_contentCount = -1; + + if (m_reply) { + m_reply->abort(); + m_reply->deleteLater(); + m_reply = 0; + } + + m_nextRequest.clear(); +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::initializeCollection(int totalCount, const QPlaceContent::Collection &collection) +{ + beginResetModel(); + + int initialCount = m_contentCount; + clearData(); + + QMapIterator<int, QPlaceContent> i(collection); + while (i.hasNext()) { + i.next(); + + const QPlaceContent &content = i.value(); + if (content.type() != m_type) + continue; + + m_content.insert(i.key(), content); + if (!m_suppliers.contains(content.supplier().supplierId())) { + m_suppliers.insert(content.supplier().supplierId(), + new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this)); + } + if (!m_users.contains(content.user().userId())) { + m_users.insert(content.user().userId(), + new QDeclarativePlaceUser(content.user(), this)); + } + } + + m_contentCount = totalCount; + + if (initialCount != totalCount) + emit totalCountChanged(); + + endResetModel(); +} + +/*! + \internal +*/ +int QDeclarativePlaceContentModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_content.count(); +} + +/*! + \internal +*/ +QVariant QDeclarativePlaceContentModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount(index.parent()) || index.row() < 0) + return QVariant(); + + const QPlaceContent &content = m_content.value(index.row()); + + switch (role) { + case SupplierRole: + return QVariant::fromValue(static_cast<QObject *>(m_suppliers.value(content.supplier().supplierId()))); + case PlaceUserRole: + return QVariant::fromValue(static_cast<QObject *>(m_users.value(content.user().userId()))); + case AttributionRole: + return content.attribution(); + default: + return QVariant(); + } +} + +QHash<int, QByteArray> QDeclarativePlaceContentModel::roleNames() const +{ + QHash<int, QByteArray> roles = QAbstractListModel::roleNames(); + roles.insert(SupplierRole, "supplier"); + roles.insert(PlaceUserRole, "user"); + roles.insert(AttributionRole, "attribution"); + return roles; +} + +/*! + \internal +*/ +bool QDeclarativePlaceContentModel::canFetchMore(const QModelIndex &parent) const +{ + if (parent.isValid()) + return false; + + if (!m_place) + return false; + + if (m_contentCount == -1) + return true; + + return m_content.count() != m_contentCount; +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::fetchMore(const QModelIndex &parent) +{ + if (parent.isValid()) + return; + + if (!m_place) + return; + + if (m_reply) + return; + + if (!m_place->plugin()) + return; + + QDeclarativeGeoServiceProvider *plugin = m_place->plugin(); + + QGeoServiceProvider *serviceProvider = plugin->sharedGeoServiceProvider(); + if (!serviceProvider) + return; + + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager) + return; + + if (m_nextRequest == QPlaceContentRequest()) { + QPlaceContentRequest request; + request.setContentType(m_type); + request.setPlaceId(m_place->place().placeId()); + request.setLimit(m_batchSize); + + m_reply = placeManager->getPlaceContent(request); + } else { + m_reply = placeManager->getPlaceContent(m_nextRequest); + } + + connect(m_reply, SIGNAL(finished()), this, SLOT(fetchFinished()), Qt::QueuedConnection); +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::classBegin() +{ +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::componentComplete() +{ + m_complete = true; + fetchMore(QModelIndex()); +} + +/*! + \internal +*/ +void QDeclarativePlaceContentModel::fetchFinished() +{ + if (!m_reply) + return; + + QPlaceContentReply *reply = m_reply; + m_reply = 0; + + m_nextRequest = reply->nextPageRequest(); + + if (m_contentCount != reply->totalCount()) { + m_contentCount = reply->totalCount(); + emit totalCountChanged(); + } + + if (!reply->content().isEmpty()) { + QPlaceContent::Collection contents = reply->content(); + + //find out which indexes are new and which ones have changed. + QMapIterator<int, QPlaceContent> it(contents); + QList<int> changedIndexes; + QList<int> newIndexes; + while (it.hasNext()) { + it.next(); + if (!m_content.contains(it.key())) + newIndexes.append(it.key()); + else if (it.value() != m_content.value(it.key())) + changedIndexes.append(it.key()); + } + + //insert new indexes in blocks where within each + //block, the indexes are consecutive. + QListIterator<int> newIndexesIter(newIndexes); + int startIndex = -1; + while (newIndexesIter.hasNext()) { + int currentIndex = newIndexesIter.next(); + if (startIndex == -1) + startIndex = currentIndex; + + if (!newIndexesIter.hasNext() || (newIndexesIter.hasNext() && (newIndexesIter.peekNext() > (currentIndex + 1)))) { + beginInsertRows(QModelIndex(),startIndex,currentIndex); + for (int i = startIndex; i <= currentIndex; ++i) { + const QPlaceContent &content = contents.value(i); + + m_content.insert(i, content); + if (!m_suppliers.contains(content.supplier().supplierId())) { + m_suppliers.insert(content.supplier().supplierId(), + new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this)); + } + if (!m_users.contains(content.user().userId())) { + m_users.insert(content.user().userId(), + new QDeclarativePlaceUser(content.user(), this)); + } + } + endInsertRows(); + startIndex = -1; + } + } + + //modify changed indexes in blocks where within each + //block, the indexes are consecutive. + startIndex = -1; + QListIterator<int> changedIndexesIter(changedIndexes); + while (changedIndexesIter.hasNext()) { + int currentIndex = changedIndexesIter.next(); + if (startIndex == -1) + startIndex = currentIndex; + + if (!changedIndexesIter.hasNext() || (changedIndexesIter.hasNext() && changedIndexesIter.peekNext() > (currentIndex + 1))) { + for (int i = startIndex; i <= currentIndex; ++i) { + const QPlaceContent &content = contents.value(i); + m_content.insert(i, content); + if (!m_suppliers.contains(content.supplier().supplierId())) { + m_suppliers.insert(content.supplier().supplierId(), + new QDeclarativeSupplier(content.supplier(), m_place->plugin(), this)); + } + if (!m_users.contains(content.user().userId())) { + m_users.insert(content.user().userId(), + new QDeclarativePlaceUser(content.user(), this)); + } + } + emit dataChanged(index(startIndex),index(currentIndex)); + startIndex = -1; + } + } + + // The fetch didn't add any new content and we haven't fetched all content yet. This is + // likely due to the model being prepopulated by Place::getDetails(). Keep fetching more + // data until new content is available. + if (newIndexes.isEmpty() && m_content.count() != m_contentCount) + fetchMore(QModelIndex()); + } + + reply->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h new file mode 100644 index 00000000..a8ed2fdb --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplacecontentmodel_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACECONTENTMODEL_H +#define QDECLARATIVEPLACECONTENTMODEL_H + +#include <QtLocation/private/qlocationglobal_p.h> +#include <QtCore/QAbstractListModel> +#include <QtQml/QQmlParserStatus> +#include <QtLocation/QPlaceContent> +#include <QtLocation/QPlaceContentReply> + +QT_BEGIN_NAMESPACE + +class QDeclarativePlace; +class QDeclarativeGeoServiceProvider; +class QGeoServiceProvider; +class QDeclarativeSupplier; +class QDeclarativePlaceUser; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceContentModel : public QAbstractListModel, public QQmlParserStatus +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativePlace *place READ place WRITE setPlace NOTIFY placeChanged) + Q_PROPERTY(int batchSize READ batchSize WRITE setBatchSize NOTIFY batchSizeChanged) + Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged) + + Q_INTERFACES(QQmlParserStatus) + +public: + explicit QDeclarativePlaceContentModel(QPlaceContent::Type type, QObject *parent = 0); + ~QDeclarativePlaceContentModel(); + + QDeclarativePlace *place() const; + void setPlace(QDeclarativePlace *place); + + int batchSize() const; + void setBatchSize(int batchSize); + + int totalCount() const; + + void clearData(); + + void initializeCollection(int totalCount, const QPlaceContent::Collection &collection); + + // from QAbstractListModel + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + enum Roles { + SupplierRole = Qt::UserRole, + PlaceUserRole, + AttributionRole, + UserRole //indicator for next conten type specific role + }; + + bool canFetchMore(const QModelIndex &parent) const; + void fetchMore(const QModelIndex &parent); + + // from QQmlParserStatus + void classBegin(); + void componentComplete(); + +Q_SIGNALS: + void placeChanged(); + void batchSizeChanged(); + void totalCountChanged(); + +private Q_SLOTS: + void fetchFinished(); + +protected: + QPlaceContent::Collection m_content; + QMap<QString, QDeclarativeSupplier *> m_suppliers; + QMap<QString, QDeclarativePlaceUser *>m_users; + +private: + QDeclarativePlace *m_place; + QPlaceContent::Type m_type; + int m_batchSize; + int m_contentCount; + + QPlaceContentReply *m_reply; + QPlaceContentRequest m_nextRequest; + + bool m_complete; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPLACECONTENTMODEL_H diff --git a/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp new file mode 100644 index 00000000..dbc23737 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplaceeditorialmodel_p.h" + +#include <QtCore/QUrl> +#include <QtLocation/QPlaceEditorial> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype EditorialModel + \instantiates QDeclarativePlaceEditorialModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief The EditorialModel type provides a model of place editorials. + + The EditorialModel is a read-only model used to fetch editorials related to a \l Place. + Binding a \l Place via \l EditorialModel::place initiates an initial fetch of editorials. + The model performs fetches incrementally and is intended to be used in conjunction + with a View such as a \l ListView. When the View reaches the last of the editorials + currently in the model, a fetch is performed to retrieve more if they are available. + The View is automatically updated as the editorials are received. The number of + editorials which are fetched at a time is specified by the \l batchSize property. + The total number of editorials available can be accessed via the \l totalCount property. + + The model returns data for the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li text + \li string + \li The editorial's textual description of the place. It can be either rich (HTML based) text or plain text + depending upon the provider. + \row + \li title + \li string + \li The title of the editorial. + \row + \li language + \li string + \li The language that the editorial is written in. + \row + \li supplier + \li \l Supplier + \li The supplier of the editorial. + \row + \li user + \li \l {QtLocation::User}{User} + \li The user who contributed the editorial. + \row + \li attribution + \li string + \li Attribution text which must be displayed when displaying the editorial. + \endtable + + \section1 Example + + The following example shows how to display editorials for a place: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml EditorialModel + +*/ + +/*! + \qmlproperty Place EditorialModel::place + + This property holds the Place that the editorials are for. +*/ + +/*! + \qmlproperty int EditorialModel::batchSize + + This property holds the batch size to use when fetching more editorials items. +*/ + +/*! + \qmlproperty int EditorialModel::totalCount + + This property holds the total number of editorial items for the place. +*/ + +QDeclarativePlaceEditorialModel::QDeclarativePlaceEditorialModel(QObject *parent) +: QDeclarativePlaceContentModel(QPlaceContent::EditorialType, parent) +{ +} + +QDeclarativePlaceEditorialModel::~QDeclarativePlaceEditorialModel() +{ +} + +/*! + \internal +*/ +QVariant QDeclarativePlaceEditorialModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount(index.parent()) || index.row() < 0) + return QVariant(); + + const QPlaceEditorial &description = m_content.value(index.row()); + + switch (role) { + case TextRole: + return description.text(); + case TitleRole: + return description.title(); + case LanguageRole: + return description.language(); + } + + return QDeclarativePlaceContentModel::data(index, role); +} + +QHash<int, QByteArray> QDeclarativePlaceEditorialModel::roleNames() const +{ + QHash<int, QByteArray> roleNames = QDeclarativePlaceContentModel::roleNames(); + roleNames.insert(TextRole, "text"); + roleNames.insert(TitleRole, "title"); + roleNames.insert(LanguageRole, "language"); + return roleNames; +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h new file mode 100644 index 00000000..f574677a --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceeditorialmodel_p.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACEEDITORIALMODEL_H +#define QDECLARATIVEPLACEEDITORIALMODEL_H + +#include <QtLocation/private/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceEditorialModel : public QDeclarativePlaceContentModel +{ + Q_OBJECT + +public: + explicit QDeclarativePlaceEditorialModel(QObject *parent = 0); + ~QDeclarativePlaceEditorialModel(); + + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + enum Roles { + TextRole = UserRole, + TitleRole, + LanguageRole + }; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEPLACEEDITORIALMODEL_H diff --git a/src/location/declarativeplaces/qdeclarativeplaceicon.cpp b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp new file mode 100644 index 00000000..24891138 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceicon.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplaceicon_p.h" +#include "error_messages.h" + +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceManager> +#include <QtQml/QQmlInfo> +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Icon + \instantiates QDeclarativePlaceIcon + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The Icon type represents an icon image source which can have multiple sizes. + + The Icon type can be used in conjunction with an \l Image type to display an icon. + The \l url() function is used to construct an icon URL of a requested size, + the icon which most closely matches the requested size is returned. + + The Icon type also has a parameters map which is a set of key value pairs. The precise + keys to use depend on the + \l {Qt Location#Plugin References and Parameters}{plugin} being used. + The parameters map is used by the \l Plugin to determine which URL to return. + + In the case where an icon can only possibly have one image URL, the + parameter key of \c "singleUrl" can be used with a QUrl value. Any Icon with this + parameter will always return the specified URL regardless of the requested icon + size and not defer to any Plugin. + + The following code shows how to display a 64x64 pixel icon: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml Icon + + Alternatively, a default sized icon can be specified like so: + \snippet declarative/places.qml Icon default +*/ + +QDeclarativePlaceIcon::QDeclarativePlaceIcon(QObject *parent) +: QObject(parent), m_plugin(0), m_parameters(new QQmlPropertyMap(this)) +{ +} + +QDeclarativePlaceIcon::QDeclarativePlaceIcon(const QPlaceIcon &icon, QDeclarativeGeoServiceProvider *plugin, QObject *parent) +: QObject(parent), m_parameters(new QQmlPropertyMap(this)) +{ + if (icon.isEmpty()) + m_plugin = 0; + else + m_plugin = plugin; + + initParameters(icon.parameters()); +} + +QDeclarativePlaceIcon::~QDeclarativePlaceIcon() +{ +} + +/*! + \qmlproperty QPlaceIcon Icon::icon + + For details on how to use this property to interface between C++ and QML see + "\l {Icon - QPlaceIcon} {Interfaces between C++ and QML Code}". +*/ +QPlaceIcon QDeclarativePlaceIcon::icon() const +{ + QPlaceIcon result; + + if (m_plugin) + result.setManager(manager()); + else + result.setManager(0); + + QVariantMap params; + foreach (const QString &key, m_parameters->keys()) { + const QVariant value = m_parameters->value(key); + if (value.isValid()) { + params.insert(key, value); + } + } + + result.setParameters(params); + + return result; +} + +void QDeclarativePlaceIcon::setIcon(const QPlaceIcon &src) +{ + initParameters(src.parameters()); +} + +/*! + \qmlmethod url Icon::url(size size) + + Returns a URL for the icon image that most closely matches the given \a size. + + If no plugin has been assigned to the icon, and the parameters do not contain the 'singleUrl' key, a default constructed URL + is returned. + +*/ +QUrl QDeclarativePlaceIcon::url(const QSize &size) const +{ + return icon().url(size); +} + +/*! + \qmlproperty Object Icon::parameters + + This property holds the parameters of the icon and is a map. These parameters + are used by the plugin to return the appropriate URL when url() is called and to + specify locations to save to when saving icons. + + Consult the \l {Qt Location#Plugin References and Parameters}{plugin documentation} + for what parameters are supported and how they should be used. + + Note, due to limitations of the QQmlPropertyMap, it is not possible + to declaratively specify the parameters in QML, assignment of parameters keys + and values can only be accomplished by JavaScript. + +*/ +QQmlPropertyMap *QDeclarativePlaceIcon::parameters() const +{ + return m_parameters; +} + +/*! + \qmlproperty Plugin Icon::plugin + + The property holds the plugin that is responsible for managing this icon. +*/ +QDeclarativeGeoServiceProvider *QDeclarativePlaceIcon::plugin() const +{ + return m_plugin; +} + +void QDeclarativePlaceIcon::setPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_plugin == plugin) + return; + + m_plugin = plugin; + emit pluginChanged(); + + if (!m_plugin) + return; + + if (m_plugin->isAttached()) { + pluginReady(); + } else { + connect(m_plugin, SIGNAL(attached()), + this, SLOT(pluginReady())); + } +} + +/*! + \internal +*/ +void QDeclarativePlaceIcon::pluginReady() +{ + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager || serviceProvider->error() != QGeoServiceProvider::NoError) { + qmlWarning(this) << QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString()); + return; + } +} + +/*! + \internal + Helper function to return the manager from the plugin +*/ +QPlaceManager *QDeclarativePlaceIcon::manager() const +{ + if (!m_plugin) { + qmlWarning(this) << QStringLiteral("Plugin is not assigned to place."); + return 0; + } + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider) + return 0; + + QPlaceManager *placeManager = serviceProvider->placeManager(); + + if (!placeManager) + return 0; + + return placeManager; +} + +/*! + \internal +*/ +void QDeclarativePlaceIcon::initParameters(const QVariantMap ¶meterMap) +{ + //clear out old parameters + foreach (const QString &key, m_parameters->keys()) + m_parameters->clear(key); + + foreach (const QString &key, parameterMap.keys()) { + QVariant value = parameterMap.value(key); + m_parameters->insert(key, value); + } +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplaceicon_p.h b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h new file mode 100644 index 00000000..535d98eb --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceicon_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACEICON_P_H +#define QDECLARATIVEPLACEICON_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> + +#include <QtLocation/qplaceicon.h> +#include <QtQml/qqml.h> +#include <QtQml/QQmlPropertyMap> + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class QQmlPropertyMap; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceIcon : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPlaceIcon icon READ icon WRITE setIcon) + Q_PROPERTY(QObject *parameters READ parameters NOTIFY parametersChanged) + Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) + +public: + explicit QDeclarativePlaceIcon(QObject *parent = 0); + QDeclarativePlaceIcon(const QPlaceIcon &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0); + ~QDeclarativePlaceIcon(); + + QPlaceIcon icon() const; + void setIcon(const QPlaceIcon &src); + + Q_INVOKABLE QUrl url(const QSize &size = QSize()) const; + + QQmlPropertyMap *parameters() const; + + void setPlugin(QDeclarativeGeoServiceProvider *plugin); + QDeclarativeGeoServiceProvider *plugin() const; + +Q_SIGNALS: + void pluginChanged(); + void parametersChanged(); //in practice is never emitted since parameters cannot be re-assigned + //the declaration is needed to avoid warnings about non-notifyable properties + +private Q_SLOTS: + void pluginReady(); + +private: + QPlaceManager *manager() const; + void initParameters(const QVariantMap ¶meterMap); + QDeclarativeGeoServiceProvider *m_plugin; + QQmlPropertyMap *m_parameters; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp new file mode 100644 index 00000000..4da37081 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplaceimagemodel_p.h" +#include "qdeclarativesupplier_p.h" + +#include <QtCore/QUrl> +#include <QtLocation/QPlaceImage> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ImageModel + \instantiates QDeclarativePlaceImageModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief The ImageModel type provides a model of place images. + + The ImageModel is a read-only model used to fetch images related to a \l Place. + Binding a \l Place via \l ImageModel::place initiates an initial fetch of images. + The model performs fetches incrementally and is intended to be used in conjunction + with a View such as a \l ListView. When the View reaches the last of the images + currently in the model, a fetch is performed to retrieve more if they are available. + The View is automatically updated as the images are received. The number of images + which are fetched at a time is specified by the \l batchSize property. The total number + of images available can be accessed via the \l totalCount property. + + The model returns data for the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li url + \li url + \li The URL of the image. + \row + \li imageId + \li string + \li The identifier of the image. + \row + \li mimeType + \li string + \li The MIME type of the image. + \row + \li supplier + \li \l Supplier + \li The supplier of the image. + \row + \li user + \li \l {QtLocation::User}{User} + \li The user who contributed the image. + \row + \li attribution + \li string + \li Attribution text which must be displayed when displaying the image. + \endtable + + + \section1 Example + + The following example shows how to display images for a place: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml ImageModel +*/ + +/*! + \qmlproperty Place ImageModel::place + + This property holds the Place that the images are for. +*/ + +/*! + \qmlproperty int ImageModel::batchSize + + This property holds the batch size to use when fetching more image items. +*/ + +/*! + \qmlproperty int ImageModel::totalCount + + This property holds the total number of image items for the place. +*/ + +QDeclarativePlaceImageModel::QDeclarativePlaceImageModel(QObject *parent) +: QDeclarativePlaceContentModel(QPlaceContent::ImageType, parent) +{ +} + +QDeclarativePlaceImageModel::~QDeclarativePlaceImageModel() +{ + qDeleteAll(m_suppliers); +} + +/*! + \internal +*/ +QVariant QDeclarativePlaceImageModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount(index.parent()) || index.row() < 0) + return QVariant(); + + const QPlaceImage &image = m_content.value(index.row()); + + switch (role) { + case UrlRole: + return image.url(); + case ImageIdRole: + return image.imageId(); + case MimeTypeRole: + return image.mimeType(); + } + + return QDeclarativePlaceContentModel::data(index, role); +} + +QHash<int, QByteArray> QDeclarativePlaceImageModel::roleNames() const +{ + QHash<int, QByteArray> roles = QDeclarativePlaceContentModel::roleNames(); + roles.insert(UrlRole, "url"); + roles.insert(ImageIdRole, "imageId"); + roles.insert(MimeTypeRole, "mimeType"); + return roles; +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h new file mode 100644 index 00000000..2c244219 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceimagemodel_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACEIMAGEMODEL_P_H +#define QDECLARATIVEPLACEIMAGEMODEL_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeSupplier; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceImageModel : public QDeclarativePlaceContentModel +{ + Q_OBJECT + +public: + explicit QDeclarativePlaceImageModel(QObject *parent = 0); + ~QDeclarativePlaceImageModel(); + + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + enum Roles { + UrlRole = UserRole, + ImageIdRole, + MimeTypeRole + }; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/location/declarativeplaces/qdeclarativeplaceuser.cpp b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp new file mode 100644 index 00000000..86901a98 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceuser.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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 "qdeclarativeplaceuser_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype User + \instantiates QDeclarativePlaceUser + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The User type identifies a user who contributed a particular \l Place content item. + + Each \l Place content item has an associated user who contributed the content. This type + provides information about that user. + + \sa ImageModel, ReviewModel, EditorialModel + + \section1 Example + + The following example shows how to display information about the user who + submitted an editorial: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml EditorialModel +*/ + +QDeclarativePlaceUser::QDeclarativePlaceUser(QObject *parent) + : QObject(parent) {} + +QDeclarativePlaceUser::QDeclarativePlaceUser(const QPlaceUser &user, + QObject *parent) + : QObject(parent), + m_user(user) {} + +QDeclarativePlaceUser::~QDeclarativePlaceUser() {} + +/*! + \qmlproperty QPlaceUser QtLocation::User::user + + For details on how to use this property to interface between C++ and QML see + "\l {User - QPlaceUser} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativePlaceUser::setUser(const QPlaceUser &user) +{ + QPlaceUser previousUser = m_user; + m_user = user; + + if (m_user.userId() != previousUser.userId()) + emit userIdChanged(); + + if (m_user.name() != previousUser.name()) + emit nameChanged(); +} + +QPlaceUser QDeclarativePlaceUser::user() const +{ + return m_user; +} + +/*! + \qmlproperty string QtLocation::User::userId + + This property holds the unique identifier of the user. +*/ + +void QDeclarativePlaceUser::setUserId(const QString &id) +{ + if (m_user.userId() == id) + return; + + m_user.setUserId(id); + emit userIdChanged(); +} + +QString QDeclarativePlaceUser::userId() const +{ + return m_user.userId(); +} + +/*! + \qmlproperty string QtLocation::User::name + + This property holds the name of a user. +*/ +void QDeclarativePlaceUser::setName(const QString &name) +{ + if (m_user.name() == name) + return; + + m_user.setName(name); + emit nameChanged(); +} + +QString QDeclarativePlaceUser::name() const +{ + return m_user.name(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeplaceuser_p.h b/src/location/declarativeplaces/qdeclarativeplaceuser_p.h new file mode 100644 index 00000000..8cd64493 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeplaceuser_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEPLACEUSER_P_H +#define QDECLARATIVEPLACEUSER_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/qlocationglobal_p.h> +#include <QtCore/QObject> +#include <QtQml/qqml.h> +#include <QtLocation/QPlaceUser> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativePlaceUser : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPlaceUser user READ user WRITE setUser) + Q_PROPERTY(QString userId READ userId WRITE setUserId NOTIFY userIdChanged) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + +public: + explicit QDeclarativePlaceUser(QObject *parent = 0); + explicit QDeclarativePlaceUser(const QPlaceUser &src, QObject *parent = 0); + ~QDeclarativePlaceUser(); + + QPlaceUser user() const; + void setUser(const QPlaceUser &src); + + QString userId() const; + void setUserId(const QString &id); + + QString name() const; + void setName(const QString &name); + +Q_SIGNALS: + void userIdChanged(); + void nameChanged(); + +private: + QPlaceUser m_user; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativePlaceUser) + +#endif diff --git a/src/location/declarativeplaces/qdeclarativeratings.cpp b/src/location/declarativeplaces/qdeclarativeratings.cpp new file mode 100644 index 00000000..150e5966 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeratings.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** 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 "qdeclarativeratings_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Ratings + \instantiates QDeclarativeRatings + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief The Ratings type holds place rating information. + + Rating information is used to describe how \e good a place is conceived to be. Typically this + information is visualized as a number of stars. The \l average property gives an aggregated + ratings value out of a possible maximum as given by the \l maximum property. + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml Ratings +*/ + +QDeclarativeRatings::QDeclarativeRatings(QObject *parent) + : QObject(parent) {} + +QDeclarativeRatings::QDeclarativeRatings(const QPlaceRatings &rating, + QObject *parent) + : QObject(parent), + m_ratings(rating) {} + +QDeclarativeRatings::~QDeclarativeRatings() {} + +/*! + \qmlproperty QPlaceRatings Ratings::ratings + + For details on how to use this property to interface between C++ and QML see + "\l {Ratings - QPlaceRatings} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativeRatings::setRatings(const QPlaceRatings &ratings) +{ + QPlaceRatings previous = m_ratings; + m_ratings = ratings; + + if (ratings.average() != previous.average()) { + emit averageChanged(); + } + if (ratings.count() != previous.count()) { + emit countChanged(); + } +} + +QPlaceRatings QDeclarativeRatings::ratings() const +{ + return m_ratings; +} + +/*! + \qmlproperty real Ratings::average + + This property holds the average of the individual ratings. + + \sa maximum +*/ +void QDeclarativeRatings::setAverage(qreal average) +{ + if (m_ratings.average() != average) { + m_ratings.setAverage(average); + emit averageChanged(); + } +} + +qreal QDeclarativeRatings::average() const +{ + return m_ratings.average(); +} + +/*! + \qmlproperty real Ratings::maximum + + This property holds the maximum rating value. +*/ +void QDeclarativeRatings::setMaximum(qreal max) +{ + if (m_ratings.maximum() == max) + return; + + m_ratings.setMaximum(max); + emit maximumChanged(); +} + +qreal QDeclarativeRatings::maximum() const +{ + return m_ratings.maximum(); +} + +/*! + \qmlproperty int Ratings::count + + This property holds the total number of individual user ratings + used in determining the overall ratings \l average. +*/ +void QDeclarativeRatings::setCount(int count) +{ + if (m_ratings.count() != count) { + m_ratings.setCount(count); + emit countChanged(); + } +} + +int QDeclarativeRatings::count() const +{ + return m_ratings.count(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativeratings_p.h b/src/location/declarativeplaces/qdeclarativeratings_p.h new file mode 100644 index 00000000..5ee530dc --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativeratings_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVERATINGS_P_H +#define QDECLARATIVERATINGS_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/qlocationglobal_p.h> +#include <QtLocation/qplaceratings.h> +#include <QtQml/qqml.h> + +#include <QObject> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeRatings : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QPlaceRatings ratings READ ratings WRITE setRatings) + Q_PROPERTY(qreal average READ average WRITE setAverage NOTIFY averageChanged) + Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged) + +public: + explicit QDeclarativeRatings(QObject *parent = 0); + explicit QDeclarativeRatings(const QPlaceRatings &src, QObject *parent = 0); + ~QDeclarativeRatings(); + + QPlaceRatings ratings() const; + void setRatings(const QPlaceRatings &src); + + qreal average() const; + void setAverage(qreal average); + + qreal maximum() const; + void setMaximum(qreal max); + + int count() const; + void setCount(int count); + +Q_SIGNALS: + void averageChanged(); + void maximumChanged(); + void countChanged(); + +private: + QPlaceRatings m_ratings; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeRatings) + +#endif // QDECLARATIVERATING_P_H diff --git a/src/location/declarativeplaces/qdeclarativereviewmodel.cpp b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp new file mode 100644 index 00000000..b7237bc9 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativereviewmodel.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** 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 "qdeclarativereviewmodel_p.h" +#include "qdeclarativesupplier_p.h" + +#include <QtCore/QDateTime> +#include <QtLocation/QPlaceReview> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype ReviewModel + \instantiates QDeclarativeReviewModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief Provides access to reviews of a \l Place. + + The ReviewModel is a read-only model used to fetch reviews about a \l Place. The model + incrementally fetches. The number of reviews which are fetched at a time is specified + by the \l batchSize property. The total number of reviews available can be accessed via the + \l totalCount property. + + To use the ReviewModel we need a view and a delegate. In this snippet we + see the setting up of a ListView with a ReviewModel model and a delegate. + + \snippet places/views/ReviewView.qml ReviewModel delegate + + The model returns data for the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li dateTime + \li datetime + \li The date and time that the review was posted. + \row + \li text + \li string + \li The review's textual description of the place. It can be either rich (HTML based) text or plain text + depending on the provider. + \row + \li language + \li string + \li The language that the review is written in. + \row + \li rating + \li real + \li The rating that the reviewer gave to the place. + \row + \li reviewId + \li string + \li The identifier of the review. + \row + \li title + \li string + \li The title of the review. + \row + \li supplier + \li \l Supplier + \li The supplier of the review. + \row + \li user + \li \l {QtLocation::User}{User} + \li The user who contributed the review. + \row + \li attribution + \li string + \li Attribution text which must be displayed when displaying the review. + \endtable +*/ + +/*! + \qmlproperty Place QtLocation::ReviewModel::place + + This property holds the Place that the reviews are for. +*/ + +/*! + \qmlproperty int QtLocation::ReviewModel::batchSize + + This property holds the batch size to use when fetching more reviews. +*/ + +/*! + \qmlproperty int QtLocation::ReviewModel::totalCount + + This property holds the total number of reviews for the place. +*/ + +QDeclarativeReviewModel::QDeclarativeReviewModel(QObject *parent) +: QDeclarativePlaceContentModel(QPlaceContent::ReviewType, parent) +{ +} + +QDeclarativeReviewModel::~QDeclarativeReviewModel() +{ + qDeleteAll(m_suppliers); +} + +/*! + \internal +*/ +QVariant QDeclarativeReviewModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount(index.parent()) || index.row() < 0) + return QVariant(); + + const QPlaceReview &review = m_content.value(index.row()); + + switch (role) { + case DateTimeRole: + return review.dateTime(); + case TextRole: + return review.text(); + case LanguageRole: + return review.language(); + case RatingRole: + return review.rating(); + case ReviewIdRole: + return review.reviewId(); + case TitleRole: + return review.title(); + } + + return QDeclarativePlaceContentModel::data(index, role); +} + +QHash<int, QByteArray> QDeclarativeReviewModel::roleNames() const +{ + QHash<int, QByteArray> roles = QDeclarativePlaceContentModel::roleNames(); + roles.insert(DateTimeRole, "dateTime"); + roles.insert(TextRole, "text"); + roles.insert(LanguageRole, "language"); + roles.insert(RatingRole, "rating"); + roles.insert(ReviewIdRole, "reviewId"); + roles.insert(TitleRole, "title"); + return roles; +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativereviewmodel_p.h b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h new file mode 100644 index 00000000..e6d2bd95 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativereviewmodel_p.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVEREVIEWMODEL_P_H +#define QDECLARATIVEREVIEWMODEL_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativeplacecontentmodel_p.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeReviewModel : public QDeclarativePlaceContentModel +{ + Q_OBJECT + +public: + explicit QDeclarativeReviewModel(QObject *parent = 0); + ~QDeclarativeReviewModel(); + + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + enum Roles { + DateTimeRole = UserRole, + TextRole, + LanguageRole, + RatingRole, + ReviewIdRole, + TitleRole + }; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVEREVIEWMODEL_P_H diff --git a/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp new file mode 100644 index 00000000..3a3faa56 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** 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 "qdeclarativesearchmodelbase_p.h" +#include "qdeclarativeplace_p.h" +#include "error_messages.h" + +#include <QtCore/QCoreApplication> +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceManager> +#include <QtLocation/QPlaceSearchRequest> +#include <QtLocation/QPlaceSearchReply> +#include <QtPositioning/QGeoCircle> + +QT_BEGIN_NAMESPACE + +QDeclarativeSearchModelBase::QDeclarativeSearchModelBase(QObject *parent) +: QAbstractListModel(parent), m_plugin(0), m_reply(0), m_complete(false), m_status(Null) +{ +} + +QDeclarativeSearchModelBase::~QDeclarativeSearchModelBase() +{ +} + +/*! + \internal +*/ +QDeclarativeGeoServiceProvider *QDeclarativeSearchModelBase::plugin() const +{ + return m_plugin; +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::setPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_plugin == plugin) + return; + + initializePlugin(plugin); + + if (m_complete) + emit pluginChanged(); +} + +/*! + \internal +*/ +QVariant QDeclarativeSearchModelBase::searchArea() const +{ + QGeoShape s = m_request.searchArea(); + if (s.type() == QGeoShape::RectangleType) + return QVariant::fromValue(QGeoRectangle(s)); + else if (s.type() == QGeoShape::CircleType) + return QVariant::fromValue(QGeoCircle(s)); + else + return QVariant::fromValue(s); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::setSearchArea(const QVariant &searchArea) +{ + QGeoShape s; + + if (searchArea.userType() == qMetaTypeId<QGeoRectangle>()) + s = searchArea.value<QGeoRectangle>(); + else if (searchArea.userType() == qMetaTypeId<QGeoCircle>()) + s = searchArea.value<QGeoCircle>(); + else if (searchArea.userType() == qMetaTypeId<QGeoShape>()) + s = searchArea.value<QGeoShape>(); + + if (m_request.searchArea() == s) + return; + + m_request.setSearchArea(s); + emit searchAreaChanged(); +} + +/*! + \internal +*/ +int QDeclarativeSearchModelBase::limit() const +{ + return m_request.limit(); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::setLimit(int limit) +{ + if (m_request.limit() == limit) + return; + + m_request.setLimit(limit); + emit limitChanged(); +} + +/*! + \internal +*/ +bool QDeclarativeSearchModelBase::previousPagesAvailable() const +{ + return m_previousPageRequest != QPlaceSearchRequest(); +} + +/*! + \internal +*/ +bool QDeclarativeSearchModelBase::nextPagesAvailable() const +{ + return m_nextPageRequest != QPlaceSearchRequest(); +} + +/*! + \internal +*/ +QDeclarativeSearchModelBase::Status QDeclarativeSearchModelBase::status() const +{ + return m_status; +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::setStatus(Status status, const QString &errorString) +{ + Status prevStatus = m_status; + + m_status = status; + m_errorString = errorString; + + if (prevStatus != m_status) + emit statusChanged(); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::update() +{ + if (m_reply) + return; + + setStatus(Loading); + + if (!m_plugin) { + clearData(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET)); + return; + } + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider) { + clearData(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROVIDER_ERROR) + .arg(m_plugin->name())); + return; + } + + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager) { + clearData(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return; + } + + m_reply = sendQuery(placeManager, m_request); + if (!m_reply) { + clearData(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, UNABLE_TO_MAKE_REQUEST)); + return; + } + + m_reply->setParent(this); + connect(m_reply, SIGNAL(finished()), this, SLOT(queryFinished())); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::cancel() +{ + if (!m_reply) + return; + + if (!m_reply->isFinished()) + m_reply->abort(); + + if (m_reply) { + m_reply->deleteLater(); + m_reply = 0; + } + + setStatus(Ready); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::reset() +{ + beginResetModel(); + clearData(); + setStatus(Null); + endResetModel(); +} + +/*! + \internal +*/ +QString QDeclarativeSearchModelBase::errorString() const +{ + return m_errorString; +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::previousPage() +{ + if (m_previousPageRequest == QPlaceSearchRequest()) + return; + + m_request = m_previousPageRequest; + update(); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::nextPage() +{ + if (m_nextPageRequest == QPlaceSearchRequest()) + return; + + m_request = m_nextPageRequest; + update(); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::clearData(bool suppressSignal) +{ + Q_UNUSED(suppressSignal) +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::classBegin() +{ +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::componentComplete() +{ + m_complete = true; +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::initializePlugin(QDeclarativeGeoServiceProvider *plugin) +{ + beginResetModel(); + if (plugin != m_plugin) { + if (m_plugin) + disconnect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(pluginNameChanged())); + if (plugin) + connect(plugin, SIGNAL(nameChanged(QString)), this, SLOT(pluginNameChanged())); + m_plugin = plugin; + } + + if (m_plugin) { + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (serviceProvider) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + if (placeManager->childCategoryIds().isEmpty()) { + QPlaceReply *reply = placeManager->initializeCategories(); + connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater())); + } + } + } + } + + endResetModel(); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::pluginNameChanged() +{ + initializePlugin(m_plugin); +} + +/*! + \internal +*/ +void QDeclarativeSearchModelBase::setPreviousPageRequest(const QPlaceSearchRequest &previous) +{ + if (m_previousPageRequest == previous) + return; + + m_previousPageRequest = previous; + emit previousPagesAvailableChanged(); +} + +void QDeclarativeSearchModelBase::setNextPageRequest(const QPlaceSearchRequest &next) +{ + if (m_nextPageRequest == next) + return; + + m_nextPageRequest = next; + emit nextPagesAvailableChanged(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h new file mode 100644 index 00000000..cb8e4032 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchmodelbase_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESEARCHMODELBASE_H +#define QDECLARATIVESEARCHMODELBASE_H + +#include <QtLocation/private/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> +#include <QtCore/QAbstractListModel> +#include <QtQml/QQmlParserStatus> +#include <QtLocation/QPlaceSearchRequest> +#include <QtLocation/QPlaceSearchResult> +#include <QtLocation/QPlaceReply> + +QT_BEGIN_NAMESPACE + +class QPlaceManager; +class QPlaceSearchRequest; +class QPlaceSearchReply; +class QDeclarativePlace; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchModelBase : public QAbstractListModel, public QQmlParserStatus +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) + Q_PROPERTY(QVariant searchArea READ searchArea WRITE setSearchArea NOTIFY searchAreaChanged) + Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged) + Q_PROPERTY(bool previousPagesAvailable READ previousPagesAvailable NOTIFY previousPagesAvailableChanged) + Q_PROPERTY(bool nextPagesAvailable READ nextPagesAvailable NOTIFY nextPagesAvailableChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + + Q_ENUMS(Status) + + Q_INTERFACES(QQmlParserStatus) + +public: + enum Status { + Null, + Ready, + Loading, + Error + }; + + explicit QDeclarativeSearchModelBase(QObject *parent = 0); + ~QDeclarativeSearchModelBase(); + + QDeclarativeGeoServiceProvider *plugin() const; + void setPlugin(QDeclarativeGeoServiceProvider *plugin); + + QVariant searchArea() const; + void setSearchArea(const QVariant &searchArea); + + int limit() const; + void setLimit(int limit); + + bool previousPagesAvailable() const; + bool nextPagesAvailable() const; + + Status status() const; + void setStatus(Status status, const QString &errorString = QString()); + + Q_INVOKABLE void update(); + + Q_INVOKABLE void cancel(); + Q_INVOKABLE void reset(); + + Q_INVOKABLE QString errorString() const; + + Q_INVOKABLE void previousPage(); + Q_INVOKABLE void nextPage(); + + virtual void clearData(bool suppressSignal = false); + + // From QQmlParserStatus + virtual void classBegin(); + virtual void componentComplete(); + +Q_SIGNALS: + void pluginChanged(); + void searchAreaChanged(); + void limitChanged(); + void previousPagesAvailableChanged(); + void nextPagesAvailableChanged(); + void statusChanged(); + +protected: + virtual void initializePlugin(QDeclarativeGeoServiceProvider *plugin); + +protected Q_SLOTS: + virtual void queryFinished() = 0; + +private Q_SLOTS: + void pluginNameChanged(); + +protected: + virtual QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request) = 0; + void setPreviousPageRequest(const QPlaceSearchRequest &previous); + void setNextPageRequest(const QPlaceSearchRequest &next); + + QPlaceSearchRequest m_request; + QDeclarativeGeoServiceProvider *m_plugin; + QPlaceReply *m_reply; + +private: + bool m_complete; + Status m_status; + QString m_errorString; + QPlaceSearchRequest m_previousPageRequest; + QPlaceSearchRequest m_nextPageRequest; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVESEARCHMODELBASE_H diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp new file mode 100644 index 00000000..31d152db --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel.cpp @@ -0,0 +1,917 @@ +/**************************************************************************** +** +** 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 "qdeclarativesearchresultmodel_p.h" +#include "qdeclarativeplace_p.h" +#include "qdeclarativeplaceicon_p.h" + +#include <QtQml/QQmlEngine> +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> +#include <QtLocation/QPlaceSearchReply> +#include <QtLocation/QPlaceManager> +#include <QtLocation/QPlaceMatchRequest> +#include <QtLocation/QPlaceMatchReply> +#include <QtLocation/QPlaceResult> +#include <QtLocation/QPlaceProposedSearchResult> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PlaceSearchModel + \instantiates QDeclarativeSearchResultModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief Provides access to place search results. + + PlaceSearchModel provides a model of place search results within the \l searchArea. The + \l searchTerm and \l categories properties can be set to restrict the search results to + places matching those criteria. + + The PlaceSearchModel returns both sponsored and + \l {http://en.wikipedia.org/wiki/Organic_search}{organic search results}. Sponsored search + results will have the \c sponsored role set to true. + + \target PlaceSearchModel Roles + The model returns data for the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li type + \li enum + \li The type of search result. + \row + \li title + \li string + \li A string describing the search result. + \row + \li icon + \li PlaceIcon + \li Icon representing the search result. + \row + \li distance + \li real + \li Valid only when the \c type role is \c PlaceResult, the distance to the place + from the center of the \l searchArea. If no \l searchArea + has been specified, the distance is NaN. + \row + \li place + \li \l Place + \li Valid only when the \c type role is \c PlaceResult, an object representing the + place. + \row + \li sponsored + \li bool + \li Valid only when the \c type role is \c PlaceResult, true if the search result is a + sponsored result. + \endtable + + \section2 Search Result Types + + The \c type role can take on the following values: + + \table + \row + \li PlaceSearchModel.UnknownSearchResult + \li The contents of the search result are unknown. + \row + \li PlaceSearchModel.PlaceResult + \li The search result contains a place. + \row + \li PlaceSearchModel.ProposedSearchResult + \li The search result contains a proposed search which may be relevant. + \endtable + + + It can often be helpful to use a \l Loader to create a delegate + that will choose different \l {Component}s based on the search result type. + + \snippet declarative/places_loader.qml Handle Result Types + + \section1 Detection of Updated and Removed Places + + The PlaceSearchModel listens for places that have been updated or removed from its plugin's backend. + If it detects that a place has been updated and that place is currently present in the model, then + it will call \l Place::getDetails to refresh the details. If it detects that a place has been + removed, then correspondingly the place will be removed from the model if it is currently + present. + + \section1 Example + + The following example shows how to use the PlaceSearchModel to search for Pizza restaurants in + close proximity of a given position. A \l searchTerm and \l searchArea are provided to the model + and \l update() is used to perform a lookup query. Note that the model does not incrementally + fetch search results, but rather performs a single fetch when \l update() is run. The \l count + is set to the number of search results returned during the fetch. + + \snippet places_list/places_list.qml Imports + \codeline + \snippet places_list/places_list.qml PlaceSearchModel + + \sa CategoryModel, {QPlaceManager} + + \section1 Paging + The PlaceSearchModel API has some limited support + for paging. The \l nextPage() and \l previousPage() functions as well as + the \l limit property can be used to access + paged search results. When the \l limit property is set + the search result page contains at most \l limit entries (of type place result). + For example, if the backend has 5 search results in total + [a,b,c,d,e], and assuming the first page is shown and limit of 3 has been set + then a,b,c is returned. The \l nextPage() would return d,e. The + \l nextPagesAvailable and \l previousPagesAvailable properties + can be used to check for further pages. At the moment the API does not + support the means to retrieve the total number of items available from the + backed. Note that support for \l nextPage(), previousPage() and \l limit can vary + according to the \l plugin. +*/ + +/*! + \qmlproperty Plugin PlaceSearchModel::plugin + + This property holds the \l Plugin which will be used to perform the search. +*/ + +/*! + \qmlproperty Plugin PlaceSearchModel::favoritesPlugin + + This property holds the \l Plugin which will be used to search for favorites. + Any places from the search which can be cross-referenced or matched + in the favoritesPlugin will have their \l {Place::favorite}{favorite} property + set to the corresponding \l Place from the favoritesPlugin. + + If the favoritesPlugin is not set, the \l {Place::favorite}{favorite} property + of the places in the results will always be null. + + \sa Favorites +*/ + +/*! + \qmlproperty VariantMap PlaceSearchModel::favoritesMatchParameters + + This property holds a set of parameters used to specify how search result places + are matched to favorites in the favoritesPlugin. + + By default the parameter map is empty and implies that the favorites plugin + matches by \l {Alternative Identifier Cross-Referencing}{alternative identifiers}. Generally, + an application developer will not need to set this property. + + In cases where the favorites plugin does not support matching by alternative identifiers, + then the \l {Qt Location#Plugin References and Parameters}{plugin documentation} should + be consulted to see precisely what key-value parameters to set. +*/ + +/*! + \qmlproperty variant PlaceSearchModel::searchArea + + This property holds the search area. The search result returned by the model will be within + the search area. + + If this property is set to a \l {geocircle} its + \l {geocircle}{radius} property may be left unset, in which case the \l Plugin + will choose an appropriate radius for the search. + + Support for specifying a search area can vary according to the \l plugin backend + implementation. For example, some may support a search center only while others may only + support geo rectangles. +*/ + +/*! + \qmlproperty int PlaceSearchModel::limit + + This property holds the limit of the number of items that will be returned. +*/ + +/*! + \qmlproperty bool PlaceSearchModel::previousPagesAvailable + + This property holds whether there is one or more previous pages of search results available. + + \sa previousPage() +*/ + +/*! + \qmlproperty bool PlaceSearchModel::nextPagesAvailable + + This property holds whether there is one or more additional pages of search results available. + + \sa nextPage() +*/ + +/*! + \qmlproperty enum PlaceSearchModel::status + + This property holds the status of the model. It can be one of: + + \table + \row + \li PlaceSearchModel.Null + \li No search query has been executed. The model is empty. + \row + \li PlaceSearchModel.Ready + \li The search query has completed, and the results are available. + \row + \li PlaceSearchModel.Loading + \li A search query is currently being executed. + \row + \li PlaceSearchModel.Error + \li An error occurred when executing the previous search query. + \endtable +*/ + +/*! + \qmlmethod void PlaceSearchModel::update() + + Updates the model based on the provided query parameters. The model will be populated with a + list of places matching the search parameters specified by the type's properties. Search + criteria is specified by setting properties such as the \l searchTerm, \l categories, \l searchArea and \l limit. + Support for these properties may vary according to \l plugin. \c update() then + submits the set of criteria to the \l plugin to process. + + While the model is updating the \l status of the model is set to + \c PlaceSearchModel.Loading. If the model is successfully updated the \l status is set to + \c PlaceSearchModel.Ready, while if it unsuccessfully completes, the \l status is set to + \c PlaceSearchModel.Error and the model cleared. + + \code + PlaceSearchModel { + id: model + plugin: backendPlugin + searchArea: QtPositioning.circle(QtPositioning.coordinate(10, 10)) + ... + } + + MouseArea { + ... + onClicked: { + model.searchTerm = "pizza"; + model.categories = null; //not searching by any category + model.searchArea.center.latitude = -27.5; + model.searchArea.center.longitude = 153; + model.update(); + } + } + \endcode + + \sa cancel(), status +*/ + +/*! + \qmlmethod void PlaceSearchModel::cancel() + + Cancels an ongoing search operation immediately and sets the model + status to PlaceSearchModel.Ready. The model retains any search + results it had before the operation was started. + + If an operation is not ongoing, invoking cancel() has no effect. + + \sa update(), status +*/ + +/*! + \qmlmethod void PlaceSearchModel::reset() + + Resets the model. All search results are cleared, any outstanding requests are aborted and + possible errors are cleared. Model status will be set to PlaceSearchModel.Null. +*/ + +/*! + \qmlmethod string PlaceSearchModel::errorString() const + + This read-only property holds the textual presentation of the latest place search model error. + If no error has occurred or if the model was cleared, an empty string is returned. + + An empty string may also be returned if an error occurred which has no associated + textual representation. +*/ + +/*! + \qmlmethod void PlaceSearchModel::previousPage() + + Updates the model to display the previous page of search results. If there is no previous page + then this method does nothing. +*/ + +/*! + \qmlmethod void PlaceSearchModel::nextPage() + + Updates the model to display the next page of search results. If there is no next page then + this method does nothing. +*/ + +QDeclarativeSearchResultModel::QDeclarativeSearchResultModel(QObject *parent) + : QDeclarativeSearchModelBase(parent), m_favoritesPlugin(0) +{ +} + +QDeclarativeSearchResultModel::~QDeclarativeSearchResultModel() +{ +} + +/*! + \qmlproperty string PlaceSearchModel::searchTerm + + This property holds search term used in query. The search term is a free-form text string. +*/ +QString QDeclarativeSearchResultModel::searchTerm() const +{ + return m_request.searchTerm(); +} + +void QDeclarativeSearchResultModel::setSearchTerm(const QString &searchTerm) +{ + m_request.setSearchContext(QVariant()); + + if (m_request.searchTerm() == searchTerm) + return; + + m_request.setSearchTerm(searchTerm); + emit searchTermChanged(); +} + +/*! + \qmlproperty list<Category> PlaceSearchModel::categories + + This property holds a list of categories to be used when searching. Returned search results + will be for places that match at least one of the categories. +*/ +QQmlListProperty<QDeclarativeCategory> QDeclarativeSearchResultModel::categories() +{ + return QQmlListProperty<QDeclarativeCategory>(this, + 0, // opaque data parameter + categories_append, + categories_count, + category_at, + categories_clear); +} + +void QDeclarativeSearchResultModel::categories_append(QQmlListProperty<QDeclarativeCategory> *list, + QDeclarativeCategory *declCategory) +{ + QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object); + if (searchModel && declCategory) { + searchModel->m_request.setSearchContext(QVariant()); + searchModel->m_categories.append(declCategory); + QList<QPlaceCategory> categories = searchModel->m_request.categories(); + categories.append(declCategory->category()); + searchModel->m_request.setCategories(categories); + emit searchModel->categoriesChanged(); + } +} + +int QDeclarativeSearchResultModel::categories_count(QQmlListProperty<QDeclarativeCategory> *list) +{ + QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object); + if (searchModel) + return searchModel->m_categories.count(); + else + return -1; +} + +QDeclarativeCategory *QDeclarativeSearchResultModel::category_at(QQmlListProperty<QDeclarativeCategory> *list, + int index) +{ + QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object); + if (searchModel && (searchModel->m_categories.count() > index) && (index > -1)) + return searchModel->m_categories.at(index); + else + return 0; +} + +void QDeclarativeSearchResultModel::categories_clear(QQmlListProperty<QDeclarativeCategory> *list) +{ + QDeclarativeSearchResultModel *searchModel = qobject_cast<QDeclarativeSearchResultModel *>(list->object); + if (searchModel) { + //note: we do not need to delete each of the objects in m_categories since the search model + //should never be the parent of the categories anyway. + searchModel->m_request.setSearchContext(QVariant()); + searchModel->m_categories.clear(); + searchModel->m_request.setCategories(QList<QPlaceCategory>()); + emit searchModel->categoriesChanged(); + } +} + +/*! + \qmlproperty string PlaceSearchModel::recommendationId + + This property holds the placeId to be used in order to find recommendations + for similar places. +*/ +QString QDeclarativeSearchResultModel::recommendationId() const +{ + return m_request.recommendationId(); +} + +void QDeclarativeSearchResultModel::setRecommendationId(const QString &placeId) +{ + if (m_request.recommendationId() == placeId) + return; + + m_request.setRecommendationId(placeId); + emit recommendationIdChanged(); +} + +/*! + \qmlproperty enumeration PlaceSearchModel::relevanceHint + + This property holds a relevance hint used in the search query. The hint is given to the + provider to help but not dictate the ranking of results. For example, the distance hint may + give closer places a higher ranking but it does not necessarily mean the results will be + strictly ordered according to distance. A provider may ignore the hint altogether. + + \table + \row + \li SearchResultModel.UnspecifiedHint + \li No relevance hint is given to the provider. + \row + \li SearchResultModel.DistanceHint + \li The distance of the place from the user's current location is important to the user. + This hint is only meaningful when a circular search area is used. + \row + \li SearchResultModel.LexicalPlaceNameHint + \li The lexical ordering of place names (in ascending alphabetical order) is relevant to + the user. This hint is useful for providers based on a local data store. + \endtable +*/ +QDeclarativeSearchResultModel::RelevanceHint QDeclarativeSearchResultModel::relevanceHint() const +{ + return static_cast<QDeclarativeSearchResultModel::RelevanceHint>(m_request.relevanceHint()); +} + +void QDeclarativeSearchResultModel::setRelevanceHint(QDeclarativeSearchResultModel::RelevanceHint hint) +{ + if (m_request.relevanceHint() != static_cast<QPlaceSearchRequest::RelevanceHint>(hint)) { + m_request.setRelevanceHint(static_cast<QPlaceSearchRequest::RelevanceHint>(hint)); + emit relevanceHintChanged(); + } +} + +/*! + \qmlproperty enum PlaceSearchModel::visibilityScope + + This property holds the visibility scope of the places to search. Only places with the + specified visibility will be returned in the search results. + + The visibility scope can be one of: + + \table + \row + \li Place.UnspecifiedVisibility + \li No explicit visibility scope specified, places with any visibility may be part of + search results. + \row + \li Place.DeviceVisibility + \li Only places stored on the local device will be part of the search results. + \row + \li Place.PrivateVisibility + \li Only places that are private to the current user will be part of the search results. + \row + \li Place.PublicVisibility + \li Only places that are public will be part of the search results. + \endtable +*/ +QDeclarativePlace::Visibility QDeclarativeSearchResultModel::visibilityScope() const +{ + return QDeclarativePlace::Visibility(int(m_visibilityScope)); +} + +void QDeclarativeSearchResultModel::setVisibilityScope(QDeclarativePlace::Visibility visibilityScope) +{ + QLocation::VisibilityScope scope = QLocation::VisibilityScope(visibilityScope); + + if (m_visibilityScope == scope) + return; + + m_visibilityScope = scope; + emit visibilityScopeChanged(); +} + +/*! + \internal +*/ +QDeclarativeGeoServiceProvider *QDeclarativeSearchResultModel::favoritesPlugin() const +{ + return m_favoritesPlugin; +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::setFavoritesPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + + if (m_favoritesPlugin == plugin) + return; + + m_favoritesPlugin = plugin; + + if (m_favoritesPlugin) { + QGeoServiceProvider *serviceProvider = m_favoritesPlugin->sharedGeoServiceProvider(); + if (serviceProvider) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + if (placeManager->childCategoryIds().isEmpty()) { + QPlaceReply *reply = placeManager->initializeCategories(); + connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater())); + } + } + } + } + + emit favoritesPluginChanged(); +} + +/*! + \internal +*/ +QVariantMap QDeclarativeSearchResultModel::favoritesMatchParameters() const +{ + return m_matchParameters; +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::setFavoritesMatchParameters(const QVariantMap ¶meters) +{ + if (m_matchParameters == parameters) + return; + + m_matchParameters = parameters; + emit favoritesMatchParametersChanged(); +} + +/*! + \internal +*/ +int QDeclarativeSearchResultModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + + return m_results.count(); +} + +void QDeclarativeSearchResultModel::clearData(bool suppressSignal) +{ + QDeclarativeSearchModelBase::clearData(suppressSignal); + + qDeleteAll(m_places); + m_places.clear(); + qDeleteAll(m_icons); + m_icons.clear(); + if (!m_results.isEmpty()) { + m_results.clear(); + + if (!suppressSignal) + emit rowCountChanged(); + } +} + +QVariant QDeclarativeSearchResultModel::data(const QModelIndex &index, int role) const +{ + if (index.row() > m_results.count()) + return QVariant(); + + const QPlaceSearchResult &result = m_results.at(index.row()); + + switch (role) { + case SearchResultTypeRole: + return result.type(); + case Qt::DisplayRole: + case TitleRole: + return result.title(); + case IconRole: + return QVariant::fromValue(static_cast<QObject *>(m_icons.at(index.row()))); + case DistanceRole: + if (result.type() == QPlaceSearchResult::PlaceResult) { + QPlaceResult placeResult = result; + return placeResult.distance(); + } + break; + case PlaceRole: + if (result.type() == QPlaceSearchResult::PlaceResult) + return QVariant::fromValue(static_cast<QObject *>(m_places.at(index.row()))); + case SponsoredRole: + if (result.type() == QPlaceSearchResult::PlaceResult) { + QPlaceResult placeResult = result; + return placeResult.isSponsored(); + } + break; + } + return QVariant(); +} + +/*! + \internal +*/ +QVariant QDeclarativeSearchResultModel::data(int index, const QString &role) const +{ + QModelIndex modelIndex = createIndex(index, 0); + return data(modelIndex, roleNames().key(role.toLatin1())); +} + +QHash<int, QByteArray> QDeclarativeSearchResultModel::roleNames() const +{ + QHash<int, QByteArray> roles = QDeclarativeSearchModelBase::roleNames(); + roles.insert(SearchResultTypeRole, "type"); + roles.insert(TitleRole, "title"); + roles.insert(IconRole, "icon"); + roles.insert(DistanceRole, "distance"); + roles.insert(PlaceRole, "place"); + roles.insert(SponsoredRole, "sponsored"); + + return roles; +} + +/*! + \qmlmethod void PlaceSearchModel::updateWith(int proposedSearchIndex) + + Updates the model based on the ProposedSearchResult at index \a proposedSearchIndex. The model + will be populated with a list of places matching the proposed search. Model status will be set + to PlaceSearchModel.Loading. If the model is updated successfully status will be set to + PlaceSearchModel.Ready. If an error occurs status will be set to PlaceSearchModel.Error and the + model cleared. + + If \a proposedSearchIndex does not reference a ProposedSearchResult this method does nothing. +*/ +void QDeclarativeSearchResultModel::updateWith(int proposedSearchIndex) +{ + if (m_results.at(proposedSearchIndex).type() != QPlaceSearchResult::ProposedSearchResult) + return; + + m_request = QPlaceProposedSearchResult(m_results.at(proposedSearchIndex)).searchRequest(); + update(); +} + +QPlaceReply *QDeclarativeSearchResultModel::sendQuery(QPlaceManager *manager, + const QPlaceSearchRequest &request) +{ + Q_ASSERT(manager); + return manager->search(request); +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::initializePlugin(QDeclarativeGeoServiceProvider *plugin) +{ + //disconnect the manager of the old plugin if we have one + if (m_plugin) { + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (serviceProvider) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + disconnect(placeManager, SIGNAL(placeUpdated(QString)), this, SLOT(placeUpdated(QString))); + disconnect(placeManager, SIGNAL(placeRemoved(QString)), this, SLOT(placeRemoved(QString))); + connect(placeManager, SIGNAL(dataChanged()), this, SIGNAL(dataChanged())); + } + } + } + + //connect to the manager of the new plugin. + if (plugin) { + QGeoServiceProvider *serviceProvider = plugin->sharedGeoServiceProvider(); + if (serviceProvider) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + connect(placeManager, SIGNAL(placeUpdated(QString)), this, SLOT(placeUpdated(QString))); + connect(placeManager, SIGNAL(placeRemoved(QString)), this, SLOT(placeRemoved(QString))); + disconnect(placeManager, SIGNAL(dataChanged()), this, SIGNAL(dataChanged())); + } + } + } + QDeclarativeSearchModelBase::initializePlugin(plugin); +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::queryFinished() +{ + if (!m_reply) + return; + QPlaceReply *reply = m_reply; + m_reply = 0; + if (reply->error() != QPlaceReply::NoError) { + m_resultsBuffer.clear(); + updateLayout(); + setStatus(Error, reply->errorString()); + reply->deleteLater(); + return; + } + + if (reply->type() == QPlaceReply::SearchReply) { + QPlaceSearchReply *searchReply = qobject_cast<QPlaceSearchReply *>(reply); + Q_ASSERT(searchReply); + + m_resultsBuffer = searchReply->results(); + setPreviousPageRequest(searchReply->previousPageRequest()); + setNextPageRequest(searchReply->nextPageRequest()); + + reply->deleteLater(); + + if (!m_favoritesPlugin) { + updateLayout(); + setStatus(Ready); + } else { + QGeoServiceProvider *serviceProvider = m_favoritesPlugin->sharedGeoServiceProvider(); + if (!serviceProvider) { + updateLayout(); + setStatus(Error, QStringLiteral("Favorites plugin returns a null QGeoServiceProvider instance")); + return; + } + + QPlaceManager *favoritesManager = serviceProvider->placeManager(); + if (!favoritesManager) { + updateLayout(); + setStatus(Error, QStringLiteral("Favorites plugin returns a null QPlaceManager")); + return; + } + + QPlaceMatchRequest request; + if (m_matchParameters.isEmpty()) { + if (!m_plugin) { + reply->deleteLater(); + setStatus(Error, QStringLiteral("Plugin not assigned")); + return; + } + + QVariantMap params; + params.insert(QPlaceMatchRequest::AlternativeId, QVariant(QString::fromLatin1("x_id_") + m_plugin->name())); + request.setParameters(params); + } else { + request.setParameters(m_matchParameters); + } + + request.setResults(m_resultsBuffer); + m_reply = favoritesManager->matchingPlaces(request); + connect(m_reply, SIGNAL(finished()), this, SLOT(queryFinished())); + } + } else if (reply->type() == QPlaceReply::MatchReply) { + QPlaceMatchReply *matchReply = qobject_cast<QPlaceMatchReply *>(reply); + Q_ASSERT(matchReply); + updateLayout(matchReply->places()); + setStatus(Ready); + reply->deleteLater(); + } else { + setStatus(Error, QStringLiteral("Unknown reply type")); + reply->deleteLater(); + } +} + +/*! + \qmlmethod void PlaceSearchModel::data(int index, string role) + + Returns the data for a given \a role at the specified row \a index. +*/ + +/*! + \qmlproperty int PlaceSearchModel::count + + This property holds the number of results the model has. + + Note that it does not refer to the total number of search results + available in the backend. The total number of search results + is not currently supported by the API. +*/ + +/*! + \internal + Note: m_results buffer should be correctly populated before + calling this function +*/ +void QDeclarativeSearchResultModel::updateLayout(const QList<QPlace> &favoritePlaces) +{ + int oldRowCount = rowCount(); + + beginResetModel(); + clearData(true); + m_results = m_resultsBuffer; + m_resultsBuffer.clear(); + + for (int i = 0; i < m_results.count(); ++i) { + const QPlaceSearchResult &result = m_results.at(i); + + if (result.type() == QPlaceSearchResult::PlaceResult) { + QPlaceResult placeResult = result; + QDeclarativePlace *place = new QDeclarativePlace(placeResult.place(), plugin(), this); + m_places.append(place); + + if ((favoritePlaces.count() == m_results.count()) && favoritePlaces.at(i) != QPlace()) + m_places[i]->setFavorite(new QDeclarativePlace(favoritePlaces.at(i), + m_favoritesPlugin, m_places[i])); + } else if (result.type() == QPlaceSearchResult::ProposedSearchResult) { + m_places.append(0); + } + + QDeclarativePlaceIcon *icon = 0; + if (!result.icon().isEmpty()) + icon = new QDeclarativePlaceIcon(result.icon(), plugin(), this); + m_icons.append(icon); + } + + endResetModel(); + if (m_results.count() != oldRowCount) + emit rowCountChanged(); +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::placeUpdated(const QString &placeId) +{ + int row = getRow(placeId); + if (row < 0 || row > m_places.count()) + return; + + if (m_places.at(row)) + m_places.at(row)->getDetails(); +} + +/*! + \internal +*/ +void QDeclarativeSearchResultModel::placeRemoved(const QString &placeId) +{ + int row = getRow(placeId); + if (row < 0 || row > m_places.count()) + return; + + beginRemoveRows(QModelIndex(), row, row); + delete m_places.at(row); + m_places.removeAt(row); + m_results.removeAt(row); + endRemoveRows(); + + emit rowCountChanged(); +} + +/*! + \internal +*/ +int QDeclarativeSearchResultModel::getRow(const QString &placeId) const +{ + for (int i = 0; i < m_places.count(); ++i) { + if (!m_places.at(i)) + continue; + else if (m_places.at(i)->placeId() == placeId) + return i; + } + + return -1; +} + +/*! + \qmlsignal PlaceSearchResultModel::dataChanged() + + This signal is emitted when significant changes have been made to the underlying datastore. + + Applications should act on this signal at their own discretion. The data + provided by the model could be out of date and so the model should be reupdated + sometime, however an immediate reupdate may be disconcerting to users if the results + change without any action on their part. + + The corresponding handler is \c onDataChanged. +*/ + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h new file mode 100644 index 00000000..77526fd0 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchresultmodel_p.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESEARCHRESULTMODEL_P_H +#define QDECLARATIVESEARCHRESULTMODEL_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativesearchmodelbase_p.h> +#include <QtLocation/private/qdeclarativecategory_p.h> +#include <QtLocation/private/qdeclarativeplace_p.h> +#include <QtLocation/private/qdeclarativeplaceicon_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeGeoServiceProvider; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchResultModel : public QDeclarativeSearchModelBase +{ + Q_OBJECT + + Q_PROPERTY(QString searchTerm READ searchTerm WRITE setSearchTerm NOTIFY searchTermChanged) + Q_PROPERTY(QQmlListProperty<QDeclarativeCategory> categories READ categories NOTIFY categoriesChanged) + Q_PROPERTY(QString recommendationId READ recommendationId WRITE setRecommendationId NOTIFY recommendationIdChanged) + Q_PROPERTY(RelevanceHint relevanceHint READ relevanceHint WRITE setRelevanceHint NOTIFY relevanceHintChanged) + Q_PROPERTY(QDeclarativePlace::Visibility visibilityScope READ visibilityScope WRITE setVisibilityScope NOTIFY visibilityScopeChanged) + + Q_PROPERTY(int count READ rowCount NOTIFY rowCountChanged) + Q_PROPERTY(QDeclarativeGeoServiceProvider *favoritesPlugin READ favoritesPlugin WRITE setFavoritesPlugin NOTIFY favoritesPluginChanged) + Q_PROPERTY(QVariantMap favoritesMatchParameters READ favoritesMatchParameters WRITE setFavoritesMatchParameters NOTIFY favoritesMatchParametersChanged) + + Q_ENUMS(SearchResultType RelevanceHint) + +public: + enum SearchResultType { + UnknownSearchResult = QPlaceSearchResult::UnknownSearchResult, + PlaceResult = QPlaceSearchResult::PlaceResult, + ProposedSearchResult = QPlaceSearchResult::ProposedSearchResult + }; + + enum RelevanceHint { + UnspecifiedHint = QPlaceSearchRequest::UnspecifiedHint, + DistanceHint = QPlaceSearchRequest::DistanceHint, + LexicalPlaceNameHint = QPlaceSearchRequest::LexicalPlaceNameHint + }; + + explicit QDeclarativeSearchResultModel(QObject *parent = 0); + ~QDeclarativeSearchResultModel(); + + QString searchTerm() const; + void setSearchTerm(const QString &searchTerm); + + QQmlListProperty<QDeclarativeCategory> categories(); + static void categories_append(QQmlListProperty<QDeclarativeCategory> *list, + QDeclarativeCategory *category); + static int categories_count(QQmlListProperty<QDeclarativeCategory> *list); + static QDeclarativeCategory *category_at(QQmlListProperty<QDeclarativeCategory> *list, int index); + static void categories_clear(QQmlListProperty<QDeclarativeCategory> *list); + + QString recommendationId() const; + void setRecommendationId(const QString &recommendationId); + + QDeclarativeSearchResultModel::RelevanceHint relevanceHint() const; + void setRelevanceHint(QDeclarativeSearchResultModel::RelevanceHint hint); + + QDeclarativePlace::Visibility visibilityScope() const; + void setVisibilityScope(QDeclarativePlace::Visibility visibilityScope); + + QDeclarativeGeoServiceProvider *favoritesPlugin() const; + void setFavoritesPlugin(QDeclarativeGeoServiceProvider *plugin); + + QVariantMap favoritesMatchParameters() const; + void setFavoritesMatchParameters(const QVariantMap ¶meters); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + + virtual void clearData(bool suppressSignal = false); + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + Q_INVOKABLE QVariant data(int index, const QString &roleName) const; + QHash<int, QByteArray> roleNames() const; + + Q_INVOKABLE void updateWith(int proposedSearchIndex); + + void updateSearchRequest(); + +Q_SIGNALS: + void searchTermChanged(); + void categoriesChanged(); + void recommendationIdChanged(); + void relevanceHintChanged(); + void visibilityScopeChanged(); + + void rowCountChanged(); + void favoritesPluginChanged(); + void favoritesMatchParametersChanged(); + void dataChanged(); + +protected: + QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request); + virtual void initializePlugin(QDeclarativeGeoServiceProvider *plugin); + +protected Q_SLOTS: + virtual void queryFinished(); + +private Q_SLOTS: + void updateLayout(const QList<QPlace> &favoritePlaces = QList<QPlace>()); + + void placeUpdated(const QString &placeId); + void placeRemoved(const QString &placeId); + +private: + enum Roles { + SearchResultTypeRole = Qt::UserRole, + TitleRole, + IconRole, + DistanceRole, + PlaceRole, + SponsoredRole + }; + + int getRow(const QString &placeId) const; + QList<QDeclarativeCategory *> m_categories; + QLocation::VisibilityScope m_visibilityScope; + + QList<QPlaceSearchResult> m_results; + QList<QPlaceSearchResult> m_resultsBuffer; + QList<QDeclarativePlace *> m_places; + QList<QDeclarativePlaceIcon *> m_icons; + + QDeclarativeGeoServiceProvider *m_favoritesPlugin; + QVariantMap m_matchParameters; +}; + +QT_END_NAMESPACE + +#endif // QDECLARATIVESEARCHRESULTMODEL_P_H diff --git a/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp new file mode 100644 index 00000000..95cd3277 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel.cpp @@ -0,0 +1,353 @@ +/**************************************************************************** +** +** 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 "qdeclarativesearchsuggestionmodel_p.h" +#include "qdeclarativegeoserviceprovider_p.h" + +#include <QtQml/QQmlInfo> +#include <QtLocation/QGeoServiceProvider> + +#include <qplacemanager.h> +#include <qplacesearchrequest.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype PlaceSearchSuggestionModel + \instantiates QDeclarativeSearchSuggestionModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief Provides access to search term suggestions. + + The PlaceSearchSuggestionModel can be used to provide search term suggestions as the user enters their + search term. The properties of this model should match that of the \l PlaceSearchModel, which + will be used to perform the actual search query, to ensure that the search suggestion results are + relevant. + + There are two ways of accessing the data provided by this model, either through the + \l suggestions property or through views and delegates. The latter is the preferred + method. + + The \l offset and \l limit properties can be used to access paged suggestions. When the + \l offset and \l limit properties are set the suggestions between \l offset and + (\l offset + \l limit - 1) will be returned. Support for paging may vary + from plugin to plugin. + + The model returns data for the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li suggestion + \li string + \li Suggested search term. + \endtable + + The following example shows how to use the PlaceSearchSuggestionModel to get suggested search terms + from a partial search term. The \l searchArea is set to match what would be used to perform the + actual place search with \l PlaceSearchModel. + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml SearchSuggestionModel + + \sa PlaceSearchModel, {QPlaceManager} +*/ + +/*! + \qmlproperty Plugin PlaceSearchSuggestionModel::plugin + + This property holds the provider \l Plugin which will be used to perform the search. +*/ + +/*! + \qmlproperty geoshape PlaceSearchSuggestionModel::searchArea + + This property holds the search area. Search suggestion results returned by the model will be + relevant to the given search area. + + If this property is set to a \l {geocircle} its + \l {geocircle}{radius} property may be left unset, in which case the \l Plugin + will choose an appropriate radius for the search. +*/ + +/*! + \qmlproperty int PlaceSearchSuggestionModel::offset + + This property holds the index of the first item in the model. + + \sa limit +*/ + +/*! + \qmlproperty int PlaceSearchSuggestionModel::limit + + This property holds the limit of the number of items that will be returned. + + \sa offset +*/ + +/*! + \qmlproperty enum PlaceSearchSuggestionModel::status + + This property holds the status of the model. It can be one of: + + \table + \row + \li PlaceSearchSuggestionModel.Null + \li No search query has been executed. The model is empty. + \row + \li PlaceSearchSuggestionModel.Ready + \li The search query has completed, and the results are available. + \row + \li PlaceSearchSuggestionModel.Loading + \li A search query is currently being executed. + \row + \li PlaceSearchSuggestionModel.Error + \li An error occurred when executing the previous search query. + \endtable +*/ + +/*! + \qmlmethod void PlaceSearchSuggestionModel::update() + + Updates the model based on the provided query parameters. The model will be populated with a + list of search suggestions for the partial \l searchTerm and \l searchArea. If the \l plugin + supports it, other parameters such as \l limit and \l offset may be specified. \c update() + submits the set of parameters to the \l plugin to process. + + + While the model is updating the \l status of the model is set to + \c PlaceSearchSuggestionModel.Loading. If the model is successfully updated, the \l status is + set to \c PlaceSearchSuggestionModel.Ready, while if it unsuccessfully completes, the \l status + is set to \c PlaceSearchSuggestionModel.Error and the model cleared. + + This example shows use of the model + \code + PlaceSeachSuggestionModel { + id: model + plugin: backendPlugin + searchArea: QtPositioning.circle(QtPositioning.coordinate(10, 10)) + ... + } + + MouseArea { + ... + onClicked: { + model.searchTerm = "piz" + model.searchArea.center.latitude = -27.5; + model.searchArea.cetner.longitude = 153; + model.update(); + } + } + \endcode + + A more detailed example can be found in the in + \l {Places (QML)#Presenting-Search-Suggestions}{Places (QML)} example. + + \sa cancel(), status +*/ + +/*! + \qmlmethod void PlaceSearchSuggestionModel::cancel() + + Cancels an ongoing search suggestion operation immediately and sets the model + status to PlaceSearchSuggestionModel.Ready. The model retains any search + suggestions it had before the operation was started. + + If an operation is not ongoing, invoking cancel() has no effect. + + \sa update(), status +*/ + +/*! + \qmlmethod void PlaceSearchSuggestionModel::reset() + + Resets the model. All search suggestions are cleared, any outstanding requests are aborted and + possible errors are cleared. Model status will be set to PlaceSearchSuggestionModel.Null. +*/ + + +/*! + \qmlmethod string QtLocation::PlaceSearchSuggestionModel::errorString() const + + This read-only property holds the textual presentation of the latest search suggestion model error. + If no error has occurred, or if the model was cleared, an empty string is returned. + + An empty string may also be returned if an error occurred which has no associated + textual representation. +*/ + +QDeclarativeSearchSuggestionModel::QDeclarativeSearchSuggestionModel(QObject *parent) +: QDeclarativeSearchModelBase(parent) +{ +} + +QDeclarativeSearchSuggestionModel::~QDeclarativeSearchSuggestionModel() +{ +} + +/*! + \qmlproperty string PlaceSearchSuggestionModel::searchTerm + + This property holds the partial search term used in query. +*/ +QString QDeclarativeSearchSuggestionModel::searchTerm() const +{ + return m_request.searchTerm(); +} + +void QDeclarativeSearchSuggestionModel::setSearchTerm(const QString &searchTerm) +{ + if (m_request.searchTerm() == searchTerm) + return; + + m_request.setSearchTerm(searchTerm); + emit searchTermChanged(); +} + +/*! + \qmlproperty stringlist PlaceSearchSuggestionModel::suggestions + + This property holds the list of predicted search terms that the model currently has. +*/ +QStringList QDeclarativeSearchSuggestionModel::suggestions() const +{ + return m_suggestions; +} + +/*! + \internal +*/ +void QDeclarativeSearchSuggestionModel::clearData(bool suppressSignal) +{ + QDeclarativeSearchModelBase::clearData(suppressSignal); + + if (!m_suggestions.isEmpty()) { + m_suggestions.clear(); + + if (!suppressSignal) + emit suggestionsChanged(); + } +} + +/*! + \internal +*/ +int QDeclarativeSearchSuggestionModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return m_suggestions.count(); +} + +/*! + \internal +*/ +QVariant QDeclarativeSearchSuggestionModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= rowCount(index.parent()) || index.row() < 0) + return QVariant(); + + switch (role) { + case Qt::DisplayRole: + case SearchSuggestionRole: + return m_suggestions.at(index.row()); + } + + return QVariant(); +} + +QHash<int, QByteArray> QDeclarativeSearchSuggestionModel::roleNames() const +{ + QHash<int, QByteArray> roleNames = QDeclarativeSearchModelBase::roleNames(); + roleNames.insert(SearchSuggestionRole, "suggestion"); + return roleNames; +} + +/*! + \internal +*/ +void QDeclarativeSearchSuggestionModel::queryFinished() +{ + if (!m_reply) + return; + + QPlaceReply *reply = m_reply; + m_reply = 0; + + int initialCount = m_suggestions.count(); + beginResetModel(); + + clearData(true); + + QPlaceSearchSuggestionReply *suggestionReply = qobject_cast<QPlaceSearchSuggestionReply *>(reply); + m_suggestions = suggestionReply->suggestions(); + + if (initialCount != m_suggestions.count()) + emit suggestionsChanged(); + + endResetModel(); + + if (suggestionReply->error() != QPlaceReply::NoError) + setStatus(Error, suggestionReply->errorString()); + else + setStatus(Ready); + + + reply->deleteLater(); +} + +/*! + \internal +*/ +QPlaceReply *QDeclarativeSearchSuggestionModel::sendQuery(QPlaceManager *manager, + const QPlaceSearchRequest &request) +{ + return manager->searchSuggestions(request); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h new file mode 100644 index 00000000..5d75ee4b --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesearchsuggestionmodel_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESEARCHSUGGESTIONMODEL_P_H +#define QDECLARATIVESEARCHSUGGESTIONMODEL_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativesearchmodelbase_p.h> + +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QDeclarativeGeoServiceProvider; +class QGeoServiceProvider; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSearchSuggestionModel : public QDeclarativeSearchModelBase +{ + Q_OBJECT + + Q_PROPERTY(QString searchTerm READ searchTerm WRITE setSearchTerm NOTIFY searchTermChanged) + Q_PROPERTY(QStringList suggestions READ suggestions NOTIFY suggestionsChanged) + +public: + explicit QDeclarativeSearchSuggestionModel(QObject *parent = 0); + ~QDeclarativeSearchSuggestionModel(); + + QString searchTerm() const; + void setSearchTerm(const QString &searchTerm); + + QStringList suggestions() const; + + void clearData(bool suppressSignal = false); + + // From QAbstractListModel + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + enum Roles { + SearchSuggestionRole = Qt::UserRole + }; + +protected Q_SLOTS: + virtual void queryFinished(); + +Q_SIGNALS: + void searchTermChanged(); + void suggestionsChanged(); + +protected: + QPlaceReply *sendQuery(QPlaceManager *manager, const QPlaceSearchRequest &request); + +private: + QStringList m_suggestions; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/location/declarativeplaces/qdeclarativesupplier.cpp b/src/location/declarativeplaces/qdeclarativesupplier.cpp new file mode 100644 index 00000000..92e9a8fd --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesupplier.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** 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 "qdeclarativesupplier_p.h" + +#include <QtCore/QUrl> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype Supplier + \instantiates QDeclarativeSupplier + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-data + \since Qt Location 5.5 + + \brief Holds data regarding the supplier of a place, a place's image, review, or editorial. + + Each instance represents a set of data about a supplier, which can include + supplier's name, url and icon. The supplier is typically a business or organization. + + Note: The Places API only supports suppliers as 'retrieve-only' objects. Submitting + suppliers to a provider is not a supported use case. + + \sa ImageModel, ReviewModel, EditorialModel + + \section1 Example + + The following example shows how to create and display a supplier in QML: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml Supplier +*/ + +QDeclarativeSupplier::QDeclarativeSupplier(QObject *parent) + : QObject(parent), m_icon(0) +{ +} + +QDeclarativeSupplier::QDeclarativeSupplier(const QPlaceSupplier &src, + QDeclarativeGeoServiceProvider *plugin, + QObject *parent) + : QObject(parent), + m_src(src), + m_icon(0) +{ + setSupplier(src, plugin); +} + +QDeclarativeSupplier::~QDeclarativeSupplier() +{ +} + +/*! + \internal +*/ +void QDeclarativeSupplier::componentComplete() +{ + // delayed instantiation of QObject based properties. + if (!m_icon) + m_icon = new QDeclarativePlaceIcon(this); +} + +/*! + \qmlproperty QPlaceSupplier Supplier::supplier + + For details on how to use this property to interface between C++ and QML see + "\l {Supplier - QPlaceSupplier} {Interfaces between C++ and QML Code}". +*/ +void QDeclarativeSupplier::setSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin) +{ + QPlaceSupplier previous = m_src; + m_src = src; + + if (previous.name() != m_src.name()) + emit nameChanged(); + + if (previous.supplierId() != m_src.supplierId()) + emit supplierIdChanged(); + + if (previous.url() != m_src.url()) + emit urlChanged(); + + if (m_icon && m_icon->parent() == this) { + m_icon->setPlugin(plugin); + m_icon->setIcon(m_src.icon()); + } else if (!m_icon || m_icon->parent() != this) { + m_icon = new QDeclarativePlaceIcon(m_src.icon(), plugin, this); + emit iconChanged(); + } +} + +QPlaceSupplier QDeclarativeSupplier::supplier() +{ + m_src.setIcon(m_icon ? m_icon->icon() : QPlaceIcon()); + return m_src; +} + +/*! + \qmlproperty string Supplier::supplierId + + This property holds the identifier of the supplier. The identifier is unique + to the Plugin backend which provided the supplier and is generally + not suitable for displaying to the user. +*/ + +void QDeclarativeSupplier::setSupplierId(const QString &supplierId) +{ + if (m_src.supplierId() != supplierId) { + m_src.setSupplierId(supplierId); + emit supplierIdChanged(); + } +} + +QString QDeclarativeSupplier::supplierId() const +{ + return m_src.supplierId(); +} + +/*! + \qmlproperty string Supplier::name + + This property holds the name of the supplier which can be displayed + to the user. + + The name can potentially be localized. The language is dependent on the + entity that sets it, typically this is the \l Plugin. The \l {Plugin::locales} + property defines what language is used. +*/ + +void QDeclarativeSupplier::setName(const QString &name) +{ + if (m_src.name() != name) { + m_src.setName(name); + emit nameChanged(); + } +} + +QString QDeclarativeSupplier::name() const +{ + return m_src.name(); +} + +/*! + \qmlproperty url Supplier::url + + This property holds the URL of the supplier's website. +*/ + +void QDeclarativeSupplier::setUrl(const QUrl &url) +{ + if (m_src.url() != url) { + m_src.setUrl(url); + emit urlChanged(); + } +} + +QUrl QDeclarativeSupplier::url() const +{ + return m_src.url(); +} + +/*! + \qmlproperty PlaceIcon Supplier::icon + + This property holds the icon of the supplier. +*/ +QDeclarativePlaceIcon *QDeclarativeSupplier::icon() const +{ + return m_icon; +} + +void QDeclarativeSupplier::setIcon(QDeclarativePlaceIcon *icon) +{ + if (m_icon == icon) + return; + + if (m_icon && m_icon->parent() == this) + delete m_icon; + + m_icon = icon; + emit iconChanged(); +} + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativesupplier_p.h b/src/location/declarativeplaces/qdeclarativesupplier_p.h new file mode 100644 index 00000000..b344d674 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesupplier_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESUPPLIER_P_H +#define QDECLARATIVESUPPLIER_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/qlocationglobal_p.h> +#include <QObject> +#include <QtCore/QUrl> +#include <QtQml/qqml.h> +#include <QtQml/QQmlParserStatus> +#include <QtLocation/qplacesupplier.h> + +#include <QtLocation/private/qdeclarativeplaceicon_p.h> + +QT_BEGIN_NAMESPACE + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupplier : public QObject, public QQmlParserStatus +{ + Q_OBJECT + + Q_PROPERTY(QPlaceSupplier supplier READ supplier WRITE setSupplier) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QString supplierId READ supplierId WRITE setSupplierId NOTIFY supplierIdChanged) + Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) + Q_PROPERTY(QDeclarativePlaceIcon *icon READ icon WRITE setIcon NOTIFY iconChanged) + + Q_INTERFACES(QQmlParserStatus) + +public: + explicit QDeclarativeSupplier(QObject *parent = 0); + explicit QDeclarativeSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin, QObject *parent = 0); + ~QDeclarativeSupplier(); + + // From QQmlParserStatus + void classBegin() { } + void componentComplete(); + + QPlaceSupplier supplier(); + void setSupplier(const QPlaceSupplier &src, QDeclarativeGeoServiceProvider *plugin = 0); + + QString name() const; + void setName(const QString &data); + QString supplierId() const; + void setSupplierId(const QString &data); + QUrl url() const; + void setUrl(const QUrl &data); + + QDeclarativePlaceIcon *icon() const; + void setIcon(QDeclarativePlaceIcon *icon); + +Q_SIGNALS: + void nameChanged(); + void supplierIdChanged(); + void urlChanged(); + void iconChanged(); + +private: + QPlaceSupplier m_src; + QDeclarativePlaceIcon *m_icon; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeSupplier) + +#endif // QDECLARATIVESUPPLIER_P_H diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp new file mode 100644 index 00000000..d832ff40 --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp @@ -0,0 +1,689 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com> +** 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 "qdeclarativesupportedcategoriesmodel_p.h" +#include "qdeclarativeplaceicon_p.h" +#include "qgeoserviceprovider.h" +#include "error_messages.h" + +#include <QCoreApplication> +#include <QtQml/QQmlInfo> +#include <QtLocation/QPlaceManager> +#include <QtLocation/QPlaceIcon> + +QT_BEGIN_NAMESPACE + +/*! + \qmltype CategoryModel + \instantiates QDeclarativeSupportedCategoriesModel + \inqmlmodule QtLocation + \ingroup qml-QtLocation5-places + \ingroup qml-QtLocation5-places-models + \since Qt Location 5.5 + + \brief The CategoryModel type provides a model of the categories supported by a \l Plugin. + + The CategoryModel type provides a model of the categories that are available from the + current \l Plugin. The model supports both a flat list of categories and a hierarchical tree + representing category groupings. This can be controlled by the \l hierarchical property. + + The model supports the following roles: + + \table + \header + \li Role + \li Type + \li Description + \row + \li category + \li \l Category + \li Category object for the current item. + \row + \li parentCategory + \li \l Category + \li Parent category object for the current item. + If there is no parent, null is returned. + \endtable + + The following example displays a flat list of all available categories: + + \snippet declarative/places.qml QtQuick import + \snippet declarative/maps.qml QtLocation import + \codeline + \snippet declarative/places.qml CategoryView + + To access the hierarchical category model it is necessary to use a \l DelegateModel to access + the child items. +*/ + +/*! + \qmlproperty Plugin CategoryModel::plugin + + This property holds the provider \l Plugin used by this model. +*/ + +/*! + \qmlproperty bool CategoryModel::hierarchical + + This property holds whether the model provides a hierarchical tree of categories or a flat + list. The default is true. +*/ + +/*! + \qmlmethod string QtLocation::CategoryModel::data(ModelIndex index, int role) + \internal + + This method retrieves the model's data per \a index and \a role. +*/ + +/*! + \qmlmethod string QtLocation::CategoryModel::errorString() const + + This read-only property holds the textual presentation of the latest category model error. + If no error has occurred, an empty string is returned. + + An empty string may also be returned if an error occurred which has no associated + textual representation. +*/ + +/*! + \internal + \enum QDeclarativeSupportedCategoriesModel::Roles +*/ + +QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel(QObject *parent) +: QAbstractItemModel(parent), m_response(0), m_plugin(0), m_hierarchical(true), + m_complete(false), m_status(Null) +{ +} + +QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel() +{ + qDeleteAll(m_categoriesTree); +} + +/*! + \internal +*/ +// From QQmlParserStatus +void QDeclarativeSupportedCategoriesModel::componentComplete() +{ + m_complete = true; +} + +/*! + \internal +*/ +int QDeclarativeSupportedCategoriesModel::rowCount(const QModelIndex &parent) const +{ + if (m_categoriesTree.keys().isEmpty()) + return 0; + + PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer()); + if (!node) + node = m_categoriesTree.value(QString()); + else if (m_categoriesTree.keys(node).isEmpty()) + return 0; + + return node->childIds.count(); +} + +/*! + \internal +*/ +int QDeclarativeSupportedCategoriesModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return 1; +} + +/*! + \internal +*/ +QModelIndex QDeclarativeSupportedCategoriesModel::index(int row, int column, const QModelIndex &parent) const +{ + if (column != 0 || row < 0) + return QModelIndex(); + + PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer()); + + if (!node) + node = m_categoriesTree.value(QString()); + else if (m_categoriesTree.keys(node).isEmpty()) //return root index if parent is non-existent + return QModelIndex(); + + if (row > node->childIds.count()) + return QModelIndex(); + + QString id = node->childIds.at(row); + Q_ASSERT(m_categoriesTree.contains(id)); + + return createIndex(row, 0, m_categoriesTree.value(id)); +} + +/*! + \internal +*/ +QModelIndex QDeclarativeSupportedCategoriesModel::parent(const QModelIndex &child) const +{ + PlaceCategoryNode *childNode = static_cast<PlaceCategoryNode *>(child.internalPointer()); + if (m_categoriesTree.keys(childNode).isEmpty()) + return QModelIndex(); + + return index(childNode->parentId); +} + +/*! + \internal +*/ +QVariant QDeclarativeSupportedCategoriesModel::data(const QModelIndex &index, int role) const +{ + PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(index.internalPointer()); + if (!node) + node = m_categoriesTree.value(QString()); + else if (m_categoriesTree.keys(node).isEmpty()) + return QVariant(); + + QDeclarativeCategory *category = node->declCategory.data(); + + switch (role) { + case Qt::DisplayRole: + return category->name(); + case CategoryRole: + return QVariant::fromValue(category); + case ParentCategoryRole: { + if (!m_categoriesTree.keys().contains(node->parentId)) + return QVariant(); + else + return QVariant::fromValue(m_categoriesTree.value(node->parentId)->declCategory.data()); + } + default: + return QVariant(); + } +} + +QHash<int, QByteArray> QDeclarativeSupportedCategoriesModel::roleNames() const +{ + QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); + roles.insert(CategoryRole, "category"); + roles.insert(ParentCategoryRole, "parentCategory"); + return roles; +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvider *plugin) +{ + if (m_plugin == plugin) + return; + + //disconnect the manager of the old plugin if we have one + if (m_plugin) { + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (serviceProvider) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + disconnect(placeManager, SIGNAL(categoryAdded(QPlaceCategory,QString)), + this, SLOT(addedCategory(QPlaceCategory,QString))); + disconnect(placeManager, SIGNAL(categoryUpdated(QPlaceCategory,QString)), + this, SLOT(updatedCategory(QPlaceCategory,QString))); + disconnect(placeManager, SIGNAL(categoryRemoved(QString,QString)), + this, SLOT(removedCategory(QString,QString))); + disconnect(placeManager, SIGNAL(dataChanged()), + this, SIGNAL(dataChanged())); + } + } + } + + m_plugin = plugin; + + // handle plugin name changes -> update categories + if (m_plugin) { + connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(connectNotificationSignals())); + connect(m_plugin, SIGNAL(nameChanged(QString)), this, SLOT(update())); + } + + connectNotificationSignals(); + + if (m_complete) + emit pluginChanged(); +} + +/*! + \internal +*/ +QDeclarativeGeoServiceProvider *QDeclarativeSupportedCategoriesModel::plugin() const +{ + return m_plugin; +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::setHierarchical(bool hierarchical) +{ + if (m_hierarchical == hierarchical) + return; + + m_hierarchical = hierarchical; + emit hierarchicalChanged(); + + updateLayout(); +} + +/*! + \internal +*/ +bool QDeclarativeSupportedCategoriesModel::hierarchical() const +{ + return m_hierarchical; +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::replyFinished() +{ + if (!m_response) + return; + + m_response->deleteLater(); + + if (m_response->error() == QPlaceReply::NoError) { + m_errorString.clear(); + + m_response = 0; + + updateLayout(); + setStatus(QDeclarativeSupportedCategoriesModel::Ready); + } else { + const QString errorString = m_response->errorString(); + + m_response = 0; + + setStatus(Error, errorString); + } +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::addedCategory(const QPlaceCategory &category, + const QString &parentId) +{ + if (m_response) + return; + + if (!m_categoriesTree.contains(parentId)) + return; + + if (category.categoryId().isEmpty()) + return; + + PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId); + if (!parentNode) + return; + + int rowToBeAdded = rowToAddChild(parentNode, category); + QModelIndex parentIndex = index(parentId); + beginInsertRows(parentIndex, rowToBeAdded, rowToBeAdded); + PlaceCategoryNode *categoryNode = new PlaceCategoryNode; + categoryNode->parentId = parentId; + categoryNode->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, m_plugin, this)); + + m_categoriesTree.insert(category.categoryId(), categoryNode); + parentNode->childIds.insert(rowToBeAdded,category.categoryId()); + endInsertRows(); + + //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel + //does not get updated when a child is added to a model + beginResetModel(); + endResetModel(); +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::updatedCategory(const QPlaceCategory &category, + const QString &parentId) +{ + if (m_response) + return; + + QString categoryId = category.categoryId(); + + if (!m_categoriesTree.contains(parentId)) + return; + + if (category.categoryId().isEmpty() || !m_categoriesTree.contains(categoryId)) + return; + + PlaceCategoryNode *newParentNode = m_categoriesTree.value(parentId); + if (!newParentNode) + return; + + PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId); + if (!categoryNode) + return; + + categoryNode->declCategory->setCategory(category); + + if (categoryNode->parentId == parentId) { //reparenting to same parent + QModelIndex parentIndex = index(parentId); + int rowToBeAdded = rowToAddChild(newParentNode, category); + int oldRow = newParentNode->childIds.indexOf(categoryId); + + //check if we are changing the position of the category + if (qAbs(rowToBeAdded - newParentNode->childIds.indexOf(categoryId)) > 1) { + //if the position has changed we are moving rows + beginMoveRows(parentIndex, oldRow, oldRow, + parentIndex, rowToBeAdded); + + newParentNode->childIds.removeAll(categoryId); + newParentNode->childIds.insert(rowToBeAdded, categoryId); + endMoveRows(); + } else {// if the position has not changed we modifying an existing row + QModelIndex categoryIndex = index(categoryId); + emit dataChanged(categoryIndex, categoryIndex); + } + } else { //reparenting to different parents + QPlaceCategory oldCategory = categoryNode->declCategory->category(); + PlaceCategoryNode *oldParentNode = m_categoriesTree.value(categoryNode->parentId); + if (!oldParentNode) + return; + QModelIndex oldParentIndex = index(categoryNode->parentId); + QModelIndex newParentIndex = index(parentId); + + int rowToBeAdded = rowToAddChild(newParentNode, category); + beginMoveRows(oldParentIndex, oldParentNode->childIds.indexOf(categoryId), + oldParentNode->childIds.indexOf(categoryId), newParentIndex, rowToBeAdded); + oldParentNode->childIds.removeAll(oldCategory.categoryId()); + newParentNode->childIds.insert(rowToBeAdded, categoryId); + categoryNode->parentId = parentId; + endMoveRows(); + + //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel + //does not get updated when an index is updated to contain children + beginResetModel(); + endResetModel(); + } +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::removedCategory(const QString &categoryId, const QString &parentId) +{ + if (m_response) + return; + + if (!m_categoriesTree.contains(categoryId) || !m_categoriesTree.contains(parentId)) + return; + + QModelIndex parentIndex = index(parentId); + QModelIndex categoryIndex = index(categoryId); + + beginRemoveRows(parentIndex, categoryIndex.row(), categoryIndex.row()); + PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId); + parentNode->childIds.removeAll(categoryId); + delete m_categoriesTree.take(categoryId); + endRemoveRows(); +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::connectNotificationSignals() +{ + if (!m_plugin) + return; + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError) + return; + + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager) + return; + + // listen for any category notifications so that we can reupdate the categories + // model. + connect(placeManager, SIGNAL(categoryAdded(QPlaceCategory,QString)), + this, SLOT(addedCategory(QPlaceCategory,QString))); + connect(placeManager, SIGNAL(categoryUpdated(QPlaceCategory,QString)), + this, SLOT(updatedCategory(QPlaceCategory,QString))); + connect(placeManager, SIGNAL(categoryRemoved(QString,QString)), + this, SLOT(removedCategory(QString,QString))); + connect(placeManager, SIGNAL(dataChanged()), + this, SIGNAL(dataChanged())); +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::update() +{ + if (m_response) + return; + + setStatus(Loading); + + if (!m_plugin) { + updateLayout(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET)); + return; + } + + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError) { + updateLayout(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROVIDER_ERROR) + .arg(m_plugin->name())); + return; + } + + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (!placeManager) { + updateLayout(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR) + .arg(m_plugin->name()).arg(serviceProvider->errorString())); + return; + } + + m_response = placeManager->initializeCategories(); + if (m_response) { + connect(m_response, SIGNAL(finished()), this, SLOT(replyFinished())); + } else { + updateLayout(); + setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, + CATEGORIES_NOT_INITIALIZED)); + } +} + +/*! + \internal +*/ +void QDeclarativeSupportedCategoriesModel::updateLayout() +{ + beginResetModel(); + qDeleteAll(m_categoriesTree); + m_categoriesTree.clear(); + + if (m_plugin) { + QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); + if (serviceProvider && serviceProvider->error() == QGeoServiceProvider::NoError) { + QPlaceManager *placeManager = serviceProvider->placeManager(); + if (placeManager) { + PlaceCategoryNode *node = new PlaceCategoryNode; + node->childIds = populateCategories(placeManager, QPlaceCategory()); + m_categoriesTree.insert(QString(), node); + node->declCategory = QSharedPointer<QDeclarativeCategory> + (new QDeclarativeCategory(QPlaceCategory(), m_plugin, this)); + } + } + } + + endResetModel(); +} + +QString QDeclarativeSupportedCategoriesModel::errorString() const +{ + return m_errorString; +} + +/*! + \qmlproperty enumeration CategoryModel::status + + This property holds the status of the model. It can be one of: + + \table + \row + \li CategoryModel.Null + \li No category fetch query has been executed. The model is empty. + \row + \li CategoryModel.Ready + \li No error occurred during the last operation, further operations may be performed on + the model. + \row + \li CategoryModel.Loading + \li The model is being updated, no other operations may be performed until complete. + \row + \li CategoryModel.Error + \li An error occurred during the last operation, further operations can still be + performed on the model. + \endtable +*/ +void QDeclarativeSupportedCategoriesModel::setStatus(Status status, const QString &errorString) +{ + Status originalStatus = m_status; + m_status = status; + m_errorString = errorString; + + if (originalStatus != m_status) + emit statusChanged(); +} + +QDeclarativeSupportedCategoriesModel::Status QDeclarativeSupportedCategoriesModel::status() const +{ + return m_status; +} + +/*! + \internal +*/ +QStringList QDeclarativeSupportedCategoriesModel::populateCategories(QPlaceManager *manager, const QPlaceCategory &parent) +{ + Q_ASSERT(manager); + + QStringList childIds; + PlaceCategoryNode *node; + + QMap<QString, QPlaceCategory> sortedCategories; + foreach ( const QPlaceCategory &category, manager->childCategories(parent.categoryId())) + sortedCategories.insert(category.name(), category); + + QMapIterator<QString, QPlaceCategory> iter(sortedCategories); + while (iter.hasNext()) { + iter.next(); + node = new PlaceCategoryNode; + node->parentId = parent.categoryId(); + node->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(iter.value(), m_plugin ,this)); + + if (m_hierarchical) + node->childIds = populateCategories(manager, iter.value()); + + m_categoriesTree.insert(node->declCategory->categoryId(), node); + childIds.append(iter.value().categoryId()); + + if (!m_hierarchical) { + childIds.append(populateCategories(manager,node->declCategory->category())); + } + } + return childIds; +} + +/*! + \internal +*/ +QModelIndex QDeclarativeSupportedCategoriesModel::index(const QString &categoryId) const +{ + if (categoryId.isEmpty()) + return QModelIndex(); + + if (!m_categoriesTree.contains(categoryId)) + return QModelIndex(); + + PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId); + if (!categoryNode) + return QModelIndex(); + + QString parentCategoryId = categoryNode->parentId; + + PlaceCategoryNode *parentNode = m_categoriesTree.value(parentCategoryId); + + return createIndex(parentNode->childIds.indexOf(categoryId), 0, categoryNode); +} + +/*! + \internal +*/ +int QDeclarativeSupportedCategoriesModel::rowToAddChild(PlaceCategoryNode *node, const QPlaceCategory &category) +{ + Q_ASSERT(node); + for (int i = 0; i < node->childIds.count(); ++i) { + if (category.name() < m_categoriesTree.value(node->childIds.at(i))->declCategory->name()) + return i; + } + return node->childIds.count(); +} + +/*! + \qmlsignal CategoryModel::dataChanged() + + This signal is emitted when significant changes have been made to the underlying datastore. + + Applications should act on this signal at their own discretion. The data + provided by the model could be out of date and so the model should be reupdated + sometime, however an immediate reupdate may be disconcerting to users if the categories + change without any action on their part. + + The corresponding handler is \c onDataChanged. +*/ + +QT_END_NAMESPACE diff --git a/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h new file mode 100644 index 00000000..9f17ab4d --- /dev/null +++ b/src/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QDECLARATIVESUPPORTEDCATEGORIESMODEL_H +#define QDECLARATIVESUPPORTEDCATEGORIESMODEL_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/qlocationglobal_p.h> +#include <QtLocation/private/qdeclarativegeoserviceprovider_p.h> + +#include <QObject> +#include <QtCore/QStringList> +#include <QtCore/QSharedPointer> +#include <QAbstractListModel> +#include <QQmlListProperty> +#include <QtQml/QQmlParserStatus> + +#include <QtLocation/QPlaceCategory> + +#include <QtLocation/private/qdeclarativecategory_p.h> + +QT_BEGIN_NAMESPACE + +class QGeoServiceProvider; +class QPlaceManager; +class QPlaceReply; + +class PlaceCategoryNode +{ +public: + QString parentId; + QStringList childIds; + QSharedPointer<QDeclarativeCategory> declCategory; +}; + +class Q_LOCATION_PRIVATE_EXPORT QDeclarativeSupportedCategoriesModel : public QAbstractItemModel, public QQmlParserStatus +{ + Q_OBJECT + + Q_ENUMS(Status) + + Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) + Q_PROPERTY(bool hierarchical READ hierarchical WRITE setHierarchical NOTIFY hierarchicalChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + + Q_INTERFACES(QQmlParserStatus) + Q_ENUMS(Roles) //The Roles enum is for internal usage only. + +public: + explicit QDeclarativeSupportedCategoriesModel(QObject *parent = 0); + virtual ~QDeclarativeSupportedCategoriesModel(); + + // From QQmlParserStatus + virtual void classBegin() {} + virtual void componentComplete(); + + // From QAbstractItemModel + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + + QModelIndex index(int row, int column, const QModelIndex &parent) const; + QModelIndex parent(const QModelIndex &child) const; + + Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const; + QHash<int, QByteArray> roleNames() const; + + enum Roles { + CategoryRole = Qt::UserRole, + ParentCategoryRole + }; //for internal usage only + + enum Status {Null, Ready, Loading, Error}; + + void setPlugin(QDeclarativeGeoServiceProvider *plugin); + QDeclarativeGeoServiceProvider *plugin() const; + + void setHierarchical(bool hierarchical); + bool hierarchical() const; + + Q_INVOKABLE QString errorString() const; + + Status status() const; + void setStatus(Status status, const QString &errorString = QString()); + + using QAbstractItemModel::dataChanged; +Q_SIGNALS: + void pluginChanged(); + void hierarchicalChanged(); + void statusChanged(); + void dataChanged(); + +public Q_SLOTS: + void update(); + +private Q_SLOTS: + void replyFinished(); + void addedCategory(const QPlaceCategory &category, const QString &parentId); + void updatedCategory(const QPlaceCategory &category, const QString &parentId); + void removedCategory(const QString &categoryId, const QString &parentId); + void connectNotificationSignals(); + +private: + QStringList populateCategories(QPlaceManager *, const QPlaceCategory &parent); + QModelIndex index(const QString &categoryId) const; + int rowToAddChild(PlaceCategoryNode *, const QPlaceCategory &category); + void updateLayout(); + + QPlaceReply *m_response; + + QDeclarativeGeoServiceProvider *m_plugin; + bool m_hierarchical; + bool m_complete; + Status m_status; + QString m_errorString; + + QHash<QString, PlaceCategoryNode *> m_categoriesTree; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QDeclarativeSupportedCategoriesModel) + +#endif // QDECLARATIVESUPPORTEDCATEGORIESMODEL_H |