diff options
author | Aaron McCarthy <aaron.mccarthy@nokia.com> | 2011-08-12 11:34:01 +1000 |
---|---|---|
committer | Aaron McCarthy <aaron.mccarthy@nokia.com> | 2011-08-15 09:54:32 +0200 |
commit | 4f2581c853ac01a6874b7987c5513a6157e22f9d (patch) | |
tree | 37e2fa13bfd82ddb85facd29618c9b96c27e5ea2 /src | |
parent | 02e9bc25bf811caf1b21c5ae575b0dd94e147341 (diff) | |
download | qtlocation-4f2581c853ac01a6874b7987c5513a6157e22f9d.tar.gz |
Hierarchical categories.
Change-Id: I5028f4a617128bb9fa95ea94efe4b1ac8722dbb2
Reviewed-on: http://codereview.qt.nokia.com/2923
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Aaron McCarthy <aaron.mccarthy@nokia.com>
Diffstat (limited to 'src')
17 files changed, 510 insertions, 199 deletions
diff --git a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp b/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp index 580e0602..9046b49b 100644 --- a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp +++ b/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel.cpp @@ -9,25 +9,25 @@ QT_USE_NAMESPACE /*! \qmlclass SupportedCategoryModel QDeclarativeSupportedCategoriesModel - \brief The SupportedCategoryModel element provides access to suported categories list. + \brief The SupportedCategoryModel element provides access to supported categories list. \inherits QAbstractListModel \ingroup qml-places + \since QtLocation 5.0 - SupportedCategoryModel provides a model of categories from the supported categories list. - The contents of the model can contains parent categories. All categories might have childrens. + SupportedCategoryModel provides a model of categories from the supported categories list. The + model can provide both a flat list of categories or a hierarchical tree representing category + grouping. This can be controlled by the \l hierarchy property. - There are two ways of accessing the category data: through model by using views and delegates, - or alternatively via \l category list property. Of the two, the model access is preferred. - - At the moment only data role provided by the model is \c category (\l Category). - Through that one can access any data provided by the Category element. + The model provides a single data role, \c category (\l Category). To use SupportedCategoryModel user need to create it in qml file and connect it to some view \code - import places 1.0 + import QtQuick 2.0 + import Qt.location 5.0 SupportedCategoriesModel { id: categoriesModel + hierarchical: false } ListView { @@ -39,14 +39,36 @@ QT_USE_NAMESPACE } \endcode + To access the hierarchical category model it is necessary to use a VisualDataModel to access + the child items. + \sa SearchResultModel, SuggestionModel, {QPlaceManager} */ + +/*! + \qmlproperty Plugin SupportedCategoriesModel::plugin + + this property holds the provider Plugin used by this model. +*/ + +/*! + \qmlproperty bool SupportedCategoriesModel::hierarchical + + This property holds whether the model provides a hierarchical tree of categories or a flat + list. The default is true. +*/ + +PlaceCategoryTree::PlaceCategoryTree() +{ +} + +PlaceCategoryTree::~PlaceCategoryTree() +{ +} + QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel(QObject *parent) -: QAbstractListModel(parent), m_plugin(0), m_complete(false) +: QAbstractItemModel(parent), m_plugin(0), m_hierarchical(true), m_complete(false) { -#if defined(QT_PLACESPLUGIN_LOGGING) - qDebug() << "QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel"; -#endif QHash<int, QByteArray> roleNames; roleNames = QAbstractItemModel::roleNames(); roleNames.insert(CategoryRole, "category"); @@ -55,13 +77,6 @@ QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel(QObje QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel() { -#if defined(QT_PLACESPLUGIN_LOGGING) - qDebug() << "QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel"; -#endif - foreach (const QString id, m_categoryMap.keys()) { - delete m_categoryMap.value(id); - m_categoryMap.remove(id); - } } // From QDeclarativeParserStatus @@ -70,41 +85,74 @@ void QDeclarativeSupportedCategoriesModel::componentComplete() m_complete = true; } -/*! - \qmlsignal SupportedCategoryModel::categoriesChanged() +int QDeclarativeSupportedCategoriesModel::rowCount(const QModelIndex& parent) const +{ + PlaceCategoryTree tree = findCategoryTreeByCategory(static_cast<QDeclarativeCategory *>(parent.internalPointer()), m_categoryTree); + return tree.subCategories.count(); +} - This handler is called when the list of categories is changed and - client should take new data. -*/ +int QDeclarativeSupportedCategoriesModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) -int QDeclarativeSupportedCategoriesModel::rowCount(const QModelIndex& parent) const + return 1; +} + +QModelIndex QDeclarativeSupportedCategoriesModel::index(int row, int column, const QModelIndex &parent) const { - Q_UNUSED(parent); - return m_categories.count(); + if (column != 0 || row < 0) + return QModelIndex(); + + PlaceCategoryTree tree = findCategoryTreeByCategory(static_cast<QDeclarativeCategory *>(parent.internalPointer()), m_categoryTree); + + if (row > tree.subCategories.count()) + return QModelIndex(); + + QMap<QString, QDeclarativeCategory *> sortedCategories; + QHashIterator<QString, PlaceCategoryTree> it(tree.subCategories); + while (it.hasNext()) { + it.next(); + sortedCategories.insert(it.value().category->name(), it.value().category.data()); + } + + return createIndex(row, 0, sortedCategories.values().at(row)); } -QVariant QDeclarativeSupportedCategoriesModel::data(const QModelIndex& index, int role) const +QModelIndex QDeclarativeSupportedCategoriesModel::parent(const QModelIndex &child) const { - QPlaceCategory item = m_categories[index.row()]; - QDeclarativeCategory *res = NULL; - if (m_categoryMap.contains(item.categoryId())) { - res = m_categoryMap[item.categoryId()]; + QDeclarativeCategory *parentCategory = findParentCategoryByCategory(static_cast<QDeclarativeCategory *>(child.internalPointer()), m_categoryTree); + if (!parentCategory) + return QModelIndex(); + + QDeclarativeCategory *grandParentCategory = findParentCategoryByCategory(parentCategory, m_categoryTree); + PlaceCategoryTree tree = findCategoryTreeByCategory(grandParentCategory, m_categoryTree); + + QMap<QString, QDeclarativeCategory *> sortedCategories; + QHashIterator<QString, PlaceCategoryTree> it(tree.subCategories); + while (it.hasNext()) { + it.next(); + sortedCategories.insert(it.value().category->name(), it.value().category.data()); } + + return createIndex(sortedCategories.values().indexOf(parentCategory), 0, parentCategory); +} + +QVariant QDeclarativeSupportedCategoriesModel::data(const QModelIndex &index, int role) const +{ + PlaceCategoryTree tree = findCategoryTreeByCategory(static_cast<QDeclarativeCategory *>(index.internalPointer()), m_categoryTree); + QDeclarativeCategory *category = tree.category.data(); + + if (!category) + return QVariant(); + switch (role) { - case Qt::DisplayRole: - if (res) { - return res->name(); - } else { - return QString(); - } - case CategoryRole: - if (res) { - return QVariant::fromValue(res); - } else { - return QVariant(); - } - } - return QVariant(); + case Qt::DisplayRole: + return category->name(); + case CategoryRole: + return QVariant::fromValue(category); + default: + return QVariant(); + } } void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvider *plugin) @@ -123,8 +171,7 @@ void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvi return; } - m_categories = placeManager->categories(); - convertCategoriesToDeclarative(); + m_categoryTree.subCategories = populatedCategories(placeManager); m_response = placeManager->initializeCategories(); if (m_response) { @@ -139,49 +186,20 @@ QDeclarativeGeoServiceProvider* QDeclarativeSupportedCategoriesModel::plugin() c return m_plugin; } -/*! - \qmlproperty QDeclarativeListProperty SupportedCategoryModel::categories - - This element holds the list of \l Category elements that the model currently has. -*/ - -QDeclarativeListProperty<QDeclarativeCategory> QDeclarativeSupportedCategoriesModel::categories() +void QDeclarativeSupportedCategoriesModel::setHierarchical(bool hierarchical) { - return QDeclarativeListProperty<QDeclarativeCategory>(this, - 0, // opaque data parameter - categories_append, - categories_count, - categories_at, - categories_clear); -} + if (m_hierarchical == hierarchical) + return; -void QDeclarativeSupportedCategoriesModel::categories_append(QDeclarativeListProperty<QDeclarativeCategory> *prop, - QDeclarativeCategory* category) -{ - Q_UNUSED(prop); - Q_UNUSED(category); -} + m_hierarchical = hierarchical; + emit hierarchicalChanged(); -int QDeclarativeSupportedCategoriesModel::categories_count(QDeclarativeListProperty<QDeclarativeCategory> *prop) -{ - return static_cast<QDeclarativeSupportedCategoriesModel*>(prop->object)->m_categories.count(); + updateCategories(); } -QDeclarativeCategory* QDeclarativeSupportedCategoriesModel::categories_at(QDeclarativeListProperty<QDeclarativeCategory> *prop, - int index) +bool QDeclarativeSupportedCategoriesModel::hierarchical() const { - QDeclarativeSupportedCategoriesModel* model = static_cast<QDeclarativeSupportedCategoriesModel*>(prop->object); - QPlaceCategory item = model->m_categories[index]; - QDeclarativeCategory *res = NULL; - if (model->m_categoryMap.contains(item.categoryId())) { - res = model->m_categoryMap[item.categoryId()]; - } - return res; -} - -void QDeclarativeSupportedCategoriesModel::categories_clear(QDeclarativeListProperty<QDeclarativeCategory> *prop) -{ - Q_UNUSED(prop) + return m_hierarchical; } void QDeclarativeSupportedCategoriesModel::replyFinished() @@ -192,10 +210,20 @@ void QDeclarativeSupportedCategoriesModel::replyFinished() m_response->deleteLater(); m_response = 0; - if (!m_plugin) { - qmlInfo(this) << "plugin not set."; + updateCategories(); +} + +void QDeclarativeSupportedCategoriesModel::replyError(QPlaceReply::Error error, + const QString &errorString) +{ + Q_UNUSED(error); + Q_UNUSED(errorString); +} + +void QDeclarativeSupportedCategoriesModel::updateCategories() +{ + if (!m_plugin) return; - } QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider(); if (!serviceProvider) @@ -208,29 +236,72 @@ void QDeclarativeSupportedCategoriesModel::replyFinished() } beginResetModel(); - m_categories = placeManager->categories(); - convertCategoriesToDeclarative(); + m_categoryTree.subCategories = populatedCategories(placeManager); endResetModel(); - emit categoriesChanged(); } -void QDeclarativeSupportedCategoriesModel::replyError(QPlaceReply::Error error, - const QString &errorString) +QHash<QString, PlaceCategoryTree> QDeclarativeSupportedCategoriesModel::populatedCategories(QPlaceManager *manager, const QPlaceCategory &parent) { - Q_UNUSED(error); - Q_UNUSED(errorString); + QHash<QString, PlaceCategoryTree> declarativeTree; + + foreach (const QPlaceCategory &category, manager->categories(parent)) { + PlaceCategoryTree dt; + dt.category = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, this)); + if (m_hierarchical) + dt.subCategories = populatedCategories(manager, category); + declarativeTree.insert(category.categoryId(), dt); + + if (!m_hierarchical) { + QHash<QString, PlaceCategoryTree> sub = populatedCategories(manager, category); + QHashIterator<QString, PlaceCategoryTree> it(sub); + while (it.hasNext()) { + it.next(); + dt.category = QSharedPointer<QDeclarativeCategory>(it.value().category); + Q_ASSERT(it.value().subCategories.isEmpty()); + declarativeTree.insert(it.key(), dt); + } + } + } + + return declarativeTree; } -void QDeclarativeSupportedCategoriesModel::convertCategoriesToDeclarative() +PlaceCategoryTree QDeclarativeSupportedCategoriesModel::findCategoryTreeByCategory(QDeclarativeCategory *category, const PlaceCategoryTree &tree) const { - foreach (const QString id, m_categoryMap.keys()) { - delete m_categoryMap.value(id); - m_categoryMap.remove(id); + if (tree.category == category) + return tree; + + QHashIterator<QString, PlaceCategoryTree> it(tree.subCategories); + while (it.hasNext()) { + it.next(); + + if (it.value().category == category) + return it.value(); + + PlaceCategoryTree t = findCategoryTreeByCategory(category, it.value()); + if (t.category == category) + return t; } - m_categoryMap.clear(); - foreach (const QPlaceCategory& category, m_categories) { - QDeclarativeCategory* declarativeCategory = new QDeclarativeCategory(category, this); - m_categoryMap.insert(category.categoryId(), declarativeCategory); + return PlaceCategoryTree(); +} + +QDeclarativeCategory *QDeclarativeSupportedCategoriesModel::findParentCategoryByCategory(QDeclarativeCategory *category, const PlaceCategoryTree &tree) const +{ + if (tree.category == category) + return 0; + + QHashIterator<QString, PlaceCategoryTree> it(tree.subCategories); + while (it.hasNext()) { + it.next(); + + if (it.value().category == category) + return tree.category.data(); + + QDeclarativeCategory *p = findParentCategoryByCategory(category, it.value()); + if (p) + return p; } + + return 0; } diff --git a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h b/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h index 6fefa00b..982c3352 100644 --- a/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h +++ b/src/imports/location/declarativeplaces/qdeclarativesupportedcategoriesmodel_p.h @@ -17,12 +17,22 @@ QT_BEGIN_NAMESPACE class QGeoServiceProvider; -class QDeclarativeSupportedCategoriesModel : public QAbstractListModel, public QDeclarativeParserStatus +class PlaceCategoryTree +{ +public: + PlaceCategoryTree(); + ~PlaceCategoryTree(); + + QSharedPointer<QDeclarativeCategory> category; + QHash<QString, PlaceCategoryTree> subCategories; +}; + +class QDeclarativeSupportedCategoriesModel : public QAbstractItemModel, public QDeclarativeParserStatus { Q_OBJECT Q_PROPERTY(QDeclarativeGeoServiceProvider *plugin READ plugin WRITE setPlugin NOTIFY pluginChanged) - Q_PROPERTY(QDeclarativeListProperty<QDeclarativeCategory> categories READ categories NOTIFY categoriesChanged) + Q_PROPERTY(bool hierarchical READ hierarchical WRITE setHierarchical NOTIFY hierarchicalChanged) Q_INTERFACES(QDeclarativeParserStatus) @@ -34,15 +44,13 @@ public: virtual void classBegin() {} virtual void componentComplete(); - QDeclarativeListProperty<QDeclarativeCategory> categories(); - static void categories_append(QDeclarativeListProperty<QDeclarativeCategory> *prop, - QDeclarativeCategory* category); - static int categories_count(QDeclarativeListProperty<QDeclarativeCategory> *prop); - static QDeclarativeCategory* categories_at(QDeclarativeListProperty<QDeclarativeCategory> *prop, int index); - static void categories_clear(QDeclarativeListProperty<QDeclarativeCategory> *prop); - - // From QAbstractListModel + // 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; + QVariant data(const QModelIndex &index, int role) const; // Roles for exposing data via model. Only one role because // everything can be accessed via QDeclarativeLandmark @@ -53,22 +61,28 @@ public: void setPlugin(QDeclarativeGeoServiceProvider *plugin); QDeclarativeGeoServiceProvider* plugin() const; + void setHierarchical(bool hierarchical); + bool hierarchical() const; + signals: - void categoriesChanged(); void pluginChanged(); + void hierarchicalChanged(); private slots: void replyFinished(); void replyError(QPlaceReply::Error error, const QString &errorString); private: - void convertCategoriesToDeclarative(); + void updateCategories(); + QHash<QString, PlaceCategoryTree> populatedCategories(QPlaceManager *manager, const QPlaceCategory &parent = QPlaceCategory()); + PlaceCategoryTree findCategoryTreeByCategory(QDeclarativeCategory *category, const PlaceCategoryTree &tree) const; + QDeclarativeCategory *findParentCategoryByCategory(QDeclarativeCategory *category, const PlaceCategoryTree &tree) const; QPlaceReply *m_response; - QList<QPlaceCategory> m_categories; - QMap<QString, QDeclarativeCategory*> m_categoryMap; + PlaceCategoryTree m_categoryTree; QDeclarativeGeoServiceProvider *m_plugin; + bool m_hierarchical; bool m_complete; }; diff --git a/src/location/places/qplacemanager.cpp b/src/location/places/qplacemanager.cpp index 047edc3b..b8115a17 100644 --- a/src/location/places/qplacemanager.cpp +++ b/src/location/places/qplacemanager.cpp @@ -231,11 +231,12 @@ QPlaceReply *QPlaceManager::initializeCategories() } /*! - Returns a list of top level categories. + Returns a list of top level categories if \a parent is default contstructed; otherwise returns + a list of subcategories of \a parent. */ -QList<QPlaceCategory> QPlaceManager::categories() const +QList<QPlaceCategory> QPlaceManager::categories(const QPlaceCategory &parent) const { - return d->engine->categories(); + return d->engine->categories(parent); } /*! diff --git a/src/location/places/qplacemanager.h b/src/location/places/qplacemanager.h index 569c76fa..703e980d 100644 --- a/src/location/places/qplacemanager.h +++ b/src/location/places/qplacemanager.h @@ -131,7 +131,7 @@ public: QPlaceReply *removePlace(const QGeoPlace &place); QPlaceReply *initializeCategories(); - QList<QPlaceCategory> categories() const; + QList<QPlaceCategory> categories(const QPlaceCategory &parent = QPlaceCategory()) const; static QStringList availableManagers(); diff --git a/src/location/places/qplacemanagerengine.h b/src/location/places/qplacemanagerengine.h index 324ea953..0c620658 100644 --- a/src/location/places/qplacemanagerengine.h +++ b/src/location/places/qplacemanagerengine.h @@ -82,7 +82,7 @@ public: virtual QPlaceReply *removePlace(const QGeoPlace &place) = 0; virtual QPlaceReply *initializeCategories() = 0; - virtual QList<QPlaceCategory> categories() const = 0; + virtual QList<QPlaceCategory> categories(const QPlaceCategory &parent) const = 0; virtual QLocale locale() const = 0; virtual void setLocale(const QLocale &locale) = 0; diff --git a/src/plugins/geoservices/nokia/places/places.pri b/src/plugins/geoservices/nokia/places/places.pri index b24b5f90..911262f3 100644 --- a/src/plugins/geoservices/nokia/places/places.pri +++ b/src/plugins/geoservices/nokia/places/places.pri @@ -26,7 +26,8 @@ HEADERS += \ places/qplacecategoriesrepository.h \ places/qplacerestreply.h \ places/qplacerestmanager.h \ - places/qplacesuppliersrepository.h + places/qplacesuppliersrepository.h \ + places/qplacecategorytree.h SOURCES += \ #data classes @@ -54,6 +55,9 @@ SOURCES += \ places/qplacecategoriesrepository.cpp \ places/qplacerestreply.cpp \ places/qplacerestmanager.cpp \ - places/qplacesuppliersrepository.cpp + places/qplacesuppliersrepository.cpp \ + places/qplacecategorytree.cpp + + diff --git a/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.cpp b/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.cpp index e312813e..c17468f7 100644 --- a/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.cpp +++ b/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.cpp @@ -31,9 +31,14 @@ QPlaceCategoriesReplyImpl::~QPlaceCategoriesReplyImpl() { } -QList<QPlaceCategory> QPlaceCategoriesReplyImpl::categories() +QPlaceCategoryTree QPlaceCategoriesReplyImpl::categories() const { - return m_categories; + return m_categoryTree; +} + +QList<QPlaceCategory> QPlaceCategoriesReplyImpl::categoriesFlat() const +{ + return m_categoryTree.toList(); } void QPlaceCategoriesReplyImpl::abort() @@ -61,7 +66,7 @@ void QPlaceCategoriesReplyImpl::resultReady(const QPlaceJSonParser::Error &error const QString &errorMessage) { if (errorId == QPlaceJSonParser::NoError) { - m_categories = parser->resultCategories(); + m_categoryTree = parser->resultCategories(); } else if (errorId == QPlaceJSonParser::ParsingError) { setError(ParseError, errorMessage); emit error(this->error(), this->errorString()); diff --git a/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.h b/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.h index 51a0c16d..f770fde8 100644 --- a/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.h +++ b/src/plugins/geoservices/nokia/places/qplacecategoriesreplyimpl.h @@ -15,7 +15,8 @@ public: explicit QPlaceCategoriesReplyImpl(QPlaceRestReply *reply, QObject *parent = 0); ~QPlaceCategoriesReplyImpl(); - QList<QPlaceCategory> categories(); + QPlaceCategoryTree categories() const; + QList<QPlaceCategory> categoriesFlat() const; void abort(); @@ -32,7 +33,7 @@ private: QPlaceRestReply *restReply; QPlaceJSonCategoriesParser *parser; - QList<QPlaceCategory> m_categories; + QPlaceCategoryTree m_categoryTree; }; #endif // QPLACECATEGORIESREPLYIMPL_H diff --git a/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.cpp b/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.cpp index 4304f3c0..70facc77 100644 --- a/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.cpp +++ b/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.cpp @@ -90,9 +90,9 @@ QPlaceReply *QPlaceCategoriesRepository::initializeCategories() return categoriesReply; } -QList<QPlaceCategory> QPlaceCategoriesRepository::categories() const +QPlaceCategoryTree QPlaceCategoriesRepository::categories() const { - return allCategories.values(); + return m_categoryTree; } QPlaceCategory QPlaceCategoriesRepository::mapCategory(const QString &number) @@ -117,17 +117,15 @@ QString QPlaceCategoriesRepository::getCategoryTagId(const QPlaceCategory &categ QPlaceCategory QPlaceCategoriesRepository::findCategoryById(const QString &id) { - return allCategories.value(id, QPlaceCategory()); + return m_categoryTree.findCategoryById(id); } void QPlaceCategoriesRepository::replyFinished() { - if (!categoriesReply.isNull()) { - foreach (QPlaceCategory cat, categoriesReply->categories()) { - allCategories.insert(cat.categoryId(), cat); - } - } - categoriesReply = NULL; + if (!categoriesReply.isNull()) + m_categoryTree = categoriesReply->categories(); + + categoriesReply = 0; } void QPlaceCategoriesRepository::setupCategoriesMapper() diff --git a/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.h b/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.h index e0a14725..a1502187 100644 --- a/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.h +++ b/src/plugins/geoservices/nokia/places/qplacecategoriesrepository.h @@ -70,7 +70,7 @@ public: ~QPlaceCategoriesRepository(); QPlaceReply *initializeCategories(); - QList<QPlaceCategory> categories() const; + QPlaceCategoryTree categories() const; QPlaceCategory mapCategory(const QString &number); QString getCategoryTagId(const QPlaceCategory &category); @@ -85,7 +85,7 @@ private: private: QPlaceCategoriesRepository(QObject *parent = 0); - QHash<QString, QPlaceCategory> allCategories; + QPlaceCategoryTree m_categoryTree; static QPlaceCategoriesRepository *repositoryInstance; QPointer<QPlaceCategoriesReplyImpl> categoriesReply; }; diff --git a/src/plugins/geoservices/nokia/places/qplacecategorytree.cpp b/src/plugins/geoservices/nokia/places/qplacecategorytree.cpp new file mode 100644 index 00000000..e8870b9d --- /dev/null +++ b/src/plugins/geoservices/nokia/places/qplacecategorytree.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplacecategorytree.h" + +QPlaceCategoryTree::QPlaceCategoryTree() +{ +} + +QPlaceCategoryTree::~QPlaceCategoryTree() +{ +} + +void QPlaceCategoryTree::clear() +{ + category = QPlaceCategory(); + subCategories.clear(); +} + +QPlaceCategory QPlaceCategoryTree::findCategoryById(const QString &id) const +{ + if (category.categoryId() == id) + return category; + + if (subCategories.contains(id)) + return subCategories.value(id).category; + + QHashIterator<QString, QPlaceCategoryTree> it(subCategories); + while (it.hasNext()) { + it.next(); + + QPlaceCategory cat = it.value().findCategoryById(id); + if (cat.categoryId() == id) + return cat; + } + + return QPlaceCategory(); +} + +QPlaceCategoryTree QPlaceCategoryTree::findCategoryTreeById(const QString &id) const +{ + if (category.categoryId() == id) + return *this; + + QHashIterator<QString, QPlaceCategoryTree> it(subCategories); + while (it.hasNext()) { + it.next(); + + if (it.value().category.categoryId() == id) + return it.value(); + + QPlaceCategoryTree t = it.value().findCategoryTreeById(id); + if (t.category.categoryId() == id) + return t; + } + + return QPlaceCategoryTree(); +} + +QList<QPlaceCategory> QPlaceCategoryTree::toList() const +{ + QList<QPlaceCategory> results; + + QHashIterator<QString, QPlaceCategoryTree> it(subCategories); + while (it.hasNext()) { + it.next(); + + QPlaceCategory cat = it.value().category; + if (!cat.categoryId().isEmpty()) + results.append(cat); + + results.append(it.value().toList()); + } + + return results; +} diff --git a/src/plugins/geoservices/nokia/places/qplacecategorytree.h b/src/plugins/geoservices/nokia/places/qplacecategorytree.h new file mode 100644 index 00000000..30a61253 --- /dev/null +++ b/src/plugins/geoservices/nokia/places/qplacecategorytree.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 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 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLACECATEGORYTREE_H +#define QPLACECATEGORYTREE_H + +#include <QtLocation/QPlaceCategory> + +class QPlaceCategoryTree +{ +public: + QPlaceCategoryTree(); + ~QPlaceCategoryTree(); + + void clear(); + + QPlaceCategory findCategoryById(const QString &id) const; + QPlaceCategoryTree findCategoryTreeById(const QString &id) const; + QList<QPlaceCategory> toList() const; + + QPlaceCategory category; + QHash<QString, QPlaceCategoryTree> subCategories; +}; + +#endif // QPLACECATEGORYTREE_H diff --git a/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.cpp b/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.cpp index 18e875a9..8939fbd4 100644 --- a/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.cpp +++ b/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.cpp @@ -74,22 +74,31 @@ QPlaceJSonCategoriesParser::QPlaceJSonCategoriesParser(QObject *parent) : QPlaceJSonCategoriesParser::~QPlaceJSonCategoriesParser() { - allCategories.clear(); } -QList<QPlaceCategory> QPlaceJSonCategoriesParser::resultCategories() +QList<QPlaceCategory> QPlaceJSonCategoriesParser::parseFlatCategoryList(const QScriptValue &categories) { - return allCategories; + return processCategories(categories).toList(); +} + +QPlaceCategoryTree QPlaceJSonCategoriesParser::resultCategories() const +{ + return m_categoryTree; +} + +QList<QPlaceCategory> QPlaceJSonCategoriesParser::resultCategoriesFlat() const +{ + return m_categoryTree.toList(); } void QPlaceJSonCategoriesParser::processJSonData(const QScriptValue &sv) { - allCategories.clear(); + m_categoryTree.clear(); if (sv.isValid()) { QScriptValue sv2 = sv.property(place_categories_element); if (sv2.isValid()) { - allCategories = processCategories(sv2); + m_categoryTree = processCategories(sv2); emit finished(NoError, QString()); } else { emit finished(ParsingError, QString("JSON data are invalid")); @@ -99,10 +108,10 @@ void QPlaceJSonCategoriesParser::processJSonData(const QScriptValue &sv) } } -QList<QPlaceCategory> QPlaceJSonCategoriesParser::processCategories(const QScriptValue &categories) +QPlaceCategoryTree QPlaceJSonCategoriesParser::processCategories(const QScriptValue &categories) { - QHash<QString, QPlaceCategory> results; - QPlaceCategory cat; + QPlaceCategoryTree results; + QScriptValue value = categories.property(place_category_element); if (value.isValid()) { if (value.isArray()) { @@ -110,27 +119,62 @@ QList<QPlaceCategory> QPlaceJSonCategoriesParser::processCategories(const QScrip while (it.hasNext()) { it.next(); // array contains count as last element - if (it.name() != "length") { - cat = processCategory(it.value()); - if (!cat.categoryId().isEmpty() && !results.contains(cat.categoryId())) { - results.insert(cat.categoryId(), cat); + if (it.name() != QLatin1String("length")) { + QPlaceCategoryTree catTree; + catTree.category = processCategory(it.value()); + if (!catTree.category.categoryId().isEmpty() && + !results.subCategories.contains(catTree.category.categoryId())) { + results.subCategories.insert(catTree.category.categoryId(), catTree); } } } } else { - cat = processCategory(value); - if (!cat.categoryId().isEmpty() && !results.contains(cat.categoryId())) { - results.insert(cat.categoryId(), cat); + QPlaceCategoryTree catTree; + catTree.category = processCategory(value); + if (!catTree.category.categoryId().isEmpty() && + !results.subCategories.contains(catTree.category.categoryId())) { + results.subCategories.insert(catTree.category.categoryId(), catTree); } } } - foreach (cat, processGroups(categories)) { - if (!results.contains(cat.categoryId())) { - results.insert(cat.categoryId(), cat); + + value = categories.property(place_group_element); + if (value.isValid()) { + if (value.isArray()) { + QScriptValueIterator it(value); + while (it.hasNext()) { + it.next(); + // array contains count as last element + if (it.name() != QLatin1String("length")) { + QPlaceCategoryTree catTree = processGroup(it.value()); + if (!results.subCategories.contains(catTree.category.categoryId())) { + results.subCategories.insert(catTree.category.categoryId(), catTree); + } else { + QHashIterator<QString, QPlaceCategoryTree> treeIt(catTree.subCategories); + while (treeIt.hasNext()) { + treeIt.next(); + + results.subCategories[catTree.category.categoryId()].subCategories.insert(treeIt.key(), treeIt.value()); + } + } + } + } + } else { + QPlaceCategoryTree catTree = processGroup(value); + if (!results.subCategories.contains(catTree.category.categoryId())) { + results.subCategories.insert(catTree.category.categoryId(), catTree); + } else { + QHashIterator<QString, QPlaceCategoryTree> treeIt(catTree.subCategories); + while (treeIt.hasNext()) { + treeIt.next(); + + results.subCategories[catTree.category.categoryId()].subCategories.insert(treeIt.key(), treeIt.value()); + } + } } } - return results.values(); + return results; } QPlaceCategory QPlaceJSonCategoriesParser::processCategory(const QScriptValue &categoryValue) @@ -147,39 +191,18 @@ QPlaceCategory QPlaceJSonCategoriesParser::processCategory(const QScriptValue &c return category; } -QList<QPlaceCategory> QPlaceJSonCategoriesParser::processGroups(const QScriptValue &categories) +QPlaceCategoryTree QPlaceJSonCategoriesParser::processGroup(const QScriptValue &group) { - QList<QPlaceCategory> results; - QScriptValue value = categories.property(place_group_element); - if (value.isValid()) { - if (value.isArray()) { - QScriptValueIterator it(value); - while (it.hasNext()) { - it.next(); - // array contains count as last element - if (it.name() != "length") { - results.append(processGroup(it.value())); - } - } - } else { - results.append(processGroup(value)); - } - } - return results; -} + QScriptValue value = group.property(place_groupingcategory_element); + if (!value.isValid()) + return QPlaceCategoryTree(); -QList<QPlaceCategory> QPlaceJSonCategoriesParser::processGroup(const QScriptValue &group) -{ - QList<QPlaceCategory> results; - QPlaceCategory parentCategory; + QPlaceCategoryTree results; + results.category = processCategory(value); + if (results.category.categoryId().isEmpty()) + return QPlaceCategoryTree(); - QScriptValue value = group.property(place_groupingcategory_element); - if (value.isValid()) { - parentCategory = processCategory(value); - } - if (!parentCategory.categoryId().isEmpty()) { - results = processCategories(group); - } + results.subCategories = processCategories(group).subCategories; return results; } diff --git a/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.h b/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.h index c6c95717..e9428476 100644 --- a/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.h +++ b/src/plugins/geoservices/nokia/places/qplacejsoncategoriesparser.h @@ -55,6 +55,7 @@ #include <qplacecategory.h> #include "qplacejsonparser_p.h" +#include "qplacecategorytree.h" class QScriptEngine; class QScriptValue; @@ -64,21 +65,25 @@ QT_BEGIN_NAMESPACE class QPlaceJSonCategoriesParser : public QPlaceJSonParser { Q_OBJECT + public: explicit QPlaceJSonCategoriesParser(QObject *parent = 0); virtual ~QPlaceJSonCategoriesParser(); - static QList<QPlaceCategory> processCategories(const QScriptValue &categories); + QPlaceCategoryTree resultCategories() const; + QList<QPlaceCategory> resultCategoriesFlat() const; - QList<QPlaceCategory> resultCategories(); + static QList<QPlaceCategory> parseFlatCategoryList(const QScriptValue &categories); private: void processJSonData(const QScriptValue &sv); + + static QPlaceCategoryTree processCategories(const QScriptValue &categories); + static QPlaceCategoryTree processGroup(const QScriptValue &group); static QPlaceCategory processCategory(const QScriptValue &categoryValue); - static QList<QPlaceCategory> processGroups(const QScriptValue &categories); - static QList<QPlaceCategory> processGroup(const QScriptValue &group); + private: - QList<QPlaceCategory> allCategories; + QPlaceCategoryTree m_categoryTree; }; QT_END_NAMESPACE diff --git a/src/plugins/geoservices/nokia/places/qplacejsondetailsparser.cpp b/src/plugins/geoservices/nokia/places/qplacejsondetailsparser.cpp index 8b0d77f7..aafb661a 100644 --- a/src/plugins/geoservices/nokia/places/qplacejsondetailsparser.cpp +++ b/src/plugins/geoservices/nokia/places/qplacejsondetailsparser.cpp @@ -325,7 +325,7 @@ void QPlaceJSonDetailsParser::processContacts(const QScriptValue &contactsValue, void QPlaceJSonDetailsParser::processCategories(const QScriptValue &categories, QGeoPlace*targetPlace) { - targetPlace->setCategories(QPlaceJSonCategoriesParser::processCategories(categories)); + targetPlace->setCategories(QPlaceJSonCategoriesParser::parseFlatCategoryList(categories)); } void QPlaceJSonDetailsParser::processRatings(const QScriptValue &ratings, QGeoPlace*targetPlace) diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.cpp b/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.cpp index 5edb91df..8ecc52ef 100644 --- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.cpp +++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.cpp @@ -250,9 +250,21 @@ QPlaceReply *QPlaceManagerEngineNokia::initializeCategories() return reply; } -QList<QPlaceCategory> QPlaceManagerEngineNokia::categories() const +QList<QPlaceCategory> QPlaceManagerEngineNokia::categories(const QPlaceCategory &parent) const { - return QPlaceCategoriesRepository::instance()->categories(); + QPlaceCategoryTree tree = QPlaceCategoriesRepository::instance()->categories(); + tree = tree.findCategoryTreeById(parent.categoryId()); + + QList<QPlaceCategory> results; + + QHashIterator<QString, QPlaceCategoryTree> it(tree.subCategories); + while (it.hasNext()) { + it.next(); + + results.append(it.value().category); + } + + return results; } QLocale QPlaceManagerEngineNokia::locale() const diff --git a/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.h b/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.h index 0a42a648..8962562c 100644 --- a/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.h +++ b/src/plugins/geoservices/nokia/qplacemanagerengine_nokia.h @@ -87,7 +87,7 @@ public: QPlaceReply *removePlace(const QGeoPlace &place); QPlaceReply *initializeCategories(); - QList<QPlaceCategory> categories() const; + QList<QPlaceCategory> categories(const QPlaceCategory &parent) const; QLocale locale() const; void setLocale(const QLocale &locale); |