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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
99QQmlTreeModel::QQmlTreeModel(QObject *parent)
100 : QQmlAbstractColumnModel(parent)
104QQmlTreeModel::~QQmlTreeModel() =
default;
107
108
109
110
111
112
113QVariant QQmlTreeModel::rows()
const
115 QVariantList rowsAsVariant;
116 for (
const auto &row : mRows)
117 rowsAsVariant.append(row->toVariant());
119 return rowsAsVariant;
122void QQmlTreeModel::setRows(
const QVariant &rows)
124 const std::optional<QVariantList> validated = validateRowsArgument(rows);
128 const QVariantList rowsAsVariantList = *validated;
130 if (!mComponentCompleted) {
132 mInitialRows = rowsAsVariantList;
136 setRowsPrivate(rowsAsVariantList);
139void QQmlTreeModel::setRowsPrivate(
const QVariantList &rowsAsVariantList)
141 Q_ASSERT(mComponentCompleted);
144 if (mColumns.isEmpty()) {
145 qmlWarning(
this) <<
"No TableModelColumns were set; model will be empty";
149 const bool firstTimeValidRowsHaveBeenSet = mColumnMetadata.isEmpty();
150 if (!firstTimeValidRowsHaveBeenSet) {
152 for (
const auto &row : rowsAsVariantList) {
155 const QVariant wrappedRow = QVariant::fromValue(row);
156 if (!validateNewRow(
"TreeModel::setRows"_L1, wrappedRow, SetRowsOperation))
165 const bool wasEmpty = mRows.empty();
171 for (
const auto &rowAsVariant : rowsAsVariantList) {
172 if (rowAsVariant.canConvert<QVariantMap>())
173 mRows.push_back(std::make_unique<QQmlTreeRow>(rowAsVariant));
175 qmlWarning(
this) <<
"Cannot create tree row as the row does not contain "
176 <<
"key-value pairs";
181 if (firstTimeValidRowsHaveBeenSet && (!mRows.empty() || !mInitialRows.isEmpty()))
182 fetchColumnMetadata();
191 if (!wasEmpty || !mRows.empty())
195QVariant QQmlTreeModel::dataPrivate(
const QModelIndex &index,
const QString &roleName)
const
197 const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
198 const QString propertyName = columnMetadata.roles.value(roleName).name;
199 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
200 return thisRow->data(propertyName);
203void QQmlTreeModel::setDataPrivate(
const QModelIndex &index,
const QString &roleName, QVariant value)
205 auto *row =
static_cast<QQmlTreeRow *>(index.internalPointer());
206 row->setField(roleName, value);
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246void QQmlTreeModel::appendRow(QModelIndex parent,
const QVariant &row)
248 if (!validateNewRow(
"TreeModel::appendRow"_L1, row))
251 const QVariant data = row.userType() == QMetaType::QVariantMap ? row : row.value<QJSValue>().toVariant();
253 if (parent.isValid()) {
254 auto *parentRow =
static_cast<QQmlTreeRow *>(parent.internalPointer());
255 auto *newChild =
new QQmlTreeRow(data);
257 beginInsertRows(parent,
static_cast<
int>(parentRow->rowCount()),
static_cast<
int>(parentRow->rowCount()));
258 parentRow->addChild(newChild);
261 if (mColumnMetadata.isEmpty())
262 fetchColumnMetadata();
266 qmlWarning(
this) <<
"append: could not find any node at the specified index"
267 <<
" - the new row will be appended to root";
269 if (data.canConvert<QVariantMap>()) {
270 beginInsertRows(QModelIndex(),
271 static_cast<
int>(mRows.size()),
272 static_cast<
int>(mRows.size()));
274 mRows.push_back(std::make_unique<QQmlTreeRow>(data));
277 if (mColumnMetadata.isEmpty())
278 fetchColumnMetadata();
282 qmlWarning(
this) <<
"Cannot create tree row as the row does not contain "
283 <<
"key-value pairs";
292
293
294
295
296
297
298void QQmlTreeModel::appendRow(
const QVariant &row)
304
305
306
307
308
309
310void QQmlTreeModel::clear()
312 QQmlEngine *engine = qmlEngine(
this);
314 setRows(QVariant::fromValue(engine->newArray()));
318
319
320
321
322
323
324
325
326
327
328QVariant QQmlTreeModel::getRow(
const QModelIndex &rowIndex)
const
330 if (rowIndex.isValid())
331 return static_cast<QQmlTreeRow*>(rowIndex.internalPointer())->toVariant();
333 qmlWarning(
this) <<
"getRow: could not find any node at the specified index";
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
357void QQmlTreeModel::insertRow(
int rowIndex, QModelIndex parent,
const QVariant &row)
360 qmlWarning(
this).noquote() <<
"insertRow(): rowIndex cannot be negative";
363 if (rowIndex > rowCount(parent)) {
364 qmlWarning(
this).noquote() <<
"insertRow(): rowIndex " << rowIndex
365 <<
" is greater than rowCount() of "
369 if (!validateNewRow(
"insertRow()"_L1, row))
372 doInsert(parent, rowIndex, row);
376
377
378
379
380
381
382
383
384void QQmlTreeModel::insertRow(
int rowIndex,
const QVariant &row)
386 insertRow(rowIndex, {}, row);
389void QQmlTreeModel::doInsert(
const QModelIndex &parent,
int rowIndex,
const QVariant &row)
391 beginInsertRows(parent, rowIndex, rowIndex);
393 const QVariant data =
394 row.userType() == QMetaType::QVariantMap
396 : row.value<QJSValue>().toVariant();
398 auto *newChild =
new QQmlTreeRow(data);
399 if (parent.isValid())
400 static_cast<QQmlTreeRow *>(parent.internalPointer())->insertChild(rowIndex, newChild);
402 mRows.insert(mRows.begin() + rowIndex, std::unique_ptr<QQmlTreeRow>(newChild));
404 qCDebug(lcTreeModel).nospace() <<
"inserted the following row to the row "
405 << parent <<
" at index "
406 << rowIndex <<
":\n" << data.toMap();
409 if (mColumnMetadata.isEmpty())
410 fetchColumnMetadata();
416QVariant QQmlTreeModel::firstRow()
const
418 return mRows.front().get()->data();
421void QQmlTreeModel::setInitialRows()
423 setRowsPrivate(mInitialRows);
427
428
429
430
431
432
433
434
435
436
437
438void QQmlTreeModel::removeRow(QModelIndex rowIndex)
440 if (rowIndex.isValid()) {
441 QModelIndex mIndexParent = rowIndex.parent();
443 beginRemoveRows(mIndexParent, rowIndex.row(), rowIndex.row());
445 if (mIndexParent.isValid()) {
446 auto *parent =
static_cast<QQmlTreeRow *>(mIndexParent.internalPointer());
447 parent->removeChildAt(rowIndex.row());
449 mRows.erase(std::next(mRows.begin(), rowIndex.row()));
454 qmlWarning(
this) <<
"TreeModel::removeRow could not find any node at the specified index";
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487void QQmlTreeModel::setRow(QModelIndex rowIndex,
const QVariant &rowData)
489 if (!rowIndex.isValid()) {
490 qmlWarning(
this) <<
"TreeModel::setRow: invalid modelIndex";
494 const QVariantMap rowAsMap = rowData.toMap();
495 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList) {
496 qmlWarning(
this) <<
"TreeModel::setRow: child rows are not allowed";
500 if (!validateNewRow(
"TreeModel::setRow"_L1, rowData))
503 const QVariant rowAsVariant = rowData.userType() == QMetaType::QVariantMap ? rowData : rowData.value<QJSValue>().toVariant();
504 auto *row =
static_cast<QQmlTreeRow *>(rowIndex.internalPointer());
505 row->setData(rowAsVariant);
507 const QModelIndex topLeftModelIndex(createIndex(rowIndex.row(), 0, rowIndex.internalPointer()));
508 const QModelIndex bottomRightModelIndex(createIndex(rowIndex.row(), mColumnCount-1, rowIndex.internalPointer()));
510 emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
515
516
517
518
519
520
521
522
523
524
525QModelIndex QQmlTreeModel::index(
int row,
int column,
const QModelIndex &parent)
const
527 if (!parent.isValid()){
528 if (
static_cast<size_t>(row) >= mRows.size())
531 return createIndex(row, column, mRows.at(row).get());
534 const auto *treeRow =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
535 if (treeRow->rowCount() <=
static_cast<size_t>(row))
538 return createIndex(row, column, treeRow->getRow(row));
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588QModelIndex QQmlTreeModel::index(
const std::vector<
int> &treeIndex,
int column)
591 QQmlTreeRow *row = getPointerToTreeRow(mIndex, treeIndex);
594 return createIndex(treeIndex.back(), column, row);
596 qmlWarning(
this) <<
"TreeModel::index: could not find any node at the specified index: "
601QModelIndex QQmlTreeModel::parent(
const QModelIndex &index)
const
603 if (!index.isValid())
606 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
607 const QQmlTreeRow *parentRow = thisRow->parent();
612 const QQmlTreeRow *grandparentRow = parentRow->parent();
614 if (!grandparentRow) {
615 for (size_t i = 0; i < mRows.size(); i++) {
616 if (mRows[i].get() == parentRow)
617 return createIndex(
static_cast<
int>(i), 0, parentRow);
619 Q_UNREACHABLE_RETURN(QModelIndex());
622 for (size_t i = 0; i < grandparentRow->rowCount(); i++) {
623 if (grandparentRow->getRow(
static_cast<
int>(i)) == parentRow)
624 return createIndex(
static_cast<
int>(i), 0, parentRow);
626 Q_UNREACHABLE_RETURN(QModelIndex());
630int QQmlTreeModel::rowCount(
const QModelIndex &parent)
const
632 if (!parent.isValid())
633 return static_cast<
int>(mRows.size());
635 const auto *row =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
636 return static_cast<
int>(row->rowCount());
640
641
642
643
644
645
646
647
648
649int QQmlTreeModel::columnCount(
const QModelIndex &parent)
const
657
658
659
660
661
662
663
664
665
668
669
670
671
672
673
674
675
676
678bool QQmlTreeModel::validateNewRow(QLatin1StringView functionName,
const QVariant &row,
679 NewRowOperationFlag operation)
const
681 const bool isVariantMap = (row.userType() == QMetaType::QVariantMap);
682 const QVariant rowAsVariant = operation == SetRowsOperation || isVariantMap
683 ? row : row.value<QJSValue>().toVariant();
684 const QVariantMap rowAsMap = rowAsVariant.toMap();
685 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList)
687 const QList<QVariant> variantList = rowAsMap[ROWS_PROPERTY_NAME].toList();
688 for (
const QVariant &rowAsVariant : variantList)
689 if (!validateNewRow(functionName, rowAsVariant))
693 return QQmlAbstractColumnModel::validateNewRow(functionName, row, operation);
696int QQmlTreeModel::treeSize()
const
700 for (
const auto &treeRow : mRows)
701 treeSize += treeRow->subTreeSize();
706QQmlTreeRow *QQmlTreeModel::getPointerToTreeRow(QModelIndex &modIndex,
707 const std::vector<
int> &rowIndex)
const
709 for (
int r : rowIndex) {
710 modIndex = index(r, 0, modIndex);
711 if (!modIndex.isValid())
715 return static_cast<QQmlTreeRow*>(modIndex.internalPointer());
720#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