1/*
2 * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "ItemBuilder.h"
8
9#include "charts_general_logging.h"
10
11class ItemIncubator : public QQmlIncubator
12{
13public:
14 ItemIncubator(QQmlComponent *component, QQmlContext *context)
15 {
16 m_component = component;
17 m_context = context;
18 }
19
20 void setStateCallback(std::function<void(QQuickItem*)> callback)
21 {
22 m_stateCallback = callback;
23 }
24
25 void setCompletedCallback(std::function<void(ItemIncubator*)> callback)
26 {
27 m_completedCallback = callback;
28 }
29
30 void create()
31 {
32 m_component->create(*this, context: m_context);
33 }
34
35 bool isFinished()
36 {
37 return m_finished;
38 }
39
40private:
41 void setInitialState(QObject *object) override
42 {
43 auto item = qobject_cast<QQuickItem*>(o: object);
44 if (item) {
45 m_stateCallback(item);
46 }
47 }
48
49 void statusChanged(QQmlIncubator::Status status) override
50 {
51 if (status == QQmlIncubator::Error) {
52 qWarning() << "Could not create delegate in ItemBuilder";
53 const auto e = errors();
54 for (const auto &error : e) {
55 qWarning() << error;
56 }
57 m_finished = true;
58 }
59
60 if (status == QQmlIncubator::Ready) {
61 m_completedCallback(this);
62 m_finished = true;
63 }
64 }
65
66 QQmlComponent *m_component;
67 QQmlContext *m_context;
68 std::function<void(QQuickItem*)> m_stateCallback;
69 std::function<void(ItemIncubator*)> m_completedCallback;
70 bool m_finished = false;
71};
72
73ItemBuilder::ItemBuilder(QObject *parent)
74 : QObject(parent)
75{
76}
77
78ItemBuilder::~ItemBuilder()
79{
80 clear();
81}
82
83QQmlComponent *ItemBuilder::component() const
84{
85 return m_component;
86}
87
88void ItemBuilder::setComponent(QQmlComponent *newComponent)
89{
90 if (newComponent == m_component) {
91 return;
92 }
93
94 m_component = newComponent;
95 clear();
96}
97
98QQmlContext *ItemBuilder::context() const
99{
100 return m_context;
101}
102
103void ItemBuilder::setContext(QQmlContext *newContext)
104{
105 if (newContext == m_context) {
106 return;
107 }
108
109 m_context = newContext;
110 clear();
111}
112
113
114int ItemBuilder::count() const
115{
116 return m_count;
117}
118
119void ItemBuilder::setCount(int newCount)
120{
121 if (newCount == m_count) {
122 return;
123 }
124
125 // Bound the count of items to build to a reasonable limit.
126 if (m_count < 0 || m_count > std::numeric_limits<int16_t>::max()) {
127 qCWarning(GENERAL) << "Request item count of" << newCount << "which is out of range";
128 return;
129 }
130
131 m_count = newCount;
132 clear();
133}
134
135QQmlIncubator::IncubationMode ItemBuilder::incubationMode() const
136{
137 return m_incubationMode;
138}
139
140void ItemBuilder::setIncubationMode(QQmlIncubator::IncubationMode newIncubationMode)
141{
142 if (newIncubationMode == m_incubationMode) {
143 return;
144 }
145
146 m_incubationMode = newIncubationMode;
147}
148
149QVariantMap ItemBuilder::initialProperties() const
150{
151 return m_initialProperties;
152}
153
154void ItemBuilder::setInitialProperties(const QVariantMap & newInitialProperties)
155{
156 if (newInitialProperties == m_initialProperties) {
157 return;
158 }
159
160 m_initialProperties = newInitialProperties;
161}
162
163void ItemBuilder::build(QQuickItem *parent)
164{
165 if ((int(m_items.size()) == m_count && m_incubators.empty()) || !m_incubators.empty() || !m_component) {
166 return;
167 }
168
169 m_incubators.reserve(n: m_count);
170 std::fill_n(first: std::back_inserter(x&: m_items), n: m_count, value: std::shared_ptr<QQuickItem>());
171
172 for (int i = 0; i < m_count; ++i) {
173 auto context = m_context ? m_context : qmlContext(m_component);
174 auto incubator = std::make_unique<ItemIncubator>(args&: m_component, args&: context);
175
176 incubator->setStateCallback([this, parent, i](QQuickItem *item) {
177 item->setParentItem(parent);
178
179 for (auto itr = m_initialProperties.keyValueBegin(); itr != m_initialProperties.keyValueEnd(); ++itr) {
180 item->setProperty(name: (*itr).first.toUtf8().data(), value: (*itr).second);
181 }
182
183 Q_EMIT beginCreate(index: i, item);
184 });
185
186 incubator->setCompletedCallback([this, i](ItemIncubator *incubator) {
187 auto item = std::shared_ptr<QQuickItem>(qobject_cast<QQuickItem*>(o: incubator->object()));
188 m_items[i] = item;
189
190 Q_EMIT endCreate(index: i, item: item.get());
191
192 m_completed++;
193 if (m_completed == m_count) {
194 QMetaObject::invokeMethod(object: this, function: [this]() {
195 m_incubators.clear();
196 }, type: Qt::QueuedConnection);
197 Q_EMIT finished();
198 }
199 });
200
201 incubator->create();
202
203 m_incubators.push_back(x: std::move(incubator));
204 }
205}
206
207bool ItemBuilder::isFinished() const
208{
209 return m_completed == m_count;
210}
211
212std::vector<std::shared_ptr<QQuickItem>> ItemBuilder::items() const
213{
214 return m_items;
215}
216
217void ItemBuilder::clear()
218{
219 m_items.clear();
220
221 if (m_incubators.size() > 0) {
222 for (auto &incubator : m_incubators) {
223 incubator->clear();
224 }
225 }
226 m_incubators.clear();
227
228 m_completed = 0;
229}
230
231#include "moc_ItemBuilder.cpp"
232

source code of kquickcharts/src/ItemBuilder.cpp