File indexing completed on 2024-07-21 12:13:20

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  * 
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "ItemBuilder.h"
0008 
0009 class ItemIncubator : public QQmlIncubator
0010 {
0011 public:
0012     ItemIncubator(QQmlComponent *component, QQmlContext *context)
0013     {
0014         m_component = component;
0015         m_context = context;
0016     }
0017 
0018     void setStateCallback(std::function<void(QQuickItem*)> callback)
0019     {
0020         m_stateCallback = callback;
0021     }
0022 
0023     void setCompletedCallback(std::function<void(ItemIncubator*)> callback)
0024     {
0025         m_completedCallback = callback;
0026     }
0027 
0028     void create()
0029     {
0030         m_component->create(*this, m_context);
0031     }
0032 
0033     bool isFinished()
0034     {
0035         return m_finished;
0036     }
0037 
0038 private:
0039     void setInitialState(QObject *object) override
0040     {
0041         auto item = qobject_cast<QQuickItem*>(object);
0042         if (item) {
0043             m_stateCallback(item);
0044         }
0045     }
0046 
0047     void statusChanged(QQmlIncubator::Status status) override
0048     {
0049         if (status == QQmlIncubator::Error) {
0050             qWarning() << "Could not create delegate in ItemBuilder";
0051             const auto e = errors();
0052             for (const auto &error : e) {
0053                 qWarning() << error;
0054             }
0055             m_finished = true;
0056         }
0057 
0058         if (status == QQmlIncubator::Ready) {
0059             m_completedCallback(this);
0060             m_finished = true;
0061         }
0062     }
0063 
0064     QQmlComponent *m_component;
0065     QQmlContext *m_context;
0066     std::function<void(QQuickItem*)> m_stateCallback;
0067     std::function<void(ItemIncubator*)> m_completedCallback;
0068     bool m_finished = false;
0069 };
0070 
0071 ItemBuilder::ItemBuilder(QObject *parent)
0072     : QObject(parent)
0073 {
0074 }
0075 
0076 ItemBuilder::~ItemBuilder()
0077 {
0078     clear();
0079 }
0080 
0081 QQmlComponent *ItemBuilder::component() const
0082 {
0083     return m_component;
0084 }
0085 
0086 void ItemBuilder::setComponent(QQmlComponent *newComponent)
0087 {
0088     if (newComponent == m_component) {
0089         return;
0090     }
0091 
0092     m_component = newComponent;
0093     clear();
0094 }
0095 
0096 QQmlContext *ItemBuilder::context() const
0097 {
0098     return m_context;
0099 }
0100 
0101 void ItemBuilder::setContext(QQmlContext *newContext)
0102 {
0103     if (newContext == m_context) {
0104         return;
0105     }
0106 
0107     m_context = newContext;
0108     clear();
0109 }
0110 
0111 
0112 int ItemBuilder::count() const
0113 {
0114     return m_count;
0115 }
0116 
0117 void ItemBuilder::setCount(int newCount)
0118 {
0119     if (newCount == m_count) {
0120         return;
0121     }
0122 
0123     m_count = newCount;
0124     clear();
0125 }
0126 
0127 QQmlIncubator::IncubationMode ItemBuilder::incubationMode() const
0128 {
0129     return m_incubationMode;
0130 }
0131 
0132 void ItemBuilder::setIncubationMode(QQmlIncubator::IncubationMode newIncubationMode)
0133 {
0134     if (newIncubationMode == m_incubationMode) {
0135         return;
0136     }
0137 
0138     m_incubationMode = newIncubationMode;
0139 }
0140 
0141 QVariantMap ItemBuilder::initialProperties() const
0142 {
0143     return m_initialProperties;
0144 }
0145 
0146 void ItemBuilder::setInitialProperties(const QVariantMap & newInitialProperties)
0147 {
0148     if (newInitialProperties == m_initialProperties) {
0149         return;
0150     }
0151 
0152     m_initialProperties = newInitialProperties;
0153 }
0154 
0155 void ItemBuilder::build(QQuickItem *parent)
0156 {
0157     if ((int(m_items.size()) == m_count && m_incubators.empty()) || !m_incubators.empty() || !m_component) {
0158         return;
0159     }
0160 
0161     m_incubators.reserve(m_count);
0162     std::fill_n(std::back_inserter(m_items), m_count, std::shared_ptr<QQuickItem>());
0163 
0164     for (int i = 0; i < m_count; ++i) {
0165         auto context = m_context ? m_context : qmlContext(m_component);
0166         auto incubator = std::make_unique<ItemIncubator>(m_component, context);
0167 
0168         incubator->setStateCallback([this, parent, i](QQuickItem *item) {
0169             item->setParentItem(parent);
0170 
0171             for (auto itr = m_initialProperties.keyValueBegin(); itr != m_initialProperties.keyValueEnd(); ++itr) {
0172                 item->setProperty((*itr).first.toUtf8().data(), (*itr).second);
0173             }
0174 
0175             Q_EMIT beginCreate(i, item);
0176         });
0177 
0178         incubator->setCompletedCallback([this, i](ItemIncubator *incubator) {
0179             auto item = std::shared_ptr<QQuickItem>(qobject_cast<QQuickItem*>(incubator->object()));
0180             m_items[i] = item;
0181 
0182             Q_EMIT endCreate(i, item.get());
0183 
0184             m_completed++;
0185             if (m_completed == m_count) {
0186                 QMetaObject::invokeMethod(this, [this]() {
0187                     m_incubators.clear();
0188                 }, Qt::QueuedConnection);
0189                 Q_EMIT finished();
0190             }
0191         });
0192 
0193         incubator->create();
0194 
0195         m_incubators.push_back(std::move(incubator));
0196     }
0197 }
0198 
0199 bool ItemBuilder::isFinished() const
0200 {
0201     return m_completed == m_count;
0202 }
0203 
0204 std::vector<std::shared_ptr<QQuickItem>> ItemBuilder::items() const
0205 {
0206     return m_items;
0207 }
0208 
0209 void ItemBuilder::clear()
0210 {
0211     m_items.clear();
0212 
0213     if (m_incubators.size() > 0) {
0214         for (auto &incubator : m_incubators) {
0215             incubator->clear();
0216         }
0217     }
0218     m_incubators.clear();
0219 
0220     m_completed = 0;
0221 }
0222 
0223 #include "moc_ItemBuilder.cpp"