1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qqmlcomponent.h"
43 #include "qqmlcomponent_p.h"
44 #include "qqmlcomponentattached_p.h"
46 #include "qqmlcompiler_p.h"
47 #include "qqmlcontext_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlvme_p.h"
51 #include "qqmlengine.h"
52 #include "qqmlbinding_p.h"
53 #include "qqmlglobal_p.h"
54 #include "qqmlscript_p.h"
55 #include <private/qqmlprofilerservice_p.h>
56 #include <private/qqmlenginedebugservice_p.h>
57 #include "qqmlincubator.h"
58 #include "qqmlincubator_p.h"
59 #include <private/qqmljavascriptexpression_p.h>
61 #include <private/qv8engine_p.h>
62 #include <private/qv8include_p.h>
65 #include <QStringList>
66 #include <QThreadStorage>
67 #include <QtCore/qdebug.h>
69 #include "qqmlmemoryprofiler_p.h"
72 QThreadStorage<int> creationDepth;
77 class QQmlComponentExtension : public QV8Engine::Deletable
80 QQmlComponentExtension(QV8Engine *);
81 virtual ~QQmlComponentExtension();
83 v8::Persistent<v8::Function> incubationConstructor;
84 v8::Persistent<v8::Script> initialProperties;
85 v8::Persistent<v8::Function> forceCompletion;
87 V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
90 Try to do what's necessary for a reasonable display of the type
91 name, but no more (just enough for the client to do more extensive cleanup).
93 Should only be called when debugging is enabled.
95 static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
97 static const QString qmlMarker(QLatin1String("_QML"));
98 static const QChar underscore(QLatin1Char('_'));
99 static const QChar asterisk(QLatin1Char('*'));
100 QQmlType *type = QQmlMetaType::qmlType(metaObject);
101 QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(metaObject->className());
103 //### optimize further?
104 int marker = typeName.indexOf(qmlMarker);
105 if (marker != -1 && marker < typeName.count() - 1) {
106 if (typeName[marker + 1] == underscore) {
107 const QString className = typeName.left(marker) + asterisk;
108 type = QQmlMetaType::qmlType(QMetaType::type(className.toUtf8()));
110 typeName = type->qmlTypeName();
123 \brief The QQmlComponent class encapsulates a QML component definition
125 Components are reusable, encapsulated QML types with well-defined interfaces.
127 A QQmlComponent instance can be created from a QML file.
128 For example, if there is a \c main.qml file like this:
139 The following code loads this QML file as a component, creates an instance of
140 this component using create(), and then queries the \l Item's \l {Item::}{width}
144 QQmlEngine *engine = new QQmlEngine;
145 QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
147 QObject *myObject = component.create();
148 QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
149 int width = item->width(); // width = 200
153 \section2 Network Components
155 If the URL passed to QQmlComponent is a network resource, or if the QML document references a
156 network resource, the QQmlComponent has to fetch the network data before it is able to create
157 objects. In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading}
158 \l {QQmlComponent::status()}{status}. An application will have to wait until the component
159 is \l {QQmlComponent::Ready}{Ready} before calling \l {QQmlComponent::create()}.
161 The following example shows how to load a QML file from a network resource. After creating
162 the QQmlComponent, it tests whether the component is loading. If it is, it connects to the
163 QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
164 directly. Note that QQmlComponent::isLoading() may be false for a network component if the
165 component has been cached and is ready immediately.
168 MyApplication::MyApplication()
171 component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
172 if (component->isLoading())
173 QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
174 this, SLOT(continueLoading()));
179 void MyApplication::continueLoading()
181 if (component->isError()) {
182 qWarning() << component->errors();
184 QObject *myObject = component->create();
189 Note that the QtQuick 1 version is named QDeclarativeComponent.
194 \instantiates QQmlComponent
195 \ingroup qml-utility-elements
197 \inqmlmodule QtQuick 2
198 \brief Encapsulates a QML component definition
200 Components are reusable, encapsulated QML types with well-defined interfaces.
202 Components are often defined by \l {{QML Documents}}{component files} -
203 that is, \c .qml files. The \e Component type essentially allows QML components
204 to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
205 This may be useful for reusing a small component within a QML file, or for defining
206 a component that logically belongs with other QML components within a file.
208 For example, here is a component that is used by multiple \l Loader objects.
209 It contains a single item, a \l Rectangle:
211 \snippet qml/component.qml 0
213 Notice that while a \l Rectangle by itself would be automatically
214 rendered and displayed, this is not the case for the above rectangle
215 because it is defined inside a \c Component. The component encapsulates the
216 QML types within, as if they were defined in a separate QML
217 file, and is not loaded until requested (in this case, by the
218 two \l Loader objects).
220 Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
221 A QML document has a single top-level item that defines the behaviors and
222 properties of that component, and cannot define properties or behaviors outside
223 of that top-level item. In the same way, a \c Component definition contains a single
224 top level item (which in the above example is a \l Rectangle) and cannot define any
225 data outside of this item, with the exception of an \e id (which in the above example
228 The \c Component type is commonly used to provide graphical components
229 for views. For example, the ListView::delegate property requires a \c Component
230 to specify how each list item is to be displayed.
232 \c Component objects can also be created dynamically using
233 \l{QML:Qt::createComponent()}{Qt.createComponent()}.
235 \section2 Creation Context
237 The creation context of a Component corresponds to the context where the Component was declared.
238 This context is used as the parent context (creating a \l{qtqml-documents-scope.html#component-instance-hierarchy}{context hierarchy})
239 when the component is instantiated by an object such as a ListView or a Loader.
241 In the following example, \c comp1 is created within the root context of MyItem.qml, and any objects
242 instantiated from this component will have access to the ids and properties within that context,
243 such as \c internalSettings.color. When \c comp1 is used as a ListView delegate in another context
244 (as in main.qml below), it will continue to have access to the properties of its creation context
245 (which would otherwise be private to external users).
252 \li \snippet qml/component/MyItem.qml 0
253 \li \snippet qml/component/main.qml 0
258 \qmlattachedsignal Component::onCompleted()
260 Emitted after component "startup" has completed. This can be used to
261 execute script code at startup, once the full QML environment has been
264 The \c {Component::onCompleted} attached property can be declared on
265 any object. The order of running the \c onCompleted scripts is
270 Component.onCompleted: console.log("Completed Running!")
272 Component.onCompleted: console.log("Nested Completed Running!")
279 \qmlattachedsignal Component::onDestruction()
281 Emitted as the component begins destruction. This can be used to undo
282 work done in the onCompleted signal, or other imperative code in your
285 The \c {Component::onDestruction} attached property can be declared on
286 any object. However, it applies to the destruction of the component as
287 a whole, and not the destruction of the specific object. The order of
288 running the \c onDestruction scripts is undefined.
292 Component.onDestruction: console.log("Destruction Beginning!")
294 Component.onDestruction: console.log("Nested Destruction Beginning!")
303 \enum QQmlComponent::Status
305 Specifies the loading status of the QQmlComponent.
307 \value Null This QQmlComponent has no data. Call loadUrl() or setData() to add QML content.
308 \value Ready This QQmlComponent is ready and create() may be called.
309 \value Loading This QQmlComponent is loading network data.
310 \value Error An error has occurred. Call errors() to retrieve a list of \{QQmlError}{errors}.
314 \enum QQmlComponent::CompilationMode
316 Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
318 \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
319 This is not always possible, e.g. remote URLs will always load asynchronously.
320 \value Asynchronous Load/compile the component in a background thread.
323 void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
329 fromTypeData(typeData);
333 emit q->statusChanged(q->status());
334 emit q->progressChanged(progress);
337 void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
343 emit q->progressChanged(p);
346 void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
348 url = data->finalUrl();
349 QQmlCompiledData *c = data->compiledData();
352 Q_ASSERT(data->isError());
353 state.errors = data->errors();
362 void QQmlComponentPrivate::clear()
365 typeData->unregisterCallback(this);
379 QQmlComponent::QQmlComponent(QObject *parent)
380 : QObject(*(new QQmlComponentPrivate), parent)
385 Destruct the QQmlComponent.
387 QQmlComponent::~QQmlComponent()
391 if (d->state.completePending) {
392 qWarning("QQmlComponent: Component destroyed while completion pending");
397 d->typeData->unregisterCallback(d);
398 d->typeData->release();
405 \qmlproperty enumeration Component::status
406 This property holds the status of component loading. It can be one of:
408 \li Component.Null - no data is available for the component
409 \li Component.Ready - the component has been loaded, and can be used to create instances.
410 \li Component.Loading - the component is currently being loaded
411 \li Component.Error - an error occurred while loading the component.
412 Calling errorString() will provide a human-readable description of any errors.
417 \property QQmlComponent::status
418 The component's current \l{QQmlComponent::Status} {status}.
420 QQmlComponent::Status QQmlComponent::status() const
422 Q_D(const QQmlComponent);
426 else if (!d->state.errors.isEmpty())
428 else if (d->engine && d->cc)
435 Returns true if status() == QQmlComponent::Null.
437 bool QQmlComponent::isNull() const
439 return status() == Null;
443 Returns true if status() == QQmlComponent::Ready.
445 bool QQmlComponent::isReady() const
447 return status() == Ready;
451 Returns true if status() == QQmlComponent::Error.
453 bool QQmlComponent::isError() const
455 return status() == Error;
459 Returns true if status() == QQmlComponent::Loading.
461 bool QQmlComponent::isLoading() const
463 return status() == Loading;
467 \qmlproperty real Component::progress
468 The progress of loading the component, from 0.0 (nothing loaded)
473 \property QQmlComponent::progress
474 The progress of loading the component, from 0.0 (nothing loaded)
477 qreal QQmlComponent::progress() const
479 Q_D(const QQmlComponent);
484 \fn void QQmlComponent::progressChanged(qreal progress)
486 Emitted whenever the component's loading progress changes. \a progress will be the
487 current progress between 0.0 (nothing loaded) and 1.0 (finished).
491 \fn void QQmlComponent::statusChanged(QQmlComponent::Status status)
493 Emitted whenever the component's status changes. \a status will be the
498 Create a QQmlComponent with no data and give it the specified
499 \a engine and \a parent. Set the data with setData().
501 QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
502 : QObject(*(new QQmlComponentPrivate), parent)
509 Create a QQmlComponent from the given \a url and give it the
510 specified \a parent and \a engine.
512 Ensure that the URL provided is full and correct, in particular, use
513 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
517 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
518 : QObject(*(new QQmlComponentPrivate), parent)
526 Create a QQmlComponent from the given \a url and give it the
527 specified \a parent and \a engine. If \a mode is \l Asynchronous,
528 the component will be loaded and compiled asynchronously.
530 Ensure that the URL provided is full and correct, in particular, use
531 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
535 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode,
537 : QObject(*(new QQmlComponentPrivate), parent)
541 d->loadUrl(url, mode);
545 Create a QQmlComponent from the given \a fileName and give it the specified
546 \a parent and \a engine.
550 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
552 : QObject(*(new QQmlComponentPrivate), parent)
556 d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
560 Create a QQmlComponent from the given \a fileName and give it the specified
561 \a parent and \a engine. If \a mode is \l Asynchronous,
562 the component will be loaded and compiled asynchronously.
566 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
567 CompilationMode mode, QObject *parent)
568 : QObject(*(new QQmlComponentPrivate), parent)
572 d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
578 QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
579 : QObject(*(new QQmlComponentPrivate), parent)
591 Sets the QQmlComponent to use the given QML \a data. If \a url
592 is provided, it is used to set the component name and to provide
593 a base path for items resolved by this component.
595 void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
603 QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.getType(data, url);
605 if (typeData->isCompleteOrError()) {
606 d->fromTypeData(typeData);
608 d->typeData = typeData;
609 d->typeData->registerCallback(d);
613 emit statusChanged(status());
614 emit progressChanged(d->progress);
618 Returns the QQmlContext the component was created in. This is only
619 valid for components created directly from QML.
621 QQmlContext *QQmlComponent::creationContext() const
623 Q_D(const QQmlComponent);
624 if(d->creationContext)
625 return d->creationContext->asQQmlContext();
627 return qmlContext(this);
631 Load the QQmlComponent from the provided \a url.
633 Ensure that the URL provided is full and correct, in particular, use
634 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
636 void QQmlComponent::loadUrl(const QUrl &url)
643 Load the QQmlComponent from the provided \a url.
644 If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
646 Ensure that the URL provided is full and correct, in particular, use
647 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
649 void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
652 d->loadUrl(url, mode);
655 void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
660 if ((newUrl.isRelative() && !newUrl.isEmpty())
661 || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
662 url = engine->baseUrl().resolved(newUrl);
666 if (newUrl.isEmpty()) {
668 error.setDescription(q->tr("Invalid empty URL"));
669 state.errors << error;
673 if (progress != 0.0) {
675 emit q->progressChanged(progress);
678 QQmlDataLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
679 ? QQmlDataLoader::Asynchronous
680 : QQmlDataLoader::PreferSynchronous;
682 QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
684 if (data->isCompleteOrError()) {
689 typeData->registerCallback(this);
690 progress = data->progress();
693 emit q->statusChanged(q->status());
695 emit q->progressChanged(progress);
699 Return the list of errors that occurred during the last compile or create
700 operation. An empty list is returned if isError() is not set.
702 QList<QQmlError> QQmlComponent::errors() const
704 Q_D(const QQmlComponent);
706 return d->state.errors;
708 return QList<QQmlError>();
712 \qmlmethod string Component::errorString()
714 Returns a human-readable description of any errors.
716 The string includes the file, location, and description of each error.
717 If multiple errors are present they are separated by a newline character.
719 If no errors are present, an empty string is returned.
724 errorString is only meant as a way to get the errors in script
726 QString QQmlComponent::errorString() const
728 Q_D(const QQmlComponent);
732 foreach(const QQmlError &e, d->state.errors) {
733 ret += e.url().toString() + QLatin1Char(':') +
734 QString::number(e.line()) + QLatin1Char(' ') +
735 e.description() + QLatin1Char('\n');
741 \qmlproperty url Component::url
742 The component URL. This is the URL that was used to construct the component.
746 \property QQmlComponent::url
747 The component URL. This is the URL passed to either the constructor,
748 or the loadUrl() or setData() methods.
750 QUrl QQmlComponent::url() const
752 Q_D(const QQmlComponent);
759 QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
760 : QObject(dd, parent)
765 Create an object instance from this component. Returns 0 if creation
766 failed. \a context specifies the context within which to create the object
769 If \a context is 0 (the default), it will create the instance in the
770 engine' s \l {QQmlEngine::rootContext()}{root context}.
772 QObject *QQmlComponent::create(QQmlContext *context)
775 QML_MEMORY_SCOPE_URL(url());
778 context = d->engine->rootContext();
780 QObject *rv = beginCreate(context);
787 This method provides more advanced control over component instance creation.
788 In general, programmers should use QQmlComponent::create() to create a
791 Create an object instance from this component. Returns 0 if creation
792 failed. \a publicContext specifies the context within which to create the object
795 When QQmlComponent constructs an instance, it occurs in three steps:
797 \li The object hierarchy is created, and constant values are assigned.
798 \li Property bindings are evaluated for the the first time.
799 \li If applicable, QQmlParserStatus::componentComplete() is called on objects.
801 QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
802 only performs step 1. QQmlComponent::completeCreate() must be called to
803 complete steps 2 and 3.
805 This breaking point is sometimes useful when using attached properties to
806 communicate information to an instantiated component, as it allows their
807 initial values to be configured before property bindings take effect.
811 QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
815 Q_ASSERT(publicContext);
816 QQmlContextData *context = QQmlContextData::get(publicContext);
818 return d->beginCreate(context);
822 QQmlComponentPrivate::beginCreate(QQmlContextData *context)
826 qWarning("QQmlComponent: Cannot create a component in a null context");
830 if (!context->isValid()) {
831 qWarning("QQmlComponent: Cannot create a component in an invalid context");
835 if (context->engine != engine) {
836 qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
840 if (state.completePending) {
841 qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
846 qWarning("QQmlComponent: Component is not ready");
850 // Do not create infinite recursion in object creation
851 static const int maxCreationDepth = 10;
852 if (++creationDepth.localData() >= maxCreationDepth) {
853 qWarning("QQmlComponent: Component creation is recursing - aborting");
854 --creationDepth.localData();
857 Q_ASSERT(creationDepth.localData() >= 1);
858 depthIncreased = true;
860 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
862 if (enginePriv->inProgressCreations == 0) {
863 // only track root, since further ones might not be properly nested
864 profiler = new QQmlObjectCreatingProfiler();
867 enginePriv->inProgressCreations++;
868 state.errors.clear();
869 state.completePending = true;
871 enginePriv->referenceScarceResources();
872 state.vme.init(context, cc, start, creationContext);
873 QObject *rv = state.vme.execute(&state.errors);
874 enginePriv->dereferenceScarceResources();
877 QQmlData *ddata = QQmlData::get(rv);
879 //top level objects should never get JS ownership.
880 //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
881 ddata->indestructible = true;
882 ddata->explicitIndestructibleSet = true;
883 ddata->rootObjectInCreation = false;
885 Q_ASSERT(creationDepth.localData() >= 1);
886 --creationDepth.localData();
887 depthIncreased = false;
890 if (enginePriv->isDebugging && rv) {
891 if (!context->isInternal)
892 context->asQQmlContextPrivate()->instances.append(rv);
893 QQmlEngineDebugService::instance()->objectCreated(engine, rv);
895 if (profiler && profiler->enabled) {
896 profiler->setTypeName(buildTypeNameForDebug(rv->metaObject()));
897 QQmlData *data = QQmlData::get(rv);
899 profiler->setLocation(cc->url, data->lineNumber, data->columnNumber);
906 void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
907 QObject *object, ConstructionState *state)
909 enginePriv->inProgressCreations++;
910 state->errors.clear();
911 state->completePending = true;
913 state->vme.initDeferred(object);
914 state->vme.execute(&state->errors);
917 void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
919 if (state->completePending) {
920 state->vme.complete();
922 state->completePending = false;
924 enginePriv->inProgressCreations--;
926 if (0 == enginePriv->inProgressCreations) {
927 while (enginePriv->erroredBindings) {
928 enginePriv->warning(enginePriv->erroredBindings);
929 enginePriv->erroredBindings->removeError();
936 This method provides more advanced control over component instance creation.
937 In general, programmers should use QQmlComponent::create() to create a
940 Complete a component creation begin with QQmlComponent::beginCreate().
944 void QQmlComponent::completeCreate()
951 void QQmlComponentPrivate::completeCreate()
953 if (state.completePending) {
954 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
955 complete(ep, &state);
961 if (depthIncreased) {
962 Q_ASSERT(creationDepth.localData() >= 1);
963 --creationDepth.localData();
964 depthIncreased = false;
968 QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
969 : QObject(parent), prev(0), next(0)
973 QQmlComponentAttached::~QQmlComponentAttached()
975 if (prev) *prev = next;
976 if (next) next->prev = prev;
984 QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
986 QQmlComponentAttached *a = new QQmlComponentAttached(obj);
988 QQmlEngine *engine = qmlEngine(obj);
992 if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
993 QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
994 a->add(&p->activeVME->componentAttached);
996 QQmlData *d = QQmlData::get(obj);
998 Q_ASSERT(d->context);
999 a->add(&d->context->componentAttached);
1006 Create an object instance from this component using the provided
1007 \a incubator. \a context specifies the context within which to create the object
1010 If \a context is 0 (the default), it will create the instance in the
1011 engine's \l {QQmlEngine::rootContext()}{root context}.
1013 \a forContext specifies a context that this object creation depends upon.
1014 If the \a forContext is being created asynchronously, and the
1015 \l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
1016 this object will also be created asynchronously. If \a forContext is 0
1017 (the default), the \a context will be used for this decision.
1019 The created object and its creation status are available via the
1025 void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
1026 QQmlContext *forContext)
1031 context = d->engine->rootContext();
1033 QQmlContextData *contextData = QQmlContextData::get(context);
1034 QQmlContextData *forContextData = contextData;
1035 if (forContext) forContextData = QQmlContextData::get(forContext);
1037 if (!contextData->isValid()) {
1038 qWarning("QQmlComponent: Cannot create a component in an invalid context");
1042 if (contextData->engine != d->engine) {
1043 qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
1048 qWarning("QQmlComponent: Component is not ready");
1053 QQmlIncubatorPrivate *p = incubator.d;
1055 QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
1057 p->compiledData = d->cc;
1058 p->compiledData->addref();
1059 p->vme.init(contextData, d->cc, d->start, d->creationContext);
1061 enginePriv->incubate(incubator, forContextData);
1064 class QV8IncubatorResource : public QV8ObjectResource,
1065 public QQmlIncubator
1067 V8_RESOURCE_TYPE(IncubatorType)
1069 QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
1071 static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>,
1072 const v8::AccessorInfo& info);
1073 static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>,
1074 const v8::AccessorInfo& info);
1075 static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>,
1076 const v8::AccessorInfo& info);
1077 static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>,
1078 const v8::AccessorInfo& info);
1079 static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
1081 static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
1082 const v8::AccessorInfo& info);
1086 v8::Persistent<v8::Object> me;
1087 QQmlGuard<QObject> parent;
1088 v8::Persistent<v8::Value> valuemap;
1089 v8::Persistent<v8::Object> qmlGlobal;
1091 virtual void statusChanged(Status);
1092 virtual void setInitialState(QObject *);
1095 static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
1098 me->setParent(parent);
1099 typedef QQmlPrivate::AutoParentFunction APF;
1100 QList<APF> functions = QQmlMetaType::parentFunctions();
1102 bool needParent = false;
1103 for (int ii = 0; ii < functions.count(); ++ii) {
1104 QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
1105 if (res == QQmlPrivate::Parented) {
1108 } else if (res == QQmlPrivate::IncompatibleParent) {
1113 qWarning("QQmlComponent: Created graphical object was not "
1114 "placed in the graphics scene.");
1119 \qmlmethod object Component::createObject(Item parent, object properties)
1121 Creates and returns an object instance of this component that will have
1122 the given \a parent and \a properties. The \a properties argument is optional.
1123 Returns null if object creation fails.
1125 The object will be created in the same context as the one in which the component
1126 was created. This function will always return null when called on components
1127 which were not created in QML.
1129 If you wish to create an object without setting a parent, specify \c null for
1130 the \a parent value. Note that if the returned object is to be displayed, you
1131 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
1132 property, or else the object will not be visible.
1134 If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
1135 it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
1136 since setting the Item parent does not change object ownership; only the graphical parent is changed.
1138 As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
1139 map of initial property values for the created object. These values are applied before object
1140 creation is finalized. (This is more efficient than setting property values after object creation,
1141 particularly where large sets of property values are defined, and also allows property bindings
1142 to be set up before the object is created.)
1144 The \a properties argument is specified as a map of property-value items. For example, the code
1145 below creates an object with initial \c x and \c y values of 100 and 200, respectively:
1148 var component = Qt.createComponent("Button.qml");
1149 if (component.status == Component.Ready)
1150 component.createObject(parent, {"x": 100, "y": 100});
1153 Dynamically created instances can be deleted with the \c destroy() method.
1154 See \l {Dynamic QML Object Creation from JavaScript} for more information.
1156 \sa incubateObject()
1162 void QQmlComponent::createObject(QQmlV8Function *args)
1165 Q_ASSERT(d->engine);
1168 QObject *parent = 0;
1169 v8::Local<v8::Object> valuemap;
1171 if (args->Length() >= 1)
1172 parent = args->engine()->toQObject((*args)[0]);
1174 if (args->Length() >= 2) {
1175 v8::Local<v8::Value> v = (*args)[1];
1176 if (!v->IsObject() || v->IsArray()) {
1177 qmlInfo(this) << tr("createObject: value is not an object");
1178 args->returnValue(v8::Null());
1181 valuemap = v8::Local<v8::Object>::Cast(v);
1184 QV8Engine *v8engine = args->engine();
1186 QQmlContext *ctxt = creationContext();
1187 if (!ctxt) ctxt = d->engine->rootContext();
1189 QObject *rv = beginCreate(ctxt);
1192 args->returnValue(v8::Null());
1196 QQmlComponent_setQmlParent(rv, parent);
1198 v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
1199 Q_ASSERT(ov->IsObject());
1200 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
1202 if (!valuemap.IsEmpty()) {
1203 QQmlComponentExtension *e = componentExtension(v8engine);
1204 // Try catch isn't needed as the function itself is loaded with try/catch
1205 v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
1206 v8::Handle<v8::Value> args[] = { object, valuemap };
1207 v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
1210 d->completeCreate();
1212 Q_ASSERT(QQmlData::get(rv));
1213 QQmlData::get(rv)->explicitIndestructibleSet = false;
1214 QQmlData::get(rv)->indestructible = false;
1217 args->returnValue(v8::Null());
1219 args->returnValue(object);
1223 \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
1225 Creates an incubator for instance of this component. Incubators allow new component
1226 instances to be instantiated asynchronously and not cause freezes in the UI.
1228 The \a parent argument specifies the parent the created instance will have. Omitting the
1229 parameter or passing null will create anobject with no parent. In this case, a reference
1230 to the created object must be maintained by the application of the object will eventually
1231 be garbage collected.
1233 The \a properties argument is specified as a map of property-value items which will be
1234 set on the created object during its construction. \a mode may be Qt.Synchronous or
1235 Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously.
1236 The default is asynchronously. In some circumstances, even if Qt.Synchronous is specified,
1237 the incubator may create the object asynchronously. This happens if the component calling
1238 incubateObject() is itself being created asynchronously.
1240 All three arguments are optional.
1242 If successful, the method returns an incubator, otherwise null. The incubator has the following
1246 \li status The status of the incubator. Valid values are Component.Ready, Component.Loading and
1248 \li object The created object instance. Will only be available once the incubator is in the
1250 \li onStatusChanged Specifies a callback function to be invoked when the status changes. The
1251 status is passed as a parameter to the callback.
1252 \li forceCompletion() Call to complete incubation synchronously.
1255 The following example demonstrates how to use an incubator:
1258 var component = Qt.createComponent("Button.qml");
1260 var incubator = component.incubateObject(parent, { x: 10, y: 10 });
1261 if (incubator.status != Component.Ready) {
1262 incubator.onStatusChanged = function(status) {
1263 if (status == Component.Ready) {
1264 print ("Object", incubator.object, "is now ready!");
1268 print ("Object", incubator.object, "is ready immediately!");
1272 Dynamically created instances can be deleted with the \c destroy() method.
1273 See \l {Dynamic QML Object Creation from JavaScript} for more information.
1281 void QQmlComponent::incubateObject(QQmlV8Function *args)
1284 Q_ASSERT(d->engine);
1288 QObject *parent = 0;
1289 v8::Local<v8::Object> valuemap;
1290 QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
1292 if (args->Length() >= 1)
1293 parent = args->engine()->toQObject((*args)[0]);
1295 if (args->Length() >= 2) {
1296 v8::Local<v8::Value> v = (*args)[1];
1298 } else if (!v->IsObject() || v->IsArray()) {
1299 qmlInfo(this) << tr("createObject: value is not an object");
1300 args->returnValue(v8::Null());
1303 valuemap = v8::Local<v8::Object>::Cast(v);
1307 if (args->Length() >= 3) {
1308 quint32 v = (*args)[2]->Uint32Value();
1310 mode = QQmlIncubator::Asynchronous;
1312 mode = QQmlIncubator::AsynchronousIfNested;
1315 QQmlComponentExtension *e = componentExtension(args->engine());
1317 QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
1318 v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
1319 o->SetExternalResource(r);
1321 if (!valuemap.IsEmpty()) {
1322 r->valuemap = qPersistentNew(valuemap);
1323 r->qmlGlobal = qPersistentNew(args->qmlGlobal());
1326 r->me = qPersistentNew(o);
1328 create(*r, creationContext());
1330 if (r->status() == QQmlIncubator::Null) {
1332 args->returnValue(v8::Null());
1334 args->returnValue(o);
1338 // XXX used by QSGLoader
1339 void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
1341 QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1342 QV8Engine *v8engine = ep->v8engine();
1344 v8::HandleScope handle_scope;
1345 v8::Context::Scope scope(v8engine->context());
1346 v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
1347 Q_ASSERT(ov->IsObject());
1348 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
1350 if (!valuemap.IsEmpty()) {
1351 QQmlComponentExtension *e = componentExtension(v8engine);
1352 // Try catch isn't needed as the function itself is loaded with try/catch
1353 v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
1354 v8::Handle<v8::Value> args[] = { object, valuemap };
1355 v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
1360 QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
1362 v8::HandleScope handle_scope;
1363 v8::Context::Scope scope(engine->context());
1365 forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
1368 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
1369 ft->InstanceTemplate()->SetHasExternalResource(true);
1370 ft->InstanceTemplate()->SetInternalFieldCount(1);
1371 ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"),
1372 QV8IncubatorResource::StatusChangedGetter,
1373 QV8IncubatorResource::StatusChangedSetter);
1374 ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
1375 QV8IncubatorResource::StatusGetter);
1376 ft->InstanceTemplate()->SetAccessor(v8::String::New("object"),
1377 QV8IncubatorResource::ObjectGetter);
1378 ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"),
1379 QV8IncubatorResource::ForceCompletionGetter);
1380 incubationConstructor = qPersistentNew(ft->GetFunction());
1384 #define INITIALPROPERTIES_SOURCE \
1385 "(function(object, values) {"\
1387 "for(var property in values) {" \
1389 "var properties = property.split(\".\");"\
1391 "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
1392 "o = o[properties[ii]];"\
1394 "o[properties[properties.length - 1]] = values[property];"\
1399 initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
1400 #undef INITIALPROPERTIES_SOURCE
1404 v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>,
1405 const v8::AccessorInfo& info)
1407 QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1408 return r->engine->newQObject(r->object());
1411 v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>,
1412 const v8::AccessorInfo& info)
1414 QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1415 return componentExtension(r->engine)->forceCompletion;
1418 v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args)
1420 QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
1422 V8THROW_TYPE("Not an incubator object");
1424 r->forceCompletion();
1426 return v8::Undefined();
1429 v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>,
1430 const v8::AccessorInfo& info)
1432 QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1433 return v8::Integer::NewFromUnsigned(r->status());
1436 v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>,
1437 const v8::AccessorInfo& info)
1439 return info.This()->GetInternalField(0);
1442 void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
1443 const v8::AccessorInfo& info)
1445 info.This()->SetInternalField(0, value);
1448 QQmlComponentExtension::~QQmlComponentExtension()
1450 qPersistentDispose(incubationConstructor);
1451 qPersistentDispose(initialProperties);
1452 qPersistentDispose(forceCompletion);
1455 QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
1456 : QV8ObjectResource(engine), QQmlIncubator(m)
1460 void QV8IncubatorResource::setInitialState(QObject *o)
1462 QQmlComponent_setQmlParent(o, parent);
1464 if (!valuemap.IsEmpty()) {
1465 QQmlComponentExtension *e = componentExtension(engine);
1467 v8::HandleScope handle_scope;
1468 v8::Context::Scope scope(engine->context());
1470 v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
1471 v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
1472 v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
1474 qPersistentDispose(valuemap);
1475 qPersistentDispose(qmlGlobal);
1479 void QV8IncubatorResource::dispose()
1481 qPersistentDispose(valuemap);
1482 qPersistentDispose(qmlGlobal);
1483 // No further status changes are forthcoming, so we no long need a self reference
1484 qPersistentDispose(me);
1487 void QV8IncubatorResource::statusChanged(Status s)
1490 Q_ASSERT(QQmlData::get(object()));
1491 QQmlData::get(object())->explicitIndestructibleSet = false;
1492 QQmlData::get(object())->indestructible = false;
1495 if (!me.IsEmpty()) { // Will be false in synchronous mode
1496 v8::HandleScope scope;
1497 v8::Local<v8::Value> callback = me->GetInternalField(0);
1499 if (!callback.IsEmpty() && !callback->IsUndefined()) {
1501 if (callback->IsFunction()) {
1502 v8::Context::Scope context_scope(engine->context());
1503 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
1504 v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
1506 f->Call(me, 1, args);
1507 if (tc.HasCaught()) {
1509 QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
1510 QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
1516 if (s == Ready || s == Error)