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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
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"
57 #include <QtScript/qscriptvalueiterator.h>
60 #include <QStringList>
61 #include <QtCore/qdebug.h>
62 #include <QApplication>
63 #include <qdeclarativeinfo.h>
70 \class QDeclarativeComponent
72 \brief The QDeclarativeComponent class encapsulates a QML component definition.
75 Components are reusable, encapsulated QML elements with well-defined interfaces.
76 They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
78 A QDeclarativeComponent instance can be created from a QML file.
79 For example, if there is a \c main.qml file like this:
90 The following code loads this QML file as a component, creates an instance of
91 this component using create(), and then queries the \l Item's \l {Item::}{width}
95 QDeclarativeEngine *engine = new QDeclarativeEngine;
96 QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
98 QObject *myObject = component.create();
99 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject);
100 int width = item->width(); // width = 200
104 \section2 Network Components
106 If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a
107 network resource, the QDeclarativeComponent has to fetch the network data before it is able to create
108 objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading}
109 \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component
110 is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}.
112 The following example shows how to load a QML file from a network resource. After creating
113 the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the
114 QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
115 directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the
116 component has been cached and is ready immediately.
119 MyApplication::MyApplication()
122 component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
123 if (component->isLoading())
124 QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
125 this, SLOT(continueLoading()));
130 void MyApplication::continueLoading()
132 if (component->isError()) {
133 qWarning() << component->errors();
135 QObject *myObject = component->create();
140 \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code}
144 \qmlclass Component QDeclarativeComponent
145 \ingroup qml-utility-elements
147 \brief The Component element encapsulates a QML component definition.
149 Components are reusable, encapsulated QML elements with well-defined interfaces.
151 Components are often defined by \l {qdeclarativedocuments.html}{component files} -
152 that is, \c .qml files. The \e Component element essentially allows QML components
153 to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
154 This may be useful for reusing a small component within a QML file, or for defining
155 a component that logically belongs with other QML components within a file.
157 For example, here is a component that is used by multiple \l Loader objects.
158 It contains a single item, a \l Rectangle:
160 \snippet doc/src/snippets/declarative/component.qml 0
162 Notice that while a \l Rectangle by itself would be automatically
163 rendered and displayed, this is not the case for the above rectangle
164 because it is defined inside a \c Component. The component encapsulates the
165 QML elements within, as if they were defined in a separate QML
166 file, and is not loaded until requested (in this case, by the
167 two \l Loader objects).
169 Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
170 A QML document has a single top-level item that defines the behaviors and
171 properties of that component, and cannot define properties or behaviors outside
172 of that top-level item. In the same way, a \c Component definition contains a single
173 top level item (which in the above example is a \l Rectangle) and cannot define any
174 data outside of this item, with the exception of an \e id (which in the above example
177 The \c Component element is commonly used to provide graphical components
178 for views. For example, the ListView::delegate property requires a \c Component
179 to specify how each list item is to be displayed.
181 \c Component objects can also be created dynamically using
182 \l{QML:Qt::createComponent()}{Qt.createComponent()}.
186 \qmlattachedsignal Component::onCompleted()
188 Emitted after component "startup" has completed. This can be used to
189 execute script code at startup, once the full QML environment has been
192 The \c {Component::onCompleted} attached property can be applied to
193 any element. The order of running the \c onCompleted scripts is
198 Component.onCompleted: console.log("Completed Running!")
200 Component.onCompleted: console.log("Nested Completed Running!")
207 \qmlattachedsignal Component::onDestruction()
209 Emitted as the component begins destruction. This can be used to undo
210 work done in the onCompleted signal, or other imperative code in your
213 The \c {Component::onDestruction} attached property can be applied to
214 any element. However, it applies to the destruction of the component as
215 a whole, and not the destruction of the specific object. The order of
216 running the \c onDestruction scripts is undefined.
220 Component.onDestruction: console.log("Destruction Beginning!")
222 Component.onDestruction: console.log("Nested Destruction Beginning!")
231 \enum QDeclarativeComponent::Status
233 Specifies the loading status of the QDeclarativeComponent.
235 \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content.
236 \value Ready This QDeclarativeComponent is ready and create() may be called.
237 \value Loading This QDeclarativeComponent is loading network data.
238 \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}.
241 void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *)
243 Q_Q(QDeclarativeComponent);
247 fromTypeData(typeData);
250 emit q->statusChanged(q->status());
253 void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p)
255 Q_Q(QDeclarativeComponent);
259 emit q->progressChanged(p);
262 void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data)
264 url = data->finalUrl();
265 QDeclarativeCompiledData *c = data->compiledData();
268 Q_ASSERT(data->isError());
269 state.errors = data->errors();
277 void QDeclarativeComponentPrivate::clear()
280 typeData->unregisterCallback(this);
294 QDeclarativeComponent::QDeclarativeComponent(QObject *parent)
295 : QObject(*(new QDeclarativeComponentPrivate), parent)
300 Destruct the QDeclarativeComponent.
302 QDeclarativeComponent::~QDeclarativeComponent()
304 Q_D(QDeclarativeComponent);
306 if (d->state.completePending) {
307 qWarning("QDeclarativeComponent: Component destroyed while completion pending");
312 d->typeData->unregisterCallback(d);
313 d->typeData->release();
320 \qmlproperty enumeration Component::status
321 This property holds the status of component loading. It can be one of:
323 \o Component.Null - no data is available for the component
324 \o Component.Ready - the component has been loaded, and can be used to create instances.
325 \o Component.Loading - the component is currently being loaded
326 \o Component.Error - an error occurred while loading the component.
327 Calling errorString() will provide a human-readable description of any errors.
332 \property QDeclarativeComponent::status
333 The component's current \l{QDeclarativeComponent::Status} {status}.
335 QDeclarativeComponent::Status QDeclarativeComponent::status() const
337 Q_D(const QDeclarativeComponent);
341 else if (!d->state.errors.isEmpty())
343 else if (d->engine && d->cc)
350 Returns true if status() == QDeclarativeComponent::Null.
352 bool QDeclarativeComponent::isNull() const
354 return status() == Null;
358 Returns true if status() == QDeclarativeComponent::Ready.
360 bool QDeclarativeComponent::isReady() const
362 return status() == Ready;
366 Returns true if status() == QDeclarativeComponent::Error.
368 bool QDeclarativeComponent::isError() const
370 return status() == Error;
374 Returns true if status() == QDeclarativeComponent::Loading.
376 bool QDeclarativeComponent::isLoading() const
378 return status() == Loading;
382 \qmlproperty real Component::progress
383 The progress of loading the component, from 0.0 (nothing loaded)
388 \property QDeclarativeComponent::progress
389 The progress of loading the component, from 0.0 (nothing loaded)
392 qreal QDeclarativeComponent::progress() const
394 Q_D(const QDeclarativeComponent);
399 \fn void QDeclarativeComponent::progressChanged(qreal progress)
401 Emitted whenever the component's loading progress changes. \a progress will be the
402 current progress between 0.0 (nothing loaded) and 1.0 (finished).
406 \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status)
408 Emitted whenever the component's status changes. \a status will be the
413 Create a QDeclarativeComponent with no data and give it the specified
414 \a engine and \a parent. Set the data with setData().
416 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent)
417 : QObject(*(new QDeclarativeComponentPrivate), parent)
419 Q_D(QDeclarativeComponent);
424 Create a QDeclarativeComponent from the given \a url and give it the
425 specified \a parent and \a engine.
427 Ensure that the URL provided is full and correct, in particular, use
428 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
432 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent)
433 : QObject(*(new QDeclarativeComponentPrivate), parent)
435 Q_D(QDeclarativeComponent);
441 Create a QDeclarativeComponent from the given \a fileName and give it the specified
442 \a parent and \a engine.
446 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName,
448 : QObject(*(new QDeclarativeComponentPrivate), parent)
450 Q_D(QDeclarativeComponent);
452 loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
458 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, QObject *parent)
459 : QObject(*(new QDeclarativeComponentPrivate), parent)
461 Q_D(QDeclarativeComponent);
471 Sets the QDeclarativeComponent to use the given QML \a data. If \a url
472 is provided, it is used to set the component name and to provide
473 a base path for items resolved by this component.
475 void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url)
477 Q_D(QDeclarativeComponent);
483 QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url);
485 if (typeData->isCompleteOrError()) {
486 d->fromTypeData(typeData);
488 d->typeData = typeData;
489 d->typeData->registerCallback(d);
493 emit statusChanged(status());
494 emit progressChanged(d->progress);
498 Returns the QDeclarativeContext the component was created in. This is only
499 valid for components created directly from QML.
501 QDeclarativeContext *QDeclarativeComponent::creationContext() const
503 Q_D(const QDeclarativeComponent);
504 if(d->creationContext)
505 return d->creationContext->asQDeclarativeContext();
507 return qmlContext(this);
511 Load the QDeclarativeComponent from the provided \a url.
513 Ensure that the URL provided is full and correct, in particular, use
514 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
516 void QDeclarativeComponent::loadUrl(const QUrl &url)
518 Q_D(QDeclarativeComponent);
522 if ((url.isRelative() && !url.isEmpty())
523 || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
524 d->url = d->engine->baseUrl().resolved(url);
529 QDeclarativeError error;
530 error.setDescription(tr("Invalid empty URL"));
531 d->state.errors << error;
535 QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url);
537 if (data->isCompleteOrError()) {
538 d->fromTypeData(data);
542 d->typeData->registerCallback(d);
543 d->progress = data->progress();
546 emit statusChanged(status());
547 emit progressChanged(d->progress);
551 Return the list of errors that occurred during the last compile or create
552 operation. An empty list is returned if isError() is not set.
554 QList<QDeclarativeError> QDeclarativeComponent::errors() const
556 Q_D(const QDeclarativeComponent);
558 return d->state.errors;
560 return QList<QDeclarativeError>();
564 \qmlmethod string Component::errorString()
566 Returns a human-readable description of any errors.
568 The string includes the file, location, and description of each error.
569 If multiple errors are present they are separated by a newline character.
571 If no errors are present, an empty string is returned.
576 errorString is only meant as a way to get the errors in script
578 QString QDeclarativeComponent::errorString() const
580 Q_D(const QDeclarativeComponent);
584 foreach(const QDeclarativeError &e, d->state.errors) {
585 ret += e.url().toString() + QLatin1Char(':') +
586 QString::number(e.line()) + QLatin1Char(' ') +
587 e.description() + QLatin1Char('\n');
593 \qmlproperty url Component::url
594 The component URL. This is the URL that was used to construct the component.
598 \property QDeclarativeComponent::url
599 The component URL. This is the URL passed to either the constructor,
600 or the loadUrl() or setData() methods.
602 QUrl QDeclarativeComponent::url() const
604 Q_D(const QDeclarativeComponent);
611 QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent)
612 : QObject(dd, parent)
617 \qmlmethod object Component::createObject(Item parent, object properties)
619 Creates and returns an object instance of this component that will have
620 the given \a parent and \a properties. The \a properties argument is optional.
621 Returns null if object creation fails.
623 The object will be created in the same context as the one in which the component
624 was created. This function will always return null when called on components
625 which were not created in QML.
627 If you wish to create an object without setting a parent, specify \c null for
628 the \a parent value. Note that if the returned object is to be displayed, you
629 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
630 property, or else the object will not be visible.
632 If a \a parent is not provided to createObject(), a reference to the returned object must be held so that
633 it is not destroyed by the garbage collector. This is true regardless of whether \l{Item::parent} is set afterwards,
634 since setting the Item parent does not change object ownership; only the graphical parent is changed.
636 As of QtQuick 1.1, this method accepts an optional \a properties argument that specifies a
637 map of initial property values for the created object. These values are applied before object
638 creation is finalized. (This is more efficient than setting property values after object creation,
639 particularly where large sets of property values are defined, and also allows property bindings
640 to be set up before the object is created.)
642 The \a properties argument is specified as a map of property-value items. For example, the code
643 below creates an object with initial \c x and \c y values of 100 and 200, respectively:
646 var component = Qt.createComponent("Button.qml");
647 if (component.status == Component.Ready)
648 component.createObject(parent, {"x": 100, "y": 100});
651 Dynamically created instances can be deleted with the \c destroy() method.
652 See \l {Dynamic Object Management in QML} for more information.
657 A version of create which returns a scriptObject, for use in script.
658 This function will only work on components created in QML.
660 Sets graphics object parent because forgetting to do this is a frequent
663 QScriptValue QDeclarativeComponent::createObject(QObject* parent)
665 Q_D(QDeclarativeComponent);
666 return d->createObject(parent, QScriptValue(QScriptValue::NullValue));
671 Overloadable method allows properties to be set during creation
673 QScriptValue QDeclarativeComponent::createObject(QObject* parent, const QScriptValue& valuemap)
675 Q_D(QDeclarativeComponent);
677 if (!valuemap.isObject() || valuemap.isArray()) {
678 qmlInfo(this) << tr("createObject: value is not an object");
679 return QScriptValue(QScriptValue::NullValue);
681 return d->createObject(parent, valuemap);
684 QScriptValue QDeclarativeComponentPrivate::createObject(QObject *publicParent, const QScriptValue valuemap)
686 Q_Q(QDeclarativeComponent);
687 QDeclarativeContext* ctxt = q->creationContext();
689 ctxt = engine->rootContext();
691 return QScriptValue(QScriptValue::NullValue);
692 QObject* ret = q->beginCreate(ctxt);
695 return QScriptValue(QScriptValue::NullValue);
699 ret->setParent(publicParent);
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, publicParent);
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 QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine);
719 QDeclarativeData::get(ret, true)->setImplicitDestructible();
720 QScriptValue newObject = priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
722 if (valuemap.isObject() && !valuemap.isArray()) {
723 //Iterate through and assign properties
724 QScriptValueIterator it(valuemap);
725 while (it.hasNext()) {
727 QScriptValue prop = newObject;
728 QString propName = it.name();
729 int index = propName.indexOf(QLatin1Char('.'));
731 QString subProp = propName;
734 subProp = propName.mid(lastIndex, index - lastIndex);
735 prop = prop.property(subProp);
736 lastIndex = index + 1;
737 index = propName.indexOf(QLatin1Char('.'), index + 1);
739 prop.setProperty(propName.mid(propName.lastIndexOf(QLatin1Char('.')) + 1), it.value());
741 newObject.setProperty(propName, it.value());
752 Create an object instance from this component. Returns 0 if creation
753 failed. \a context specifies the context within which to create the object
756 If \a context is 0 (the default), it will create the instance in the
757 engine' s \l {QDeclarativeEngine::rootContext()}{root context}.
759 QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
761 Q_D(QDeclarativeComponent);
764 context = d->engine->rootContext();
766 QObject *rv = beginCreate(context);
772 This method provides more advanced control over component instance creation.
773 In general, programmers should use QDeclarativeComponent::create() to create a
776 Create an object instance from this component. Returns 0 if creation
777 failed. \a context specifies the context within which to create the object
780 When QDeclarativeComponent constructs an instance, it occurs in three steps:
782 \i The object hierarchy is created, and constant values are assigned.
783 \i Property bindings are evaluated for the the first time.
784 \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects.
786 QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it
787 only performs step 1. QDeclarativeComponent::completeCreate() must be called to
788 complete steps 2 and 3.
790 This breaking point is sometimes useful when using attached properties to
791 communicate information to an instantiated component, as it allows their
792 initial values to be configured before property bindings take effect.
794 QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
796 Q_D(QDeclarativeComponent);
797 QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
799 QDeclarativeData *ddata = QDeclarativeData::get(rv);
801 ddata->indestructible = true;
807 QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
809 Q_Q(QDeclarativeComponent);
811 qWarning("QDeclarativeComponent: Cannot create a component in a null context");
815 if (!context->isValid()) {
816 qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
820 if (context->engine != engine) {
821 qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
825 if (state.completePending) {
826 qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous");
831 qWarning("QDeclarativeComponent: Component is not ready");
835 return begin(context, creationContext, cc, start, &state, 0, bindings);
839 Try to do what's necessary for a reasonable display of the type
840 name, but no more (just enough for the client to do more extensive cleanup).
842 Should only be called when debugging is enabled.
844 static inline QString buildTypeNameForDebug(const QMetaObject *metaObject)
846 static const QString qmlMarker(QLatin1String("_QML"));
847 static const QChar underscore(QLatin1Char('_'));
848 static const QChar asterisk(QLatin1Char('*'));
849 QDeclarativeType *type = QDeclarativeMetaType::qmlType(metaObject);
850 QString typeName = type ? QLatin1String(type->qmlTypeName()) : QLatin1String(metaObject->className());
852 //### optimize further?
853 int marker = typeName.indexOf(qmlMarker);
854 if (marker != -1 && marker < typeName.count() - 1) {
855 if (typeName[marker + 1] == underscore) {
856 const QString className = typeName.left(marker) + asterisk;
857 type = QDeclarativeMetaType::qmlType(QMetaType::type(className.toLatin1()));
859 typeName = QLatin1String(type->qmlTypeName());
866 QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
867 QDeclarativeContextData *componentCreationContext,
868 QDeclarativeCompiledData *component, int start,
869 ConstructionState *state, QList<QDeclarativeError> *errors,
870 const QBitField &bindings)
872 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
873 bool isRoot = !enginePriv->inBeginCreate;
875 Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
876 Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
879 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
881 QDeclarativeContextData *ctxt = new QDeclarativeContextData;
882 ctxt->isInternal = true;
883 ctxt->url = component->url;
884 ctxt->imports = component->importCache;
886 // Nested global imports
887 if (componentCreationContext && start != -1)
888 ctxt->importedScripts = componentCreationContext->importedScripts;
890 component->importCache->addref();
891 ctxt->setParent(parentContext);
893 enginePriv->inBeginCreate = true;
896 enginePriv->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
897 QObject *rv = vme.run(ctxt, component, start, bindings);
898 enginePriv->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
901 if(errors) *errors = vme.errors();
902 else state->errors = vme.errors();
906 enginePriv->inBeginCreate = false;
908 state->bindValues = enginePriv->bindValues;
909 state->parserStatus = enginePriv->parserStatus;
910 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
911 state->componentAttached = enginePriv->componentAttached;
912 if (state->componentAttached)
913 state->componentAttached->prev = &state->componentAttached;
915 enginePriv->componentAttached = 0;
916 enginePriv->bindValues.clear();
917 enginePriv->parserStatus.clear();
918 enginePriv->finalizedParserStatus.clear();
919 state->completePending = true;
920 enginePriv->inProgressCreations++;
923 if (enginePriv->isDebugging && rv) {
924 if (!parentContext->isInternal)
925 parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
926 QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
928 QDeclarativeDebugTrace::rangeData(QDeclarativeDebugTrace::Creating, buildTypeNameForDebug(rv->metaObject()));
929 QDeclarativeData *data = QDeclarativeData::get(rv);
930 QDeclarativeDebugTrace::rangeLocation(QDeclarativeDebugTrace::Creating, component->url, data ? data->lineNumber : -1);
937 void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
938 QObject *object, ConstructionState *state)
940 bool isRoot = !enginePriv->inBeginCreate;
941 enginePriv->inBeginCreate = true;
944 vme.runDeferred(object);
947 state->errors = vme.errors();
950 enginePriv->inBeginCreate = false;
952 state->bindValues = enginePriv->bindValues;
953 state->parserStatus = enginePriv->parserStatus;
954 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
955 state->componentAttached = enginePriv->componentAttached;
956 if (state->componentAttached)
957 state->componentAttached->prev = &state->componentAttached;
959 enginePriv->componentAttached = 0;
960 enginePriv->bindValues.clear();
961 enginePriv->parserStatus.clear();
962 enginePriv->finalizedParserStatus.clear();
963 state->completePending = true;
964 enginePriv->inProgressCreations++;
968 void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
970 if (state->completePending) {
972 for (int ii = 0; ii < state->bindValues.count(); ++ii) {
973 QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
974 state->bindValues.at(ii);
975 for (int jj = 0; jj < bv.count; ++jj) {
978 bv.at(jj)->m_mePtr = 0;
979 bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
980 QDeclarativePropertyPrivate::DontRemoveBinding);
983 QDeclarativeEnginePrivate::clear(bv);
986 for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
987 QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
988 state->parserStatus.at(ii);
990 for (int jj = ps.count - 1; jj >= 0; --jj) {
991 QDeclarativeParserStatus *status = ps.at(jj);
992 if (status && status->d) {
994 status->componentComplete();
997 QDeclarativeEnginePrivate::clear(ps);
1000 for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
1001 QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
1002 QObject *obj = status.first;
1004 void *args[] = { 0 };
1005 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
1006 status.second, args);
1010 //componentComplete() can register additional finalization objects
1011 //that are then never handled. Handle them manually here.
1012 if (1 == enginePriv->inProgressCreations) {
1013 for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) {
1014 QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii);
1015 QObject *obj = status.first;
1017 void *args[] = { 0 };
1018 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
1019 status.second, args);
1022 enginePriv->finalizedParserStatus.clear();
1025 while (state->componentAttached) {
1026 QDeclarativeComponentAttached *a = state->componentAttached;
1028 QDeclarativeData *d = QDeclarativeData::get(a->parent());
1030 Q_ASSERT(d->context);
1031 a->add(&d->context->componentAttached);
1032 emit a->completed();
1035 state->bindValues.clear();
1036 state->parserStatus.clear();
1037 state->finalizedParserStatus.clear();
1038 state->completePending = false;
1040 enginePriv->inProgressCreations--;
1041 if (0 == enginePriv->inProgressCreations) {
1042 while (enginePriv->erroredBindings) {
1043 enginePriv->warning(enginePriv->erroredBindings->error);
1044 enginePriv->erroredBindings->removeError();
1051 This method provides more advanced control over component instance creation.
1052 In general, programmers should use QDeclarativeComponent::create() to create a
1055 Complete a component creation begin with QDeclarativeComponent::beginCreate().
1057 void QDeclarativeComponent::completeCreate()
1059 Q_D(QDeclarativeComponent);
1060 d->completeCreate();
1063 void QDeclarativeComponentPrivate::completeCreate()
1065 if (state.completePending) {
1066 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
1067 complete(ep, &state);
1069 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
1073 QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent)
1074 : QObject(parent), prev(0), next(0)
1078 QDeclarativeComponentAttached::~QDeclarativeComponentAttached()
1080 if (prev) *prev = next;
1081 if (next) next->prev = prev;
1089 QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj)
1091 QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj);
1093 QDeclarativeEngine *engine = qmlEngine(obj);
1097 if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
1098 QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
1099 a->add(&p->componentAttached);
1101 QDeclarativeData *d = QDeclarativeData::get(obj);
1103 Q_ASSERT(d->context);
1104 a->add(&d->context->componentAttached);