qqmlcomponent.cpp 45.1 KB
Newer Older
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 9
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
10 11 12 13 14 15
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** 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 20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
21 22 23 24 25 26 27 28 29 30 31
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
32 33 34 35 36
**
**
**
**
**
37
**
38 39 40 41
** $QT_END_LICENSE$
**
****************************************************************************/

42 43 44 45 46 47 48 49 50 51 52
#include "qqmlcomponent.h"
#include "qqmlcomponent_p.h"
#include "qqmlcomponentattached_p.h"

#include "qqmlcompiler_p.h"
#include "qqmlcontext_p.h"
#include "qqmlengine_p.h"
#include "qqmlvme_p.h"
#include "qqml.h"
#include "qqmlengine.h"
#include "qqmlbinding_p.h"
53
#include "qqmlglobal_p.h"
54 55 56 57 58
#include "qqmlscript_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlenginedebugservice_p.h>
#include "qqmlincubator.h"
#include "qqmlincubator_p.h"
59
#include <private/qqmljavascriptexpression_p.h>
60

61 62
#include <private/qv8engine_p.h>
#include <private/qv8include_p.h>
63

64 65 66
#include <QStack>
#include <QStringList>
#include <QtCore/qdebug.h>
67
#include <qqmlinfo.h>
68 69 70

QT_BEGIN_NAMESPACE

71
class QQmlComponentExtension : public QV8Engine::Deletable
72 73
{
public:
74 75
    QQmlComponentExtension(QV8Engine *);
    virtual ~QQmlComponentExtension();
76 77 78

    v8::Persistent<v8::Function> incubationConstructor;
    v8::Persistent<v8::Script> initialProperties;
79
    v8::Persistent<v8::Function> forceCompletion;
80
};
81
V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
82 83 84 85 86 87 88 89 90 91 92 93

/*
    Try to do what's necessary for a reasonable display of the type
    name, but no more (just enough for the client to do more extensive cleanup).

    Should only be called when debugging is enabled.
*/
static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
{
    static const QString qmlMarker(QLatin1String("_QML"));
    static const QChar underscore(QLatin1Char('_'));
    static const QChar asterisk(QLatin1Char('*'));
94
    QQmlType *type = QQmlMetaType::qmlType(metaObject);
95
    QString typeName = type ? type->qmlTypeName() : QString::fromUtf8(metaObject->className());
96 97 98 99 100 101
    if (!type) {
        //### optimize further?
        int marker = typeName.indexOf(qmlMarker);
        if (marker != -1 && marker < typeName.count() - 1) {
            if (typeName[marker + 1] == underscore) {
                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 109
            }
        }
    }
    return typeName;
}
110 111

/*!
112
    \class QQmlComponent
113
    \since 4.7
114
    \brief The QQmlComponent class encapsulates a QML component definition.
115 116 117 118 119
    \mainclass

    Components are reusable, encapsulated QML elements with well-defined interfaces.
    They are often defined in \l {qdeclarativedocuments.html}{Component Files}.

120
    A QQmlComponent instance can be created from a QML file.
121 122 123
    For example, if there is a \c main.qml file like this:

    \qml
124
    import QtQuick 2.0
125 126 127 128 129 130 131 132 133 134 135 136

    Item {
        width: 200
        height: 200
    }
    \endqml

    The following code loads this QML file as a component, creates an instance of
    this component using create(), and then queries the \l Item's \l {Item::}{width}
    value:

    \code
137 138
    QQmlEngine *engine = new QQmlEngine;
    QQmlComponent component(engine, QUrl::fromLocalFile("main.qml"));
139 140

    QObject *myObject = component.create();
141
    QQuickItem *item = qobject_cast<QQuickItem*>(myObject);
142 143 144 145 146 147
    int width = item->width();  // width = 200
    \endcode


    \section2 Network Components

148 149 150 151 152
    If the URL passed to QQmlComponent is a network resource, or if the QML document references a
    network resource, the QQmlComponent has to fetch the network data before it is able to create
    objects.  In this case, the QQmlComponent will have a \l {QQmlComponent::Loading}{Loading}
    \l {QQmlComponent::status()}{status}.  An application will have to wait until the component
    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 156 157
    the QQmlComponent, it tests whether the component is loading.  If it is, it connects to the
    QQmlComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
    directly. Note that QQmlComponent::isLoading() may be false for a network component if the
158 159 160 161 162 163
    component has been cached and is ready immediately.

    \code
    MyApplication::MyApplication()
    {
        // ...
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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
                             this, SLOT(continueLoading()));
        else
            continueLoading();
    }

    void MyApplication::continueLoading()
    {
        if (component->isError()) {
            qWarning() << component->errors();
        } else {
            QObject *myObject = component->create();
        }
    }
    \endcode

    \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
*/

