8#include <QtCore/qloggingcategory.h>
10#include <QtQml/qqmlinfo.h>
11#include <QtQml/qqmlengine.h>
15using namespace Qt::StringLiterals;
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
60
61
63QQmlTreeModel::QQmlTreeModel(QObject *parent)
64 : QQmlAbstractColumnModel(parent)
68QQmlTreeModel::~QQmlTreeModel() =
default;
71
72
73
74
75
76
77QVariant QQmlTreeModel::rows()
const
79 QVariantList rowsAsVariant;
80 for (
const auto &row : mRows)
81 rowsAsVariant.append(row->toVariant());
86void QQmlTreeModel::setRows(
const QVariant &rows)
88 const std::optional<QVariantList> validated = validateRowsArgument(rows);
92 const QVariantList rowsAsVariantList = *validated;
94 if (!mComponentCompleted) {
96 mInitialRows = rowsAsVariantList;
100 setRowsPrivate(rowsAsVariantList);
103void QQmlTreeModel::setRowsPrivate(
const QVariantList &rowsAsVariantList)
105 Q_ASSERT(mComponentCompleted);
108 if (mColumns.isEmpty()) {
109 qmlWarning(
this) <<
"No TableModelColumns were set; model will be empty";
113 const bool firstTimeValidRowsHaveBeenSet = mColumnMetadata.isEmpty();
114 if (!firstTimeValidRowsHaveBeenSet) {
116 for (
const auto &row : rowsAsVariantList) {
119 const QVariant wrappedRow = QVariant::fromValue(row);
120 if (!validateNewRow(
"TreeModel::setRows"_L1, wrappedRow, SetRowsOperation))
129 const bool wasEmpty = mRows.empty();
135 for (
const auto &rowAsVariant : rowsAsVariantList) {
136 if (rowAsVariant.canConvert<QVariantMap>())
137 mRows.push_back(std::make_unique<QQmlTreeRow>(rowAsVariant));
139 qmlWarning(
this) <<
"Cannot create tree row as the row does not contain "
140 <<
"key-value pairs";
145 if (firstTimeValidRowsHaveBeenSet && (!mRows.empty() || !mInitialRows.isEmpty()))
146 fetchColumnMetadata();
155 if (!wasEmpty || !mRows.empty())
159QVariant QQmlTreeModel::dataPrivate(
const QModelIndex &index,
const QString &roleName)
const
161 const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
162 const QString propertyName = columnMetadata.roles.value(roleName).name;
163 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
164 return thisRow->data(propertyName);
167void QQmlTreeModel::setDataPrivate(
const QModelIndex &index,
const QString &roleName, QVariant value)
169 auto *row =
static_cast<QQmlTreeRow *>(index.internalPointer());
170 row->setField(roleName, value);
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210void QQmlTreeModel::appendRow(QModelIndex parent,
const QVariant &row)
212 if (!validateNewRow(
"TreeModel::appendRow"_L1, row))
215 const QVariant data = row.userType() == QMetaType::QVariantMap ? row : row.value<QJSValue>().toVariant();
217 if (parent.isValid()) {
218 auto *parentRow =
static_cast<QQmlTreeRow *>(parent.internalPointer());
219 auto *newChild =
new QQmlTreeRow(data);
221 beginInsertRows(parent,
static_cast<
int>(parentRow->rowCount()),
static_cast<
int>(parentRow->rowCount()));
222 parentRow->addChild(newChild);
225 if (mColumnMetadata.isEmpty())
226 fetchColumnMetadata();
230 qmlWarning(
this) <<
"append: could not find any node at the specified index"
231 <<
" - the new row will be appended to root";
233 if (data.canConvert<QVariantMap>()) {
234 beginInsertRows(QModelIndex(),
235 static_cast<
int>(mRows.size()),
236 static_cast<
int>(mRows.size()));
238 mRows.push_back(std::make_unique<QQmlTreeRow>(data));
241 if (mColumnMetadata.isEmpty())
242 fetchColumnMetadata();
246 qmlWarning(
this) <<
"Cannot create tree row as the row does not contain "
247 <<
"key-value pairs";
256
257
258
259
260
261
262void QQmlTreeModel::appendRow(
const QVariant &row)
268
269
270
271
272
273
274void QQmlTreeModel::clear()
276 QQmlEngine *engine = qmlEngine(
this);
278 setRows(QVariant::fromValue(engine->newArray()));
282
283
284
285
286
287
288
289
290
291
292QVariant QQmlTreeModel::getRow(
const QModelIndex &rowIndex)
const
294 if (rowIndex.isValid())
295 return static_cast<QQmlTreeRow*>(rowIndex.internalPointer())->toVariant();
297 qmlWarning(
this) <<
"getRow: could not find any node at the specified index";
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
321void QQmlTreeModel::insertRow(
int rowIndex, QModelIndex parent,
const QVariant &row)
324 qmlWarning(
this).noquote() <<
"insertRow(): rowIndex cannot be negative";
327 if (rowIndex > rowCount(parent)) {
328 qmlWarning(
this).noquote() <<
"insertRow(): rowIndex " << rowIndex
329 <<
" is greater than rowCount() of "
333 if (!validateNewRow(
"insertRow()"_L1, row))
336 doInsert(parent, rowIndex, row);
340
341
342
343
344
345
346
347
348void QQmlTreeModel::insertRow(
int rowIndex,
const QVariant &row)
350 insertRow(rowIndex, {}, row);
353void QQmlTreeModel::doInsert(
const QModelIndex &parent,
int rowIndex,
const QVariant &row)
355 beginInsertRows(parent, rowIndex, rowIndex);
357 const QVariant data =
358 row.userType() == QMetaType::QVariantMap
360 : row.value<QJSValue>().toVariant();
362 auto *newChild =
new QQmlTreeRow(data);
363 if (parent.isValid())
364 static_cast<QQmlTreeRow *>(parent.internalPointer())->insertChild(rowIndex, newChild);
366 mRows.insert(mRows.begin() + rowIndex, std::unique_ptr<QQmlTreeRow>(newChild));
368 qCDebug(lcTreeModel).nospace() <<
"inserted the following row to the row "
369 << parent <<
" at index "
370 << rowIndex <<
":\n" << data.toMap();
373 if (mColumnMetadata.isEmpty())
374 fetchColumnMetadata();
380QVariant QQmlTreeModel::firstRow()
const
382 return mRows.front().get()->data();
385void QQmlTreeModel::setInitialRows()
387 setRowsPrivate(mInitialRows);
391
392
393
394
395
396
397
398
399
400
401
402void QQmlTreeModel::removeRow(QModelIndex rowIndex)
404 if (rowIndex.isValid()) {
405 QModelIndex mIndexParent = rowIndex.parent();
407 beginRemoveRows(mIndexParent, rowIndex.row(), rowIndex.row());
409 if (mIndexParent.isValid()) {
410 auto *parent =
static_cast<QQmlTreeRow *>(mIndexParent.internalPointer());
411 parent->removeChildAt(rowIndex.row());
413 mRows.erase(std::next(mRows.begin(), rowIndex.row()));
418 qmlWarning(
this) <<
"TreeModel::removeRow could not find any node at the specified index";
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451void QQmlTreeModel::setRow(QModelIndex rowIndex,
const QVariant &rowData)
453 if (!rowIndex.isValid()) {
454 qmlWarning(
this) <<
"TreeModel::setRow: invalid modelIndex";
458 const QVariantMap rowAsMap = rowData.toMap();
459 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList) {
460 qmlWarning(
this) <<
"TreeModel::setRow: child rows are not allowed";
464 if (!validateNewRow(
"TreeModel::setRow"_L1, rowData))
467 const QVariant rowAsVariant = rowData.userType() == QMetaType::QVariantMap ? rowData : rowData.value<QJSValue>().toVariant();
468 auto *row =
static_cast<QQmlTreeRow *>(rowIndex.internalPointer());
469 row->setData(rowAsVariant);
471 const QModelIndex topLeftModelIndex(createIndex(rowIndex.row(), 0, rowIndex.internalPointer()));
472 const QModelIndex bottomRightModelIndex(createIndex(rowIndex.row(), mColumnCount-1, rowIndex.internalPointer()));
474 emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
479
480
481
482
483
484
485
486
487
488
489QModelIndex QQmlTreeModel::index(
int row,
int column,
const QModelIndex &parent)
const
491 if (!parent.isValid()){
492 if (
static_cast<size_t>(row) >= mRows.size())
495 return createIndex(row, column, mRows.at(row).get());
498 const auto *treeRow =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
499 if (treeRow->rowCount() <=
static_cast<size_t>(row))
502 return createIndex(row, column, treeRow->getRow(row));
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551QModelIndex QQmlTreeModel::index(
const std::vector<
int> &treeIndex,
int column)
554 QQmlTreeRow *row = getPointerToTreeRow(mIndex, treeIndex);
557 return createIndex(treeIndex.back(), column, row);
559 qmlWarning(
this) <<
"TreeModel::index: could not find any node at the specified index: "
564QModelIndex QQmlTreeModel::parent(
const QModelIndex &index)
const
566 if (!index.isValid())
569 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
570 const QQmlTreeRow *parentRow = thisRow->parent();
575 const QQmlTreeRow *grandparentRow = parentRow->parent();
577 if (!grandparentRow) {
578 for (size_t i = 0; i < mRows.size(); i++) {
579 if (mRows[i].get() == parentRow)
580 return createIndex(
static_cast<
int>(i), 0, parentRow);
582 Q_UNREACHABLE_RETURN(QModelIndex());
585 for (size_t i = 0; i < grandparentRow->rowCount(); i++) {
586 if (grandparentRow->getRow(
static_cast<
int>(i)) == parentRow)
587 return createIndex(
static_cast<
int>(i), 0, parentRow);
589 Q_UNREACHABLE_RETURN(QModelIndex());
593int QQmlTreeModel::rowCount(
const QModelIndex &parent)
const
595 if (!parent.isValid())
596 return static_cast<
int>(mRows.size());
598 const auto *row =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
599 return static_cast<
int>(row->rowCount());
603
604
605
606
607
608
609
610
611
612int QQmlTreeModel::columnCount(
const QModelIndex &parent)
const
620
621
622
623
624
625
626
627
628
631
632
633
634
635
636
637
638
639
641bool QQmlTreeModel::validateNewRow(QLatin1StringView functionName,
const QVariant &row,
642 NewRowOperationFlag operation)
const
644 const bool isVariantMap = (row.userType() == QMetaType::QVariantMap);
645 const QVariant rowAsVariant = operation == SetRowsOperation || isVariantMap
646 ? row : row.value<QJSValue>().toVariant();
647 const QVariantMap rowAsMap = rowAsVariant.toMap();
648 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList)
650 const QList<QVariant> variantList = rowAsMap[ROWS_PROPERTY_NAME].toList();
651 for (
const QVariant &rowAsVariant : variantList)
652 if (!validateNewRow(functionName, rowAsVariant))
656 return QQmlAbstractColumnModel::validateNewRow(functionName, row, operation);
659int QQmlTreeModel::treeSize()
const
663 for (
const auto &treeRow : mRows)
664 treeSize += treeRow->subTreeSize();
669QQmlTreeRow *QQmlTreeModel::getPointerToTreeRow(QModelIndex &modIndex,
670 const std::vector<
int> &rowIndex)
const
672 for (
int r : rowIndex) {
673 modIndex = index(r, 0, modIndex);
674 if (!modIndex.isValid())
678 return static_cast<QQmlTreeRow*>(modIndex.internalPointer());
683#include "moc_qqmltreemodel_p.cpp"
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
static const QString ROWS_PROPERTY_NAME