diff --git a/src/controls/PagePoolAction.qml b/src/controls/PagePoolAction.qml --- a/src/controls/PagePoolAction.qml +++ b/src/controls/PagePoolAction.qml @@ -49,6 +49,13 @@ */ property Controls.Page basePage + /** + * initialProperties: JavaScript Object + * The properties object specifies a map of initial property values for the created page + * when it is pushed onto the Kirigami.PagePool. + */ + property var initialProperties + checked: pagePool && pagePool.resolvedUrl(page) == pagePool.lastLoadedUrl onTriggered: { if (page.length == 0 || !pagePool || !pageStack) { @@ -69,7 +76,10 @@ } else { pageStack.clear(); } - pageStack.push(pagePool.loadPage(page)); + + pageStack.push(properties ? + pagePool.loadPageWithProperties(page, properties) : + pagePool.loadPage(page)); } else { pagePool.loadPage(page, function(item) { if (basePage) { diff --git a/src/pagepool.h b/src/pagepool.h --- a/src/pagepool.h +++ b/src/pagepool.h @@ -56,6 +56,9 @@ */ Q_INVOKABLE QQuickItem *loadPage(const QString &url, QJSValue callback = QJSValue()); + Q_INVOKABLE QQuickItem *loadPageWithProperties( + const QString &url, const QVariantMap &properties, QJSValue callback = QJSValue()); + /** * @returns The url of the page for the given instance, empty if there is no correspondence */ @@ -89,7 +92,7 @@ void cachePagesChanged(); private: - QQuickItem *createFromComponent(QQmlComponent *component); + QQuickItem *createFromComponent(QQmlComponent *component, const QVariantMap &properties); QUrl m_lastLoadedUrl; QPointer m_lastLoadedItem; diff --git a/src/pagepool.cpp b/src/pagepool.cpp --- a/src/pagepool.cpp +++ b/src/pagepool.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include PagePool::PagePool(QObject *parent) : QObject(parent) @@ -57,6 +59,12 @@ } QQuickItem *PagePool::loadPage(const QString &url, QJSValue callback) +{ + return loadPageWithProperties(url, QVariantMap(), callback); +} + +QQuickItem *PagePool::loadPageWithProperties( + const QString &url, const QVariantMap &properties, QJSValue callback) { Q_ASSERT(qmlEngine(this)); QQmlContext *ctx = QQmlEngine::contextForObject(this); @@ -100,14 +108,14 @@ } connect(component, &QQmlComponent::statusChanged, this, - [this, component, callback] (QQmlComponent::Status status) mutable { + [this, component, callback, properties] (QQmlComponent::Status status) mutable { if (status != QQmlComponent::Ready) { qWarning() << component->errors(); m_componentForUrl.remove(component->url()); component->deleteLater(); return; } - QQuickItem *item = createFromComponent(component); + QQuickItem *item = createFromComponent(component, properties); if (item) { QJSValueList args = {qmlEngine(this)->newQObject(item)}; callback.call(args); @@ -127,7 +135,7 @@ return nullptr; } - QQuickItem *item = createFromComponent(component); + QQuickItem *item = createFromComponent(component, properties); if (m_cachePages) { component->deleteLater(); } else { @@ -148,12 +156,55 @@ } } -QQuickItem *PagePool::createFromComponent(QQmlComponent *component) +// As soon as we can depend on Qt 5.14, usage of this incubator should be +// replaced with a call to QQmlComponent::createWithInitialProperties +class PropertyInitializingIncubator : public QQmlIncubator +{ + const QVariantMap &_props; + QQmlContext *_ctx; + +public: + PropertyInitializingIncubator( + const QVariantMap &props, QQmlContext *ctx, + IncubationMode mode = Asynchronous) + : QQmlIncubator(mode), _props(props), _ctx(ctx) + {} + +protected: + void setInitialState(QObject *obj) override + { + QMapIterator i(_props); + while (i.hasNext()) { + i.next(); + + QQmlProperty p(obj, i.key(), _ctx); + if (!p.isValid()) { + qWarning() << "Invalid property " << i.key(); + continue; + } + if (!p.write(i.value())) { + qWarning() << "Could not set property " << i.key(); + continue; + } + } + } +}; + + +QQuickItem *PagePool::createFromComponent(QQmlComponent *component, const QVariantMap &properties) { QQmlContext *ctx = QQmlEngine::contextForObject(this); Q_ASSERT(ctx); - QObject *obj = component->create(ctx); + PropertyInitializingIncubator incubator(properties, ctx); + component->create(incubator, ctx); + + while (!incubator.isReady()) { + QCoreApplication::processEvents(QEventLoop::AllEvents, 50); + } + + QObject *obj = incubator.object(); + // Error? if (!obj) { return nullptr;