8#include <QtCore/qloggingcategory.h>
10#include <QtQml/qqmlinfo.h>
11#include <QtQml/qqmlengine.h>
15using namespace Qt::StringLiterals;
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
61QQmlTreeModel::QQmlTreeModel(QObject *parent)
62 : QQmlAbstractColumnModel(parent)
66QQmlTreeModel::~QQmlTreeModel() =
default;
69
70
71
72
73
74
75QVariant QQmlTreeModel::rows()
const
77 QVariantList rowsAsVariant;
78 for (
const auto &row : mRows)
79 rowsAsVariant.append(row->toVariant());
84void QQmlTreeModel::setRows(
const QVariant &rows)
86 if (rows.userType() != qMetaTypeId<QJSValue>()) {
87 qmlWarning(
this) <<
"setRows(): \"rows\" must be an array; actual type is " << rows.typeName();
91 const auto rowsAsJSValue = rows.value<QJSValue>();
92 const QVariantList rowsAsVariantList = rowsAsJSValue.toVariant().toList();
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))
131 for (
const auto &rowAsVariant : rowsAsVariantList)
132 mRows.push_back(std::make_unique<QQmlTreeRow>(rowAsVariant));
136 if (firstTimeValidRowsHaveBeenSet && (!mRows.empty() || !mInitialRows.isEmpty()))
137 fetchColumnMetadata();
143QVariant QQmlTreeModel::dataPrivate(
const QModelIndex &index,
const QString &roleName)
const
145 const ColumnMetadata columnMetadata = mColumnMetadata.at(index.column());
146 const QString propertyName = columnMetadata.roles.value(roleName).name;
147 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
148 return thisRow->data(propertyName);
151void QQmlTreeModel::setDataPrivate(
const QModelIndex &index,
const QString &roleName, QVariant value)
153 auto *row =
static_cast<QQmlTreeRow *>(index.internalPointer());
154 row->setField(roleName, value);
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193void QQmlTreeModel::appendRow(QModelIndex parent,
const QVariant &row)
195 if (!validateNewRow(
"TreeModel::appendRow"_L1, row))
198 const QVariant data = row.userType() == QMetaType::QVariantMap ? row : row.value<QJSValue>().toVariant();
200 if (parent.isValid()) {
201 auto *parentRow =
static_cast<QQmlTreeRow *>(parent.internalPointer());
202 auto *newChild =
new QQmlTreeRow(data);
204 beginInsertRows(parent,
static_cast<
int>(parentRow->rowCount()),
static_cast<
int>(parentRow->rowCount()));
205 parentRow->addChild(newChild);
208 if (mColumnMetadata.isEmpty())
209 fetchColumnMetadata();
213 qmlWarning(
this) <<
"append: could not find any node at the specified index"
214 <<
" - the new row will be appended to root";
216 beginInsertRows(QModelIndex(),
217 static_cast<
int>(mRows.size()),
218 static_cast<
int>(mRows.size()));
220 mRows.push_back(std::make_unique<QQmlTreeRow>(data));
223 if (mColumnMetadata.isEmpty())
224 fetchColumnMetadata();
233
234
235
236
237
238
239void QQmlTreeModel::appendRow(
const QVariant &row)
245
246
247
248
249
250
251void QQmlTreeModel::clear()
253 QQmlEngine *engine = qmlEngine(
this);
255 setRows(QVariant::fromValue(engine->newArray()));
259
260
261
262
263
264
265
266
267
268QVariant QQmlTreeModel::getRow(
const QModelIndex &rowIndex)
const
270 if (rowIndex.isValid())
271 return static_cast<QQmlTreeRow*>(rowIndex.internalPointer())->toVariant();
273 qmlWarning(
this) <<
"getRow: could not find any node at the specified index";
277QVariant QQmlTreeModel::firstRow()
const
279 return mRows.front().get()->data();
282void QQmlTreeModel::setInitialRows()
284 setRowsPrivate(mInitialRows);
288
289
290
291
292
293
294
295
296
297
298void QQmlTreeModel::removeRow(QModelIndex rowIndex)
300 if (rowIndex.isValid()) {
301 QModelIndex mIndexParent = rowIndex.parent();
303 beginRemoveRows(mIndexParent, rowIndex.row(), rowIndex.row());
305 if (mIndexParent.isValid()) {
306 auto *parent =
static_cast<QQmlTreeRow *>(mIndexParent.internalPointer());
307 parent->removeChildAt(rowIndex.row());
309 mRows.erase(std::next(mRows.begin(), rowIndex.row()));
314 qmlWarning(
this) <<
"TreeModel::removeRow could not find any node at the specified index";
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345void QQmlTreeModel::setRow(QModelIndex rowIndex,
const QVariant &rowData)
347 if (!rowIndex.isValid()) {
348 qmlWarning(
this) <<
"TreeModel::setRow: invalid modelIndex";
352 const QVariantMap rowAsMap = rowData.toMap();
353 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList) {
354 qmlWarning(
this) <<
"TreeModel::setRow: child rows are not allowed";
358 if (!validateNewRow(
"TreeModel::setRow"_L1, rowData))
361 const QVariant rowAsVariant = rowData.userType() == QMetaType::QVariantMap ? rowData : rowData.value<QJSValue>().toVariant();
362 auto *row =
static_cast<QQmlTreeRow *>(rowIndex.internalPointer());
363 row->setData(rowAsVariant);
365 const QModelIndex topLeftModelIndex(createIndex(rowIndex.row(), 0, rowIndex.internalPointer()));
366 const QModelIndex bottomRightModelIndex(createIndex(rowIndex.row(), mColumnCount-1, rowIndex.internalPointer()));
368 emit dataChanged(topLeftModelIndex, bottomRightModelIndex);
373
374
375
376
377
378
379
380
381QModelIndex QQmlTreeModel::index(
int row,
int column,
const QModelIndex &parent)
const
383 if (!parent.isValid()){
384 if (
static_cast<size_t>(row) >= mRows.size())
387 return createIndex(row, column, mRows.at(row).get());
390 const auto *treeRow =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
391 if (treeRow->rowCount() <=
static_cast<size_t>(row))
394 return createIndex(row, column, treeRow->getRow(row));
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441QModelIndex QQmlTreeModel::index(
const std::vector<
int> &treeIndex,
int column)
444 QQmlTreeRow *row = getPointerToTreeRow(mIndex, treeIndex);
447 return createIndex(treeIndex.back(), column, row);
449 qmlWarning(
this) <<
"TreeModel::index: could not find any node at the specified index";
453QModelIndex QQmlTreeModel::parent(
const QModelIndex &index)
const
455 if (!index.isValid())
458 const auto *thisRow =
static_cast<
const QQmlTreeRow *>(index.internalPointer());
459 const QQmlTreeRow *parentRow = thisRow->parent();
464 const QQmlTreeRow *grandparentRow = parentRow->parent();
466 if (!grandparentRow) {
467 for (size_t i = 0; i < mRows.size(); i++) {
468 if (mRows[i].get() == parentRow)
469 return createIndex(
static_cast<
int>(i), 0, parentRow);
471 Q_UNREACHABLE_RETURN(QModelIndex());
474 for (size_t i = 0; i < grandparentRow->rowCount(); i++) {
475 if (grandparentRow->getRow(
static_cast<
int>(i)) == parentRow)
476 return createIndex(
static_cast<
int>(i), 0, parentRow);
478 Q_UNREACHABLE_RETURN(QModelIndex());
482int QQmlTreeModel::rowCount(
const QModelIndex &parent)
const
484 if (!parent.isValid())
485 return static_cast<
int>(mRows.size());
487 const auto *row =
static_cast<
const QQmlTreeRow *>(parent.internalPointer());
488 return static_cast<
int>(row->rowCount());
492
493
494
495
496
497
498
499
500
501int QQmlTreeModel::columnCount(
const QModelIndex &parent)
const
509
510
511
512
513
514
515
518
519
520
521
522
523
524
526bool QQmlTreeModel::validateNewRow(QLatin1StringView functionName,
const QVariant &row,
527 NewRowOperationFlag operation)
const
529 const bool isVariantMap = (row.userType() == QMetaType::QVariantMap);
530 const QVariant rowAsVariant = operation == SetRowsOperation || isVariantMap
531 ? row : row.value<QJSValue>().toVariant();
532 const QVariantMap rowAsMap = rowAsVariant.toMap();
533 if (rowAsMap.contains(ROWS_PROPERTY_NAME) && rowAsMap[ROWS_PROPERTY_NAME].userType() == QMetaType::Type::QVariantList)
535 const QList<QVariant> variantList = rowAsMap[ROWS_PROPERTY_NAME].toList();
536 for (
const QVariant &rowAsVariant : variantList)
537 if (!validateNewRow(functionName, rowAsVariant))
541 return QQmlAbstractColumnModel::validateNewRow(functionName, row, operation);
544int QQmlTreeModel::treeSize()
const
548 for (
const auto &treeRow : mRows)
549 treeSize += treeRow->subTreeSize();
554QQmlTreeRow *QQmlTreeModel::getPointerToTreeRow(QModelIndex &modIndex,
555 const std::vector<
int> &rowIndex)
const
557 for (
int r : rowIndex) {
558 modIndex = index(r, 0, modIndex);
559 if (!modIndex.isValid())
563 return static_cast<QQmlTreeRow*>(modIndex.internalPointer());
568#include "moc_qqmltreemodel_p.cpp"
static const QString ROWS_PROPERTY_NAME