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