/*!
186
    \qmlclass Component QQmlComponent
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    \ingroup qml-utility-elements
    \since 4.7
    \brief The Component element encapsulates a QML component definition.

    Components are reusable, encapsulated QML elements with well-defined interfaces.

    Components are often defined by \l {qdeclarativedocuments.html}{component files} -
    that is, \c .qml files. The \e Component element essentially allows QML components
    to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
    This may be useful for reusing a small component within a QML file, or for defining
    a component that logically belongs with other QML components within a file.

    For example, here is a component that is used by multiple \l Loader objects.
    It contains a single item, a \l Rectangle:

202
    \snippet doc/src/snippets/qml/component.qml 0
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

    Notice that while a \l Rectangle by itself would be automatically 
    rendered and displayed, this is not the case for the above rectangle
    because it is defined inside a \c Component. The component encapsulates the
    QML elements within, as if they were defined in a separate QML
    file, and is not loaded until requested (in this case, by the
    two \l Loader objects).

    Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
    A QML document has a single top-level item that defines the behaviors and
    properties of that component, and cannot define properties or behaviors outside
    of that top-level item. In the same way, a \c Component definition contains a single
    top level item (which in the above example is a \l Rectangle) and cannot define any
    data outside of this item, with the exception of an \e id (which in the above example
    is \e redSquare).

    The \c Component element is commonly used to provide graphical components
    for views. For example, the ListView::delegate property requires a \c Component
    to specify how each list item is to be displayed.

    \c Component objects can also be created dynamically using
    \l{QML:Qt::createComponent()}{Qt.createComponent()}.
*/

/*!
    \qmlattachedsignal Component::onCompleted()

    Emitted after component "startup" has completed.  This can be used to
    execute script code at startup, once the full QML environment has been
    established.

    The \c {Component::onCompleted} attached property can be applied to
    any element.  The order of running the \c onCompleted scripts is
    undefined.

    \qml
    Rectangle {
        Component.onCompleted: console.log("Completed Running!")
        Rectangle {
            Component.onCompleted: console.log("Nested Completed Running!")
        }
    }
    \endqml
*/

/*!
    \qmlattachedsignal Component::onDestruction()

    Emitted as the component begins destruction.  This can be used to undo
    work done in the onCompleted signal, or other imperative code in your
    application.

    The \c {Component::onDestruction} attached property can be applied to
    any element.  However, it applies to the destruction of the component as
    a whole, and not the destruction of the specific object.  The order of
    running the \c onDestruction scripts is undefined.

    \qml
    Rectangle {
        Component.onDestruction: console.log("Destruction Beginning!")
        Rectangle {
            Component.onDestruction: console.log("Nested Destruction Beginning!")
        }
    }
    \endqml

269
    \sa QtQml
270 271 272
*/

/*!
273
    \enum QQmlComponent::Status
274
    
275
    Specifies the loading status of the QQmlComponent.
276

277 278 279 280
    \value Null This QQmlComponent has no data.  Call loadUrl() or setData() to add QML content.
    \value Ready This QQmlComponent is ready and create() may be called.
    \value Loading This QQmlComponent is loading network data.
    \value Error An error has occurred.  Call errors() to retrieve a list of \{QQmlError}{errors}.
281 282
*/

283 284 285 286 287 288 289 290 291 292
/*!
    \enum QQmlComponent::CompilationMode

    Specifies whether the QQmlComponent should load the component immediately, or asynchonously.

    \value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
    This is not always possible, e.g. remote URLs will always load asynchronously.
    \value Asynchronous Load/compile the component in a background thread.
*/

293
void QQmlComponentPrivate::typeDataReady(QQmlTypeData *)
294
{
295
    Q_Q(QQmlComponent);
296 297 298 299 300

    Q_ASSERT(typeData);

    fromTypeData(typeData);
    typeData = 0;
301
    progress = 1.0;
302 303

    emit q->statusChanged(q->status());
304
    emit q->progressChanged(progress);
305 306
}

307
void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p)
308
{
309
    Q_Q(QQmlComponent);
310 311 312 313 314 315

    progress = p;

    emit q->progressChanged(p);
}

316
void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data)
317 318
{
    url = data->finalUrl();
319
    QQmlCompiledData *c = data->compiledData();
320 321 322 323 324 325 326 327 328 329 330

    if (!c) {
        Q_ASSERT(data->isError());
        state.errors = data->errors();
    } else {
        cc = c;
    }

    data->release();
}

331
void QQmlComponentPrivate::clear()
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
{
    if (typeData) {
        typeData->unregisterCallback(this);
        typeData->release();
        typeData = 0;
    }
        
    if (cc) { 
        cc->release();
        cc = 0;
    }
}

/*!
    \internal
*/
348 349
QQmlComponent::QQmlComponent(QObject *parent)
    : QObject(*(new QQmlComponentPrivate), parent)
350 351 352 353
{
}

/*!
354
    Destruct the QQmlComponent.
355
*/
356
QQmlComponent::~QQmlComponent()
357
{
358
    Q_D(QQmlComponent);
359 360

    if (d->state.completePending) {
361
        qWarning("QQmlComponent: Component destroyed while completion pending");
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
        d->completeCreate();
    }

    if (d->typeData) {
        d->typeData->unregisterCallback(d);
        d->typeData->release();
    }
    if (d->cc)
        d->cc->release();
}

/*!
    \qmlproperty enumeration Component::status
    This property holds the status of component loading.  It can be one of:
    \list
377 378 379 380
    \li Component.Null - no data is available for the component
    \li Component.Ready - the component has been loaded, and can be used to create instances.
    \li Component.Loading - the component is currently being loaded
    \li Component.Error - an error occurred while loading the component.
381 382 383 384 385
               Calling errorString() will provide a human-readable description of any errors.
    \endlist
 */

/*!
386 387
    \property QQmlComponent::status
    The component's current \l{QQmlComponent::Status} {status}.
388
 */
