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