Document QQmlComponent::create(QQmlIncubator&, ...)
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlcomponent.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlcomponent.h"
43 #include "qqmlcomponent_p.h"
44 #include "qqmlcomponentattached_p.h"
45
46 #include "qqmlcompiler_p.h"
47 #include "qqmlcontext_p.h"
48 #include "qqmlengine_p.h"
49 #include "qqmlvme_p.h"
50 #include "qqml.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>
60
61 #include <private/qv8engine_p.h>
62 #include <private/qv8include_p.h>
63
64 #include <QStack>
65 #include <QStringList>
66 #include <QtCore/qdebug.h>
67 #include <qqmlinfo.h>
68 #include "qqmlmemoryprofiler_p.h"
69
70 QT_BEGIN_NAMESPACE
71
72 class QQmlComponentExtension : public QV8Engine::Deletable
73 {
74 public:
75     QQmlComponentExtension(QV8Engine *);
76     virtual ~QQmlComponentExtension();
77
78     v8::Persistent<v8::Function> incubationConstructor;
79     v8::Persistent<v8::Script> initialProperties;
80     v8::Persistent<v8::Function> forceCompletion;
81 };
82 V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
83
84 /*
85     Try to do what's necessary for a reasonable display of the type
86     name, but no more (just enough for the client to do more extensive cleanup).
87
88     Should only be called when debugging is enabled.
89 */
90 static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
91 {
92     static const QString qmlMarker(QLatin1String("_QML"));
93     static const QChar underscore(QLatin1Char('_'));
94     static const QChar asterisk(QLatin1Char('*'));
95     QQmlType *type = QQmlMetaType::qmlType(metaObject);
96     QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(metaObject->className());
97     if (!type) {
98         //### optimize further?
99         int marker = typeName.indexOf(qmlMarker);
100         if (marker != -1 && marker < typeName.count() - 1) {
101             if (typeName[marker + 1] == underscore) {
102                 const QString className = typeName.left(marker) + asterisk;
103                 type = QQmlMetaType::qmlType(QMetaType::type(className.toUtf8()));
104                 if (type)
105                     typeName = type->qmlTypeName();
106             }
107         }
108     }
109     return typeName;
110 }
111
112 /*!
113     \class QQmlComponent
114     \since 5.0
115     \inmodule QtQml
116     \mainclass
117
118     \brief The QQmlComponent class encapsulates a QML component definition
119
120     Components are reusable, encapsulated QML elements with well-defined interfaces.
121
122     A QQmlComponent instance can be created from a QML file.
123     For example, if there is a \c main.qml file like this:
124
125     \qml
126     import QtQuick 2.0
127
128     Item {
129         width: 200
130         height: 200
131     }
132     \endqml
133
134     The following code loads this QML file as a component, creates an instance of
135     this component using create(), and then queries the \l Item's \l {Item::}{width}
136     value:
137
138     \code
139     QQmlEngine *engine = new QQmlEngine;
140     QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
141
142     QObject *myObject = component.create();
143     QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
144     int width = item->width();  // width = 200
145     \endcode
146
147
148     \section2 Network Components
149
150     If the URL passed to QQmlComponent is a network resource, or if the QML document references a
151     network resource, the QQmlComponent has to fetch the network data before it is able to create
152     objects.  In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading}
153     \l {QQmlComponent::status()}{status}.  An application will have to wait until the component
154     is \l {QQmlComponent::Ready}{Ready} before calling \l {QQmlComponent::create()}.
155
156     The following example shows how to load a QML file from a network resource.  After creating
157     the QQmlComponent, it tests whether the component is loading.  If it is, it connects to the
158     QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
159     directly. Note that QQmlComponent::isLoading() may be false for a network component if the
160     component has been cached and is ready immediately.
161
162     \code
163     MyApplication::MyApplication()
164     {
165         // ...
166         component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
167         if (component->isLoading())
168             QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
169                              this, SLOT(continueLoading()));
170         else
171             continueLoading();
172     }
173
174     void MyApplication::continueLoading()
175     {
176         if (component->isError()) {
177             qWarning() << component->errors();
178         } else {
179             QObject *myObject = component->create();
180         }
181     }
182     \endcode
183
184     Note that the QtQuick 1 version is named QDeclarativeComponent.
185 */
186
187 /*!
188     \qmlclass Component QQmlComponent
189     \ingroup qml-utility-elements
190     \since 4.7
191     \inqmlmodule QtQuick 2
192     \brief Encapsulates a QML component definition
193
194     Components are reusable, encapsulated QML elements with well-defined interfaces.
195
196     Components are often defined by \l {{QML Documents}}{component files} -
197     that is, \c .qml files. The \e Component element essentially allows QML components
198     to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
199     This may be useful for reusing a small component within a QML file, or for defining
200     a component that logically belongs with other QML components within a file.
201
202     For example, here is a component that is used by multiple \l Loader objects.
203     It contains a single item, a \l Rectangle:
204
205     \snippet qml/component.qml 0
206
207     Notice that while a \l Rectangle by itself would be automatically 
208     rendered and displayed, this is not the case for the above rectangle
209     because it is defined inside a \c Component. The component encapsulates the
210     QML elements within, as if they were defined in a separate QML
211     file, and is not loaded until requested (in this case, by the
212     two \l Loader objects).
213
214     Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
215     A QML document has a single top-level item that defines the behaviors and
216     properties of that component, and cannot define properties or behaviors outside
217     of that top-level item. In the same way, a \c Component definition contains a single
218     top level item (which in the above example is a \l Rectangle) and cannot define any
219     data outside of this item, with the exception of an \e id (which in the above example
220     is \e redSquare).
221
222     The \c Component element is commonly used to provide graphical components
223     for views. For example, the ListView::delegate property requires a \c Component
224     to specify how each list item is to be displayed.
225
226     \c Component objects can also be created dynamically using
227     \l{QML:Qt::createComponent()}{Qt.createComponent()}.
228
229     \section2 Creation Context
230
231     The creation context of a Component corresponds to the context where the Component was declared.
232     This context is used as the parent context (creating a \l{qtqml-documents-scope.html#component-instance-hierarchy}{context hierarchy})
233     when the component is instantiated by an object such as a ListView or a Loader.
234
235     In the following example, \c comp1 is created within the root context of MyItem.qml, and any objects
236     instantiated from this component will have access to the ids and properties within that context,
237     such as \c internalSettings.color. When \c comp1 is used as a ListView delegate in another context
238     (as in main.qml below), it will continue to have access to the properties of its creation context
239     (which would otherwise be private to external users).
240
241     \table
242     \row
243     \li MyItem.qml
244     \li main.qml
245     \row
246     \li \snippet qml/component/MyItem.qml 0
247     \li \snippet qml/component/main.qml 0
248     \endtable
249 */
250
251 /*!
252     \qmlattachedsignal Component::onCompleted()
253
254     Emitted after component "startup" has completed.  This can be used to
255     execute script code at startup, once the full QML environment has been
256     established.
257
258     The \c {Component::onCompleted} attached property can be applied to
259     any element.  The order of running the \c onCompleted scripts is
260     undefined.
261
262     \qml
263     Rectangle {
264         Component.onCompleted: console.log("Completed Running!")
265         Rectangle {
266             Component.onCompleted: console.log("Nested Completed Running!")
267         }
268     }
269     \endqml
270 */
271
272 /*!
273     \qmlattachedsignal Component::onDestruction()
274
275     Emitted as the component begins destruction.  This can be used to undo
276     work done in the onCompleted signal, or other imperative code in your
277     application.
278
279     The \c {Component::onDestruction} attached property can be applied to
280     any element.  However, it applies to the destruction of the component as
281     a whole, and not the destruction of the specific object.  The order of
282     running the \c onDestruction scripts is undefined.
283
284     \qml
285     Rectangle {
286         Component.onDestruction: console.log("Destruction Beginning!")
287         Rectangle {
288             Component.onDestruction: console.log("Nested Destruction Beginning!")
289         }
290     }
291     \endqml
292
293     \sa QtQml
294 */
295
296 /*!
297     \enum QQmlComponent::Status
298     
299     Specifies the loading status of the QQmlComponent.
300
301     \value Null This QQmlComponent has no data.  Call loadUrl() or setData() to add QML content.
302     \value Ready This QQmlComponent is ready and create() may be called.
303     \value Loading This QQmlComponent is loading network data.
304     \value Error An error has occurred.  Call errors() to retrieve a list of \{QQmlError}{errors}.
305 */
306
307 /*!
308     \enum QQmlComponent::CompilationMode
309
310     Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
311
312     \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
313     This is not always possible, e.g. remote URLs will always load asynchronously.
314     \value Asynchronous Load/compile the component in a background thread.
315 */
316
317 void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
318 {
319     Q_Q(QQmlComponent);
320
321     Q_ASSERT(typeData);
322
323     fromTypeData(typeData);
324     typeData = 0;
325     progress = 1.0;
326
327     emit q->statusChanged(q->status());
328     emit q->progressChanged(progress);
329 }
330
331 void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
332 {
333     Q_Q(QQmlComponent);
334
335     progress = p;
336
337     emit q->progressChanged(p);
338 }
339
340 void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
341 {
342     url = data->finalUrl();
343     QQmlCompiledData *c = data->compiledData();
344
345     if (!c) {
346         Q_ASSERT(data->isError());
347         state.errors = data->errors();
348     } else {
349         cc = c;
350         cc->addref();
351     }
352
353     data->release();
354 }
355
356 void QQmlComponentPrivate::clear()
357 {
358     if (typeData) {
359         typeData->unregisterCallback(this);
360         typeData->release();
361         typeData = 0;
362     }
363         
364     if (cc) { 
365         cc->release();
366         cc = 0;
367     }
368 }
369
370 /*!
371     \internal
372 */
373 QQmlComponent::QQmlComponent(QObject *parent)
374     : QObject(*(new QQmlComponentPrivate), parent)
375 {
376 }
377
378 /*!
379     Destruct the QQmlComponent.
380 */
381 QQmlComponent::~QQmlComponent()
382 {
383     Q_D(QQmlComponent);
384
385     if (d->state.completePending) {
386         qWarning("QQmlComponent: Component destroyed while completion pending");
387         d->completeCreate();
388     }
389
390     if (d->typeData) {
391         d->typeData->unregisterCallback(d);
392         d->typeData->release();
393     }
394     if (d->cc)
395         d->cc->release();
396 }
397
398 /*!
399     \qmlproperty enumeration Component::status
400     This property holds the status of component loading.  It can be one of:
401     \list
402     \li Component.Null - no data is available for the component
403     \li Component.Ready - the component has been loaded, and can be used to create instances.
404     \li Component.Loading - the component is currently being loaded
405     \li Component.Error - an error occurred while loading the component.
406                Calling errorString() will provide a human-readable description of any errors.
407     \endlist
408  */
409
410 /*!
411     \property QQmlComponent::status
412     The component's current \l{QQmlComponent::Status} {status}.
413  */
414 QQmlComponent::Status QQmlComponent::status() const
415 {
416     Q_D(const QQmlComponent);
417
418     if (d->typeData)
419         return Loading;
420     else if (!d->state.errors.isEmpty())
421         return Error;
422     else if (d->engine && d->cc)
423         return Ready;
424     else
425         return Null;
426 }
427
428 /*!
429     Returns true if status() == QQmlComponent::Null.
430 */
431 bool QQmlComponent::isNull() const
432 {
433     return status() == Null;
434 }
435
436 /*!
437     Returns true if status() == QQmlComponent::Ready.
438 */
439 bool QQmlComponent::isReady() const
440 {
441     return status() == Ready;
442 }
443
444 /*!
445     Returns true if status() == QQmlComponent::Error.
446 */
447 bool QQmlComponent::isError() const
448 {
449     return status() == Error;
450 }
451
452 /*!
453     Returns true if status() == QQmlComponent::Loading.
454 */
455 bool QQmlComponent::isLoading() const
456 {
457     return status() == Loading;
458 }
459
460 /*!
461     \qmlproperty real Component::progress
462     The progress of loading the component, from 0.0 (nothing loaded)
463     to 1.0 (finished).
464 */
465
466 /*!
467     \property QQmlComponent::progress
468     The progress of loading the component, from 0.0 (nothing loaded)
469     to 1.0 (finished).
470 */
471 qreal QQmlComponent::progress() const
472 {
473     Q_D(const QQmlComponent);
474     return d->progress;
475 }
476
477 /*!
478     \fn void QQmlComponent::progressChanged(qreal progress)
479
480     Emitted whenever the component's loading progress changes.  \a progress will be the
481     current progress between 0.0 (nothing loaded) and 1.0 (finished).
482 */
483
484 /*!
485     \fn void QQmlComponent::statusChanged(QQmlComponent::Status status)
486
487     Emitted whenever the component's status changes.  \a status will be the
488     new status.
489 */
490
491 /*!
492     Create a QQmlComponent with no data and give it the specified
493     \a engine and \a parent. Set the data with setData().
494 */
495 QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
496     : QObject(*(new QQmlComponentPrivate), parent)
497 {
498     Q_D(QQmlComponent);
499     d->engine = engine;
500 }
501
502 /*!
503     Create a QQmlComponent from the given \a url and give it the
504     specified \a parent and \a engine.
505
506     Ensure that the URL provided is full and correct, in particular, use
507     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
508
509     \sa loadUrl()
510 */
511 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
512 : QObject(*(new QQmlComponentPrivate), parent)
513 {
514     Q_D(QQmlComponent);
515     d->engine = engine;
516     d->loadUrl(url);
517 }
518
519 /*!
520     Create a QQmlComponent from the given \a url and give it the
521     specified \a parent and \a engine.  If \a mode is \l Asynchronous,
522     the component will be loaded and compiled asynchronously.
523
524     Ensure that the URL provided is full and correct, in particular, use
525     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
526
527     \sa loadUrl()
528 */
529 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode,
530                              QObject *parent)
531 : QObject(*(new QQmlComponentPrivate), parent)
532 {
533     Q_D(QQmlComponent);
534     d->engine = engine;
535     d->loadUrl(url, mode);
536 }
537
538 /*!
539     Create a QQmlComponent from the given \a fileName and give it the specified 
540     \a parent and \a engine.
541
542     \sa loadUrl()
543 */
544 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, 
545                              QObject *parent)
546 : QObject(*(new QQmlComponentPrivate), parent)
547 {
548     Q_D(QQmlComponent);
549     d->engine = engine;
550     d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
551 }
552
553 /*!
554     Create a QQmlComponent from the given \a fileName and give it the specified
555     \a parent and \a engine.  If \a mode is \l Asynchronous,
556     the component will be loaded and compiled asynchronously.
557
558     \sa loadUrl()
559 */
560 QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
561                              CompilationMode mode, QObject *parent)
562 : QObject(*(new QQmlComponentPrivate), parent)
563 {
564     Q_D(QQmlComponent);
565     d->engine = engine;
566     d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
567 }
568
569 /*!
570     \internal
571 */
572 QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
573     : QObject(*(new QQmlComponentPrivate), parent)
574 {
575     Q_D(QQmlComponent);
576     d->engine = engine;
577     d->cc = cc;
578     cc->addref();
579     d->start = start;
580     d->url = cc->url;
581     d->progress = 1.0;
582 }
583
584 /*!
585     Sets the QQmlComponent to use the given QML \a data.  If \a url
586     is provided, it is used to set the component name and to provide
587     a base path for items resolved by this component.
588 */
589 void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
590 {
591     Q_D(QQmlComponent);
592
593     d->clear();
594
595     d->url = url;
596
597     QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.getType(data, url);
598     
599     if (typeData->isCompleteOrError()) {
600         d->fromTypeData(typeData);
601     } else {
602         d->typeData = typeData;
603         d->typeData->registerCallback(d);
604     }
605
606     d->progress = 1.0;
607     emit statusChanged(status());
608     emit progressChanged(d->progress);
609 }
610
611 /*!
612 Returns the QQmlContext the component was created in.  This is only
613 valid for components created directly from QML.
614 */
615 QQmlContext *QQmlComponent::creationContext() const
616 {
617     Q_D(const QQmlComponent);
618     if(d->creationContext)
619         return d->creationContext->asQQmlContext();
620
621     return qmlContext(this);
622 }
623
624 /*!
625     Load the QQmlComponent from the provided \a url.
626
627     Ensure that the URL provided is full and correct, in particular, use
628     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
629 */
630 void QQmlComponent::loadUrl(const QUrl &url)
631 {
632     Q_D(QQmlComponent);
633     d->loadUrl(url);
634 }
635
636 /*!
637     Load the QQmlComponent from the provided \a url.
638     If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.
639
640     Ensure that the URL provided is full and correct, in particular, use
641     \l QUrl::fromLocalFile() when loading a file from the local filesystem.
642 */
643 void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
644 {
645     Q_D(QQmlComponent);
646     d->loadUrl(url, mode);
647 }
648
649 void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
650 {
651     Q_Q(QQmlComponent);
652     clear();
653
654     if ((newUrl.isRelative() && !newUrl.isEmpty())
655     || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
656         url = engine->baseUrl().resolved(newUrl);
657     else
658         url = newUrl;
659
660     if (newUrl.isEmpty()) {
661         QQmlError error;
662         error.setDescription(q->tr("Invalid empty URL"));
663         state.errors << error;
664         return;
665     }
666
667     if (progress != 0.0) {
668         progress = 0.0;
669         emit q->progressChanged(progress);
670     }
671
672     QQmlDataLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
673             ? QQmlDataLoader::Asynchronous
674             : QQmlDataLoader::PreferSynchronous;
675
676     QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.getType(url, loaderMode);
677
678     if (data->isCompleteOrError()) {
679         fromTypeData(data);
680         progress = 1.0;
681     } else {
682         typeData = data;
683         typeData->registerCallback(this);
684         progress = data->progress();
685     }
686
687     emit q->statusChanged(q->status());
688     if (progress != 0.0)
689         emit q->progressChanged(progress);
690 }
691
692 /*!
693     Return the list of errors that occurred during the last compile or create
694     operation.  An empty list is returned if isError() is not set.
695 */
696 QList<QQmlError> QQmlComponent::errors() const
697 {
698     Q_D(const QQmlComponent);
699     if (isError())
700         return d->state.errors;
701     else
702         return QList<QQmlError>();
703 }
704
705 /*!
706     \qmlmethod string Component::errorString()
707
708     Returns a human-readable description of any errors.
709
710     The string includes the file, location, and description of each error.
711     If multiple errors are present they are separated by a newline character.
712
713     If no errors are present, an empty string is returned.
714 */
715
716 /*!
717     \internal
718     errorString is only meant as a way to get the errors in script
719 */
720 QString QQmlComponent::errorString() const
721 {
722     Q_D(const QQmlComponent);
723     QString ret;
724     if(!isError())
725         return ret;
726     foreach(const QQmlError &e, d->state.errors) {
727         ret += e.url().toString() + QLatin1Char(':') +
728                QString::number(e.line()) + QLatin1Char(' ') +
729                e.description() + QLatin1Char('\n');
730     }
731     return ret;
732 }
733
734 /*!
735     \qmlproperty url Component::url
736     The component URL.  This is the URL that was used to construct the component.
737 */
738
739 /*!
740     \property QQmlComponent::url
741     The component URL.  This is the URL passed to either the constructor,
742     or the loadUrl() or setData() methods.
743 */
744 QUrl QQmlComponent::url() const
745 {
746     Q_D(const QQmlComponent);
747     return d->url;
748 }
749
750 /*!
751     \internal
752 */
753 QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
754     : QObject(dd, parent)
755 {
756 }
757
758 /*!
759     Create an object instance from this component.  Returns 0 if creation
760     failed.  \a context specifies the context within which to create the object
761     instance.  
762
763     If \a context is 0 (the default), it will create the instance in the
764     engine' s \l {QQmlEngine::rootContext()}{root context}.
765 */
766 QObject *QQmlComponent::create(QQmlContext *context)
767 {
768     Q_D(QQmlComponent);
769     QML_MEMORY_SCOPE_URL(url());
770
771     if (!context)
772         context = d->engine->rootContext();
773
774     QObject *rv = beginCreate(context);
775     completeCreate();
776     return rv;
777 }
778
779 /*!
780     This method provides more advanced control over component instance creation.
781     In general, programmers should use QQmlComponent::create() to create a 
782     component.
783
784     Create an object instance from this component.  Returns 0 if creation
785     failed.  \a publicContext specifies the context within which to create the object
786     instance.  
787
788     When QQmlComponent constructs an instance, it occurs in three steps:
789     \list 1
790     \li The object hierarchy is created, and constant values are assigned.
791     \li Property bindings are evaluated for the the first time.
792     \li If applicable, QQmlParserStatus::componentComplete() is called on objects.
793     \endlist 
794     QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
795     only performs step 1.  QQmlComponent::completeCreate() must be called to 
796     complete steps 2 and 3.
797
798     This breaking point is sometimes useful when using attached properties to
799     communicate information to an instantiated component, as it allows their
800     initial values to be configured before property bindings take effect.
801 */
802 QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
803 {
804     Q_D(QQmlComponent);
805
806     Q_ASSERT(publicContext);
807     QQmlContextData *context = QQmlContextData::get(publicContext);
808
809     return d->beginCreate(context);
810 }
811
812 QObject *
813 QQmlComponentPrivate::beginCreate(QQmlContextData *context)
814 {
815     Q_Q(QQmlComponent);
816     if (!context) {
817         qWarning("QQmlComponent: Cannot create a component in a null context");
818         return 0;
819     }
820
821     if (!context->isValid()) {
822         qWarning("QQmlComponent: Cannot create a component in an invalid context");
823         return 0;
824     }
825
826     if (context->engine != engine) {
827         qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
828         return 0;
829     }
830
831     if (state.completePending) {
832         qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
833         return 0;
834     }
835
836     if (!q->isReady()) {
837         qWarning("QQmlComponent: Component is not ready");
838         return 0;
839     }
840
841     QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
842
843     if (enginePriv->inProgressCreations == 0) {
844         // only track root, since further ones might not be properly nested
845         profiler = new QQmlObjectCreatingProfiler();
846     }
847
848     enginePriv->inProgressCreations++;
849     state.errors.clear();
850     state.completePending = true;
851
852     enginePriv->referenceScarceResources();
853     state.vme.init(context, cc, start, creationContext);
854     QObject *rv = state.vme.execute(&state.errors);
855     enginePriv->dereferenceScarceResources();
856
857     if (rv) {
858         QQmlData *ddata = QQmlData::get(rv);
859         Q_ASSERT(ddata);
860         //top level objects should never get JS ownership.
861         //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
862         ddata->indestructible = true;
863         ddata->explicitIndestructibleSet = true;
864         ddata->rootObjectInCreation = false;
865     }
866
867     if (enginePriv->isDebugging && rv) {
868         if (!context->isInternal)
869             context->asQQmlContextPrivate()->instances.append(rv);
870         QQmlEngineDebugService::instance()->objectCreated(engine, rv);
871
872         if (profiler && profiler->enabled) {
873             profiler->setTypeName(buildTypeNameForDebug(rv->metaObject()));
874             QQmlData *data = QQmlData::get(rv);
875             Q_ASSERT(data);
876             profiler->setLocation(cc->url, data->lineNumber, data->columnNumber);
877         }
878     }
879
880     return rv;
881 }
882
883 void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
884                                                  QObject *object, ConstructionState *state)
885 {
886     enginePriv->inProgressCreations++;
887     state->errors.clear();
888     state->completePending = true;
889
890     state->vme.initDeferred(object);
891     state->vme.execute(&state->errors);
892 }
893
894 void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
895 {
896     if (state->completePending) {
897         state->vme.complete();
898
899         state->completePending = false;
900
901         enginePriv->inProgressCreations--;
902
903         if (0 == enginePriv->inProgressCreations) {
904             while (enginePriv->erroredBindings) {
905                 enginePriv->warning(enginePriv->erroredBindings);
906                 enginePriv->erroredBindings->removeError();
907             }
908         }
909     }
910 }
911
912 /*!
913     This method provides more advanced control over component instance creation.
914     In general, programmers should use QQmlComponent::create() to create a 
915     component.
916
917     Complete a component creation begin with QQmlComponent::beginCreate().
918 */
919 void QQmlComponent::completeCreate()
920 {
921     Q_D(QQmlComponent);
922
923     d->completeCreate();
924 }
925
926 void QQmlComponentPrivate::completeCreate()
927 {
928     if (state.completePending) {
929         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
930         complete(ep, &state);
931
932         delete profiler;
933         profiler = 0;
934     }
935 }
936
937 QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
938 : QObject(parent), prev(0), next(0)
939 {
940 }
941
942 QQmlComponentAttached::~QQmlComponentAttached()
943 {
944     if (prev) *prev = next;
945     if (next) next->prev = prev;
946     prev = 0;
947     next = 0;
948 }
949
950 /*!
951     \internal
952 */
953 QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
954 {
955     QQmlComponentAttached *a = new QQmlComponentAttached(obj);
956
957     QQmlEngine *engine = qmlEngine(obj);
958     if (!engine)
959         return a;
960
961     if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
962         QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
963         a->add(&p->activeVME->componentAttached);
964     } else {
965         QQmlData *d = QQmlData::get(obj);
966         Q_ASSERT(d);
967         Q_ASSERT(d->context);
968         a->add(&d->context->componentAttached);
969     }
970
971     return a;
972 }
973
974 /*!
975     Create an object instance from this component using the provided
976     \a incubator.  \a context specifies the context within which to create the object
977     instance.
978
979     If \a context is 0 (the default), it will create the instance in the
980     engine's \l {QQmlEngine::rootContext()}{root context}.
981
982     \a forContext specifies a context that this object creation depends upon.
983     If the \a forContext is being created asynchronously, and the
984     \l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
985     this object will also be created asynchronously.  If \a forContext is 0
986     (the default), the \a context will be used for this decision.
987
988     The created object and its creation status are available via the
989     \a incubator.
990
991     \sa QQmlIncubator
992 */
993
994 void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
995                                    QQmlContext *forContext)
996 {
997     Q_D(QQmlComponent);
998
999     if (!context) 
1000         context = d->engine->rootContext();
1001
1002     QQmlContextData *contextData = QQmlContextData::get(context);
1003     QQmlContextData *forContextData = contextData;
1004     if (forContext) forContextData = QQmlContextData::get(forContext);
1005
1006     if (!contextData->isValid()) {
1007         qWarning("QQmlComponent: Cannot create a component in an invalid context");
1008         return;
1009     }
1010
1011     if (contextData->engine != d->engine) {
1012         qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
1013         return;
1014     }
1015
1016     if (!isReady()) {
1017         qWarning("QQmlComponent: Component is not ready");
1018         return;
1019     }
1020
1021     incubator.clear();
1022     QQmlIncubatorPrivate *p = incubator.d;
1023
1024     QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
1025
1026     p->compiledData = d->cc;
1027     p->compiledData->addref();
1028     p->vme.init(contextData, d->cc, d->start, d->creationContext);
1029
1030     enginePriv->incubate(incubator, forContextData);
1031 }
1032
1033 class QV8IncubatorResource : public QV8ObjectResource,
1034                              public QQmlIncubator
1035 {
1036 V8_RESOURCE_TYPE(IncubatorType)
1037 public:
1038     QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
1039
1040     static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>, 
1041                                                      const v8::AccessorInfo& info);
1042     static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>, 
1043                                               const v8::AccessorInfo& info);
1044     static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>, 
1045                                               const v8::AccessorInfo& info);
1046     static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>, 
1047                                                        const v8::AccessorInfo& info);
1048     static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
1049
1050     static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, 
1051                                     const v8::AccessorInfo& info);
1052
1053     void dispose();
1054
1055     v8::Persistent<v8::Object> me;
1056     QQmlGuard<QObject> parent;
1057     v8::Persistent<v8::Value> valuemap;
1058     v8::Persistent<v8::Object> qmlGlobal;
1059 protected:
1060     virtual void statusChanged(Status);
1061     virtual void setInitialState(QObject *);
1062 };
1063
1064 static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
1065 {
1066     if (parent) {
1067         me->setParent(parent);
1068         typedef QQmlPrivate::AutoParentFunction APF;
1069         QList<APF> functions = QQmlMetaType::parentFunctions();
1070
1071         bool needParent = false;
1072         for (int ii = 0; ii < functions.count(); ++ii) {
1073             QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
1074             if (res == QQmlPrivate::Parented) {
1075                 needParent = false;
1076                 break;
1077             } else if (res == QQmlPrivate::IncompatibleParent) {
1078                 needParent = true;
1079             }
1080         }
1081         if (needParent) 
1082             qWarning("QQmlComponent: Created graphical object was not "
1083                      "placed in the graphics scene.");
1084     }
1085 }
1086
1087 /*!
1088     \qmlmethod object Component::createObject(Item parent, object properties)
1089
1090     Creates and returns an object instance of this component that will have
1091     the given \a parent and \a properties. The \a properties argument is optional.
1092     Returns null if object creation fails.
1093
1094     The object will be created in the same context as the one in which the component
1095     was created. This function will always return null when called on components
1096     which were not created in QML.
1097
1098     If you wish to create an object without setting a parent, specify \c null for
1099     the \a parent value. Note that if the returned object is to be displayed, you 
1100     must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent} 
1101     property, or else the object will not be visible.
1102
1103     If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
1104     it is not destroyed by the garbage collector.  This is true regardless of whether \l{Item::parent} is set afterwards,
1105     since setting the Item parent does not change object ownership; only the graphical parent is changed.
1106
1107     As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
1108     map of initial property values for the created object. These values are applied before object
1109     creation is finalized. (This is more efficient than setting property values after object creation,
1110     particularly where large sets of property values are defined, and also allows property bindings
1111     to be set up before the object is created.)
1112
1113     The \a properties argument is specified as a map of property-value items. For example, the code
1114     below creates an object with initial \c x and \c y values of 100 and 200, respectively:
1115
1116     \js
1117         var component = Qt.createComponent("Button.qml");
1118         if (component.status == Component.Ready)
1119             component.createObject(parent, {"x": 100, "y": 100});
1120     \endjs
1121
1122     Dynamically created instances can be deleted with the \c destroy() method.
1123     See \l {Dynamic QML Object Creation from JavaScript} for more information.
1124
1125     \sa incubateObject()
1126 */
1127
1128 /*!
1129     \internal
1130 */
1131 void QQmlComponent::createObject(QQmlV8Function *args)
1132 {
1133     Q_D(QQmlComponent);
1134     Q_ASSERT(d->engine);
1135     Q_ASSERT(args);
1136
1137     QObject *parent = 0;
1138     v8::Local<v8::Object> valuemap;
1139
1140     if (args->Length() >= 1) 
1141         parent = args->engine()->toQObject((*args)[0]);
1142
1143     if (args->Length() >= 2) {
1144         v8::Local<v8::Value> v = (*args)[1];
1145         if (!v->IsObject() || v->IsArray()) {
1146             qmlInfo(this) << tr("createObject: value is not an object");
1147             args->returnValue(v8::Null());
1148             return;
1149         }
1150         valuemap = v8::Local<v8::Object>::Cast(v);
1151     }
1152
1153     QV8Engine *v8engine = args->engine();
1154
1155     QQmlContext *ctxt = creationContext();
1156     if (!ctxt) ctxt = d->engine->rootContext();
1157
1158     QObject *rv = beginCreate(ctxt);
1159
1160     if (!rv) {
1161         args->returnValue(v8::Null());
1162         return;
1163     }
1164
1165     QQmlComponent_setQmlParent(rv, parent);
1166
1167     v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
1168     Q_ASSERT(ov->IsObject());
1169     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
1170
1171     if (!valuemap.IsEmpty()) {
1172         QQmlComponentExtension *e = componentExtension(v8engine);
1173         // Try catch isn't needed as the function itself is loaded with try/catch
1174         v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
1175         v8::Handle<v8::Value> args[] = { object, valuemap };
1176         v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
1177     }
1178
1179     d->completeCreate();
1180
1181     Q_ASSERT(QQmlData::get(rv));
1182     QQmlData::get(rv)->explicitIndestructibleSet = false;
1183     QQmlData::get(rv)->indestructible = false;
1184
1185     if (!rv)
1186         args->returnValue(v8::Null());
1187     else
1188         args->returnValue(object);
1189 }
1190
1191 /*!
1192     \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
1193
1194     Creates an incubator for instance of this component.  Incubators allow new component 
1195     instances to be instantiated asynchronously and not cause freezes in the UI.
1196
1197     The \a parent argument specifies the parent the created instance will have.  Omitting the 
1198     parameter or passing null will create anobject with no parent.  In this case, a reference
1199     to the created object must be maintained by the application of the object will eventually
1200     be garbage collected.
1201
1202     The \a properties argument is specified as a map of property-value items which will be
1203     set on the created object during its construction.  \a mode may be Qt.Synchronous or 
1204     Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously. 
1205     The default is asynchronously.  In some circumstances, even if Qt.Synchronous is specified,
1206     the incubator may create the object asynchronously.  This happens if the component calling
1207     incubateObject() is itself being created asynchronously.
1208
1209     All three arguments are optional.
1210
1211     If successful, the method returns an incubator, otherwise null.  The incubator has the following
1212     properties:
1213
1214     \list
1215     \li status The status of the incubator.  Valid values are Component.Ready, Component.Loading and
1216        Component.Error.
1217     \li object The created object instance.  Will only be available once the incubator is in the
1218        Ready status.
1219     \li onStatusChanged Specifies a callback function to be invoked when the status changes.  The
1220        status is passed as a parameter to the callback.
1221     \li forceCompletion() Call to complete incubation synchronously.
1222     \endlist
1223
1224     The following example demonstrates how to use an incubator:
1225
1226     \js
1227         var component = Qt.createComponent("Button.qml");
1228
1229         var incubator = component.incubateObject(parent, { x: 10, y: 10 });
1230         if (incubator.status != Component.Ready) {
1231             incubator.onStatusChanged = function(status) {
1232                 if (status == Component.Ready) {
1233                     print ("Object", incubator.object, "is now ready!");
1234                 }
1235             }
1236         } else {
1237             print ("Object", incubator.object, "is ready immediately!");
1238         }
1239     \endjs
1240
1241     Dynamically created instances can be deleted with the \c destroy() method.
1242     See \l {Dynamic QML Object Creation from JavaScript} for more information.
1243
1244     \sa createObject()
1245 */
1246
1247 /*!
1248     \internal
1249 */
1250 void QQmlComponent::incubateObject(QQmlV8Function *args)
1251 {
1252     Q_D(QQmlComponent);
1253     Q_ASSERT(d->engine);
1254     Q_UNUSED(d);
1255     Q_ASSERT(args);
1256
1257     QObject *parent = 0;
1258     v8::Local<v8::Object> valuemap;
1259     QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
1260
1261     if (args->Length() >= 1) 
1262         parent = args->engine()->toQObject((*args)[0]);
1263
1264     if (args->Length() >= 2) {
1265         v8::Local<v8::Value> v = (*args)[1];
1266         if (v->IsNull()) {
1267         } else if (!v->IsObject() || v->IsArray()) {
1268             qmlInfo(this) << tr("createObject: value is not an object");
1269             args->returnValue(v8::Null());
1270             return;
1271         } else {
1272             valuemap = v8::Local<v8::Object>::Cast(v);
1273         }
1274     }
1275
1276     if (args->Length() >= 3) {
1277         quint32 v = (*args)[2]->Uint32Value();
1278         if (v == 0)
1279             mode = QQmlIncubator::Asynchronous;
1280         else if (v == 1)
1281             mode = QQmlIncubator::AsynchronousIfNested;
1282     }
1283
1284     QQmlComponentExtension *e = componentExtension(args->engine());
1285     
1286     QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
1287     v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
1288     o->SetExternalResource(r);
1289
1290     if (!valuemap.IsEmpty()) {
1291         r->valuemap = qPersistentNew(valuemap);
1292         r->qmlGlobal = qPersistentNew(args->qmlGlobal());
1293     }
1294     r->parent = parent;
1295     r->me = qPersistentNew(o);
1296
1297     create(*r, creationContext());
1298
1299     if (r->status() == QQmlIncubator::Null) {
1300         r->dispose();
1301         args->returnValue(v8::Null());
1302     } else {
1303         args->returnValue(o);
1304     }
1305 }
1306
1307 // XXX used by QSGLoader
1308 void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
1309 {
1310     QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1311     QV8Engine *v8engine = ep->v8engine();
1312
1313     v8::HandleScope handle_scope;
1314     v8::Context::Scope scope(v8engine->context());
1315     v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
1316     Q_ASSERT(ov->IsObject());
1317     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
1318
1319     if (!valuemap.IsEmpty()) {
1320         QQmlComponentExtension *e = componentExtension(v8engine);
1321         // Try catch isn't needed as the function itself is loaded with try/catch
1322         v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
1323         v8::Handle<v8::Value> args[] = { object, valuemap };
1324         v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
1325     }
1326 }
1327
1328
1329 QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
1330 {
1331     v8::HandleScope handle_scope;
1332     v8::Context::Scope scope(engine->context());
1333
1334     forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
1335
1336     {
1337     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
1338     ft->InstanceTemplate()->SetHasExternalResource(true);
1339     ft->InstanceTemplate()->SetInternalFieldCount(1);
1340     ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"), 
1341                                         QV8IncubatorResource::StatusChangedGetter, 
1342                                         QV8IncubatorResource::StatusChangedSetter);
1343     ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
1344                                         QV8IncubatorResource::StatusGetter);
1345     ft->InstanceTemplate()->SetAccessor(v8::String::New("object"), 
1346                                         QV8IncubatorResource::ObjectGetter); 
1347     ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"), 
1348                                         QV8IncubatorResource::ForceCompletionGetter); 
1349     incubationConstructor = qPersistentNew(ft->GetFunction());
1350     }
1351
1352     {
1353 #define INITIALPROPERTIES_SOURCE \
1354         "(function(object, values) {"\
1355             "try {"\
1356                 "for(var property in values) {" \
1357                     "try {"\
1358                         "var properties = property.split(\".\");"\
1359                         "var o = object;"\
1360                         "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
1361                             "o = o[properties[ii]];"\
1362                         "}"\
1363                         "o[properties[properties.length - 1]] = values[property];"\
1364                     "} catch(e) {}"\
1365                 "}"\
1366             "} catch(e) {}"\
1367         "})"
1368     initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
1369 #undef INITIALPROPERTIES_SOURCE
1370     }
1371 }
1372
1373 v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>, 
1374                                                           const v8::AccessorInfo& info)
1375 {
1376     QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1377     return r->engine->newQObject(r->object());
1378 }
1379
1380 v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>, 
1381                                                                   const v8::AccessorInfo& info)
1382 {
1383     QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1384     return componentExtension(r->engine)->forceCompletion;
1385 }
1386
1387 v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args) 
1388 {
1389     QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
1390     if (!r)
1391         V8THROW_TYPE("Not an incubator object");
1392
1393     r->forceCompletion();
1394
1395     return v8::Undefined();
1396 }
1397
1398 v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>, 
1399                                                          const v8::AccessorInfo& info)
1400 {
1401     QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1402     return v8::Integer::NewFromUnsigned(r->status());
1403 }
1404
1405 v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>, 
1406                                                                  const v8::AccessorInfo& info)
1407 {
1408     return info.This()->GetInternalField(0);
1409 }
1410
1411 void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, 
1412                                                 const v8::AccessorInfo& info)
1413 {
1414     info.This()->SetInternalField(0, value);
1415 }
1416
1417 QQmlComponentExtension::~QQmlComponentExtension()
1418 {
1419     qPersistentDispose(incubationConstructor);
1420     qPersistentDispose(initialProperties);
1421     qPersistentDispose(forceCompletion);
1422 }
1423
1424 QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
1425 : QV8ObjectResource(engine), QQmlIncubator(m)
1426 {
1427 }
1428
1429 void QV8IncubatorResource::setInitialState(QObject *o)
1430 {
1431     QQmlComponent_setQmlParent(o, parent);
1432
1433     if (!valuemap.IsEmpty()) {
1434         QQmlComponentExtension *e = componentExtension(engine);
1435
1436         v8::HandleScope handle_scope;
1437         v8::Context::Scope scope(engine->context());
1438
1439         v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
1440         v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
1441         v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
1442
1443         qPersistentDispose(valuemap);
1444         qPersistentDispose(qmlGlobal);
1445     }
1446 }
1447     
1448 void QV8IncubatorResource::dispose()
1449 {
1450     qPersistentDispose(valuemap);
1451     qPersistentDispose(qmlGlobal);
1452     // No further status changes are forthcoming, so we no long need a self reference
1453     qPersistentDispose(me);
1454 }
1455
1456 void QV8IncubatorResource::statusChanged(Status s)
1457 {
1458     if (s == Ready) {
1459         Q_ASSERT(QQmlData::get(object()));
1460         QQmlData::get(object())->explicitIndestructibleSet = false;
1461         QQmlData::get(object())->indestructible = false;
1462     }
1463
1464     if (!me.IsEmpty()) { // Will be false in synchronous mode
1465         v8::HandleScope scope;
1466         v8::Local<v8::Value> callback = me->GetInternalField(0);
1467
1468         if (!callback.IsEmpty() && !callback->IsUndefined()) {
1469
1470             if (callback->IsFunction()) {
1471                 v8::Context::Scope context_scope(engine->context());
1472                 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
1473                 v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
1474                 v8::TryCatch tc;
1475                 f->Call(me, 1, args);
1476                 if (tc.HasCaught()) {
1477                     QQmlError error;
1478                     QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
1479                     QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
1480                 }
1481             }
1482         }
1483     }
1484
1485     if (s == Ready || s == Error) 
1486         dispose();
1487 }
1488
1489 QT_END_NAMESPACE