389
QQmlComponent::Status QQmlComponent::status() const
390
{
391
    Q_D(const QQmlComponent);
392 393 394 395 396 397 398 399 400 401 402 403

    if (d->typeData)
        return Loading;
    else if (!d->state.errors.isEmpty())
        return Error;
    else if (d->engine && d->cc)
        return Ready;
    else
        return Null;
}

/*!
404
    Returns true if status() == QQmlComponent::Null.
405
*/
406
bool QQmlComponent::isNull() const
407 408 409 410 411
{
    return status() == Null;
}

/*!
412
    Returns true if status() == QQmlComponent::Ready.
413
*/
414
bool QQmlComponent::isReady() const
415 416 417 418 419
{
    return status() == Ready;
}

/*!
420
    Returns true if status() == QQmlComponent::Error.
421
*/
422
bool QQmlComponent::isError() const
423 424 425 426 427
{
    return status() == Error;
}

/*!
428
    Returns true if status() == QQmlComponent::Loading.
429
*/
430
bool QQmlComponent::isLoading() const
431 432 433 434 435 436 437 438 439 440 441
{
    return status() == Loading;
}

/*!
    \qmlproperty real Component::progress
    The progress of loading the component, from 0.0 (nothing loaded)
    to 1.0 (finished).
*/

/*!
442
    \property QQmlComponent::progress
443 444 445
    The progress of loading the component, from 0.0 (nothing loaded)
    to 1.0 (finished).
*/
446
qreal QQmlComponent::progress() const
447
{
448
    Q_D(const QQmlComponent);
449 450 451 452
    return d->progress;
}

/*!
453
    \fn void QQmlComponent::progressChanged(qreal progress)
454 455 456 457 458 459

    Emitted whenever the component's loading progress changes.  \a progress will be the
    current progress between 0.0 (nothing loaded) and 1.0 (finished).
*/

/*!
460
    \fn void QQmlComponent::statusChanged(QQmlComponent::Status status)
461 462 463 464 465 466

    Emitted whenever the component's status changes.  \a status will be the
    new status.
*/

/*!
467
    Create a QQmlComponent with no data and give it the specified
468 469
    \a engine and \a parent. Set the data with setData().
*/
470 471
QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent)
    : QObject(*(new QQmlComponentPrivate), parent)
472
{
473
    Q_D(QQmlComponent);
474 475 476 477
    d->engine = engine;
}

/*!
478
    Create a QQmlComponent from the given \a url and give it the
479 480 481 482 483 484 485
    specified \a parent and \a engine.

    Ensure that the URL provided is full and correct, in particular, use
    \l QUrl::fromLocalFile() when loading a file from the local filesystem.

    \sa loadUrl()
*/
486 487
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent)
: QObject(*(new QQmlComponentPrivate), parent)
488
{
489
    Q_D(QQmlComponent);
490
    d->engine = engine;
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
    d->loadUrl(url);
}

/*!
    Create a QQmlComponent from the given \a url and give it the
    specified \a parent and \a engine.  If \a mode is \l Asynchronous,
    the component will be loaded and compiled asynchronously.

    Ensure that the URL provided is full and correct, in particular, use
    \l QUrl::fromLocalFile() when loading a file from the local filesystem.

    \sa loadUrl()
*/QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode, QObject *parent)
: QObject(*(new QQmlComponentPrivate), parent)
{
    Q_D(QQmlComponent);
    d->engine = engine;
    d->loadUrl(url, mode);
509 510 511
}

/*!
512
    Create a QQmlComponent from the given \a fileName and give it the specified 
513 514 515 516
    \a parent and \a engine.

    \sa loadUrl()
*/
517
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, 
518
                           QObject *parent)
519
: QObject(*(new QQmlComponentPrivate), parent)
520
{
521
    Q_D(QQmlComponent);
522
    d->engine = engine;
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
    d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
}

/*!
    Create a QQmlComponent from the given \a fileName and give it the specified
    \a parent and \a engine.  If \a mode is \l Asynchronous,
    the component will be loaded and compiled asynchronously.

    \sa loadUrl()
*/
QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName,
                           CompilationMode mode, QObject *parent)
: QObject(*(new QQmlComponentPrivate), parent)
{
    Q_D(QQmlComponent);
    d->engine = engine;
    d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode);
540 541 542 543 544
}

/*!
    \internal
*/
545 546
QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent)
    : QObject(*(new QQmlComponentPrivate), parent)
547
{
548
    Q_D(QQmlComponent);
549 550 551 552 553 554 555 556 557
    d->engine = engine;
    d->cc = cc;
    cc->addref();
    d->start = start;
    d->url = cc->url;
    d->progress = 1.0;
}

/*!
558
    Sets the QQmlComponent to use the given QML \a data.  If \a url
559 560 561
    is provided, it is used to set the component name and to provide
    a base path for items resolved by this component.
*/
562
void QQmlComponent::setData(const QByteArray &data, const QUrl &url)
563
{
564
    Q_D(QQmlComponent);
565 566 567 568 569

    d->clear();

    d->url = url;

570
    QQmlTypeData *typeData = QQmlEnginePrivate::get(d->engine)->typeLoader.get(data, url);
571 572 573 574 575 576 577 578 579 580 581 582 583 584
    
    if (typeData->isCompleteOrError()) {
        d->fromTypeData(typeData);
    } else {
        d->typeData = typeData;
        d->typeData->registerCallback(d);
    }

    d->progress = 1.0;
    emit statusChanged(status());
    emit progressChanged(d->progress);
}

