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