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
qquickvectorimageincubator.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 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
5#include <QtCore/private/qfactoryloader_p.h>
6#include <QtQml/qqmlcontext.h>
7
9
10Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, vectorImagePluginLoader,
11 (QQuickVectorImageFormatsPluginFactory_iid,
12 QLatin1String("/vectorimageformats"),
13 Qt::CaseInsensitive))
14
15void QQuickVectorImageWorker::process()
16{
17 Q_ASSERT(m_generator != nullptr);
18
19 // If we assume trusted source, we try plugins first
20 bool generatedWithPlugin = false;
21 for (const auto &pluginGenerator : std::as_const(m_pluginGenerators)) {
22 if ((generatedWithPlugin = pluginGenerator->generate(m_generator->fileName(), m_generator.get())))
23 break;
24 }
25
26 if (!generatedWithPlugin)
27 m_generator->generate();
28
29 emit finished();
30}
31
32QQuickVectorImageIncubator::QQuickVectorImageIncubator(IncubationMode incubationMode,
33 QQmlContext *context,
34 QObject *parent)
35 : QObject(parent)
36 , QQmlIncubator(incubationMode)
37 , m_qmlContext(context)
38{
39}
40
41QQuickVectorImageIncubator::~QQuickVectorImageIncubator()
42{
43 if (m_workerThread != nullptr && m_workerThread->isRunning()) {
44 m_workerThread->quit();
45 m_workerThread->wait();
46 }
47}
48
49QQmlIncubator::Status QQuickVectorImageIncubator::status() const
50{
51 return m_status;
52}
53
54void QQuickVectorImageIncubator::start(const QString &fileName,
55 QQuickVectorImageGenerator::GeneratorFlags flags)
56{
57 Q_ASSERT(m_generatorWorker == nullptr);
58 Q_ASSERT(m_workerThread == nullptr);
59
60 m_status = Loading;
61 emit statusUpdated();
62
63 const bool asynchronous = flags.testFlag(QQuickVectorImageGenerator::AsynchronousLoading);
64 if (asynchronous)
65 m_workerThread.reset(new QThread);
66
67 m_generatorWorker.reset(new QQuickVectorImageWorker);
68 m_generatorWorker->createGenerator(fileName, flags);
69 connect(m_generatorWorker.get(), &QQuickVectorImageWorker::finished,
70 this, &QQuickVectorImageIncubator::generatorFinished);
71
72 if (flags.testFlag(QQuickVectorImageGenerator::AssumeTrustedSource)) {
73 QFactoryLoader *loader = vectorImagePluginLoader();
74
75 const qsizetype count = loader->keyMap().size();
76 for (qsizetype i = 0; i < count; ++i) {
77 QQuickVectorImagePlugin *plugin = qobject_cast<QQuickVectorImagePlugin *>(loader->instance(i));
78 if (plugin != nullptr) {
79 QQuickVectorImagePluginGenerator *pluginGenerator = plugin->createGenerator(fileName);
80 if (pluginGenerator != nullptr)
81 m_generatorWorker->addPluginGenerator(pluginGenerator);
82 }
83 }
84 }
85
86 if (m_workerThread != nullptr) {
87 m_generatorWorker->moveToThread(m_workerThread.get());
88 m_workerThread->start();
89 }
90
91 // Trigger generating
92 QMetaObject::invokeMethod(m_generatorWorker.get(), &QQuickVectorImageWorker::process, Qt::AutoConnection);
93}
94
95void QQuickVectorImageIncubator::generatorFinished()
96{
97 Q_ASSERT(m_component == nullptr);
98 Q_ASSERT(m_generatorWorker != nullptr);
99 Q_ASSERT(m_generatorWorker->generator() != nullptr);
100 Q_ASSERT(m_workerThread == nullptr || m_workerThread->isRunning());
101
102 const QQuickVectorImageGenerator::ErrorState errorState = m_generatorWorker->generator()->errorState();
103 const bool asynchronous = m_generatorWorker->generator()->generatorFlags().testFlag(QQuickVectorImageGenerator::AsynchronousLoading);
104 const QByteArray result = m_generatorWorker->generator()->result();
105 const QString fileName = m_generatorWorker->generator()->fileName();
106
107 m_generatorWorker->disconnect(this);
108 m_generatorWorker.release()->deleteLater();
109
110 if (m_workerThread != nullptr) {
111 m_workerThread->quit();
112 m_workerThread->wait();
113 m_workerThread.reset(nullptr);
114 }
115
116 if (Q_LIKELY(errorState == QQuickVectorImageGenerator::NoError)) {
117 QQmlComponent::CompilationMode mode =
118 asynchronous
119 ? QQmlComponent::Asynchronous
120 : QQmlComponent::PreferSynchronous;
121
122 QQmlEngine *engine = m_qmlContext->engine();
123 if (Q_UNLIKELY(engine == nullptr)) {
124 qCWarning(lcQuickVectorImage) << "QQuickVectorImageIncubator::generatorFinished: Requires QML engine";
125 return;
126 }
127
128 m_component.reset(new QQmlComponent(engine));
129 connect(m_component.get(), &QQmlComponent::statusChanged,
130 this, &QQuickVectorImageIncubator::componentUpdated);
131 m_component->setData(result, QUrl{}, mode);
132 } else {
133 m_status = Error;
134 emit statusUpdated();
135 }
136}
137
138void QQuickVectorImageIncubator::componentUpdated()
139{
140 Q_ASSERT(m_component != nullptr);
141 Q_ASSERT(m_generatorWorker == nullptr);
142 Q_ASSERT(m_workerThread == nullptr);
143
144 if (!m_component->isLoading()) {
145 if (m_component->isReady()) {
146 m_component->create(*this, m_qmlContext);
147 } else {
148 qCWarning(lcQuickVectorImage) << "Component failed to load:"
149 << m_component->errorString();
150 m_status = Error;
151 emit statusUpdated();
152 }
153 m_component.release()->deleteLater();
154 }
155}
156
157void QQuickVectorImageIncubator::statusChanged(Status status)
158{
159 if (m_status == status)
160 return;
161 m_status = status;
162 emit statusUpdated();
163}
164
165QT_END_NAMESPACE
Combined button and popup list for selecting options.