/*!
585
Returns the QQmlContext the component was created in.  This is only
586 587
valid for components created directly from QML.
*/
588
QQmlContext *QQmlComponent::creationContext() const
589
{
590
    Q_D(const QQmlComponent);
591
    if(d->creationContext)
592
        return d->creationContext->asQQmlContext();
593 594 595 596 597

    return qmlContext(this);
}

/*!
598
    Load the QQmlComponent from the provided \a url.
599 600 601 602

    Ensure that the URL provided is full and correct, in particular, use
    \l QUrl::fromLocalFile() when loading a file from the local filesystem.
*/
603
void QQmlComponent::loadUrl(const QUrl &url)
604
{
605
    Q_D(QQmlComponent);
606 607
    d->loadUrl(url);
}
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
/*!
    Load the QQmlComponent from the provided \a url.
    If \a mode is \l Asynchronous, the component will be loaded and compiled asynchronously.

    Ensure that the URL provided is full and correct, in particular, use
    \l QUrl::fromLocalFile() when loading a file from the local filesystem.
*/
void QQmlComponent::loadUrl(const QUrl &url, QQmlComponent::CompilationMode mode)
{
    Q_D(QQmlComponent);
    d->loadUrl(url, mode);
}

void QQmlComponentPrivate::loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode)
{
    Q_Q(QQmlComponent);
    clear();
626

627 628 629
    if ((newUrl.isRelative() && !newUrl.isEmpty())
    || newUrl.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
        url = engine->baseUrl().resolved(newUrl);
630
    else
631
        url = newUrl;
632

633
    if (newUrl.isEmpty()) {
634
        QQmlError error;
635 636
        error.setDescription(q->tr("Invalid empty URL"));
        state.errors << error;
637 638 639
        return;
    }

640 641 642 643 644 645 646 647 648 649
    if (progress != 0.0) {
        progress = 0.0;
        emit q->progressChanged(progress);
    }

    QQmlDataLoader::Mode loaderMode = (mode == QQmlComponent::Asynchronous)
            ? QQmlDataLoader::Asynchronous
            : QQmlDataLoader::PreferSynchronous;

    QQmlTypeData *data = QQmlEnginePrivate::get(engine)->typeLoader.get(url, loaderMode);
650 651

    if (data->isCompleteOrError()) {
652 653
        fromTypeData(data);
        progress = 1.0;
654
    } else {
655 656 657
        typeData = data;
        typeData->registerCallback(this);
        progress = data->progress();
658 659
    }

660 661 662
    emit q->statusChanged(q->status());
    if (progress != 0.0)
        emit q->progressChanged(progress);
663 664 665 666 667 668
}

/*!
    Return the list of errors that occurred during the last compile or create
    operation.  An empty list is returned if isError() is not set.
*/
669
QList<QQmlError> QQmlComponent::errors() const
670
{
671
    Q_D(const QQmlComponent);
672 673 674
    if (isError())
        return d->state.errors;
    else
675
        return QList<QQmlError>();
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
}

/*!
    \qmlmethod string Component::errorString()

    Returns a human-readable description of any errors.

    The string includes the file, location, and description of each error.
    If multiple errors are present they are separated by a newline character.

    If no errors are present, an empty string is returned.
*/

/*!
    \internal
    errorString is only meant as a way to get the errors in script
*/
693
QString QQmlComponent::errorString() const
694
{
695
    Q_D(const QQmlComponent);
696 697 698
    QString ret;
    if(!isError())
        return ret;
699
    foreach(const QQmlError &e, d->state.errors) {
700 701 702 703 704 705 706 707 708 709 710 711 712
        ret += e.url().toString() + QLatin1Char(':') +
               QString::number(e.line()) + QLatin1Char(' ') +
               e.description() + QLatin1Char('\n');
    }
    return ret;
}

/*!
    \qmlproperty url Component::url
    The component URL.  This is the URL that was used to construct the component.
*/

/*!
713
    \property QQmlComponent::url
714 715 716
    The component URL.  This is the URL passed to either the constructor,
    or the loadUrl() or setData() methods.
*/
717
QUrl QQmlComponent::url() const
718
{
719
    Q_D(const QQmlComponent);
720 721 722 723 724 725
    return d->url;
}

/*!
    \internal
*/
726
QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
727 728 729 730 731 732 733 734 735 736
    : QObject(dd, parent)
{
}

/*!
    Create an object instance from this component.  Returns 0 if creation
    failed.  \a context specifies the context within which to create the object
    instance.  

    If \a context is 0 (the default), it will create the instance in the
737
    engine' s \l {QQmlEngine::rootContext()}{root context}.
738
*/
739
QObject *QQmlComponent::create(QQmlContext *context)
740
{
741
    Q_D(QQmlComponent);
742 743 744 745 746 747 748 749 750 751 752

    if (!context)
        context = d->engine->rootContext();

    QObject *rv = beginCreate(context);
    completeCreate();
    return rv;
}

/*!
    This method provides more advanced control over component instance creation.
753
    In general, programmers should use QQmlComponent::create() to create a 
754 755 756
    component.

    Create an object instance from this component.  Returns 0 if creation
757
    failed.  \a publicContext specifies the context within which to create the object
758 759
    instance.  

760
    When QQmlComponent constructs an instance, it occurs in three steps:
761
    \list 1
762 763 764
    \li The object hierarchy is created, and constant values are assigned.
    \li Property bindings are evaluated for the the first time.
    \li If applicable, QQmlParserStatus::componentComplete() is called on objects.
765
    \endlist 
766 767
    QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
    only performs step 1.  QQmlComponent::completeCreate() must be called to 
768 769 770 771 772 773
    complete steps 2 and 3.

    This breaking point is sometimes useful when using attached properties to
    communicate information to an instantiated component, as it allows their
    initial values to be configured before property bindings take effect.
*/
774
QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
775
{
776
    Q_D(QQmlComponent);
777 778

    Q_ASSERT(publicContext);
779
    QQmlContextData *context = QQmlContextData::get(publicContext);
780 781

    return d->beginCreate(context);
782 783 784
}

QObject *
785
QQmlComponentPrivate::beginCreate(QQmlContextData *context)
786
{
787
    Q_Q(QQmlComponent);
788
    if (!context) {
789
        qWarning("QQmlComponent: Cannot create a component in a null context");
790 791 792 793
        return 0;
    }

    if (!context->isValid()) {
794
        qWarning("QQmlComponent: Cannot create a component in an invalid context");
795 796 797 798
        return 0;
    }

    if (context->engine != engine) {
799
        qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
800 801 802 803
        return 0;
    }

    if (state.completePending) {
804
        qWarning("QQmlComponent: Cannot create new component instance before completing the previous");
805 806 807 808
        return 0;
    }

    if (!q->isReady()) {
809
        qWarning("QQmlComponent: Component is not ready");
810 811 812
        return 0;
    }

813
    QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine);
814

815 816
    if (enginePriv->inProgressCreations == 0) {
        // only track root, since further ones might not be properly nested
817
        profiler = new QQmlObjectCreatingProfiler();
818 819
    }

820 821 822
    enginePriv->inProgressCreations++;
    state.errors.clear();
    state.completePending = true;
823

824
    enginePriv->referenceScarceResources();
825
    state.vme.init(context, cc, start, creationContext);
826 827 828 829
    QObject *rv = state.vme.execute(&state.errors);
    enginePriv->dereferenceScarceResources();

    if (rv) {
830
        QQmlData *ddata = QQmlData::get(rv);
831
        Q_ASSERT(ddata);
832 833
        //top level objects should never get JS ownership.
        //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
834
        ddata->indestructible = true;
835
        ddata->explicitIndestructibleSet = true;
836 837 838
    }

    if (enginePriv->isDebugging && rv) {
839
        if (!context->isInternal)
840 841
            context->asQQmlContextPrivate()->instances.append(rv);
        QQmlEngineDebugService::instance()->objectCreated(engine, rv);
842 843 844

        if (profiler && profiler->enabled) {
            profiler->setTypeName(buildTypeNameForDebug(rv->metaObject()));
845
            QQmlData *data = QQmlData::get(rv);
846
            Q_ASSERT(data);
847
            profiler->setLocation(cc->url, data->lineNumber, data->columnNumber);
848
        }
849 850 851 852 853
    }

    return rv;
}

