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