Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmltreerow.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtCore/qjsonobject.h>
8
10
11using namespace Qt::Literals::StringLiterals;
12
14 : m_parent(parentItem)
15{
16
17}
18
19QQmlTreeRow::QQmlTreeRow(const QVariant &data, QQmlTreeRow *parentItem)
20 : m_parent(parentItem)
21{
22 QVariantMap variantMap = data.toMap();
23 unpackVariantMap(variantMap);
24}
25
26QQmlTreeRow::QQmlTreeRow(const QVariantMap &data, QQmlTreeRow *parentItem)
27 : m_parent(parentItem)
28{
29 unpackVariantMap(data);
30}
31
33{
34 // Letting m_children destroy the subtree would recurse once per level of
35 // the tree, which can be arbitrarily deep. Detach the children level by
36 // level instead, so that every row is destroyed without any children left.
37 std::vector<std::unique_ptr<QQmlTreeRow>> pending = std::move(m_children);
38 m_children.clear();
39
40 while (!pending.empty()) {
41 std::unique_ptr<QQmlTreeRow> row = std::move(pending.back());
42 pending.pop_back();
43
44 for (auto &child : row->m_children)
45 pending.push_back(std::move(child));
46 row->m_children.clear();
47 }
48}
49
51{
52 m_children.push_back(std::unique_ptr<QQmlTreeRow>(child));
53 child->setParent(this);
54}
55
56void QQmlTreeRow::insertChild(int index, std::unique_ptr<QQmlTreeRow> child)
57{
58 child->setParent(this);
59 m_children.insert(m_children.begin() + index, std::move(child));
60}
61
62void QQmlTreeRow::unpackVariantMap(const QVariantMap &variantMap)
63{
64 // Building the children through the constructor would recurse once per
65 // level of the nested rows, which can be arbitrarily deep. Use an explicit
66 // stack instead: each entry is a row whose data and children still have to
67 // be filled in from the given map.
68 std::vector<std::pair<QQmlTreeRow *, QVariantMap>> pending;
69 pending.emplace_back(this, variantMap);
70
71 while (!pending.empty()) {
72 auto [row, map] = std::move(pending.back());
73 pending.pop_back();
74
75 for (auto it = map.cbegin(); it != map.cend(); ++it) {
76 const QString& key = it.key();
77 const QVariant& value = it.value();
78
79 if ((value.typeId() == QMetaType::Type::QVariantList) && (key == ROWS_PROPERTY_NAME)) {
80 const QList<QVariant> variantList = value.toList();
81 for (const QVariant &rowAsVariant : variantList) {
82 auto child = std::make_unique<QQmlTreeRow>(row);
83 pending.emplace_back(child.get(), rowAsVariant.toMap());
84 row->m_children.push_back(std::move(child));
85 }
86 } else {
87 row->dataMap.insert(key, value);
88 }
89 }
90 }
91}
92
93void QQmlTreeRow::removeChild(std::vector<std::unique_ptr<QQmlTreeRow>>::const_iterator &child)
94{
95 m_children.erase(child);
96}
97
99{
100 m_children.erase(std::next(m_children.begin(), i));
101}
102
104{
105 auto it = std::next(m_children.begin(), i);
106 std::unique_ptr<QQmlTreeRow> child = std::move(*it);
107 m_children.erase(it);
108 return child;
109}
110
111void QQmlTreeRow::setData(const QVariant &data)
112{
113 dataMap.clear();
114 const QVariantMap variantMap = data.toJsonObject().toVariantMap();
115 unpackVariantMap(variantMap);
116}
117
118void QQmlTreeRow::setData(const QVariantMap &data)
119{
120 dataMap.clear();
121 unpackVariantMap(data);
122}
123
124void QQmlTreeRow::setField(const QString &key, const QVariant &value)
125{
126 if (dataMap.contains(key))
127 dataMap[key] = value;
128}
129
131{
132 // Recursing into the children would recurse once per level of the tree,
133 // which can be arbitrarily deep. Use an explicit stack instead, in
134 // post-order: a row's variant is complete once the variants of all its
135 // children have been collected.
136 struct Frame
137 {
138 const QQmlTreeRow *row;
139 size_t nextChild = 0;
140 QVariantList children = {};
141 };
142
143 std::vector<Frame> pending;
144 pending.push_back({ this });
145
146 QVariant result;
147 while (!pending.empty()) {
148 Frame &top = pending.back();
149 if (top.nextChild < top.row->m_children.size()) {
150 const QQmlTreeRow *child = top.row->m_children[top.nextChild++].get();
151 pending.push_back({ child }); // invalidates top
152 continue;
153 }
154
155 QVariantMap variantMap(top.row->dataMap);
156 if (!top.row->m_children.empty())
157 variantMap[ROWS_PROPERTY_NAME] = top.children;
158 pending.pop_back(); // invalidates top
159 if (pending.empty())
160 result = variantMap;
161 else
162 pending.back().children.append(QVariant(variantMap));
163 }
164
165 return result;
166}
167
169{
170 int size = 1;
171
172 for (const auto &child : m_children)
173 size += child->subTreeSize();
174
175 return size;
176}
177
178QT_END_NAMESPACE
void addChild(QQmlTreeRow *child)
QVariant toVariant() const
std::unique_ptr< QQmlTreeRow > takeChild(int i)
void setData(const QVariant &data)
void setParent(QQmlTreeRow *parent)
void setField(const QString &key, const QVariant &value)
void removeChild(std::vector< std::unique_ptr< QQmlTreeRow > >::const_iterator &child)
QQmlTreeRow(QQmlTreeRow *parentItem=nullptr)
int subTreeSize() const
QQmlTreeRow(const QVariant &data, QQmlTreeRow *parentItem=nullptr)
void insertChild(int index, std::unique_ptr< QQmlTreeRow > child)
void removeChildAt(int i)
Combined button and popup list for selecting options.