854
void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv,
855 856
                                                 QObject *object, ConstructionState *state)
{
857 858 859 860 861 862
    enginePriv->inProgressCreations++;
    state->errors.clear();
    state->completePending = true;

    state->vme.initDeferred(object);
    state->vme.execute(&state->errors);
863 864
}

865
void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionState *state)
866 867
{
    if (state->completePending) {
868
        state->vme.complete();
869 870 871 872

        state->completePending = false;

        enginePriv->inProgressCreations--;
873

874 875 876 877 878 879 880 881 882 883 884
        if (0 == enginePriv->inProgressCreations) {
            while (enginePriv->erroredBindings) {
                enginePriv->warning(enginePriv->erroredBindings->error);
                enginePriv->erroredBindings->removeError();
            }
        }
    }
}

/*!
    This method provides more advanced control over component instance creation.
885
    In general, programmers should use QQmlComponent::create() to create a 
886 887
    component.

888
    Complete a component creation begin with QQmlComponent::beginCreate().
889
*/
890
void QQmlComponent::completeCreate()
891
{
892
    Q_D(QQmlComponent);
893

894 895 896
    d->completeCreate();
}

897
void QQmlComponentPrivate::completeCreate()
898 899
{
    if (state.completePending) {
900
        QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
901 902
        complete(ep, &state);

903 904
        delete profiler;
        profiler = 0;
905 906 907
    }
}

908
QQmlComponentAttached::QQmlComponentAttached(QObject *parent)
909 910 911 912
: QObject(parent), prev(0), next(0)
{
}

913
QQmlComponentAttached::~QQmlComponentAttached()
914 915 916 917 918 919 920 921 922 923
{
    if (prev) *prev = next;
    if (next) next->prev = prev;
    prev = 0;
    next = 0;
}

/*!
    \internal
*/
924
QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
925
{
926
    QQmlComponentAttached *a = new QQmlComponentAttached(obj);
927

928
    QQmlEngine *engine = qmlEngine(obj);
929 930 931
    if (!engine)
        return a;

932 933
    if (QQmlEnginePrivate::get(engine)->activeVME) { // XXX should only be allowed during begin
        QQmlEnginePrivate *p = QQmlEnginePrivate::get(engine);
934
        a->add(&p->activeVME->componentAttached);
935
    } else {
936
        QQmlData *d = QQmlData::get(obj);
937 938 939 940 941 942 943 944
        Q_ASSERT(d);
        Q_ASSERT(d->context);
        a->add(&d->context->componentAttached);
    }

    return a;
}

