1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativecomponent.h"
43 #include "private/qdeclarativecomponent_p.h"
45 #include "private/qdeclarativecompiler_p.h"
46 #include "private/qdeclarativecontext_p.h"
47 #include "private/qdeclarativeengine_p.h"
48 #include "private/qdeclarativevme_p.h"
49 #include "qdeclarative.h"
50 #include "qdeclarativeengine.h"
51 #include "private/qdeclarativebinding_p.h"
52 #include "private/qdeclarativebinding_p_p.h"
53 #include "private/qdeclarativeglobal_p.h"
54 #include "private/qdeclarativescriptparser_p.h"
55 #include "private/qdeclarativedebugtrace_p.h"
56 #include "private/qdeclarativeenginedebug_p.h"
59 #include <QStringList>
60 #include <QtCore/qdebug.h>
61 #include <QApplication>
62 #include <qdeclarativeinfo.h>
69 \class QDeclarativeComponent
71 \brief The QDeclarativeComponent class encapsulates a QML component definition.
74 Components are reusable, encapsulated QML elements with well-defined interfaces.
75 They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
77 A QDeclarativeComponent instance can be created from a QML file.
78 For example, if there is a \c main.qml file like this:
89 The following code loads this QML file as a component, creates an instance of
90 this component using create(), and then queries the \l Item's \l {Item::}{width}
94 QDeclarativeEngine *engine = new QDeclarativeEngine;
95 QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
97 QObject *myObject = component.create();
98 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject);
99 int width = item->width(); // width = 200
103 \section2 Network Components
105 If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a
106 network resource, the QDeclarativeComponent has to fetch the network data before it is able to create
107 objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading}
108 \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component
109 is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}.
111 The following example shows how to load a QML file from a network resource. After creating
112 the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the
113 QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
114 directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the
115 component has been cached and is ready immediately.
118 MyApplication::MyApplication()
121 component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
122 if (component->isLoading())
123 QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
124 this, SLOT(continueLoading()));
129 void MyApplication::continueLoading()
131 if (component->isError()) {
132 qWarning() << component->errors();
134 QObject *myObject = component->create();
139 \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
143 \qmlclass Component QDeclarativeComponent
144 \ingroup qml-utility-elements
146 \brief The Component element encapsulates a QML component definition.
148 Components are reusable, encapsulated QML elements with well-defined interfaces.
150 Components are often defined by \l {qdeclarativedocuments.html}{component files} -
151 that is, \c .qml files. The \e Component element essentially allows QML components
152 to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
153 This may be useful for reusing a small component within a QML file, or for defining
154 a component that logically belongs with other QML components within a file.
156 For example, here is a component that is used by multiple \l Loader objects.
157 It contains a single item, a \l Rectangle:
159 \snippet doc/src/snippets/declarative/component.qml 0
161 Notice that while a \l Rectangle by itself would be automatically
162 rendered and displayed, this is not the case for the above rectangle
163 because it is defined inside a \c Component. The component encapsulates the
164 QML elements within, as if they were defined in a separate QML
165 file, and is not loaded until requested (in this case, by the
166 two \l Loader objects).
168 Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
169 A QML document has a single top-level item that defines the behaviors and
170 properties of that component, and cannot define properties or behaviors outside
171 of that top-level item. In the same way, a \c Component definition contains a single
172 top level item (which in the above example is a \l Rectangle) and cannot define any
173 data outside of this item, with the exception of an \e id (which in the above example
176 The \c Component element is commonly used to provide graphical components
177 for views. For example, the ListView::delegate property requires a \c Component
178 to specify how each list item is to be displayed.
180 \c Component objects can also be created dynamically using
181 \l{QML:Qt::createComponent()}{Qt.createComponent()}.
185 \qmlattachedsignal Component::onCompleted()
187 Emitted after component "startup" has completed. This can be used to
188 execute script code at startup, once the full QML environment has been
191 The \c {Component::onCompleted} attached property can be applied to
192 any element. The order of running the \c onCompleted scripts is
197 Component.onCompleted: console.log("Completed Running!")
199 Component.onCompleted: console.log("Nested Completed Running!")
206 \qmlattachedsignal Component::onDestruction()
208 Emitted as the component begins destruction. This can be used to undo
209 work done in the onCompleted signal, or other imperative code in your
212 The \c {Component::onDestruction} attached property can be applied to
213 any element. However, it applies to the destruction of the component as
214 a whole, and not the destruction of the specific object. The order of
215 running the \c onDestruction scripts is undefined.
219 Component.onDestruction: console.log("Destruction Beginning!")
221 Component.onDestruction: console.log("Nested Destruction Beginning!")
230 \enum QDeclarativeComponent::Status
232 Specifies the loading status of the QDeclarativeComponent.
234 \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content.
235 \value Ready This QDeclarativeComponent is ready and create() may be called.
236 \value Loading This QDeclarativeComponent is loading network data.
237 \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}.
240 void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *)
242 Q_Q(QDeclarativeComponent);
246 fromTypeData(typeData);
249 emit q->statusChanged(q->status());
252 void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p)
254 Q_Q(QDeclarativeComponent);
258 emit q->progressChanged(p);
261 void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data)
263 url = data->finalUrl();
264 QDeclarativeCompiledData *c = data->compiledData();
267 Q_ASSERT(data->isError());
268 state.errors = data->errors();
276 void QDeclarativeComponentPrivate::clear()
279 typeData->unregisterCallback(this);
293 QDeclarativeComponent::QDeclarativeComponent(QObject *parent)
294 : QObject(*(new QDeclarativeComponentPrivate), parent)
299 Destruct the QDeclarativeComponent.
301 QDeclarativeComponent::~QDeclarativeComponent()
303 Q_D(QDeclarativeComponent);
305 if (d->state.completePending) {
306 qWarning("QDeclarativeComponent: Component destroyed while completion pending");
311 d->typeData->unregisterCallback(d);
312 d->typeData->release();
319 \qmlproperty enumeration Component::status
320 This property holds the status of component loading. It can be one of:
322 \o Component.Null - no data is available for the component
323 \o Component.Ready - the component has been loaded, and can be used to create instances.
324 \o Component.Loading - the component is currently being loaded
325 \o Component.Error - an error occurred while loading the component.
326 Calling errorString() will provide a human-readable description of any errors.
331 \property QDeclarativeComponent::status
332 The component's current \l{QDeclarativeComponent::Status} {status}.
334 QDeclarativeComponent::Status QDeclarativeComponent::status() const
336 Q_D(const QDeclarativeComponent);
340 else if (!d->state.errors.isEmpty())
342 else if (d->engine && d->cc)
349 Returns true if status() == QDeclarativeComponent::Null.
351 bool QDeclarativeComponent::isNull() const
353 return status() == Null;
357 Returns true if status() == QDeclarativeComponent::Ready.
359 bool QDeclarativeComponent::isReady() const
361 return status() == Ready;
365 Returns true if status() == QDeclarativeComponent::Error.
367 bool QDeclarativeComponent::isError() const
369 return status() == Error;
373 Returns true if status() == QDeclarativeComponent::Loading.
375 bool QDeclarativeComponent::isLoading() const
377 return status() == Loading;
381 \qmlproperty real Component::progress
382 The progress of loading the component, from 0.0 (nothing loaded)
387 \property QDeclarativeComponent::progress
388 The progress of loading the component, from 0.0 (nothing loaded)
391 qreal QDeclarativeComponent::progress() const
393 Q_D(const QDeclarativeComponent);
398 \fn void QDeclarativeComponent::progressChanged(qreal progress)
400 Emitted whenever the component's loading progress changes. \a progress will be the
401 current progress between 0.0 (nothing loaded) and 1.0 (finished).
405 \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status)
407 Emitted whenever the component's status changes. \a status will be the
412 Create a QDeclarativeComponent with no data and give it the specified
413 \a engine and \a parent. Set the data with setData().
415 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent)
416 : QObject(*(new QDeclarativeComponentPrivate), parent)
418 Q_D(QDeclarativeComponent);
423 Create a QDeclarativeComponent from the given \a url and give it the
424 specified \a parent and \a engine.
426 Ensure that the URL provided is full and correct, in particular, use
427 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
431 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent)
432 : QObject(*(new QDeclarativeComponentPrivate), parent)
434 Q_D(QDeclarativeComponent);
440 Create a QDeclarativeComponent from the given \a fileName and give it the specified
441 \a parent and \a engine.
445 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName,
447 : QObject(*(new QDeclarativeComponentPrivate), parent)
449 Q_D(QDeclarativeComponent);
451 loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
457 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, QObject *parent)
458 : QObject(*(new QDeclarativeComponentPrivate), parent)
460 Q_D(QDeclarativeComponent);
470 Sets the QDeclarativeComponent to use the given QML \a data. If \a url
471 is provided, it is used to set the component name and to provide
472 a base path for items resolved by this component.
474 void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url)
476 Q_D(QDeclarativeComponent);
482 QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url);
484 if (typeData->isCompleteOrError()) {
485 d->fromTypeData(typeData);
487 d->typeData = typeData;
488 d->typeData->registerCallback(d);
492 emit statusChanged(status());
493 emit progressChanged(d->progress);
497 Returns the QDeclarativeContext the component was created in. This is only
498 valid for components created directly from QML.
500 QDeclarativeContext *QDeclarativeComponent::creationContext() const
502 Q_D(const QDeclarativeComponent);
503 if(d->creationContext)
504 return d->creationContext->asQDeclarativeContext();
506 return qmlContext(this);
510 Load the QDeclarativeComponent from the provided \a url.
512 Ensure that the URL provided is full and correct, in particular, use
513 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
515 void QDeclarativeComponent::loadUrl(const QUrl &url)
517 Q_D(QDeclarativeComponent);
521 if ((url.isRelative() && !url.isEmpty())
522 || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
523 d->url = d->engine->baseUrl().resolved(url);
528 QDeclarativeError error;
529 error.setDescription(tr("Invalid empty URL"));
530 d->state.errors << error;
534 QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url);
536 if (data->isCompleteOrError()) {
537 d->fromTypeData(data);
541 d->typeData->registerCallback(d);
542 d->progress = data->progress();
545 emit statusChanged(status());
546 emit progressChanged(d->progress);
550 Return the list of errors that occurred during the last compile or create
551 operation. An empty list is returned if isError() is not set.
553 QList<QDeclarativeError> QDeclarativeComponent::errors() const
555 Q_D(const QDeclarativeComponent);
557 return d->state.errors;
559 return QList<QDeclarativeError>();
563 \qmlmethod string Component::errorString()
565 Returns a human-readable description of any errors.
567 The string includes the file, location, and description of each error.
568 If multiple errors are present they are separated by a newline character.
570 If no errors are present, an empty string is returned.
575 errorString is only meant as a way to get the errors in script
577 QString QDeclarativeComponent::errorString() const
579 Q_D(const QDeclarativeComponent);
583 foreach(const QDeclarativeError &e, d->state.errors) {
584 ret += e.url().toString() + QLatin1Char(':') +
585 QString::number(e.line()) + QLatin1Char(' ') +
586 e.description() + QLatin1Char('\n');
592 \qmlproperty url Component::url
593 The component URL. This is the URL that was used to construct the component.
597 \property QDeclarativeComponent::url
598 The component URL. This is the URL passed to either the constructor,
599 or the loadUrl() or setData() methods.
601 QUrl QDeclarativeComponent::url() const
603 Q_D(const QDeclarativeComponent);
610 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent)
611 : QObject(dd, parent)
616 \qmlmethod object Component::createObject(Item parent, object properties)
618 Creates and returns an object instance of this component that will have
619 the given \a parent and \a properties. The \a properties argument is optional.
620 Returns null if object creation fails.
622 The object will be created in the same context as the one in which the component
623 was created. This function will always return null when called on components
624 which were not created in QML.
626 If you wish to create an object without setting a parent, specify \c null for
627 the \a parent value. Note that if the returned object is to be displayed, you
628 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
629 property, or else the object will not be visible.
631 If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
632 it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
633 since setting the Item parent does not change object ownership; only the graphical parent is changed.
635 As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
636 map of initial property values for the created object. These values are applied before object
637 creation is finalized. (This is more efficient than setting property values after object creation,
638 particularly where large sets of property values are defined, and also allows property bindings
639 to be set up before the object is created.)
641 The \a properties argument is specified as a map of property-value items. For example, the code
642 below creates an object with initial \c x and \c y values of 100 and 200, respectively:
645 var component = Qt.createComponent("Button.qml");
646 if (component.status == Component.Ready)
647 component.createObject(parent, {"x": 100, "y": 100});
650 Dynamically created instances can be deleted with the \c destroy() method.
651 See \l {Dynamic Object Management in QML} for more information.
656 A version of create which returns a scriptObject, for use in script.
657 This function will only work on components created in QML.
659 Sets graphics object parent because forgetting to do this is a frequent
662 void QDeclarativeComponent::createObject(QDeclarativeV8Function *args)
666 #define RETURN(result) { args->returnValue((result)); return; }
668 Q_D(QDeclarativeComponent);
672 QDeclarativeEngine *engine = d->engine;
673 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
674 QV8Engine *v8engine = ep->v8engine();
676 QDeclarativeContext *ctxt = creationContext();
677 if (!ctxt) ctxt = engine->rootContext();
679 v8::Local<v8::Object> valuemap;
680 if (args->Length() >= 2) {
681 v8::Local<v8::Value> v = (*args)[1];
682 if (!v->IsObject() || v->IsArray()) {
683 qmlInfo(this) << tr("createObject: value is not an object");
686 valuemap = v8::Local<v8::Object>::Cast(v);
689 QObject *parent = args->Length()?v8engine->toQObject((*args)[0]):0;
691 QObject *ret = beginCreate(ctxt);
698 ret->setParent(parent);
700 QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
702 bool needParent = false;
704 for (int ii = 0; ii < functions.count(); ++ii) {
705 QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, parent);
706 if (res == QDeclarativePrivate::Parented) {
709 } else if (res == QDeclarativePrivate::IncompatibleParent) {
715 qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
718 v8::Handle<v8::Value> ov = v8engine->newQObject(ret);
719 Q_ASSERT(ov->IsObject());
720 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
722 if (!valuemap.IsEmpty()) {
724 #define SET_ARGS_SOURCE \
725 "(function(object, values) {"\
727 "for(var property in values) {"\
729 "var properties = property.split(\".\");"\
731 "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
732 "o = o[properties[ii]];"\
734 "o[properties[properties.length - 1]] = values[property];"\
740 v8::Local<v8::Script> script = v8engine->qmlModeCompile(SET_ARGS_SOURCE);
741 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(script->Run(args->qmlGlobal()));
743 // Try catch isn't needed as the function itself is loaded with try/catch
744 v8::Handle<v8::Value> args[] = { object, valuemap };
745 function->Call(v8engine->global(), 2, args);
750 QDeclarativeData *ddata = QDeclarativeData::get(ret);
752 ddata->setImplicitDestructible();
760 Create an object instance from this component. Returns 0 if creation
761 failed. \a context specifies the context within which to create the object
764 If \a context is 0 (the default), it will create the instance in the
765 engine' s \l {QDeclarativeEngine::rootContext()}{root context}.
767 QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
769 Q_D(QDeclarativeComponent);
772 context = d->engine->rootContext();
774 QObject *rv = beginCreate(context);
780 This method provides more advanced control over component instance creation.
781 In general, programmers should use QDeclarativeComponent::create() to create a
784 Create an object instance from this component. Returns 0 if creation
785 failed. \a context specifies the context within which to create the object
788 When QDeclarativeComponent constructs an instance, it occurs in three steps:
790 \i The object hierarchy is created, and constant values are assigned.
791 \i Property bindings are evaluated for the the first time.
792 \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects.
794 QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it
795 only performs step 1. QDeclarativeComponent::completeCreate() must be called to
796 complete steps 2 and 3.
798 This breaking point is sometimes useful when using attached properties to
799 communicate information to an instantiated component, as it allows their
800 initial values to be configured before property bindings take effect.
802 QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
804 Q_D(QDeclarativeComponent);
805 QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
807 QDeclarativeData *ddata = QDeclarativeData::get(rv);
809 ddata->indestructible = true;
815 QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
817 Q_Q(QDeclarativeComponent);
819 qWarning("QDeclarativeComponent: Cannot create a component in a null context");
823 if (!context->isValid()) {
824 qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
828 if (context->engine != engine) {
829 qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
833 if (state.completePending) {
834 qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous");
839 qWarning("QDeclarativeComponent: Component is not ready");
843 return begin(context, creationContext, cc, start, &state, 0, bindings);
847 Try to do what's necessary for a reasonable display of the type
848 name, but no more (just enough for the client to do more extensive cleanup).
850 Should only be called when debugging is enabled.
852 static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
854 static const QString qmlMarker(QLatin1String("_QML"));
855 static const QChar underscore(QLatin1Char('_'));
856 static const QChar asterisk(QLatin1Char('*'));
857 QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
858 QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
860 //### optimize further?
861 int marker = typeName.indexOf(qmlMarker);
862 if (marker != -1 && marker < typeName.count() - 1) {
863 if (typeName[marker + 1] == underscore) {
864 const QString className = typeName.left(marker) + asterisk;
865 type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
867 typeName = QLatin1String(type->qmlTypeName());
874 QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
875 QDeclarativeContextData *componentCreationContext,
876 QDeclarativeCompiledData *component, int start,
877 ConstructionState *state, QList<QDeclarativeError> *errors,
878 const QBitField &bindings)
880 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
881 bool isRoot = !enginePriv->inBeginCreate;
883 Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
884 Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
887 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
889 QDeclarativeContextData *ctxt = new QDeclarativeContextData;
890 ctxt->isInternal = true;
891 ctxt->url = component->url;
892 ctxt->imports = component->importCache;
894 // Nested global imports
895 if (componentCreationContext && start != -1) {
896 ctxt->importedScripts = componentCreationContext->importedScripts;
897 for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
898 ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
901 component->importCache->addref();
902 ctxt->setParent(parentContext);
904 enginePriv->inBeginCreate = true;
907 enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
908 QObject *rv = vme.run(ctxt, component, start, bindings);
909 enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
912 if(errors) *errors = vme.errors();
913 else state->errors = vme.errors();
917 enginePriv->inBeginCreate = false;
919 state->bindValues = enginePriv->bindValues;
920 state->parserStatus = enginePriv->parserStatus;
921 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
922 state->componentAttached = enginePriv->componentAttached;
923 if (state->componentAttached)
924 state->componentAttached->prev = &state->componentAttached;
926 enginePriv->componentAttached = 0;
927 enginePriv->bindValues.clear();
928 enginePriv->parserStatus.clear();
929 enginePriv->finalizedParserStatus.clear();
930 state->completePending = true;
931 enginePriv->inProgressCreations++;
934 if (enginePriv->isDebugging && rv) {
935 if (!parentContext->isInternal)
936 parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
937 QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
939 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
940 QDeclarativeData *data = QDeclarativeData::get(rv);
941 QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
948 void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
949 QObject *object, ConstructionState *state)
951 bool isRoot = !enginePriv->inBeginCreate;
952 enginePriv->inBeginCreate = true;
955 vme.runDeferred(object);
958 state->errors = vme.errors();
961 enginePriv->inBeginCreate = false;
963 state->bindValues = enginePriv->bindValues;
964 state->parserStatus = enginePriv->parserStatus;
965 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
966 state->componentAttached = enginePriv->componentAttached;
967 if (state->componentAttached)
968 state->componentAttached->prev = &state->componentAttached;
970 enginePriv->componentAttached = 0;
971 enginePriv->bindValues.clear();
972 enginePriv->parserStatus.clear();
973 enginePriv->finalizedParserStatus.clear();
974 state->completePending = true;
975 enginePriv->inProgressCreations++;
979 void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
981 if (state->completePending) {
983 for (int ii = 0; ii < state->bindValues.count(); ++ii) {
984 QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
985 state->bindValues.at(ii);
986 for (int jj = 0; jj < bv.count; ++jj) {
988 bv.at(jj)->m_mePtr = 0;
989 bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
990 QDeclarativePropertyPrivate::DontRemoveBinding);
993 QDeclarativeEnginePrivate::clear(bv);
996 for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
997 QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
998 state->parserStatus.at(ii);
1000 for (int jj = ps.count - 1; jj >= 0; --jj) {
1001 QDeclarativeParserStatus *status = ps.at(jj);
1002 if (status && status->d) {
1004 status->componentComplete();
1007 QDeclarativeEnginePrivate::clear(ps);
1010 for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
1011 QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
1012 QObject *obj = status.first;
1014 void *args[] = { 0 };
1015 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
1016 status.second, args);
1020 //componentComplete() can register additional finalization objects
1021 //that are then never handled. Handle them manually here.
1022 if (1 == enginePriv->inProgressCreations) {
1023 for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) {
1024 QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii);
1025 QObject *obj = status.first;
1027 void *args[] = { 0 };
1028 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
1029 status.second, args);
1032 enginePriv->finalizedParserStatus.clear();
1035 while (state->componentAttached) {
1036 QDeclarativeComponentAttached *a = state->componentAttached;
1038 QDeclarativeData *d = QDeclarativeData::get(a->parent());
1040 Q_ASSERT(d->context);
1041 a->add(&d->context->componentAttached);
1042 emit a->completed();
1045 state->bindValues.clear();
1046 state->parserStatus.clear();
1047 state->finalizedParserStatus.clear();
1048 state->completePending = false;
1050 enginePriv->inProgressCreations--;
1051 if (0 == enginePriv->inProgressCreations) {
1052 while (enginePriv->erroredBindings) {
1053 enginePriv->warning(enginePriv->erroredBindings->error);
1054 enginePriv->erroredBindings->removeError();
1061 This method provides more advanced control over component instance creation.
1062 In general, programmers should use QDeclarativeComponent::create() to create a
1065 Complete a component creation begin with QDeclarativeComponent::beginCreate().
1067 void QDeclarativeComponent::completeCreate()
1069 Q_D(QDeclarativeComponent);
1070 d->completeCreate();
1073 void QDeclarativeComponentPrivate::completeCreate()
1075 if (state.completePending) {
1076 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
1077 complete(ep, &state);
1079 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
1083 QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent)
1084 : QObject(parent), prev(0), next(0)
1088 QDeclarativeComponentAttached::~QDeclarativeComponentAttached()
1090 if (prev) *prev = next;
1091 if (next) next->prev = prev;
1099 QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj)
1101 QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj);
1103 QDeclarativeEngine *engine = qmlEngine(obj);
1107 if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
1108 QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
1109 a->add(&p->componentAttached);
1111 QDeclarativeData *d = QDeclarativeData::get(obj);
1113 Q_ASSERT(d->context);
1114 a->add(&d->context->componentAttached);