KDeclarative

qmlobject.cpp
1 /*
2  SPDX-FileCopyrightText: 2013 Marco Martin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6 
7 #include "qmlobject.h"
8 #include "private/kdeclarative_p.h"
9 
10 #include <QQmlEngine>
11 #include <QQmlContext>
12 #include <QQuickItem>
13 #include <QQmlIncubator>
14 #include <QTimer>
15 
16 #include <QDebug>
17 #include <kdeclarative.h>
18 #include <KPackage/PackageLoader>
19 
20 //#include "packageaccessmanagerfactory.h"
21 //#include "private/declarative/dataenginebindings_p.h"
22 
23 namespace KDeclarative {
24 
25 class QmlObjectIncubator : public QQmlIncubator
26 {
27 public:
28  QVariantHash m_initialProperties;
29 protected:
30  void setInitialState(QObject *object) override
31  {
32  QHashIterator<QString, QVariant> i(m_initialProperties);
33  while (i.hasNext()) {
34  i.next();
35  object->setProperty(i.key().toLatin1().data(), i.value());
36  }
37  }
38 };
39 
40 class QmlObjectPrivate
41 {
42 public:
43  QmlObjectPrivate(QmlObject *parent)
44  : q(parent),
45  engine(nullptr),
46  component(nullptr),
47  delay(false)
48  {
49  executionEndTimer = new QTimer(q);
50  executionEndTimer->setInterval(0);
51  executionEndTimer->setSingleShot(true);
52  QObject::connect(executionEndTimer, SIGNAL(timeout()), q, SLOT(scheduleExecutionEnd()));
53  }
54 
55  ~QmlObjectPrivate()
56  {
57  delete incubator.object();
58  }
59 
60  void errorPrint(QQmlComponent *component);
61  void execute(const QUrl &source);
62  void scheduleExecutionEnd();
63  void minimumWidthChanged();
64  void minimumHeightChanged();
65  void maximumWidthChanged();
66  void maximumHeightChanged();
67  void preferredWidthChanged();
68  void preferredHeightChanged();
69  void checkInitializationCompleted();
70 
71  QmlObject *q;
72 
73  QUrl source;
74  QQmlEngine *engine;
75  QmlObjectIncubator incubator;
76  QQmlComponent *component;
77  QTimer *executionEndTimer;
78  KDeclarative kdeclarative;
79  KLocalizedContext *context{ nullptr };
80  KPackage::Package package;
81  QQmlContext *rootContext;
82  bool delay : 1;
83 };
84 
85 void QmlObjectPrivate::errorPrint(QQmlComponent *component)
86 {
87  QString errorStr = QStringLiteral("Error loading QML file.\n");
88  if (component->isError()) {
89  const QList<QQmlError> errors = component->errors();
90  for (const QQmlError &error : errors) {
91  errorStr += (error.line() > 0 ? QString(QString::number(error.line()) + QLatin1String(": ")) : QLatin1String(""))
92  + error.description() + QLatin1Char('\n');
93  }
94  }
95  qWarning() << component->url().toString() << '\n' << errorStr;
96 }
97 
98 void QmlObjectPrivate::execute(const QUrl &source)
99 {
100  if (source.isEmpty()) {
101  qWarning() << "File name empty!";
102  return;
103  }
104 
105  delete component;
106  component = new QQmlComponent(engine, q);
108  q, &QmlObject::statusChanged, Qt::QueuedConnection);
109  delete incubator.object();
110 
111  component->loadUrl(source);
112 
113  if (delay) {
114  executionEndTimer->start(0);
115  } else {
116  scheduleExecutionEnd();
117  }
118 }
119 
120 void QmlObjectPrivate::scheduleExecutionEnd()
121 {
122  if (component->isReady() || component->isError()) {
123  q->completeInitialization();
124  } else {
125  QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)), q, SLOT(completeInitialization()));
126  }
127 }
128 
130  // cannot do : QmlObject(new QQmlEngine(this), d->engine->rootContext(), parent)
131  : QObject(parent)
132  , d(new QmlObjectPrivate(this))
133 
134 {
135  d->engine = new QQmlEngine(this);
136  d->rootContext = d->engine->rootContext();
137  d->kdeclarative.setDeclarativeEngine(d->engine);
138  d->kdeclarative.d->qmlObj = this;
139 
140  d->context = new KLocalizedContext(this);
141  d->rootContext->setContextObject(d->context);
142  KDeclarative::setupEngine(d->engine);
143 }
144 
146  : QmlObject(engine, engine->rootContext(), parent)
147 {
148 
149 }
150 
152  : QmlObject(engine, rootContext, nullptr /*call setupEngine*/, parent)
153 {
154 
155 }
156 
158  : QObject(parent)
159  , d(new QmlObjectPrivate(this))
160 {
161  if (engine) {
162  d->engine = engine;
163  } else {
164  d->engine = new QQmlEngine(this);
165  }
166 
167  if (rootContext) {
168  d->rootContext = rootContext;
169  } else {
170  d->rootContext = d->engine->rootContext();
171  }
172  d->kdeclarative.setDeclarativeEngine(d->engine);
173  d->kdeclarative.d->qmlObj = this;
174 
175  d->context = new KLocalizedContext(this);
176  d->rootContext->setContextObject(d->context);
177 
178  if (!obj) {
179  KDeclarative::setupEngine(d->engine);
180  }
181 }
182 
183 QmlObject::~QmlObject()
184 {
185 // QDeclarativeNetworkAccessManagerFactory *factory = d->engine->networkAccessManagerFactory();
186 // d->engine->setNetworkAccessManagerFactory(0);
187 // delete factory;
188  delete d;
189 }
190 
192 {
193  d->context->setTranslationDomain(translationDomain);
194 }
195 
197 {
198  return d->context->translationDomain();
199 }
200 
201 void QmlObject::setSource(const QUrl &source)
202 {
203  d->source = source;
204  d->execute(source);
205 }
206 
207 QUrl QmlObject::source() const
208 {
209  return d->source;
210 }
211 
212 void QmlObject::loadPackage(const QString &packageName)
213 {
214  d->package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("KPackage/GenericQML"));
215  d->package.setPath(packageName);
216  setSource(QUrl::fromLocalFile(d->package.filePath("mainscript")));
217 }
218 
220 {
221  d->package = package;
222  setSource(QUrl::fromLocalFile(package.filePath("mainscript")));
223 }
224 
226 {
227  return d->package;
228 }
229 
231 {
232  d->delay = delay;
233 }
234 
236 {
237  return d->delay;
238 }
239 
241 {
242  return d->engine;
243 }
244 
246 {
247  if (d->incubator.status() == QQmlIncubator::Loading) {
248  qWarning() << "Trying to use rootObject before initialization is completed, whilst using setInitializationDelayed. Forcing completion";
249  d->incubator.forceCompletion();
250  }
251  return d->incubator.object();
252 }
253 
255 {
256  return d->component;
257 }
258 
260 {
261  return d->rootContext;
262 }
263 
265 {
266  if (!d->engine) {
267  return QQmlComponent::Error;
268  }
269 
270  if (!d->component) {
271  return QQmlComponent::Null;
272  }
273 
274  return QQmlComponent::Status(d->component->status());
275 }
276 
277 void QmlObjectPrivate::checkInitializationCompleted()
278 {
279  if (!incubator.isReady() && incubator.status() != QQmlIncubator::Error) {
280  QTimer::singleShot(0, q, SLOT(checkInitializationCompleted()));
281  return;
282  }
283 
284  if (!incubator.object()) {
285  errorPrint(component);
286  }
287 
288  Q_EMIT q->finished();
289 }
290 
291 void QmlObject::completeInitialization(const QVariantHash &initialProperties)
292 {
293  d->executionEndTimer->stop();
294  if (d->incubator.object()) {
295  return;
296  }
297 
298  if (!d->component) {
299  qWarning() << "No component for" << source();
300  return;
301  }
302 
303 
304  if (d->component->status() != QQmlComponent::Ready || d->component->isError()) {
305  d->errorPrint(d->component);
306  return;
307  }
308 
309  d->incubator.m_initialProperties = initialProperties;
310  d->component->create(d->incubator, d->rootContext);
311 
312  if (d->delay) {
313  d->checkInitializationCompleted();
314  } else {
315  d->incubator.forceCompletion();
316 
317  if (!d->incubator.object()) {
318  d->errorPrint(d->component);
319  }
320  Q_EMIT finished();
321  }
322 }
323 
324 QObject *QmlObject::createObjectFromSource(const QUrl &source, QQmlContext *context, const QVariantHash &initialProperties)
325 {
326  QQmlComponent *component = new QQmlComponent(d->engine, this);
327  component->loadUrl(source);
328 
329  return createObjectFromComponent(component, context, initialProperties);
330 }
331 
332 QObject *QmlObject::createObjectFromComponent(QQmlComponent *component, QQmlContext *context, const QVariantHash &initialProperties)
333 {
334  QmlObjectIncubator incubator;
335  incubator.m_initialProperties = initialProperties;
336  component->create(incubator, context ? context : d->rootContext);
337  incubator.forceCompletion();
338 
339  QObject *object = incubator.object();
340 
341  if (!component->isError() && object) {
342  //memory management
343  component->setParent(object);
344  //reparent to root object if wasn't specified otherwise by initialProperties
345  if (!initialProperties.contains(QLatin1String("parent"))) {
346  if (qobject_cast<QQuickItem *>(rootObject())) {
347  object->setProperty("parent", QVariant::fromValue(rootObject()));
348  } else {
349  object->setParent(rootObject());
350  }
351  }
352 
353  return object;
354 
355  } else {
356  d->errorPrint(component);
357  delete object;
358  return nullptr;
359  }
360 }
361 
362 }
363 
364 #include "moc_qmlobject.cpp"
void loadPackage(const QString &packageName)
Load the package called packageName, then loads the mainscript file for that package.
Definition: qmlobject.cpp:212
static void setupEngine(QQmlEngine *engine)
Setup a QML engine for use with any KDeclarative object.
QmlObject(QObject *parent=nullptr)
Constructs a new QmlObject.
Definition: qmlobject.cpp:129
virtual QObject * create(QQmlContext *context)
QList< QQmlError > errors() const const
QQmlComponent::Status status() const
The component&#39;s current status.
KPackage::Package package() const
Definition: qmlobject.cpp:225
An object that instantiates an entire QML context, with its own declarative engine.
Definition: qmlobject.h:38
void statusChanged(QQmlComponent::Status status)
QQmlEngine * engine()
Definition: qmlobject.cpp:240
bool isReady() const const
bool isInitializationDelayed() const
Definition: qmlobject.cpp:235
bool isEmpty() const const
QObject * createObjectFromSource(const QUrl &source, QQmlContext *context=nullptr, const QVariantHash &initialProperties=QVariantHash())
Creates and returns an object based on the provided url to a Qml file with the same QQmlEngine and th...
Definition: qmlobject.cpp:324
void loadUrl(const QUrl &url)
static PackageLoader * self()
void setPackage(const KPackage::Package &package)
Sets a package, then loads the mainscript file for that package.
Definition: qmlobject.cpp:219
QString number(int n, int base)
bool isError() const const
QString translationDomain() const
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
QQmlComponent * mainComponent() const
Definition: qmlobject.cpp:254
void setParent(QObject *parent)
void setInitializationDelayed(const bool delay)
Sets whether the execution of the QML file has to be delayed later in the event loop.
Definition: qmlobject.cpp:230
QVariant fromValue(const T &value)
QQmlContext * rootContext() const
The components&#39;s creation context.
Definition: qmlobject.cpp:259
void setSource(const QUrl &source)
Sets the path of the QML file to parse and execute.
Definition: qmlobject.cpp:201
QObject * rootObject() const
Package loadPackage(const QString &packageFormat, const QString &packagePath=QString())
void finished()
Emitted when the parsing and execution of the QML file is terminated.
QString filePath(const QByteArray &key, const QString &filename=QString()) const
void setTranslationDomain(const QString &translationDomain)
Call this method before calling setupBindings to install a translation domain for all i18n global fun...
Definition: qmlobject.cpp:191
QueuedConnection
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void completeInitialization(const QVariantHash &initialProperties=QVariantHash())
Finishes the process of initialization.
Definition: qmlobject.cpp:291
Q_EMITQ_EMIT
QUrl fromLocalFile(const QString &localFile)
QObject * createObjectFromComponent(QQmlComponent *component, QQmlContext *context=nullptr, const QVariantHash &initialProperties=QVariantHash())
Creates and returns an object based on the provided QQmlComponent with the same QQmlEngine and the sa...
Definition: qmlobject.cpp:332
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 19 2021 22:41:07 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.