945 946
void QQmlComponent::create(QQmlIncubator &i, QQmlContext *context,
                                   QQmlContext *forContext)
947
{
948
    Q_D(QQmlComponent);
949

950 951
    if (!context) 
        context = d->engine->rootContext();
952

953 954 955
    QQmlContextData *contextData = QQmlContextData::get(context);
    QQmlContextData *forContextData = contextData;
    if (forContext) forContextData = QQmlContextData::get(forContext);
956 957

    if (!contextData->isValid()) {
958
        qWarning("QQmlComponent: Cannot create a component in an invalid context");
959 960 961 962
        return;
    }

    if (contextData->engine != d->engine) {
963
        qWarning("QQmlComponent: Must create component in context from the same QQmlEngine");
964 965 966 967
        return;
    }

    if (!isReady()) {
968
        qWarning("QQmlComponent: Component is not ready");
969 970 971 972
        return;
    }

    i.clear();
973
    QQmlIncubatorPrivate *p = i.d;
974

975
    QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine);
976 977

    p->component = d->cc; p->component->addref();
978
    p->vme.init(contextData, d->cc, d->start, d->creationContext);
979 980 981 982 983

    enginePriv->incubate(i, forContextData);
}

class QV8IncubatorResource : public QV8ObjectResource,
984
                             public QQmlIncubator
985 986 987 988 989 990 991 992 993 994 995
{
V8_RESOURCE_TYPE(IncubatorType)
public:
    QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);

    static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>, 
                                                     const v8::AccessorInfo& info);
    static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>, 
                                              const v8::AccessorInfo& info);
    static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>, 
                                              const v8::AccessorInfo& info);
996
    static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>, 
997
                                                       const v8::AccessorInfo& info);
998
    static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
999 1000 1001 1002

    static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, 
                                    const v8::AccessorInfo& info);

1003 1004
    void dispose();

1005
    v8::Persistent<v8::Object> me;
1006
    QQmlGuard<QObject> parent;
1007 1008 1009 1010 1011 1012 1013
    v8::Persistent<v8::Value> valuemap;
    v8::Persistent<v8::Object> qmlGlobal;
protected:
    virtual void statusChanged(Status);
    virtual void setInitialState(QObject *);
};

1014
static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
1015 1016 1017
{
    if (parent) {
        me->setParent(parent);
1018 1019
        typedef QQmlPrivate::AutoParentFunction APF;
        QList<APF> functions = QQmlMetaType::parentFunctions();
1020 1021 1022

        bool needParent = false;
        for (int ii = 0; ii < functions.count(); ++ii) {
1023 1024
            QQmlPrivate::AutoParentResult res = functions.at(ii)(me, parent);
            if (res == QQmlPrivate::Parented) {
1025 1026
                needParent = false;
                break;
1027
            } else if (res == QQmlPrivate::IncompatibleParent) {
1028 1029 1030 1031
                needParent = true;
            }
        }
        if (needParent) 
1032
            qWarning("QQmlComponent: Created graphical object was not "
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
                     "placed in the graphics scene.");
    }
}

/*!
    \qmlmethod object Component::createObject(Item parent, object properties)

    Creates and returns an object instance of this component that will have
    the given \a parent and \a properties. The \a properties argument is optional.
    Returns null if object creation fails.

    The object will be created in the same context as the one in which the component
    was created. This function will always return null when called on components
    which were not created in QML.

    If you wish to create an object without setting a parent, specify \c null for
    the \a parent value. Note that if the returned object is to be displayed, you 
    must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent} 
    property, or else the object will not be visible.

    If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
    it is not destroyed by the garbage collector.  This is true regardless of whether \l{Item::parent} is set afterwards,
    since setting the Item parent does not change object ownership; only the graphical parent is changed.

    As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
    map of initial property values for the created object. These values are applied before object
    creation is finalized. (This is more efficient than setting property values after object creation,
    particularly where large sets of property values are defined, and also allows property bindings
    to be set up before the object is created.)

    The \a properties argument is specified as a map of property-value items. For example, the code
    below creates an object with initial \c x and \c y values of 100 and 200, respectively:

    \js
        var component = Qt.createComponent("Button.qml");
        if (component.status == Component.Ready)
            component.createObject(parent, {"x": 100, "y": 100});
    \endjs

    Dynamically created instances can be deleted with the \c destroy() method.
    See \l {Dynamic Object Management in QML} for more information.
*/
1075
void QQmlComponent::createObject(QQmlV8Function *args)
1076
{
1077
    Q_D(QQmlComponent);
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
    Q_ASSERT(d->engine);
    Q_ASSERT(args);

    QObject *parent = 0;
    v8::Local<v8::Object> valuemap;

    if (args->Length() >= 1) 
        parent = args->engine()->toQObject((*args)[0]);

    if (args->Length() >= 2) {
        v8::Local<v8::Value> v = (*args)[1];
        if (!v->IsObject() || v->IsArray()) {
            qmlInfo(this) << tr("createObject: value is not an object");
            args->returnValue(v8::Null());
            return;
        }
        valuemap = v8::Local<v8::Object>::Cast(v);
    }

    QV8Engine *v8engine = args->engine();

1099
    QQmlContext *ctxt = creationContext();
1100 1101 1102 1103 1104 1105 1106 1107 1108
    if (!ctxt) ctxt = d->engine->rootContext();

    QObject *rv = beginCreate(ctxt);

    if (!rv) {
        args->returnValue(v8::Null());
        return;
    }

1109
    QQmlComponent_setQmlParent(rv, parent);
1110 1111 1112 1113 1114 1115

    v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
    Q_ASSERT(ov->IsObject());
    v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);

    if (!valuemap.IsEmpty()) {
1116
        QQmlComponentExtension *e = componentExtension(v8engine);
1117 1118 1119 1120 1121 1122 1123 1124
        // Try catch isn't needed as the function itself is loaded with try/catch
        v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
        v8::Handle<v8::Value> args[] = { object, valuemap };
        v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
    }

    d->completeCreate();

