diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2011-08-31 14:03:16 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@nokia.com> | 2011-08-31 14:03:16 +0200 |
commit | 20c3575fc39004d6a556820543982f4a6ebef0be (patch) | |
tree | 9d8be9faae42972c85f0e296cc6dcaf27c3fcc4e /src/declarative/items | |
parent | 71478352376022faa9be6d79f2a760c289945ff5 (diff) | |
parent | 3108a36914d59d8a0d15bfdb2b5bbb09aa6e54a2 (diff) |
Merge remote-tracking branch 'origin/master' into refactor
Conflicts:
src/declarative/declarative.pro
Change-Id: I9c6d8447e1254c6acd32fa0775ff6a79d0d66acd
Diffstat (limited to 'src/declarative/items')
-rw-r--r-- | src/declarative/items/qsgloader.cpp | 237 | ||||
-rw-r--r-- | src/declarative/items/qsgloader_p.h | 10 | ||||
-rw-r--r-- | src/declarative/items/qsgloader_p_p.h | 11 |
3 files changed, 251 insertions, 7 deletions
diff --git a/src/declarative/items/qsgloader.cpp b/src/declarative/items/qsgloader.cpp index 999c174ee9..0a0a3b9cc5 100644 --- a/src/declarative/items/qsgloader.cpp +++ b/src/declarative/items/qsgloader.cpp @@ -46,16 +46,21 @@ #include <private/qdeclarativeengine_p.h> #include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativecomponent_p.h> + +#include <private/qv8_p.h> + QT_BEGIN_NAMESPACE QSGLoaderPrivate::QSGLoaderPrivate() : item(0), component(0), ownComponent(false), updatingSize(false), - itemWidthValid(false), itemHeightValid(false) + itemWidthValid(false), itemHeightValid(false), active(true) { } QSGLoaderPrivate::~QSGLoaderPrivate() { + disposeInitialPropertyValues(); } void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &newGeometry, const QRectF &oldGeometry) @@ -72,6 +77,8 @@ void QSGLoaderPrivate::itemGeometryChanged(QSGItem *resizeItem, const QRectF &ne void QSGLoaderPrivate::clear() { + disposeInitialPropertyValues(); + if (ownComponent) { component->deleteLater(); component = 0; @@ -228,6 +235,59 @@ QSGLoader::~QSGLoader() } /*! + \qmlproperty bool QtQuick2::Loader::active + This property is \c true if the Loader is currently active. + The default value for the \l active property is \c true. + + If the Loader is inactive, changing the \l source or \l sourceComponent + will not cause the item to be instantiated until the Loader is made active. + + Setting the value to inactive will cause any \l item loaded by the loader + to be released, but will not affect the \l source or \l sourceComponent. + + The \l status of an inactive loader is always \c Null. + + \sa source, sourceComponent + */ +bool QSGLoader::active() const +{ + Q_D(const QSGLoader); + return d->active; +} + +void QSGLoader::setActive(bool newVal) +{ + Q_D(QSGLoader); + if (d->active != newVal) { + d->active = newVal; + if (newVal == true) { + if (d->loadingFromSource) { + loadFromSource(); + } else { + loadFromSourceComponent(); + } + d->disposeInitialPropertyValues(); // release persistent handles + } else { + if (d->item) { + QSGItemPrivate *p = QSGItemPrivate::get(d->item); + p->removeItemChangeListener(d, QSGItemPrivate::Geometry); + + // We can't delete immediately because our item may have triggered + // the Loader to load a different item. + d->item->setParentItem(0); + d->item->setVisible(false); + d->item->deleteLater(); + d->item = 0; + emit itemChanged(); + } + emit statusChanged(); + } + emit activeChanged(); + } +} + + +/*! \qmlproperty url QtQuick2::Loader::source This property holds the URL of the QML component to instantiate. @@ -248,13 +308,30 @@ QUrl QSGLoader::source() const void QSGLoader::setSource(const QUrl &url) { + setSource(url, true); // clear previous values +} + +void QSGLoader::setSource(const QUrl &url, bool needsClear) +{ Q_D(QSGLoader); if (d->source == url) return; - d->clear(); + if (needsClear) + d->clear(); d->source = url; + d->loadingFromSource = true; + + if (d->active) + loadFromSource(); + else + emit sourceChanged(); +} + +void QSGLoader::loadFromSource() +{ + Q_D(QSGLoader); if (d->source.isEmpty()) { emit sourceChanged(); emit statusChanged(); @@ -308,6 +385,22 @@ void QSGLoader::setSourceComponent(QDeclarativeComponent *comp) d->component = comp; d->ownComponent = false; + d->loadingFromSource = false; + + if (d->active) + loadFromSourceComponent(); + else + emit sourceComponentChanged(); +} + +void QSGLoader::resetSourceComponent() +{ + setSourceComponent(0); +} + +void QSGLoader::loadFromSourceComponent() +{ + Q_D(QSGLoader); if (!d->component) { emit sourceComponentChanged(); emit statusChanged(); @@ -320,9 +413,95 @@ void QSGLoader::setSourceComponent(QDeclarativeComponent *comp) d->load(); } -void QSGLoader::resetSourceComponent() +/*! + \qmlmethod object QtQuick2::Loader::setSource(url source, object properties) + + Creates an object instance of the given \a source component that will have + the given \a properties. The \a properties argument is optional. The instance + will be accessible via the \l item property once loading and instantiation + is complete. + + If the \l active property is \c false at the time when this function is called, + the given \a source component will not be loaded but the \a source and initial + \a properties will be cached. When the loader is made \l active, an instance of + the \a source component will be created with the initial \a properties set. + + Setting the initial property values of an instance of a component in this manner + will \e not trigger any associated \l{Behavior}s. + + Note that the cached \a properties will be cleared if the \l source or \l sourceComponent + is changed after calling this function but prior to setting the loader \l active. + + Example: + \table + \row + \o + \qml + // ExampleComponent.qml + import QtQuick 2.0 + Rectangle { + id: rect + color: "red" + width: 10 + height: 10 + + Behavior on color { + NumberAnimation { + target: rect + property: "width" + to: (rect.width + 20) + duration: 0 + } + } + } + \endqml + \o + \qml + // example.qml + import QtQuick 2.0 + Item { + Loader { + id: squareLoader + onLoaded: console.log(squareLoader.item.width); // prints [10], not [30] + } + + Component.onCompleted: { + squareLoader.setSource("ExampleComponent.qml", { "color": "blue" }); + // will trigger the onLoaded code when complete. + } + } + \endqml + \endtable + + \sa source, active +*/ +void QSGLoader::setSource(QDeclarativeV8Function *args) { - setSourceComponent(0); + Q_ASSERT(args); + Q_D(QSGLoader); + + bool ipvError = false; + args->returnValue(v8::Undefined()); + v8::Handle<v8::Object> ipv = d->extractInitialPropertyValues(args, this, &ipvError); + if (ipvError) + return; + + d->clear(); + QUrl sourceUrl = d->resolveSourceUrl(args); + if (!ipv.IsEmpty()) { + d->initialPropertyValues = qPersistentNew(ipv); + d->qmlGlobalForIpv = qPersistentNew(args->qmlGlobal()); + } + + setSource(sourceUrl, false); // already cleared and set ipv above. +} + +void QSGLoaderPrivate::disposeInitialPropertyValues() +{ + if (!initialPropertyValues.IsEmpty()) + qPersistentDispose(initialPropertyValues); + if (!qmlGlobalForIpv.IsEmpty()) + qPersistentDispose(qmlGlobalForIpv); } void QSGLoaderPrivate::load() @@ -377,7 +556,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() // component to be set to something else. In that case we just // need to cleanup. if (c) - c->completeCreate(); + completeCreateWithInitialPropertyValues(c, obj, initialPropertyValues, qmlGlobalForIpv); delete obj; delete ctxt; return; @@ -402,7 +581,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() delete ctxt; source = QUrl(); } - component->completeCreate(); + completeCreateWithInitialPropertyValues(component, obj, initialPropertyValues, qmlGlobalForIpv); if (ownComponent) emit q->sourceChanged(); else @@ -419,7 +598,7 @@ void QSGLoaderPrivate::_q_sourceLoaded() This property holds the status of QML loading. It can be one of: \list - \o Loader.Null - no QML source has been set + \o Loader.Null - the loader is inactive or no QML source has been set \o Loader.Ready - the QML source has been loaded \o Loader.Loading - the QML source is currently being loaded \o Loader.Error - an error occurred while loading the QML source @@ -458,6 +637,9 @@ QSGLoader::Status QSGLoader::status() const { Q_D(const QSGLoader); + if (!d->active) + return Null; + if (d->component) return static_cast<QSGLoader::Status>(d->component->status()); @@ -548,6 +730,47 @@ void QSGLoader::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeom QSGItem::geometryChanged(newGeometry, oldGeometry); } +QUrl QSGLoaderPrivate::resolveSourceUrl(QDeclarativeV8Function *args) +{ + QV8Engine *v8engine = args->engine(); + QString arg = v8engine->toString((*args)[0]->ToString()); + if (arg.isEmpty()) + return QUrl(); + + QDeclarativeContextData *context = args->context(); + Q_ASSERT(context); + return context->resolvedUrl(QUrl(arg)); +} + +v8::Handle<v8::Object> QSGLoaderPrivate::extractInitialPropertyValues(QDeclarativeV8Function *args, QObject *loader, bool *error) +{ + v8::Local<v8::Object> valuemap; + if (args->Length() >= 2) { + v8::Local<v8::Value> v = (*args)[1]; + if (!v->IsObject() || v->IsArray()) { + *error = true; + qmlInfo(loader) << loader->tr("setSource: value is not an object"); + } else { + *error = false; + valuemap = v8::Local<v8::Object>::Cast(v); + } + } + + return valuemap; +} + +void QSGLoaderPrivate::completeCreateWithInitialPropertyValues(QDeclarativeComponent *component, QObject *object, v8::Handle<v8::Object> initialPropertyValues, v8::Handle<v8::Object> qmlGlobal) +{ + if (initialPropertyValues.IsEmpty()) { + component->completeCreate(); + return; + } + + QDeclarativeComponentPrivate *d = QDeclarativeComponentPrivate::get(component); + Q_ASSERT(d && d->engine); + d->completeCreateObjectWithInitialProperties(qmlGlobal, initialPropertyValues, object); +} + #include <moc_qsgloader_p.cpp> QT_END_NAMESPACE diff --git a/src/declarative/items/qsgloader_p.h b/src/declarative/items/qsgloader_p.h index 832d3a6138..c3ce1607e0 100644 --- a/src/declarative/items/qsgloader_p.h +++ b/src/declarative/items/qsgloader_p.h @@ -57,6 +57,7 @@ class Q_AUTOTEST_EXPORT QSGLoader : public QSGImplicitSizeItem Q_OBJECT Q_ENUMS(Status) + Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QDeclarativeComponent *sourceComponent READ sourceComponent WRITE setSourceComponent RESET resetSourceComponent NOTIFY sourceComponentChanged) Q_PROPERTY(QSGItem *item READ item NOTIFY itemChanged) @@ -67,6 +68,11 @@ public: QSGLoader(QSGItem *parent = 0); virtual ~QSGLoader(); + bool active() const; + void setActive(bool newVal); + + Q_INVOKABLE void setSource(QDeclarativeV8Function *); + QUrl source() const; void setSource(const QUrl &); @@ -82,6 +88,7 @@ public: Q_SIGNALS: void itemChanged(); + void activeChanged(); void sourceChanged(); void sourceComponentChanged(); void statusChanged(); @@ -93,6 +100,9 @@ protected: void componentComplete(); private: + void setSource(const QUrl &sourceUrl, bool needsClear); + void loadFromSource(); + void loadFromSourceComponent(); Q_DISABLE_COPY(QSGLoader) Q_DECLARE_PRIVATE(QSGLoader) Q_PRIVATE_SLOT(d_func(), void _q_sourceLoaded()) diff --git a/src/declarative/items/qsgloader_p_p.h b/src/declarative/items/qsgloader_p_p.h index 306e5ea732..732ec8679d 100644 --- a/src/declarative/items/qsgloader_p_p.h +++ b/src/declarative/items/qsgloader_p_p.h @@ -58,6 +58,8 @@ #include "qsgimplicitsizeitem_p_p.h" #include "qsgitemchangelistener_p.h" +#include <private/qv8_p.h> + QT_BEGIN_NAMESPACE class QDeclarativeContext; @@ -74,13 +76,22 @@ public: void initResize(); void load(); + void disposeInitialPropertyValues(); + QUrl resolveSourceUrl(QDeclarativeV8Function *args); + v8::Handle<v8::Object> extractInitialPropertyValues(QDeclarativeV8Function *args, QObject *loader, bool *error); + void completeCreateWithInitialPropertyValues(QDeclarativeComponent *component, QObject *object, v8::Handle<v8::Object> initialPropertyValues, v8::Handle<v8::Object> qmlGlobal); + QUrl source; QSGItem *item; QDeclarativeComponent *component; + v8::Persistent<v8::Object> initialPropertyValues; + v8::Persistent<v8::Object> qmlGlobalForIpv; bool ownComponent : 1; bool updatingSize: 1; bool itemWidthValid : 1; bool itemHeightValid : 1; + bool active : 1; + bool loadingFromSource : 1; void _q_sourceLoaded(); void _q_updateSize(bool loaderGeometryChanged = true); |