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