1125
    Q_ASSERT(QQmlData::get(rv));
1126 1127
    QQmlData::get(rv)->explicitIndestructibleSet = false;
    QQmlData::get(rv)->indestructible = false;
1128 1129 1130 1131 1132 1133 1134

    if (!rv)
        args->returnValue(v8::Null());
    else
        args->returnValue(object);
}

1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
/*!
    \qmlmethod object Component::incubateObject(Item parent, object properties, enum mode)

    Creates an incubator for instance of this component.  Incubators allow new component 
    instances to be instantiated asynchronously and not cause freezes in the UI.

    The \a parent argument specifies the parent the created instance will have.  Omitting the 
    parameter or passing null will create anobject with no parent.  In this case, a reference
    to the created object must be maintained by the application of the object will eventually
    be garbage collected.

    The \a properties argument is specified as a map of property-value items which will be
    set on the created object during its construction.  \a mode may be Qt.Synchronous or 
    Qt.Asynchronous and controls whether the instance is created synchronously or asynchronously. 
    The default is asynchronously.  In some circumstances, even if Qt.Synchronous is specified,
    the incubator may create the object asynchronously.  This happens if the component calling
    incubateObject() is itself being created asynchronously.

    All three arguments are optional.

    If successful, the method returns an incubator, otherwise null.  The incubator has the following
    properties:

    \list
1159
    \li status The status of the incubator.  Valid values are Component.Ready, Component.Loading and
1160
       Component.Error.
1161
    \li object The created object instance.  Will only be available once the incubator is in the
1162
       Ready status.
1163
    \li onStatusChanged Specifies a callback function to be invoked when the status changes.  The
1164
       status is passed as a parameter to the callback.
1165
    \li forceCompletion() Call to complete incubation synchronously.
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
    \endlist

    The following example demonstrates how to use an incubator:

    \js
        var component = Qt.createComponent("Button.qml");

        var incubator = component.incubateObject(parent, { x: 10, y: 10 });
        if (incubator.status != Component.Ready) {
            incubator.onStatusChanged = function(status) {
                if (status == Component.Ready) {
                    print ("Object", incubator.object, "is now ready!");
                }
            }
        } else {
            print ("Object", incubator.object, "is ready immediately!");
        }
    \endjs
*/

1186
void QQmlComponent::incubateObject(QQmlV8Function *args)
1187
{
1188
    Q_D(QQmlComponent);
1189
    Q_ASSERT(d->engine);
1190
    Q_UNUSED(d);
1191 1192 1193 1194
    Q_ASSERT(args);

    QObject *parent = 0;
    v8::Local<v8::Object> valuemap;
1195
    QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
1196 1197 1198 1199 1200 1201

    if (args->Length() >= 1) 
        parent = args->engine()->toQObject((*args)[0]);

    if (args->Length() >= 2) {
        v8::Local<v8::Value> v = (*args)[1];
1202 1203
        if (v->IsNull()) {
        } else if (!v->IsObject() || v->IsArray()) {
1204 1205 1206
            qmlInfo(this) << tr("createObject: value is not an object");
            args->returnValue(v8::Null());
            return;
1207 1208
        } else {
            valuemap = v8::Local<v8::Object>::Cast(v);
1209 1210 1211 1212 1213
        }
    }

    if (args->Length() >= 3) {
        quint32 v = (*args)[2]->Uint32Value();
1214
        if (v == 0)
1215
            mode = QQmlIncubator::Asynchronous;
1216
        else if (v == 1)
1217
            mode = QQmlIncubator::AsynchronousIfNested;
1218 1219
    }

1220
    QQmlComponentExtension *e = componentExtension(args->engine());
1221 1222
    
    QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
1223 1224 1225
    v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
    o->SetExternalResource(r);

1226 1227 1228 1229 1230
    if (!valuemap.IsEmpty()) {
        r->valuemap = qPersistentNew(valuemap);
        r->qmlGlobal = qPersistentNew(args->qmlGlobal());
    }
    r->parent = parent;
1231
    r->me = qPersistentNew(o);
1232 1233 1234

    create(*r, creationContext());

1235
    if (r->status() == QQmlIncubator::Null) {
1236
        r->dispose();
1237 1238 1239 1240 1241 1242 1243
        args->returnValue(v8::Null());
    } else {
        args->returnValue(o);
    }
}

