source: trunk/src/declarative/qml/qdeclarativecomponent.cpp@ 949

Last change on this file since 949 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 31.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtDeclarative module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qdeclarativecomponent.h"
43#include "private/qdeclarativecomponent_p.h"
44
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
58#include <QStack>
59#include <QStringList>
60#include <QtCore/qdebug.h>
61#include <QApplication>
62
63QT_BEGIN_NAMESPACE
64
65class QByteArray;
66
67/*!
68 \class QDeclarativeComponent
69 \since 4.7
70 \brief The QDeclarativeComponent class encapsulates a QML component definition.
71 \mainclass
72
73 Components are reusable, encapsulated QML elements with well-defined interfaces.
74 They are often defined in \l {qdeclarativedocuments.html}{Component Files}.
75
76 A QDeclarativeComponent instance can be created from a QML file.
77 For example, if there is a \c main.qml file like this:
78
79 \qml
80 import QtQuick 1.0
81
82 Item {
83 width: 200
84 height: 200
85 }
86 \endqml
87
88 The following code loads this QML file as a component, creates an instance of
89 this component using create(), and then queries the \l Item's \l {Item::}{width}
90 value:
91
92 \code
93 QDeclarativeEngine *engine = new QDeclarativeEngine;
94 QDeclarativeComponent component(engine, QUrl::fromLocalFile("main.qml"));
95
96 QObject *myObject = component.create();
97 QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(myObject);
98 int width = item->width(); // width = 200
99 \endcode
100
101
102 \section2 Network Components
103
104 If the URL passed to QDeclarativeComponent is a network resource, or if the QML document references a
105 network resource, the QDeclarativeComponent has to fetch the network data before it is able to create
106 objects. In this case, the QDeclarativeComponent will have a \l {QDeclarativeComponent::Loading}{Loading}
107 \l {QDeclarativeComponent::status()}{status}. An application will have to wait until the component
108 is \l {QDeclarativeComponent::Ready}{Ready} before calling \l {QDeclarativeComponent::create()}.
109
110 The following example shows how to load a QML file from a network resource. After creating
111 the QDeclarativeComponent, it tests whether the component is loading. If it is, it connects to the
112 QDeclarativeComponent::statusChanged() signal and otherwise calls the \c {continueLoading()} method
113 directly. Note that QDeclarativeComponent::isLoading() may be false for a network component if the
114 component has been cached and is ready immediately.
115
116 \code
117 MyApplication::MyApplication()
118 {
119 // ...
120 component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
121 if (component->isLoading())
122 QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)),
123 this, SLOT(continueLoading()));
124 else
125 continueLoading();
126 }
127
128 void MyApplication::continueLoading()
129 {
130 if (component->isError()) {
131 qWarning() << component->errors();
132 } else {
133 QObject *myObject = component->create();
134 }
135 }
136 \endcode
137
138 \sa {Using QML in C++ Applications}, {Integrating QML with existing Qt UI code}
139*/
140
141/*!
142 \qmlclass Component QDeclarativeComponent
143 \ingroup qml-utility-elements
144 \since 4.7
145 \brief The Component element encapsulates a QML component definition.
146
147 Components are reusable, encapsulated QML elements with well-defined interfaces.
148
149 Components are often defined by \l {qdeclarativedocuments.html}{component files} -
150 that is, \c .qml files. The \e Component element essentially allows QML components
151 to be defined inline, within a \l {QML Document}{QML document}, rather than as a separate QML file.
152 This may be useful for reusing a small component within a QML file, or for defining
153 a component that logically belongs with other QML components within a file.
154
155 For example, here is a component that is used by multiple \l Loader objects.
156 It contains a single item, a \l Rectangle:
157
158 \snippet doc/src/snippets/declarative/component.qml 0
159
160 Notice that while a \l Rectangle by itself would be automatically
161 rendered and displayed, this is not the case for the above rectangle
162 because it is defined inside a \c Component. The component encapsulates the
163 QML elements within, as if they were defined in a separate QML
164 file, and is not loaded until requested (in this case, by the
165 two \l Loader objects).
166
167 Defining a \c Component is similar to defining a \l {QML Document}{QML document}.
168 A QML document has a single top-level item that defines the behaviors and
169 properties of that component, and cannot define properties or behaviors outside
170 of that top-level item. In the same way, a \c Component definition contains a single
171 top level item (which in the above example is a \l Rectangle) and cannot define any
172 data outside of this item, with the exception of an \e id (which in the above example
173 is \e redSquare).
174
175 The \c Component element is commonly used to provide graphical components
176 for views. For example, the ListView::delegate property requires a \c Component
177 to specify how each list item is to be displayed.
178
179 \c Component objects can also be created dynamically using
180 \l{QML:Qt::createComponent()}{Qt.createComponent()}.
181*/
182
183/*!
184 \qmlattachedsignal Component::onCompleted()
185
186 Emitted after component "startup" has completed. This can be used to
187 execute script code at startup, once the full QML environment has been
188 established.
189
190 The \c {Component::onCompleted} attached property can be applied to
191 any element. The order of running the \c onCompleted scripts is
192 undefined.
193
194 \qml
195 Rectangle {
196 Component.onCompleted: console.log("Completed Running!")
197 Rectangle {
198 Component.onCompleted: console.log("Nested Completed Running!")
199 }
200 }
201 \endqml
202*/
203
204/*!
205 \qmlattachedsignal Component::onDestruction()
206
207 Emitted as the component begins destruction. This can be used to undo
208 work done in the onCompleted signal, or other imperative code in your
209 application.
210
211 The \c {Component::onDestruction} attached property can be applied to
212 any element. However, it applies to the destruction of the component as
213 a whole, and not the destruction of the specific object. The order of
214 running the \c onDestruction scripts is undefined.
215
216 \qml
217 Rectangle {
218 Component.onDestruction: console.log("Destruction Beginning!")
219 Rectangle {
220 Component.onDestruction: console.log("Nested Destruction Beginning!")
221 }
222 }
223 \endqml
224
225 \sa QtDeclarative
226*/
227
228/*!
229 \enum QDeclarativeComponent::Status
230
231 Specifies the loading status of the QDeclarativeComponent.
232
233 \value Null This QDeclarativeComponent has no data. Call loadUrl() or setData() to add QML content.
234 \value Ready This QDeclarativeComponent is ready and create() may be called.
235 \value Loading This QDeclarativeComponent is loading network data.
236 \value Error An error has occurred. Call errors() to retrieve a list of \{QDeclarativeError}{errors}.
237*/
238
239void QDeclarativeComponentPrivate::typeDataReady(QDeclarativeTypeData *)
240{
241 Q_Q(QDeclarativeComponent);
242
243 Q_ASSERT(typeData);
244
245 fromTypeData(typeData);
246 typeData = 0;
247
248 emit q->statusChanged(q->status());
249}
250
251void QDeclarativeComponentPrivate::typeDataProgress(QDeclarativeTypeData *, qreal p)
252{
253 Q_Q(QDeclarativeComponent);
254
255 progress = p;
256
257 emit q->progressChanged(p);
258}
259
260void QDeclarativeComponentPrivate::fromTypeData(QDeclarativeTypeData *data)
261{
262 url = data->finalUrl();
263 QDeclarativeCompiledData *c = data->compiledData();
264
265 if (!c) {
266 Q_ASSERT(data->isError());
267 state.errors = data->errors();
268 } else {
269 cc = c;
270 }
271
272 data->release();
273}
274
275void QDeclarativeComponentPrivate::clear()
276{
277 if (typeData) {
278 typeData->unregisterCallback(this);
279 typeData->release();
280 typeData = 0;
281 }
282
283 if (cc) {
284 cc->release();
285 cc = 0;
286 }
287}
288
289/*!
290 \internal
291*/
292QDeclarativeComponent::QDeclarativeComponent(QObject *parent)
293 : QObject(*(new QDeclarativeComponentPrivate), parent)
294{
295}
296
297/*!
298 Destruct the QDeclarativeComponent.
299*/
300QDeclarativeComponent::~QDeclarativeComponent()
301{
302 Q_D(QDeclarativeComponent);
303
304 if (d->state.completePending) {
305 qWarning("QDeclarativeComponent: Component destroyed while completion pending");
306 d->completeCreate();
307 }
308
309 if (d->typeData) {
310 d->typeData->unregisterCallback(d);
311 d->typeData->release();
312 }
313 if (d->cc)
314 d->cc->release();
315}
316
317/*!
318 \qmlproperty enumeration Component::status
319 This property holds the status of component loading. It can be one of:
320 \list
321 \o Component.Null - no data is available for the component
322 \o Component.Ready - the component has been loaded, and can be used to create instances.
323 \o Component.Loading - the component is currently being loaded
324 \o Component.Error - an error occurred while loading the component.
325 Calling errorString() will provide a human-readable description of any errors.
326 \endlist
327 */
328
329/*!
330 \property QDeclarativeComponent::status
331 The component's current \l{QDeclarativeComponent::Status} {status}.
332 */
333QDeclarativeComponent::Status QDeclarativeComponent::status() const
334{
335 Q_D(const QDeclarativeComponent);
336
337 if (d->typeData)
338 return Loading;
339 else if (!d->state.errors.isEmpty())
340 return Error;
341 else if (d->engine && d->cc)
342 return Ready;
343 else
344 return Null;
345}
346
347/*!
348 Returns true if status() == QDeclarativeComponent::Null.
349*/
350bool QDeclarativeComponent::isNull() const
351{
352 return status() == Null;
353}
354
355/*!
356 Returns true if status() == QDeclarativeComponent::Ready.
357*/
358bool QDeclarativeComponent::isReady() const
359{
360 return status() == Ready;
361}
362
363/*!
364 Returns true if status() == QDeclarativeComponent::Error.
365*/
366bool QDeclarativeComponent::isError() const
367{
368 return status() == Error;
369}
370
371/*!
372 Returns true if status() == QDeclarativeComponent::Loading.
373*/
374bool QDeclarativeComponent::isLoading() const
375{
376 return status() == Loading;
377}
378
379/*!
380 \qmlproperty real Component::progress
381 The progress of loading the component, from 0.0 (nothing loaded)
382 to 1.0 (finished).
383*/
384
385/*!
386 \property QDeclarativeComponent::progress
387 The progress of loading the component, from 0.0 (nothing loaded)
388 to 1.0 (finished).
389*/
390qreal QDeclarativeComponent::progress() const
391{
392 Q_D(const QDeclarativeComponent);
393 return d->progress;
394}
395
396/*!
397 \fn void QDeclarativeComponent::progressChanged(qreal progress)
398
399 Emitted whenever the component's loading progress changes. \a progress will be the
400 current progress between 0.0 (nothing loaded) and 1.0 (finished).
401*/
402
403/*!
404 \fn void QDeclarativeComponent::statusChanged(QDeclarativeComponent::Status status)
405
406 Emitted whenever the component's status changes. \a status will be the
407 new status.
408*/
409
410/*!
411 Create a QDeclarativeComponent with no data and give it the specified
412 \a engine and \a parent. Set the data with setData().
413*/
414QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QObject *parent)
415 : QObject(*(new QDeclarativeComponentPrivate), parent)
416{
417 Q_D(QDeclarativeComponent);
418 d->engine = engine;
419}
420
421/*!
422 Create a QDeclarativeComponent from the given \a url and give it the
423 specified \a parent and \a engine.
424
425 Ensure that the URL provided is full and correct, in particular, use
426 \l QUrl::fromLocalFile() when loading a file from the local filesystem.
427
428 \sa loadUrl()
429*/
430QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QUrl &url, QObject *parent)
431: QObject(*(new QDeclarativeComponentPrivate), parent)
432{
433 Q_D(QDeclarativeComponent);
434 d->engine = engine;
435 loadUrl(url);
436}
437
438/*!
439 Create a QDeclarativeComponent from the given \a fileName and give it the specified
440 \a parent and \a engine.
441
442 \sa loadUrl()
443*/
444QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, const QString &fileName,
445 QObject *parent)
446: QObject(*(new QDeclarativeComponentPrivate), parent)
447{
448 Q_D(QDeclarativeComponent);
449 d->engine = engine;
450 loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)));
451}
452
453/*!
454 \internal
455*/
456QDeclarativeComponent::QDeclarativeComponent(QDeclarativeEngine *engine, QDeclarativeCompiledData *cc, int start, int count, QObject *parent)
457 : QObject(*(new QDeclarativeComponentPrivate), parent)
458{
459 Q_D(QDeclarativeComponent);
460 d->engine = engine;
461 d->cc = cc;
462 cc->addref();
463 d->start = start;
464 d->count = count;
465 d->url = cc->url;
466 d->progress = 1.0;
467}
468
469/*!
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.
473*/
474void QDeclarativeComponent::setData(const QByteArray &data, const QUrl &url)
475{
476 Q_D(QDeclarativeComponent);
477
478 d->clear();
479
480 d->url = url;
481
482 QDeclarativeTypeData *typeData = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(data, url);
483
484 if (typeData->isCompleteOrError()) {
485 d->fromTypeData(typeData);
486 } else {
487 d->typeData = typeData;
488 d->typeData->registerCallback(d);
489 }
490
491 d->progress = 1.0;
492 emit statusChanged(status());
493 emit progressChanged(d->progress);
494}
495
496/*!
497Returns the QDeclarativeContext the component was created in. This is only
498valid for components created directly from QML.
499*/
500QDeclarativeContext *QDeclarativeComponent::creationContext() const
501{
502 Q_D(const QDeclarativeComponent);
503 if(d->creationContext)
504 return d->creationContext->asQDeclarativeContext();
505
506 return qmlContext(this);
507}
508
509/*!
510 Load the QDeclarativeComponent from the provided \a url.
511
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.
514*/
515void QDeclarativeComponent::loadUrl(const QUrl &url)
516{
517 Q_D(QDeclarativeComponent);
518
519 d->clear();
520
521 if ((url.isRelative() && !url.isEmpty())
522 || url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929
523 d->url = d->engine->baseUrl().resolved(url);
524 else
525 d->url = url;
526
527 if (url.isEmpty()) {
528 QDeclarativeError error;
529 error.setDescription(tr("Invalid empty URL"));
530 d->state.errors << error;
531 return;
532 }
533
534 QDeclarativeTypeData *data = QDeclarativeEnginePrivate::get(d->engine)->typeLoader.get(d->url);
535
536 if (data->isCompleteOrError()) {
537 d->fromTypeData(data);
538 d->progress = 1.0;
539 } else {
540 d->typeData = data;
541 d->typeData->registerCallback(d);
542 d->progress = data->progress();
543 }
544
545 emit statusChanged(status());
546 emit progressChanged(d->progress);
547}
548
549/*!
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.
552*/
553QList<QDeclarativeError> QDeclarativeComponent::errors() const
554{
555 Q_D(const QDeclarativeComponent);
556 if (isError())
557 return d->state.errors;
558 else
559 return QList<QDeclarativeError>();
560}
561
562/*!
563 \qmlmethod string Component::errorString()
564
565 Returns a human-readable description of any errors.
566
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.
569
570 If no errors are present, an empty string is returned.
571*/
572
573/*!
574 \internal
575 errorString is only meant as a way to get the errors in script
576*/
577QString QDeclarativeComponent::errorString() const
578{
579 Q_D(const QDeclarativeComponent);
580 QString ret;
581 if(!isError())
582 return ret;
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');
587 }
588 return ret;
589}
590
591/*!
592 \qmlproperty url Component::url
593 The component URL. This is the URL that was used to construct the component.
594*/
595
596/*!
597 \property QDeclarativeComponent::url
598 The component URL. This is the URL passed to either the constructor,
599 or the loadUrl() or setData() methods.
600*/
601QUrl QDeclarativeComponent::url() const
602{
603 Q_D(const QDeclarativeComponent);
604 return d->url;
605}
606
607/*!
608 \internal
609*/
610QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, QObject *parent)
611 : QObject(dd, parent)
612{
613}
614
615/*!
616 \qmlmethod object Component::createObject(Item parent)
617
618 Creates and returns an object instance of this component that will have the given
619 \a parent. Returns null if object creation fails.
620
621 The object will be created in the same context as the one in which the component
622 was created. This function will always return null when called on components
623 which were not created in QML.
624
625 If you wish to create an object without setting a parent, specify \c null for
626 the \a parent value. Note that if the returned object is to be displayed, you
627 must provide a valid \a parent value or set the returned object's \l{Item::parent}{parent}
628 property, or else the object will not be visible.
629
630 Dynamically created instances can be deleted with the \c destroy() method.
631 See \l {Dynamic Object Management in QML} for more information.
632*/
633
634/*!
635 \internal
636 A version of create which returns a scriptObject, for use in script.
637 This function will only work on components created in QML.
638
639 Sets graphics object parent because forgetting to do this is a frequent
640 and serious problem.
641*/
642QScriptValue QDeclarativeComponent::createObject(QObject* parent)
643{
644 Q_D(QDeclarativeComponent);
645 QDeclarativeContext* ctxt = creationContext();
646 if(!ctxt && d->engine)
647 ctxt = d->engine->rootContext();
648 if (!ctxt)
649 return QScriptValue(QScriptValue::NullValue);
650 QObject* ret = beginCreate(ctxt);
651 if (!ret) {
652 completeCreate();
653 return QScriptValue(QScriptValue::NullValue);
654 }
655
656 if (parent) {
657 ret->setParent(parent);
658 QList<QDeclarativePrivate::AutoParentFunction> functions = QDeclarativeMetaType::parentFunctions();
659
660 bool needParent = false;
661
662 for (int ii = 0; ii < functions.count(); ++ii) {
663 QDeclarativePrivate::AutoParentResult res = functions.at(ii)(ret, parent);
664 if (res == QDeclarativePrivate::Parented) {
665 needParent = false;
666 break;
667 } else if (res == QDeclarativePrivate::IncompatibleParent) {
668 needParent = true;
669 }
670 }
671
672 if (needParent)
673 qWarning("QDeclarativeComponent: Created graphical object was not placed in the graphics scene.");
674 }
675 completeCreate();
676
677 QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(d->engine);
678 QDeclarativeData::get(ret, true)->setImplicitDestructible();
679 return priv->objectClass->newQObject(ret, QMetaType::QObjectStar);
680}
681
682/*!
683 Create an object instance from this component. Returns 0 if creation
684 failed. \a context specifies the context within which to create the object
685 instance.
686
687 If \a context is 0 (the default), it will create the instance in the
688 engine' s \l {QDeclarativeEngine::rootContext()}{root context}.
689*/
690QObject *QDeclarativeComponent::create(QDeclarativeContext *context)
691{
692 Q_D(QDeclarativeComponent);
693
694 if (!context)
695 context = d->engine->rootContext();
696
697 QObject *rv = beginCreate(context);
698 completeCreate();
699 return rv;
700}
701
702/*!
703 This method provides more advanced control over component instance creation.
704 In general, programmers should use QDeclarativeComponent::create() to create a
705 component.
706
707 Create an object instance from this component. Returns 0 if creation
708 failed. \a context specifies the context within which to create the object
709 instance.
710
711 When QDeclarativeComponent constructs an instance, it occurs in three steps:
712 \list 1
713 \i The object hierarchy is created, and constant values are assigned.
714 \i Property bindings are evaluated for the the first time.
715 \i If applicable, QDeclarativeParserStatus::componentComplete() is called on objects.
716 \endlist
717 QDeclarativeComponent::beginCreate() differs from QDeclarativeComponent::create() in that it
718 only performs step 1. QDeclarativeComponent::completeCreate() must be called to
719 complete steps 2 and 3.
720
721 This breaking point is sometimes useful when using attached properties to
722 communicate information to an instantiated component, as it allows their
723 initial values to be configured before property bindings take effect.
724*/
725QObject *QDeclarativeComponent::beginCreate(QDeclarativeContext *context)
726{
727 Q_D(QDeclarativeComponent);
728 QObject *rv = d->beginCreate(context?QDeclarativeContextData::get(context):0, QBitField());
729 if (rv) {
730 QDeclarativeData *ddata = QDeclarativeData::get(rv);
731 Q_ASSERT(ddata);
732 ddata->indestructible = true;
733 }
734 return rv;
735}
736
737QObject *
738QDeclarativeComponentPrivate::beginCreate(QDeclarativeContextData *context, const QBitField &bindings)
739{
740 Q_Q(QDeclarativeComponent);
741 if (!context) {
742 qWarning("QDeclarativeComponent: Cannot create a component in a null context");
743 return 0;
744 }
745
746 if (!context->isValid()) {
747 qWarning("QDeclarativeComponent: Cannot create a component in an invalid context");
748 return 0;
749 }
750
751 if (context->engine != engine) {
752 qWarning("QDeclarativeComponent: Must create component in context from the same QDeclarativeEngine");
753 return 0;
754 }
755
756 if (state.completePending) {
757 qWarning("QDeclarativeComponent: Cannot create new component instance before completing the previous");
758 return 0;
759 }
760
761 if (!q->isReady()) {
762 qWarning("QDeclarativeComponent: Component is not ready");
763 return 0;
764 }
765
766 return begin(context, creationContext, cc, start, count, &state, 0, bindings);
767}
768
769QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentContext,
770 QDeclarativeContextData *componentCreationContext,
771 QDeclarativeCompiledData *component, int start, int count,
772 ConstructionState *state, QList<QDeclarativeError> *errors,
773 const QBitField &bindings)
774{
775 QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(parentContext->engine);
776 bool isRoot = !enginePriv->inBeginCreate;
777
778 Q_ASSERT(!isRoot || state); // Either this isn't a root component, or a state data must be provided
779 Q_ASSERT((state != 0) ^ (errors != 0)); // One of state or errors (but not both) must be provided
780
781 if (isRoot)
782 QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Creating);
783
784 QDeclarativeContextData *ctxt = new QDeclarativeContextData;
785 ctxt->isInternal = true;
786 ctxt->url = component->url;
787 ctxt->imports = component->importCache;
788
789 // Nested global imports
790 if (componentCreationContext && start != -1)
791 ctxt->importedScripts = componentCreationContext->importedScripts;
792
793 component->importCache->addref();
794 ctxt->setParent(parentContext);
795
796 enginePriv->inBeginCreate = true;
797
798 QDeclarativeVME vme;
799 QObject *rv = vme.run(ctxt, component, start, count, bindings);
800
801 if (vme.isError()) {
802 if(errors) *errors = vme.errors();
803 else state->errors = vme.errors();
804 }
805
806 if (isRoot) {
807 enginePriv->inBeginCreate = false;
808
809 state->bindValues = enginePriv->bindValues;
810 state->parserStatus = enginePriv->parserStatus;
811 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
812 state->componentAttached = enginePriv->componentAttached;
813 if (state->componentAttached)
814 state->componentAttached->prev = &state->componentAttached;
815
816 enginePriv->componentAttached = 0;
817 enginePriv->bindValues.clear();
818 enginePriv->parserStatus.clear();
819 enginePriv->finalizedParserStatus.clear();
820 state->completePending = true;
821 enginePriv->inProgressCreations++;
822 }
823
824 if (enginePriv->isDebugging && rv) {
825 if (!parentContext->isInternal)
826 parentContext->asQDeclarativeContextPrivate()->instances.append(rv);
827 QDeclarativeEngineDebugServer::instance()->objectCreated(parentContext->engine, rv);
828 }
829
830 return rv;
831}
832
833void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *enginePriv,
834 QObject *object, ConstructionState *state)
835{
836 bool isRoot = !enginePriv->inBeginCreate;
837 enginePriv->inBeginCreate = true;
838
839 QDeclarativeVME vme;
840 vme.runDeferred(object);
841
842 if (vme.isError())
843 state->errors = vme.errors();
844
845 if (isRoot) {
846 enginePriv->inBeginCreate = false;
847
848 state->bindValues = enginePriv->bindValues;
849 state->parserStatus = enginePriv->parserStatus;
850 state->finalizedParserStatus = enginePriv->finalizedParserStatus;
851 state->componentAttached = enginePriv->componentAttached;
852 if (state->componentAttached)
853 state->componentAttached->prev = &state->componentAttached;
854
855 enginePriv->componentAttached = 0;
856 enginePriv->bindValues.clear();
857 enginePriv->parserStatus.clear();
858 enginePriv->finalizedParserStatus.clear();
859 state->completePending = true;
860 enginePriv->inProgressCreations++;
861 }
862}
863
864void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePriv, ConstructionState *state)
865{
866 if (state->completePending) {
867
868 for (int ii = 0; ii < state->bindValues.count(); ++ii) {
869 QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> bv =
870 state->bindValues.at(ii);
871 for (int jj = 0; jj < bv.count; ++jj) {
872 if(bv.at(jj)) {
873 // XXX akennedy
874 bv.at(jj)->m_mePtr = 0;
875 bv.at(jj)->setEnabled(true, QDeclarativePropertyPrivate::BypassInterceptor |
876 QDeclarativePropertyPrivate::DontRemoveBinding);
877 }
878 }
879 QDeclarativeEnginePrivate::clear(bv);
880 }
881
882 for (int ii = 0; ii < state->parserStatus.count(); ++ii) {
883 QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> ps =
884 state->parserStatus.at(ii);
885
886 for (int jj = ps.count - 1; jj >= 0; --jj) {
887 QDeclarativeParserStatus *status = ps.at(jj);
888 if (status && status->d) {
889 status->d = 0;
890 status->componentComplete();
891 }
892 }
893 QDeclarativeEnginePrivate::clear(ps);
894 }
895
896 for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) {
897 QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii);
898 QObject *obj = status.first;
899 if (obj) {
900 void *args[] = { 0 };
901 QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod,
902 status.second, args);
903 }
904 }
905
906 while (state->componentAttached) {
907 QDeclarativeComponentAttached *a = state->componentAttached;
908 a->rem();
909 QDeclarativeData *d = QDeclarativeData::get(a->parent());
910 Q_ASSERT(d);
911 Q_ASSERT(d->context);
912 a->add(&d->context->componentAttached);
913 emit a->completed();
914 }
915
916 state->bindValues.clear();
917 state->parserStatus.clear();
918 state->finalizedParserStatus.clear();
919 state->completePending = false;
920
921 enginePriv->inProgressCreations--;
922 if (0 == enginePriv->inProgressCreations) {
923 while (enginePriv->erroredBindings) {
924 enginePriv->warning(enginePriv->erroredBindings->error);
925 enginePriv->erroredBindings->removeError();
926 }
927 }
928
929 }
930}
931
932/*!
933 This method provides more advanced control over component instance creation.
934 In general, programmers should use QDeclarativeComponent::create() to create a
935 component.
936
937 Complete a component creation begin with QDeclarativeComponent::beginCreate().
938*/
939void QDeclarativeComponent::completeCreate()
940{
941 Q_D(QDeclarativeComponent);
942 d->completeCreate();
943}
944
945void QDeclarativeComponentPrivate::completeCreate()
946{
947 if (state.completePending) {
948 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
949 complete(ep, &state);
950
951 QDeclarativeDebugTrace::endRange(QDeclarativeDebugTrace::Creating);
952 }
953}
954
955QDeclarativeComponentAttached::QDeclarativeComponentAttached(QObject *parent)
956: QObject(parent), prev(0), next(0)
957{
958}
959
960QDeclarativeComponentAttached::~QDeclarativeComponentAttached()
961{
962 if (prev) *prev = next;
963 if (next) next->prev = prev;
964 prev = 0;
965 next = 0;
966}
967
968/*!
969 \internal
970*/
971QDeclarativeComponentAttached *QDeclarativeComponent::qmlAttachedProperties(QObject *obj)
972{
973 QDeclarativeComponentAttached *a = new QDeclarativeComponentAttached(obj);
974
975 QDeclarativeEngine *engine = qmlEngine(obj);
976 if (!engine)
977 return a;
978
979 if (QDeclarativeEnginePrivate::get(engine)->inBeginCreate) {
980 QDeclarativeEnginePrivate *p = QDeclarativeEnginePrivate::get(engine);
981 a->add(&p->componentAttached);
982 } else {
983 QDeclarativeData *d = QDeclarativeData::get(obj);
984 Q_ASSERT(d);
985 Q_ASSERT(d->context);
986 a->add(&d->context->componentAttached);
987 }
988
989 return a;
990}
991
992QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.