9#include <QtCore/private/qobject_p.h>
11#include <QCoreApplication>
12#include <QtQml/QQmlInfo>
13#include <QtLocation/QPlaceManager>
14#include <QtLocation/QPlaceIcon>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
62
63
64
65
68
69
70
71
72
75
76
77
78
79
82
83
84
85
86
87
88
89
92
93
94
95
96
97
98
101
102
103
105QDeclarativeSupportedCategoriesModel::QDeclarativeSupportedCategoriesModel(QObject *parent)
106 : QAbstractItemModel(parent)
110QDeclarativeSupportedCategoriesModel::~QDeclarativeSupportedCategoriesModel()
112 qDeleteAll(m_categoriesTree);
116
117
119void QDeclarativeSupportedCategoriesModel::componentComplete()
127
128
129int QDeclarativeSupportedCategoriesModel::rowCount(
const QModelIndex &parent)
const
131 if (m_categoriesTree.keys().isEmpty())
134 PlaceCategoryNode *node =
static_cast<PlaceCategoryNode *>(parent.internalPointer());
136 node = m_categoriesTree.value(QString());
137 else if (m_categoriesTree.keys(node).isEmpty())
140 return node->childIds.count();
144
145
146int QDeclarativeSupportedCategoriesModel::columnCount(
const QModelIndex &parent)
const
154
155
156QModelIndex QDeclarativeSupportedCategoriesModel::index(
int row,
int column,
const QModelIndex &parent)
const
158 if (column != 0 || row < 0)
159 return QModelIndex();
161 PlaceCategoryNode *node =
static_cast<PlaceCategoryNode *>(parent.internalPointer());
164 node = m_categoriesTree.value(QString());
165 else if (m_categoriesTree.keys(node).isEmpty())
166 return QModelIndex();
168 if (row > node->childIds.count())
169 return QModelIndex();
171 QString id = node->childIds.at(row);
172 Q_ASSERT(m_categoriesTree.contains(id));
174 return createIndex(row, 0, m_categoriesTree.value(id));
178
179
180QModelIndex QDeclarativeSupportedCategoriesModel::parent(
const QModelIndex &child)
const
182 PlaceCategoryNode *childNode =
static_cast<PlaceCategoryNode *>(child.internalPointer());
183 if (m_categoriesTree.keys(childNode).isEmpty())
184 return QModelIndex();
186 return index(childNode->parentId);
190
191
192QVariant QDeclarativeSupportedCategoriesModel::data(
const QModelIndex &index,
int role)
const
194 PlaceCategoryNode *node =
static_cast<PlaceCategoryNode *>(index.internalPointer());
196 node = m_categoriesTree.value(QString());
197 else if (m_categoriesTree.keys(node).isEmpty())
200 QDeclarativeCategory *category = node->declCategory.data();
203 case Qt::DisplayRole:
204 return category->name();
206 return QVariant::fromValue(category);
207 case ParentCategoryRole: {
208 if (!m_categoriesTree.keys().contains(node->parentId))
211 return QVariant::fromValue(m_categoriesTree.value(node->parentId)->declCategory.data());
218QHash<
int, QByteArray> QDeclarativeSupportedCategoriesModel::roleNames()
const
220 QHash<
int, QByteArray> roles = QAbstractItemModel::roleNames();
221 roles.insert(CategoryRole,
"category");
222 roles.insert(ParentCategoryRole,
"parentCategory");
227
228
229void QDeclarativeSupportedCategoriesModel::setPlugin(QDeclarativeGeoServiceProvider *plugin)
231 if (m_plugin == plugin)
236 disconnect(m_plugin,
nullptr,
this,
nullptr);
237 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
238 if (serviceProvider) {
239 QPlaceManager *placeManager = serviceProvider->placeManager();
241 disconnect(placeManager, &QPlaceManager::categoryAdded,
242 this, &QDeclarativeSupportedCategoriesModel::addedCategory);
243 disconnect(placeManager, &QPlaceManager::categoryUpdated,
244 this, &QDeclarativeSupportedCategoriesModel::updatedCategory);
245 disconnect(placeManager, &QPlaceManager::categoryRemoved,
246 this, &QDeclarativeSupportedCategoriesModel::removedCategory);
247 disconnect(placeManager, &QPlaceManager::dataChanged,
248 this, &QDeclarativeSupportedCategoriesModel::emitDataChanged);
257 if (m_plugin->isAttached()) {
258 connectNotificationSignals();
261 connect(m_plugin, &QDeclarativeGeoServiceProvider::attached,
262 this, &QDeclarativeSupportedCategoriesModel::update);
263 connect(m_plugin, &QDeclarativeGeoServiceProvider::attached,
264 this, &QDeclarativeSupportedCategoriesModel::connectNotificationSignals);
269 emit pluginChanged();
273
274
275QDeclarativeGeoServiceProvider *QDeclarativeSupportedCategoriesModel::plugin()
const
281
282
283void QDeclarativeSupportedCategoriesModel::setHierarchical(
bool hierarchical)
285 if (m_hierarchical == hierarchical)
288 m_hierarchical = hierarchical;
289 emit hierarchicalChanged();
295
296
297bool QDeclarativeSupportedCategoriesModel::hierarchical()
const
299 return m_hierarchical;
303
304
305void QDeclarativeSupportedCategoriesModel::replyFinished()
310 m_response->deleteLater();
312 if (m_response->error() == QPlaceReply::NoError) {
313 m_errorString.clear();
315 m_response =
nullptr;
318 setStatus(QDeclarativeSupportedCategoriesModel::Ready);
320 const QString errorString = m_response->errorString();
322 m_response =
nullptr;
324 setStatus(Error, errorString);
329
330
331void QDeclarativeSupportedCategoriesModel::addedCategory(
const QPlaceCategory &category,
332 const QString &parentId)
337 if (!m_categoriesTree.contains(parentId))
340 if (category.categoryId().isEmpty())
343 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
347 int rowToBeAdded = rowToAddChild(parentNode, category);
348 QModelIndex parentIndex = index(parentId);
349 beginInsertRows(parentIndex, rowToBeAdded, rowToBeAdded);
350 PlaceCategoryNode *categoryNode =
new PlaceCategoryNode;
351 categoryNode->parentId = parentId;
352 categoryNode->declCategory = QSharedPointer<QDeclarativeCategory>(
new QDeclarativeCategory(category, m_plugin,
this));
354 m_categoriesTree.insert(category.categoryId(), categoryNode);
355 parentNode->childIds.insert(rowToBeAdded,category.categoryId());
365
366
367void QDeclarativeSupportedCategoriesModel::updatedCategory(
const QPlaceCategory &category,
368 const QString &parentId)
373 QString categoryId = category.categoryId();
375 if (!m_categoriesTree.contains(parentId))
378 if (category.categoryId().isEmpty() || !m_categoriesTree.contains(categoryId))
381 PlaceCategoryNode *newParentNode = m_categoriesTree.value(parentId);
385 PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
389 categoryNode->declCategory->setCategory(category);
391 if (categoryNode->parentId == parentId) {
392 QModelIndex parentIndex = index(parentId);
393 int rowToBeAdded = rowToAddChild(newParentNode, category);
394 int oldRow = newParentNode->childIds.indexOf(categoryId);
397 if (qAbs(rowToBeAdded - newParentNode->childIds.indexOf(categoryId)) > 1) {
399 beginMoveRows(parentIndex, oldRow, oldRow,
400 parentIndex, rowToBeAdded);
402 newParentNode->childIds.removeAll(categoryId);
403 newParentNode->childIds.insert(rowToBeAdded, categoryId);
406 QModelIndex categoryIndex = index(categoryId);
407 emit dataChanged(categoryIndex, categoryIndex);
410 QPlaceCategory oldCategory = categoryNode->declCategory->category();
411 PlaceCategoryNode *oldParentNode = m_categoriesTree.value(categoryNode->parentId);
414 QModelIndex oldParentIndex = index(categoryNode->parentId);
415 QModelIndex newParentIndex = index(parentId);
417 int rowToBeAdded = rowToAddChild(newParentNode, category);
418 beginMoveRows(oldParentIndex, oldParentNode->childIds.indexOf(categoryId),
419 oldParentNode->childIds.indexOf(categoryId), newParentIndex, rowToBeAdded);
420 oldParentNode->childIds.removeAll(oldCategory.categoryId());
421 newParentNode->childIds.insert(rowToBeAdded, categoryId);
422 categoryNode->parentId = parentId;
433
434
435void QDeclarativeSupportedCategoriesModel::removedCategory(
const QString &categoryId,
const QString &parentId)
440 if (!m_categoriesTree.contains(categoryId) || !m_categoriesTree.contains(parentId))
443 QModelIndex parentIndex = index(parentId);
444 QModelIndex categoryIndex = index(categoryId);
446 beginRemoveRows(parentIndex, categoryIndex.row(), categoryIndex.row());
447 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentId);
448 parentNode->childIds.removeAll(categoryId);
449 delete m_categoriesTree.take(categoryId);
454
455
456void QDeclarativeSupportedCategoriesModel::connectNotificationSignals()
461 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
462 if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError)
465 QPlaceManager *placeManager = serviceProvider->placeManager();
471 connect(placeManager, &QPlaceManager::categoryAdded,
472 this, &QDeclarativeSupportedCategoriesModel::addedCategory);
473 connect(placeManager, &QPlaceManager::categoryUpdated,
474 this, &QDeclarativeSupportedCategoriesModel::updatedCategory);
475 connect(placeManager, &QPlaceManager::categoryRemoved,
476 this, &QDeclarativeSupportedCategoriesModel::removedCategory);
477 connect(placeManager, &QPlaceManager::dataChanged,
478 this, &QDeclarativeSupportedCategoriesModel::emitDataChanged);
482
483
484void QDeclarativeSupportedCategoriesModel::update()
496 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROPERTY_NOT_SET));
500 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
501 if (!serviceProvider || serviceProvider->error() != QGeoServiceProvider::NoError) {
503 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_PROVIDER_ERROR)
504 .arg(m_plugin->name()));
508 QPlaceManager *placeManager = serviceProvider->placeManager();
511 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME, PLUGIN_ERROR)
512 .arg(m_plugin->name()).arg(serviceProvider->errorString()));
516 m_response = placeManager->initializeCategories();
518 connect(m_response, &QPlaceReply::finished,
519 this, &QDeclarativeSupportedCategoriesModel::replyFinished);
522 setStatus(Error, QCoreApplication::translate(CONTEXT_NAME,
523 CATEGORIES_NOT_INITIALIZED));
528
529
530void QDeclarativeSupportedCategoriesModel::updateLayout()
533 qDeleteAll(m_categoriesTree);
534 m_categoriesTree.clear();
537 QGeoServiceProvider *serviceProvider = m_plugin->sharedGeoServiceProvider();
538 if (serviceProvider && serviceProvider->error() == QGeoServiceProvider::NoError) {
539 QPlaceManager *placeManager = serviceProvider->placeManager();
541 PlaceCategoryNode *node =
new PlaceCategoryNode;
542 node->childIds = populateCategories(placeManager, QPlaceCategory());
543 m_categoriesTree.insert(QString(), node);
544 node->declCategory = QSharedPointer<QDeclarativeCategory>
545 (
new QDeclarativeCategory(QPlaceCategory(), m_plugin,
this));
553QString QDeclarativeSupportedCategoriesModel::errorString()
const
555 return m_errorString;
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580void QDeclarativeSupportedCategoriesModel::setStatus(Status status,
const QString &errorString)
582 Status originalStatus = m_status;
584 m_errorString = errorString;
586 if (originalStatus != m_status)
587 emit statusChanged();
590QDeclarativeSupportedCategoriesModel::Status QDeclarativeSupportedCategoriesModel::status()
const
596
597
598QStringList QDeclarativeSupportedCategoriesModel::populateCategories(QPlaceManager *manager,
const QPlaceCategory &parent)
602 QStringList childIds;
604 const auto byName = [](
const QPlaceCategory &lhs,
const QPlaceCategory &rhs) {
605 return lhs.name() < rhs.name();
608 auto categories = manager->childCategories(parent.categoryId());
609 std::sort(categories.begin(), categories.end(), byName);
611 for (
const auto &category : std::as_const(categories)) {
612 auto node =
new PlaceCategoryNode;
613 node->parentId = parent.categoryId();
614 node->declCategory = QSharedPointer<QDeclarativeCategory>(
new QDeclarativeCategory(category, m_plugin ,
this));
617 node->childIds = populateCategories(manager, category);
619 m_categoriesTree.insert(node->declCategory->categoryId(), node);
620 childIds.append(category.categoryId());
622 if (!m_hierarchical) {
623 childIds.append(populateCategories(manager,node->declCategory->category()));
630
631
632QModelIndex QDeclarativeSupportedCategoriesModel::index(
const QString &categoryId)
const
634 if (categoryId.isEmpty())
635 return QModelIndex();
637 if (!m_categoriesTree.contains(categoryId))
638 return QModelIndex();
640 PlaceCategoryNode *categoryNode = m_categoriesTree.value(categoryId);
642 return QModelIndex();
644 QString parentCategoryId = categoryNode->parentId;
646 PlaceCategoryNode *parentNode = m_categoriesTree.value(parentCategoryId);
648 return createIndex(parentNode->childIds.indexOf(categoryId), 0, categoryNode);
652
653
654int QDeclarativeSupportedCategoriesModel::rowToAddChild(PlaceCategoryNode *node,
const QPlaceCategory &category)
657 for (qsizetype i = 0; i < node->childIds.count(); ++i) {
658 if (category.name() < m_categoriesTree.value(node->childIds.at(i))->declCategory->name())
661 return node->childIds.count();
665
666
667
668
669
670
671
672
673
674
675
Combined button and popup list for selecting options.