// XXX used by QSGLoader
1244
void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
1245
{
1246
    QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1247
    QV8Engine *v8engine = ep->v8engine();
1248 1249 1250

    v8::HandleScope handle_scope;
    v8::Context::Scope scope(v8engine->context());
1251 1252 1253 1254 1255
    v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
    Q_ASSERT(ov->IsObject());
    v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);

    if (!valuemap.IsEmpty()) {
1256
        QQmlComponentExtension *e = componentExtension(v8engine);
1257 1258 1259 1260 1261 1262 1263 1264
        // Try catch isn't needed as the function itself is loaded with try/catch
        v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
        v8::Handle<v8::Value> args[] = { object, valuemap };
        v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
    }
}


1265
QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
1266 1267 1268 1269
{
    v8::HandleScope handle_scope;
    v8::Context::Scope scope(engine->context());

1270
    forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282

    {
    v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
    ft->InstanceTemplate()->SetHasExternalResource(true);
    ft->InstanceTemplate()->SetInternalFieldCount(1);
    ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"), 
                                        QV8IncubatorResource::StatusChangedGetter, 
                                        QV8IncubatorResource::StatusChangedSetter);
    ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
                                        QV8IncubatorResource::StatusGetter);
    ft->InstanceTemplate()->SetAccessor(v8::String::New("object"), 
                                        QV8IncubatorResource::ObjectGetter); 
1283 1284
    ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"), 
                                        QV8IncubatorResource::ForceCompletionGetter); 
1285 1286 1287 1288 1289 1290 1291
    incubationConstructor = qPersistentNew(ft->GetFunction());
    }

    {
#define INITIALPROPERTIES_SOURCE \
        "(function(object, values) {"\
            "try {"\
1292
                "for(var property in values) {" \
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
                    "try {"\
                        "var properties = property.split(\".\");"\
                        "var o = object;"\
                        "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
                            "o = o[properties[ii]];"\
                        "}"\
                        "o[properties[properties.length - 1]] = values[property];"\
                    "} catch(e) {}"\
                "}"\
            "} catch(e) {}"\
        "})"
    initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
#undef INITIALPROPERTIES_SOURCE
    }
}

v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>, 
                                                          const v8::AccessorInfo& info)
{
    QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
    return r->engine->newQObject(r->object());
}

1316
v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>, 
1317 1318 1319
                                                                  const v8::AccessorInfo& info)
{
    QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
1320
    return componentExtension(r->engine)->forceCompletion;
1321 1322
}

1323
v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args) 
1324 1325 1326 1327 1328
{
    QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
    if (!r)
        V8THROW_TYPE("Not an incubator object");

1329
    r->forceCompletion();
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352

    return v8::Undefined();
}

v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>, 
                                                         const v8::AccessorInfo& info)
{
    QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
    return v8::Integer::NewFromUnsigned(r->status());
}

v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>, 
                                                                 const v8::AccessorInfo& info)
{
    return info.This()->GetInternalField(0);
}

void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value, 
                                                const v8::AccessorInfo& info)
{
    info.This()->SetInternalField(0, value);
}

1353
QQmlComponentExtension::~QQmlComponentExtension()
1354 1355 1356
{
    qPersistentDispose(incubationConstructor);
    qPersistentDispose(initialProperties);
1357
    qPersistentDispose(forceCompletion);
1358 1359 1360
}

QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
1361
: QV8ObjectResource(engine), QQmlIncubator(m)
1362 1363 1364 1365 1366
{
}

void QV8IncubatorResource::setInitialState(QObject *o)
{
1367
    QQmlComponent_setQmlParent(o, parent);
1368 1369

    if (!valuemap.IsEmpty()) {
1370
        QQmlComponentExtension *e = componentExtension(engine);
1371 1372 1373 1374 1375

        v8::HandleScope handle_scope;
        v8::Context::Scope scope(engine->context());

        v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
1376
        v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
1377 1378 1379 1380 1381 1382
        v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);

        qPersistentDispose(valuemap);
        qPersistentDispose(qmlGlobal);
    }
}
1383 1384 1385 1386 1387 1388 1389 1390
    
void QV8IncubatorResource::dispose()
{
    qPersistentDispose(valuemap);
    qPersistentDispose(qmlGlobal);
    // No further status changes are forthcoming, so we no long need a self reference
    qPersistentDispose(me);
}
1391 1392 1393 1394

void QV8IncubatorResource::statusChanged(Status s)
{
    if (s == Ready) {
1395 1396
        Q_ASSERT(QQmlData::get(object()));
        QQmlData::get(object())->setImplicitDestructible();
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
    }

    if (!me.IsEmpty()) { // Will be false in synchronous mode
        v8::HandleScope scope;
        v8::Local<v8::Value> callback = me->GetInternalField(0);

        if (!callback.IsEmpty() && !callback->IsUndefined()) {

            if (callback->IsFunction()) {
                v8::Context::Scope context_scope(engine->context());
                v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
                v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
1409
                v8::TryCatch tc;
1410
                f->Call(me, 1, args);
1411
                if (tc.HasCaught()) {
1412
                    QQmlError error;
1413 1414
                    QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
                    QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
1415
                }
1416 1417 1418 1419
            }
        }
    }

1420 1421
    if (s == Ready || s == Error) 
        dispose();
1422 1423
}

1424
QT_END_NAMESPACE