Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdeclarativesupportedcategoriesmodel.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 Aaron McCarthy <mccarthy.aaron@gmail.com>
2// Copyright (C) 2022 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
7#include "error_messages_p.h"
8#include <QtCore/private/qobject_p.h>
9
10#include <QCoreApplication>
11#include <QtQml/QQmlInfo>
12#include <QtLocation/QPlaceManager>
13#include <QtLocation/QPlaceIcon>
14
16
108
113
117// From QQmlParserStatus
119{
120 m_complete = true;
121 if (m_plugin) // do not try to load or change status when trying to update in componentComplete() if the plugin hasn't been set yet even once.
122 update();
123}
124
129{
130 if (m_categoriesTree.keys().isEmpty())
131 return 0;
132
133 PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer());
134 if (!node)
135 node = m_categoriesTree.value(QString());
136 else if (m_categoriesTree.keys(node).isEmpty())
137 return 0;
138
139 return node->childIds.count();
140}
141
146{
148
149 return 1;
150}
151
156{
157 if (column != 0 || row < 0)
158 return QModelIndex();
159
160 PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(parent.internalPointer());
161
162 if (!node)
163 node = m_categoriesTree.value(QString());
164 else if (m_categoriesTree.keys(node).isEmpty()) //return root index if parent is non-existent
165 return QModelIndex();
166
167 if (row > node->childIds.count())
168 return QModelIndex();
169
170 QString id = node->childIds.at(row);
171 Q_ASSERT(m_categoriesTree.contains(id));
172
173 return createIndex(row, 0, m_categoriesTree.value(id));
174}
175
180{
181 PlaceCategoryNode *childNode = static_cast<PlaceCategoryNode *>(child.internalPointer());
182 if (m_categoriesTree.keys(childNode).isEmpty())
183 return QModelIndex();
184
185 return index(childNode->parentId);
186}
187
192{
193 PlaceCategoryNode *node = static_cast<PlaceCategoryNode *>(index.internalPointer());
194 if (!node)
195 node = m_categoriesTree.value(QString());
196 else if (m_categoriesTree.keys(node).isEmpty())
197 return QVariant();
198
199 QDeclarativeCategory *category = node->declCategory.data();
200
201 switch (role) {
202 case Qt::DisplayRole:
203 return category->name();
204 case CategoryRole:
206 case ParentCategoryRole: {
207 if (!m_categoriesTree.keys().contains(node->parentId))
208 return QVariant();
209 else
210 return QVariant::fromValue(m_categoriesTree.value(node->parentId)->declCategory.data());
211 }
212 default:
213 return QVariant();
214 }
215}
216
218{
219 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
220 roles.insert(CategoryRole, "category");
221 roles.insert(ParentCategoryRole, "parentCategory");
222 return roles;
223}
224
229{
230 if (m_plugin == plugin)
231 return;
232
233 //disconnect the manager of the old plugin if we have one
234 if (m_plugin) {
235 disconnect(m_plugin, nullptr, this, nullptr);
236 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
237 if (serviceProvider) {
238 QPlaceManager *placeManager = serviceProvider->placeManager();
239 if (placeManager) {
241 this, &QDeclarativeSupportedCategoriesModel::addedCategory);
243 this, &QDeclarativeSupportedCategoriesModel::updatedCategory);
245 this, &QDeclarativeSupportedCategoriesModel::removedCategory);
247 this, &QDeclarativeSupportedCategoriesModel::emitDataChanged);
248 }
249 }
250 }
251
252 m_plugin = plugin;
253
254 // handle plugin attached changes -> update categories
255 if (m_plugin) {
256 if (m_plugin->isAttached()) {
257 connectNotificationSignals();
258 update();
259 } else {
263 this, &QDeclarativeSupportedCategoriesModel::connectNotificationSignals);
264 }
265 }
266
267 if (m_complete)
269}
270
278
283{
284 if (m_hierarchical == hierarchical)
285 return;
286
287 m_hierarchical = hierarchical;
289
290 updateLayout();
291}
292
297{
298 return m_hierarchical;
299}
300
304void QDeclarativeSupportedCategoriesModel::replyFinished()
305{
306 if (!m_response)
307 return;
308
309 m_response->deleteLater();
310
311 if (m_response->error() == QPlaceReply::NoError) {
312 m_errorString.clear();
313
314 m_response = nullptr;
315
316 updateLayout();
318 } else {
319 const QString errorString = m_response->errorString();
320
321 m_response = nullptr;
322
324 }
325}
326
330void QDeclarativeSupportedCategoriesModel::addedCategory(const QPlaceCategory &category,
331 const QString &parentId)
332{
333 if (m_response)
334 return;
335
336 if (!m_categoriesTree.contains(parentId))
337 return;
338
339 if (category.categoryId().isEmpty())
340 return;
341
342 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
343 if (!parentNode)
344 return;
345
346 int rowToBeAdded = rowToAddChild(parentNode, category);
347 QModelIndex parentIndex = index(parentId);
348 beginInsertRows(parentIndex, rowToBeAdded, rowToBeAdded);
349 PlaceCategoryNode *categoryNode = new PlaceCategoryNode;
350 categoryNode->parentId = parentId;
351 categoryNode->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, m_plugin, this));
352
353 m_categoriesTree.insert(category.categoryId(), categoryNode);
354 parentNode->childIds.insert(rowToBeAdded,category.categoryId());
356
357 //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel
358 //does not get updated when a child is added to a model
361}
362
366void QDeclarativeSupportedCategoriesModel::updatedCategory(const QPlaceCategory &category,
367 const QString &parentId)
368{
369 if (m_response)
370 return;
371
372 QString categoryId = category.categoryId();
373
374 if (!m_categoriesTree.contains(parentId))
375 return;
376
377 if (category.categoryId().isEmpty() || !m_categoriesTree.contains(categoryId))
378 return;
379
380 PlaceCategoryNode *newParentNode = m_categoriesTree.value(parentId);
381 if (!newParentNode)
382 return;
383
384 PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
385 if (!categoryNode)
386 return;
387
388 categoryNode->declCategory->setCategory(category);
389
390 if (categoryNode->parentId == parentId) { //reparenting to same parent
391 QModelIndex parentIndex = index(parentId);
392 int rowToBeAdded = rowToAddChild(newParentNode, category);
393 int oldRow = newParentNode->childIds.indexOf(categoryId);
394
395 //check if we are changing the position of the category
396 if (qAbs(rowToBeAdded - newParentNode->childIds.indexOf(categoryId)) > 1) {
397 //if the position has changed we are moving rows
398 beginMoveRows(parentIndex, oldRow, oldRow,
399 parentIndex, rowToBeAdded);
400
401 newParentNode->childIds.removeAll(categoryId);
402 newParentNode->childIds.insert(rowToBeAdded, categoryId);
403 endMoveRows();
404 } else {// if the position has not changed we modifying an existing row
405 QModelIndex categoryIndex = index(categoryId);
406 emit dataChanged(categoryIndex, categoryIndex);
407 }
408 } else { //reparenting to different parents
409 QPlaceCategory oldCategory = categoryNode->declCategory->category();
410 PlaceCategoryNode *oldParentNode = m_categoriesTree.value(categoryNode->parentId);
411 if (!oldParentNode)
412 return;
413 QModelIndex oldParentIndex = index(categoryNode->parentId);
414 QModelIndex newParentIndex = index(parentId);
415
416 int rowToBeAdded = rowToAddChild(newParentNode, category);
417 beginMoveRows(oldParentIndex, oldParentNode->childIds.indexOf(categoryId),
418 oldParentNode->childIds.indexOf(categoryId), newParentIndex, rowToBeAdded);
419 oldParentNode->childIds.removeAll(oldCategory.categoryId());
420 newParentNode->childIds.insert(rowToBeAdded, categoryId);
421 categoryNode->parentId = parentId;
422 endMoveRows();
423
424 //this is a workaround to deal with the fact that the hasModelChildren field of DelegateModel
425 //does not get updated when an index is updated to contain children
428 }
429}
430
434void QDeclarativeSupportedCategoriesModel::removedCategory(const QString &categoryId, const QString &parentId)
435{
436 if (m_response)
437 return;
438
439 if (!m_categoriesTree.contains(categoryId) || !m_categoriesTree.contains(parentId))
440 return;
441
442 QModelIndex parentIndex = index(parentId);
443 QModelIndex categoryIndex = index(categoryId);
444
445 beginRemoveRows(parentIndex, categoryIndex.row(), categoryIndex.row());
446 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
447 parentNode->childIds.removeAll(categoryId);
448 delete m_categoriesTree.take(categoryId);
450}
451
455void QDeclarativeSupportedCategoriesModel::connectNotificationSignals()
456{
457 if (!m_plugin)
458 return;
459
460 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
461 if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError)
462 return;
463
464 QPlaceManager *placeManager = serviceProvider->placeManager();
465 if (!placeManager)
466 return;
467
468 // listen for any category notifications so that we can reupdate the categories
469 // model.
471 this, &QDeclarativeSupportedCategoriesModel::addedCategory);
473 this, &QDeclarativeSupportedCategoriesModel::updatedCategory);
475 this, &QDeclarativeSupportedCategoriesModel::removedCategory);
476 connect(placeManager, &QPlaceManager::dataChanged,
477 this, &QDeclarativeSupportedCategoriesModel::emitDataChanged);
478}
479
484{
485 if (!m_complete)
486 return;
487
488 if (m_response)
489 return;
490
492
493 if (!m_plugin) {
494 updateLayout();
496 return;
497 }
498
499 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
500 if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError) {
501 updateLayout();
503 .arg(m_plugin->name()));
504 return;
505 }
506
507 QPlaceManager *placeManager = serviceProvider->placeManager();
508 if (!placeManager) {
509 updateLayout();
511 .arg(m_plugin->name()).arg(serviceProvider->errorString()));
512 return;
513 }
514
515 m_response = placeManager->initializeCategories();
516 if (m_response) {
517 connect(m_response, &QPlaceReply::finished,
518 this, &QDeclarativeSupportedCategoriesModel::replyFinished);
519 } else {
520 updateLayout();
523 }
524}
525
529void QDeclarativeSupportedCategoriesModel::updateLayout()
530{
532 qDeleteAll(m_categoriesTree);
533 m_categoriesTree.clear();
534
535 if (m_plugin) {
536 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
537 if (serviceProvider && serviceProvider->error() == QGeoServiceProvider::NoError) {
538 QPlaceManager *placeManager = serviceProvider->placeManager();
539 if (placeManager) {
541 node->childIds = populateCategories(placeManager, QPlaceCategory());
542 m_categoriesTree.insert(QString(), node);
543 node->declCategory = QSharedPointer<QDeclarativeCategory>
544 (new QDeclarativeCategory(QPlaceCategory(), m_plugin, this));
545 }
546 }
547 }
548
550}
551
553{
554 return m_errorString;
555}
556
580{
581 Status originalStatus = m_status;
582 m_status = status;
583 m_errorString = errorString;
584
585 if (originalStatus != m_status)
587}
588
593
597QStringList QDeclarativeSupportedCategoriesModel::populateCategories(QPlaceManager *manager, const QPlaceCategory &parent)
598{
600
601 QStringList childIds;
602
603 const auto byName = [](const QPlaceCategory &lhs, const QPlaceCategory &rhs) {
604 return lhs.name() < rhs.name();
605 };
606
607 auto categories = manager->childCategories(parent.categoryId());
608 std::sort(categories.begin(), categories.end(), byName);
609
610 for (const auto &category : std::as_const(categories)) {
611 auto node = new PlaceCategoryNode;
612 node->parentId = parent.categoryId();
613 node->declCategory = QSharedPointer<QDeclarativeCategory>(new QDeclarativeCategory(category, m_plugin ,this));
614
615 if (m_hierarchical)
616 node->childIds = populateCategories(manager, category);
617
618 m_categoriesTree.insert(node->declCategory->categoryId(), node);
619 childIds.append(category.categoryId());
620
621 if (!m_hierarchical) {
622 childIds.append(populateCategories(manager,node->declCategory->category()));
623 }
624 }
625 return childIds;
626}
627
632{
633 if (categoryId.isEmpty())
634 return QModelIndex();
635
636 if (!m_categoriesTree.contains(categoryId))
637 return QModelIndex();
638
639 PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
640 if (!categoryNode)
641 return QModelIndex();
642
643 QString parentCategoryId = categoryNode->parentId;
644
645 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentCategoryId);
646
647 return createIndex(parentNode->childIds.indexOf(categoryId), 0, categoryNode);
648}
649
653int QDeclarativeSupportedCategoriesModel::rowToAddChild(PlaceCategoryNode *node, const QPlaceCategory &category)
654{
655 Q_ASSERT(node);
656 for (qsizetype i = 0; i < node->childIds.count(); ++i) {
657 if (category.name() < m_categoriesTree.value(node->childIds.at(i))->declCategory->name())
658 return i;
659 }
660 return node->childIds.count();
661}
662
Q_INVOKABLE int const QModelIndex & parent
Returns the parent of the model item with the given index.
void endResetModel()
Completes a model reset operation.
bool beginMoveRows(const QModelIndex &sourceParent, int sourceFirst, int sourceLast, const QModelIndex &destinationParent, int destinationRow)
void endRemoveRows()
Ends a row removal operation.
void endMoveRows()
Ends a row move operation.
virtual QHash< int, QByteArray > roleNames() const
void endInsertRows()
Ends a row insertion operation.
void beginResetModel()
Begins a model reset operation.
QModelIndex createIndex(int row, int column, const void *data=nullptr) const
Creates a model index for the given row and column with the internal pointer ptr.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
Begins a row removal operation.
void beginInsertRows(const QModelIndex &parent, int first, int last)
Begins a row insertion operation.
static QString translate(const char *context, const char *key, const char *disambiguation=nullptr, int n=-1)
\threadsafe
void setCategory(const QPlaceCategory &category)
QGeoServiceProvider * sharedGeoServiceProvider() const
int rowCount(const QModelIndex &parent) const override
Q_INVOKABLE QVariant data(const QModelIndex &index, int role) const override
void setPlugin(QDeclarativeGeoServiceProvider *plugin)
QModelIndex index(int row, int column, const QModelIndex &parent) const override
QHash< int, QByteArray > roleNames() const override
void setStatus(Status status, const QString &errorString=QString())
\qmlproperty enumeration CategoryModel::status
int columnCount(const QModelIndex &parent) const override
\inmodule QtLocation
Error error() const
Returns an error code describing the error which occurred during the last operation that was performe...
QPlaceManager * placeManager() const
Returns the QPlaceManager made available by the service provider.
QString errorString() const
Returns a string describing the error which occurred during the last operation that was performed by ...
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
Definition qhash.h:1086
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
T value(const Key &key) const noexcept
Definition qhash.h:1054
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
bool isEmpty() const noexcept
Definition qlist.h:401
\inmodule QtCore
void * internalPointer() const noexcept
Returns a {void} {*} pointer used by the model to associate the index with the internal data structur...
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
\inmodule QtLocation
QString name() const
Returns the name of category.
\inmodule QtLocation
void categoryAdded(const QPlaceCategory &category, const QString &parentId)
This signal is emitted if a category has been added to the manager's datastore.
QPlaceReply * initializeCategories()
Initializes the categories of the manager.
void categoryRemoved(const QString &categoryId, const QString &parentId)
This signal is emitted when the category corresponding to categoryId has been removed from the manage...
void dataChanged()
This signal is emitted by the manager if there are large scale changes to its underlying datastore an...
void categoryUpdated(const QPlaceCategory &category, const QString &parentId)
This signal is emitted if a category has been modified in the manager's datastore.
QPlaceReply::Error error() const
Returns the error code.
void finished()
This signal is emitted when this reply has finished processing.
QString errorString() const
Returns the error string of the reply.
T * data() const noexcept
Returns the value of the pointer referenced by this object.
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
const QLoggingCategory & category()
[1]
qDeleteAll(list.begin(), list.end())
QT_BEGIN_NAMESPACE const char CONTEXT_NAME[]
const char PLUGIN_ERROR[]
const char PLUGIN_PROVIDER_ERROR[]
const char PLUGIN_PROPERTY_NOT_SET[]
const char CATEGORIES_NOT_INITIALIZED[]
Combined button and popup list for selecting options.
@ DisplayRole
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLuint index
[2]
GLenum GLenum GLsizei void GLsizei void * column
GLsizei GLenum * categories
GLenum GLenum GLsizei void * row
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
SSL_CTX int void * arg
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
myObject disconnect()
[26]
QLayoutItem * child
[0]
QNetworkAccessManager manager
bool contains(const AT &t) const noexcept
Definition qlist.h:45