1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtDeclarative module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdeclarativecomponent.h"
43#include "private/qdeclarativecomponent_p.h"
44
45#include "private/qdeclarativecompiler_p.h"
46#include "private/qdeclarativecontext_p.h"
47#include "private/qdeclarativeengine_p.h"
48#include "private/qdeclarativevme_p.h"
49#include "qdeclarative.h"
50#include "qdeclarativeengine.h"
51#include "private/qdeclarativebinding_p.h"
52#include "private/qdeclarativebinding_p_p.h"
53#include "private/qdeclarativeglobal_p.h"
54#include "private/qdeclarativescriptparser_p.h"
55#include "private/qdeclarativedebugtrace_p.h"
56#include "private/qdeclarativeenginedebugservice_p.h"
57#include <QtScript/qscriptvalueiterator.h>
58
59#include <QStack>
60#include <QStringList>
61#include <QtCore/qdebug.h>
62#include <QApplication>
63#include <qdeclarativeinfo.h>
64
65QT_BEGIN_NAMESPACE
66
67class QByteArray;
68
69/*!
70 \class QDeclarativeComponent
71 \since 4.7
72 \brief The QDeclarativeComponent class encapsulates a QML component definition.
73 \mainclass
74
75 Components are reusable, encapsulated QML elements with well-defined interfaces.
76 They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
77
78 A QDeclarativeComponent instance can be created from a QML file.
79 For example, if there is a \c main.qml file like this:
80
81 \qml
82 import QtQuick 1.0
83
84 Item {
85 width: 200
86 height: 200
87 }
88 \endqml
89
90 The following code loads this QML file as a component, creates an instance of
91 this component using create(), and then queries the \l Item's \l {Item::}{width}
92 value:
93
94 \code
95 QDeclarativeEngine *engine = new QDeclarativeEngine;
96 QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
97
98 QObject *myObject = component.create();
99 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject);
100 int width = item->width(); // width = 200
101 \endcode
102
103
104 \section2 Network Components
105
106 If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a
107 network resource, the QDeclarativeComponent has to fetch the network data before it is able to create
108 objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading}
109 \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component
110 is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}.
111
112 The following example shows how to load a QML file from a network resource. After creating
113 the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the
114 QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
115 directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the
116 component has been cached and is ready immediately.
117
118 \code
119 MyApplication::MyApplication()
120 {
121 // ...
122 component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
123 if (component->isLoading())
124 QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
125 this, SLOT(continueLoading()));
126 else
127 continueLoading();
128 }
129
130 void MyApplication::continueLoading()
131 {
132 if (component->isError()) {
133 qWarning() << component->errors();
134 } else {
135 QObject *myObject = component->create();
136 }
137 }
138 \endcode
139
140 \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
141*/
142
143/*!
144 \qmlclass Component QDeclarativeComponent
145 \ingroup qml-utility-elements
146 \since 4.7
147 \brief The Component element encapsulates a QML component definition.
148
149 Components are reusable, encapsulated QML elements with well-defined interfaces.
150
151 Components are often defined by \l {qdeclarativedocuments.html}{component files} -
152 that is, \c .qml files. The \e Component element essentially allows QML components
153 to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
154 This may be useful for reusing a small component within a QML file, or for defining
155 a component that logically belongs with other QML components within a file.
156
157 For example, here is a component that is used by multiple \l Loader objects.
158 It contains a single item, a \l Rectangle:
159
160 \snippet doc/src/snippets/declarative/component.qml 0
161
162 Notice that while a \l Rectangle by itself would be automatically
163 rendered and displayed, this is not the case for the above rectangle
164 because it is defined inside a \c Component. The component encapsulates the
165 QML elements within, as if they were defined in a separate QML
166 file, and is not loaded until requested (in this case, by the
167 two \l Loader objects).
168
169 Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
170 A QML document has a single top-level item that defines the behaviors and
171 properties of that component, and cannot define properties or behaviors outside
172 of that top-level item. In the same way, a \c Component definition contains a single
173 top level item (which in the above example is a \l Rectangle) and cannot define any
174 data outside of this item, with the exception of an \e id (which in the above example
175 is \e redSquare).
176
177 The \c Component element is commonly used to provide graphical components
178 for views. For example, the ListView::delegate property requires a \c Component
179 to specify how each list item is to be displayed.
180
181 \c Component objects can also be created dynamically using
182 \l{QML:Qt::createComponent()}{Qt.createComponent()}.
183*/
184
185/*!
186 \qmlattachedsignal Component::onCompleted()
187
188 Emitted after component "startup" has completed. This can be used to
189 execute script code at startup, once the full QML environment has been
190 established.
191
192 The \c {Component::onCompleted} attached property can be applied to
193 any element. The order of running the \c onCompleted scripts is
194 undefined.
195
196 \qml
197 Rectangle {
198 Component.onCompleted: console.log("Completed Running!")
199 Rectangle {
200 Component.onCompleted: console.log("Nested Completed Running!")
201 }
202 }
203 \endqml
204*/
205
206/*!
207 \qmlattachedsignal Component::onDestruction()
208
209 Emitted as the component begins destruction. This can be used to undo
210 work done in the onCompleted signal, or other imperative code in your
211 application.
212
213 The \c {Component::onDestruction} attached property can be applied to
214 any element. However, it applies to the destruction of the component as
215 a whole, and not the destruction of the specific object. The order of
216 running the \c onDestruction scripts is undefined.
217
218 \qml
219 Rectangle {
220 Component.onDestruction: console.log("Destruction Beginning!")
221 Rectangle {
222 Component.onDestruction: console.log("Nested Destruction Beginning!")
223 }
224 }
225 \endqml
226
227 \sa QtDeclarative
228*/
229
230/*!
231 \enum QDeclarativeComponent::Status
232
233 Specifies the loading status of the QDeclarativeComponent.
234
235 \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content.
236 \value Ready This QDeclarativeComponent is ready and create() may be called.
237 \value Loading This QDeclarativeComponent is loading network data.
238 \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}.
239*/
240
241void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *)
242{
243 Q_Q(QDeclarativeComponent);
244
245 Q_ASSERT(typeData);
246
247 fromTypeData(typeData);
248 typeData = 0;
249
250 emit q->statusChanged(q->status());
251}
252
253void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p)
254{
255 Q_Q(QDeclarativeComponent);
256
257 progress = p;
258
259 emit q->progressChanged(p);
260}
261
262void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data)
263{
264 url = data->finalUrl();
265 QDeclarativeCompiledData *c = data->compiledData();
266
267 if (!c) {
268 Q_ASSERT(data->isError());
269 state.errors = data->errors();
270 } else {
271 cc = c;
272 }
273
274 data->release();
275}
276
277void QDeclarativeComponentPrivate::clear()
278{
279 if (typeData) {
280 typeData->unregisterCallback(this);
281 typeData->release();
282 typeData = 0;
283 }
284
285 if (cc) {
286 cc->release();
287 cc = 0;
288 }
289}
290
291/*!
292 \internal
293*/
294QDeclarativeComponent::QDeclarativeComponent(QObject *parent)
295 : QObject(*(new QDeclarativeComponentPrivate), parent)
296{
297}
298
299/*!
300 Destruct the QDeclarativeComponent.
301*/
302QDeclarativeComponent::~QDeclarativeComponent()
303{
304 Q_D(QDeclarativeComponent);
305
306 if (d->state.completePending) {
307 qWarning("QDeclarativeComponent: Component destroyed while completion pending");
308 d->completeCreate();
309 }
310
311 if (d->typeData) {
312 d->typeData->unregisterCallback(d);
313 d->typeData->release();
314 }
315 if (d->cc)
316 d->cc->release();
317}
318
319/*!
320 \qmlproperty enumeration Component::status
321 This property holds the status of component loading. It can be one of:
322 \list
323 \o Component.Null - no data is available for the component
324 \o Component.Ready - the component has been loaded, and can be used to create instances.
325 \o Component.Loading - the component is currently being loaded
326 \o Component.Error - an error occurred while loading the component.
327 Calling errorString() will provide a human-readable description of any errors.
328 \endlist
329 */
330
331/*!
332 \property QDeclarativeComponent::status
333 The component's current \l{QDeclarativeComponent::Status} {status}.
334 */
335QDeclarativeComponent::Status QDeclarativeComponent::status() const
336{
337 Q_D(const QDeclarativeComponent);
338
339 if (d->typeData)
340 return Loading;
341 else if (!d->state.errors.isEmpty())
342 return Error;
343 else if (d->engine && d->cc)
344 return Ready;
345 else
346 return Null;
347}
348
349/*!
350 Returns true if status() == QDeclarativeComponent::Null.
351*/
352bool QDeclarativeComponent::isNull() const
353{
354 return status() == Null;
355}
356
357/*!
358 Returns true if status() == QDeclarativeComponent::Ready.
359*/
360bool QDeclarativeComponent::isReady() const
361{
362 return status() == Ready;
363}
364
365/*!
366 Returns true if status() == QDeclarativeComponent::Error.
367*/
368bool QDeclarativeComponent::isError() const
369{
370 return status() == Error;
371}
372
373/*!
374 Returns true if status() == QDeclarativeComponent::Loading.
375*/
376bool QDeclarativeComponent::isLoading() const
377{
378 return status() == Loading;
379}
380
381/*!
382 \qmlproperty real Component::progress
383 The progress of loading the component, from 0.0 (nothing loaded)
384 to 1.0 (finished).
385*/
386
387/*!
388 \property QDeclarativeComponent::progress
389 The progress of loading the component, from 0.0 (nothing loaded)
390 to 1.0 (finished).
391*/
392qreal QDeclarativeComponent::progress() const
393{
394 Q_D(const QDeclarativeComponent);
395 return d->progress;
396}
397
398/*!
399 \fn void QDeclarativeComponent::progressChanged(qreal progress)
400
401 Emitted whenever the component's loading progress changes. \a progress will be the
402 current progress between 0.0 (nothing loaded) and 1.0 (finished).
403*/
404
405/*!
406 \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status)
407
408 Emitted whenever the component's status changes. \a status will be the
409 new status.
410*/
411
412/*!
413 Create a QDeclarativeComponent with no data and give it the specified
414 \a engine and \a parent. Set the data with setData().
415*/
416QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent)
417 : QObject(*(new QDeclarativeComponentPrivate), parent)
418{
419 Q_D(QDeclarativeComponent);
420 d->engine = engine;
421}
422
423/*!
424 Create a QDeclarativeComponent from the given \a url and give it the
425 specified \a parent and \a engine.
426
427 Ensure that the URL provided is full and correct, in particular, use
428 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
429
430 \sa loadUrl()
431*/
432QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent)
433: QObject(*(new QDeclarativeComponentPrivate), parent)
434{
435 Q_D(QDeclarativeComponent);
436 d->engine = engine;
437 loadUrl(url);
438}
439
440/*!
441 Create a QDeclarativeComponent from the given \a fileName and give it the specified
442 \a parent and \a engine.
443
444 \sa loadUrl()
445*/
446QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName,
447 QObject *parent)
448: QObject(*(new QDeclarativeComponentPrivate), parent)
449{
450 Q_D(QDeclarativeComponent);
451 d->engine = engine;
452 loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
453}
454
455/*!
456 \internal
457*/
458QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, int count, QObject *parent)
459 : QObject(*(new QDeclarativeComponentPrivate), parent)
460{
461 Q_D(QDeclarativeComponent);
462 d->engine = engine;
463 d->cc = cc;
464 cc->addref();
465 d->start = start;
466 d->count = count;
467 d->url = cc->url;
468 d->progress = 1.0;
469}
470
471/*!
472 Sets the QDeclarativeComponent to use the given QML \a data. If \a url
473 is provided, it is used to set the component name and to provide
474 a base path for items resolved by this component.
475*/
476void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url)
477{
478 Q_D(QDeclarativeComponent);
479
480 d->clear();
481
482 d->url = url;
483
484 QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url);
485
486 if (typeData->isCompleteOrError()) {
487 d->fromTypeData(typeData);
488 } else {
489 d->typeData = typeData;
490 d->typeData->registerCallback(d);
491 }
492
493 d->progress = 1.0;
494 emit statusChanged(status());
495 emit progressChanged(d->progress);
496}
497
498/*!
499Returns the QDeclarativeContext the component was created in. This is only
500valid for components created directly from QML.
501*/
502QDeclarativeContext *QDeclarativeComponent::creationContext() const
503{
504 Q_D(const QDeclarativeComponent);
505 if(d->creationContext)
506 return d->creationContext->asQDeclarativeContext();
507
508 return qmlContext(this);
509}
510
511/*!
512 Load the QDeclarativeComponent from the provided \a url.
513
514 Ensure that the URL provided is full and correct, in particular, use
515 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
516*/
517void QDeclarativeComponent::loadUrl(const QUrl &url)
518{
519 Q_D(QDeclarativeComponent);
520
521 d->clear();
522
523 if ((url.isRelative() && !url.isEmpty())
524 || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
525 d->url = d->engine->baseUrl().resolved(url);
526 else
527 d->url = url;
528
529 if (url.isEmpty()) {
530 QDeclarativeError error;
531 error.setDescription(tr("Invalid empty URL"));
532 d->state.errors << error;
533 return;
534 }
535
536 QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url);
537
538 if (data->isCompleteOrError()) {
539 d->fromTypeData(data);
540 d->progress = 1.0;
541 } else {
542 d->typeData = data;
543 d->typeData->registerCallback(d);
544 d->progress = data->progress();
545 }
546
547 emit statusChanged(status());
548 emit progressChanged(d->progress);
549}
550
551/*!
552 Return the list of errors that occurred during the last compile or create
553 operation. An empty list is returned if isError() is not set.
554*/
555QList<QDeclarativeError> QDeclarativeComponent::errors() const
556{
557 Q_D(const QDeclarativeComponent);
558 if (isError())
559 return d->state.errors;
560 else
561 return QList<QDeclarativeError>();
562}
563
564/*!
565 \qmlmethod string Component::errorString()
566
567 Returns a human-readable description of any errors.
568
569 The string includes the file, location, and description of each error.
570 If multiple errors are present they are separated by a newline character.
571
572 If no errors are present, an empty string is returned.
573*/
574
575/*!
576 \internal
577 errorString is only meant as a way to get the errors in script
578*/
579QString QDeclarativeComponent::errorString() const
580{
581 Q_D(const QDeclarativeComponent);
582 QString ret;
583 if(!isError())
584 return ret;
585 foreach(const QDeclarativeError &e, d->state.errors) {
586 ret += e.url().toString() + QLatin1Char(':') +
587 QString::number(e.line()) + QLatin1Char(' ') +
588 e.description() + QLatin1Char('\n');
589 }
590 return ret;
591}
592
593/*!
594 \qmlproperty url Component::url
595 The component URL. This is the URL that was used to construct the component.
596*/
597
598/*!
599 \property QDeclarativeComponent::url
600 The component URL. This is the URL passed to either the constructor,
601 or the loadUrl() or setData() methods.
602*/
603QUrl QDeclarativeComponent::url() const
604{
605 Q_D(const QDeclarativeComponent);
606 return d->url;
607}
608
609/*!
610 \internal
611*/
612QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent)
613 : QObject(dd, parent)
614{
615}
616
617/*!
618 \qmlmethod object Component::createObject(Item parent, object properties)
619
620 Creates and returns an object instance of this component that will have
621 the given \a parent and \a properties. The \a properties argument is optional.
622 Returns null if object creation fails.
623
624 The object will be created in the same context as the one in which the component
625 was created. This function will always return null when called on components
626 which were not created in QML.
627
628 If you wish to create an object without setting a parent, specify \c null for
629 the \a parent value. Note that if the returned object is to be displayed, you
630 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
631 property, or else the object will not be visible.
632
633 If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
634 it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
635 since setting the Item parent does not change object ownership; only the graphical parent is changed.
636
637 As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
638 map of initial property values for the created object. These values are applied before object
639 creation is finalized. (This is more efficient than setting property values after object creation,
640 particularly where large sets of property values are defined, and also allows property bindings
641 to be set up before the object is created.)
642
643 The \a properties argument is specified as a map of property-value items. For example, the code
644 below creates an object with initial \c x and \c y values of 100 and 200, respectively:
645
646 \js
647 var component = Qt.createComponent("Button.qml");
648 if (component.status == Component.Ready)
649 component.createObject(parent, {"x": 100, "y": 100});
650 \endjs
651
652 Dynamically created instances can be deleted with the \c destroy() method.
653 See \l {Dynamic Object Management in QML} for more information.
654*/
655
656/*!
657 \internal
658 A version of create which returns a scriptObject, for use in script.
659 This function will only work on components created in QML.
660
661 Sets graphics object parent because forgetting to do this is a frequent
662 and serious problem.
663*/
664QScriptValue QDeclarativeComponent::createObject(QObject* parent)
665{
666 Q_D(QDeclarativeComponent);
667 return d->createObject(parent, QScriptValue(QScriptValue::NullValue));
668}
669
670/*!
671 \internal
672 Overloadable method allows properties to be set during creation
673*/
674QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap)
675{
676 Q_D(QDeclarativeComponent);
677
678 if (!valuemap.isObject() || valuemap.isArray()) {
679 qmlInfo(this) << tr("createObject: value is not an object");
680 return QScriptValue(QScriptValue::NullValue);
681 }
682 return d->createObject(parent, valuemap);
683}
684
685QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap)
686{
687 Q_Q(QDeclarativeComponent);
688 QDeclarativeContext* ctxt = q->creationContext();
689 if(!ctxt && engine)
690 ctxt = engine->rootContext();
691 if (!ctxt)
692 return QScriptValue(QScriptValue::NullValue);
693 QObject* ret = q->beginCreate(ctxt);
694 if (!ret) {
695 q->completeCreate();
696 return QScriptValue(QScriptValue::NullValue);
697 }
698
699 if (publicParent) {
700 ret->setParent(publicParent);
701 QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
702
703 bool needParent = false;
704
705 for (int ii = 0; ii < functions.count(); ++ii) {
706 QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, publicParent);
707 if (res == QDeclarativePrivate::Parented) {
708 needParent = false;
709 break;
710 } else if (res == QDeclarativePrivate::IncompatibleParent) {
711 needParent = true;
712 }
713 }
714
715 if (needParent)
716 qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
717 }
718
719 QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
720 QDeclarativeData::get(ret, true)->setImplicitDestructible();
721 QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
722
723 if (valuemap.isObject() && !valuemap.isArray()) {
724 //Iterate through and assign properties
725 QScriptValueIterator it(valuemap);
726 while (it.hasNext()) {
727 it.next();
728 QScriptValue prop = newObject;
729 QString propName = it.name();
730 int index = propName.indexOf(QLatin1Char('.'));
731 if (index > 0) {
732 QString subProp = propName;
733 int lastIndex = 0;
734 while (index > 0) {
735 subProp = propName.mid(lastIndex, index - lastIndex);
736 prop = prop.property(subProp);
737 lastIndex = index + 1;
738 index = propName.indexOf(QLatin1Char('.'), index + 1);
739 }
740 prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value());
741 } else {
742 newObject.setProperty(propName, it.value());
743 }
744 }
745 }
746
747 q->completeCreate();
748
749 return newObject;
750}
751
752/*!
753 Create an object instance from this component. Returns 0 if creation
754 failed. \a context specifies the context within which to create the object
755 instance.
756
757 If \a context is 0 (the default), it will create the instance in the
758 engine' s \l {QDeclarativeEngine::rootContext()}{root context}.
759*/
760QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
761{
762 Q_D(QDeclarativeComponent);
763
764 if (!context)
765 context = d->engine->rootContext();
766
767 QObject *rv = beginCreate(context);
768 completeCreate();
769 return rv;
770}
771
772/*!
773 This method provides more advanced control over component instance creation.
774 In general, programmers should use QDeclarativeComponent::create() to create a
775 component.
776
777 Create an object instance from this component. Returns 0 if creation
778 failed. \a context specifies the context within which to create the object
779 instance.
780
781 When QDeclarativeComponent constructs an instance, it occurs in three steps:
782 \list 1
783 \i The object hierarchy is created, and constant values are assigned.
784 \i Property bindings are evaluated for the the first time.
785 \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects.
786 \endlist
787 QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it
788 only performs step 1. QDeclarativeComponent::completeCreate() must be called to
789 complete steps 2 and 3.
790
791 This breaking point is sometimes useful when using attached properties to
792 communicate information to an instantiated component, as it allows their
793 initial values to be configured before property bindings take effect.
794*/
795QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
796{
797 Q_D(QDeclarativeComponent);
798 QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
799 if (rv) {
800 QDeclarativeData *ddata = QDeclarativeData::get(rv);
801 Q_ASSERT(ddata);
802 ddata->indestructible = true;
803 }
804 return rv;
805}
806
807QObject *
808QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
809{
810 Q_Q(QDeclarativeComponent);
811 if (!context) {
812 qWarning("QDeclarativeComponent: Cannot create a component in a null context");
813 return 0;
814 }
815
816 if (!context->isValid()) {
817 qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
818 return 0;
819 }
820
821 if (context->engine != engine) {
822 qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
823 return 0;
824 }
825
826 if (state.completePending) {
827 qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous");
828 return 0;
829 }
830
831 if (!q->isReady()) {
832 qWarning("QDeclarativeComponent: Component is not ready");
833 return 0;
834 }
835
836 return begin(context, creationContext, cc, start, count, &state, 0, bindings);
837}
838
839QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
840 QDeclarativeContextData *componentCreationContext,
841 QDeclarativeCompiledData *component, int start, int count,
842 ConstructionState *state, QList<QDeclarativeError> *errors,
843 const QBitField &bindings)
844{
845 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
846 bool isRoot = !enginePriv->inBeginCreate;
847
848 Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
849 Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
850
851 if (isRoot) {
852 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
853 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, component->url);
854 }
855
856 QDeclarativeContextData *ctxt = new QDeclarativeContextData;
857 ctxt->isInternal = true;
858 ctxt->url = component->url;
859 ctxt->imports = component->importCache;
860
861 // Nested global imports
862 if (componentCreationContext && start != -1)
863 ctxt->importedScripts = componentCreationContext->importedScripts;
864
865 component->importCache->addref();
866 ctxt->setParent(parentContext);
867
868 enginePriv->inBeginCreate = true;
869
870 QDeclarativeVME vme;
871 QObject *rv = vme.run(ctxt, component, start, count, bindings);
872
873 if (vme.isError()) {
874 if(errors) *errors = vme.errors();
875 else state->errors = vme.errors();
876 }
877
878 if (isRoot) {
879 enginePriv->inBeginCreate = false;
880
881 state->bindValues = enginePriv->bindValues;
882 state->parserStatus = enginePriv->parserStatus;
883 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
884 state->componentAttached = enginePriv->componentAttached;
885 if (state->componentAttached)
886 state->componentAttached->prev = &state->componentAttached;
887
888 enginePriv->componentAttached = 0;
889 enginePriv->bindValues.clear();
890 enginePriv->parserStatus.clear();
891 enginePriv->finalizedParserStatus.clear();
892 state->completePending = true;
893 enginePriv->inProgressCreations++;
894 }
895
896 if (enginePriv->isDebugging && rv) {
897 if (!parentContext->isInternal)
898 parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
899 QDeclarativeEngineDebugService::instance()->objectCreated(parentContext->engine, rv);
900 }
901
902 return rv;
903}
904
905void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
906 QObject *object, ConstructionState *state)
907{
908 bool isRoot = !enginePriv->inBeginCreate;
909 enginePriv->inBeginCreate = true;
910
911 QDeclarativeVME vme;
912 vme.runDeferred(object);
913
914 if (vme.isError())
915 state->errors = vme.errors();
916
917 if (isRoot) {
918 enginePriv->inBeginCreate = false;
919
920 state->bindValues = enginePriv->bindValues;
921 state->parserStatus = enginePriv->parserStatus;
922 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
923 state->componentAttached = enginePriv->componentAttached;
924 if (state->componentAttached)
925 state->componentAttached->prev = &state->componentAttached;
926
927 enginePriv->componentAttached = 0;
928 enginePriv->bindValues.clear();
929 enginePriv->parserStatus.clear();
930 enginePriv->finalizedParserStatus.clear();
931 state->completePending = true;
932 enginePriv->inProgressCreations++;
933 }
934}
935
936void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
937{
938 if (state->completePending) {
939 QT_TRY {
940 for (int ii = 0; ii < state->bindValues.count(); ++ii) {
941 QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
942 state->bindValues.at(ii);
943 for (int jj = 0; jj < bv.count; ++jj) {
944 if(bv.at(jj)) {
945 // XXX akennedy
946 bv.at(jj)->m_mePtr = 0;
947 bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
948 QDeclarativePropertyPrivate::DontRemoveBinding);
949 }
950 }
951 QDeclarativeEnginePrivate::clear(bv);
952 }
953
954 for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
955 QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
956 state->parserStatus.at(ii);
957
958 for (int jj = ps.count - 1; jj >= 0; --jj) {
959 QDeclarativeParserStatus *status = ps.at(jj);
960 if (status && status->d) {
961 status->d = 0;
962 status->componentComplete();
963 }
964 }
965 QDeclarativeEnginePrivate::clear(ps);
966 }
967
968 for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
969 QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
970 QObject *obj = status.first;
971 if (obj) {
972 void *args[] = { 0 };
973 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
974 status.second, args);
975 }
976 }
977
978 //componentComplete() can register additional finalization objects
979 //that are then never handled. Handle them manually here.
980 if (1 == enginePriv->inProgressCreations) {
981 for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) {
982 QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii);
983 QObject *obj = status.first;
984 if (obj) {
985 void *args[] = { 0 };
986 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
987 status.second, args);
988 }
989 }
990 enginePriv->finalizedParserStatus.clear();
991 }
992
993 while (state->componentAttached) {
994 QDeclarativeComponentAttached *a = state->componentAttached;
995 a->rem();
996 QDeclarativeData *d = QDeclarativeData::get(a->parent());
997 Q_ASSERT(d);
998 Q_ASSERT(d->context);
999 a->add(&d->context->componentAttached);
1000 emit a->completed();
1001 }
1002 } QT_CATCH(const std::exception&) {
1003 state->bindValues.clear();
1004 state->parserStatus.clear();
1005 state->finalizedParserStatus.clear();
1006 state->completePending = false;
1007 enginePriv->inProgressCreations--;
1008 QT_RETHROW;
1009 }
1010
1011 state->bindValues.clear();
1012 state->parserStatus.clear();
1013 state->finalizedParserStatus.clear();
1014 state->completePending = false;
1015
1016 enginePriv->inProgressCreations--;
1017 if (0 == enginePriv->inProgressCreations) {
1018 while (enginePriv->erroredBindings) {
1019 enginePriv->warning(enginePriv->erroredBindings->error);
1020 enginePriv->erroredBindings->removeError();
1021 }
1022 }
1023 }
1024}
1025
1026/*!
1027 This method provides more advanced control over component instance creation.
1028 In general, programmers should use QDeclarativeComponent::create() to create a
1029 component.
1030
1031 Complete a component creation begin with QDeclarativeComponent::beginCreate().
1032*/
1033void QDeclarativeComponent::completeCreate()
1034{
1035 Q_D(QDeclarativeComponent);
1036 d->completeCreate();
1037}
1038
1039void QDeclarativeComponentPrivate::completeCreate()
1040{
1041 if (state.completePending) {
1042 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
1043 complete(ep, &state);
1044
1045 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
1046 }
1047}
1048
1049QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent)
1050: QObject(parent), prev(0), next(0)
1051{
1052}
1053
1054QDeclarativeComponentAttached::~QDeclarativeComponentAttached()
1055{
1056 if (prev) *prev = next;
1057 if (next) next->prev = prev;
1058 prev = 0;
1059 next = 0;
1060}
1061
1062/*!
1063 \internal
1064*/
1065QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj)
1066{
1067 QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj);
1068
1069 QDeclarativeEngine *engine = qmlEngine(obj);
1070 if (!engine)
1071 return a;
1072
1073 if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
1074 QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
1075 a->add(&p->componentAttached);
1076 } else {
1077 QDeclarativeData *d = QDeclarativeData::get(obj);
1078 Q_ASSERT(d);
1079 Q_ASSERT(d->context);
1080 a->add(&d->context->componentAttached);
1081 }
1082
1083 return a;
1084}
1085
1086QT_END_NAMESPACE
1087