diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -28,5 +28,6 @@ tst_pagerow.qml tst_icon.qml tst_actiontoolbar.qml + pagepool/tst_pagepool.qml ) diff --git a/autotests/pagepool/TestPage.qml b/autotests/pagepool/TestPage.qml new file mode 100644 --- /dev/null +++ b/autotests/pagepool/TestPage.qml @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2020 Mason McParlane + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.7 +import org.kde.kirigami 2.11 as Kirigami + +Kirigami.Page { + title: qsTr("INITIAL TITLE") +} diff --git a/autotests/pagepool/tst_pagepool.qml b/autotests/pagepool/tst_pagepool.qml new file mode 100644 --- /dev/null +++ b/autotests/pagepool/tst_pagepool.qml @@ -0,0 +1,115 @@ +/* + * SPDX-FileCopyrightText: 2020 Mason McParlane + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Window 2.1 +import org.kde.kirigami 2.11 as Kirigami +import QtTest 1.0 + +TestCase { + id: testCase + width: 400 + height: 400 + name: "PagePool" + + function initTestCase() { + mainWindow.show() + } + + function cleanupTestCase() { + mainWindow.close() + } + + function applicationWindow() { return mainWindow; } + + Kirigami.ApplicationWindow { + id: mainWindow + width: 480 + height: 360 + } + + Kirigami.PagePool { + id: pool + } + + function init() { + mainWindow.pageStack.clear() + pool.clear() + } + + // Queries added to page URLs ensure the PagePool can + // have multiple instances of TestPage.qml + + Kirigami.PagePoolAction { + id: loadPageAction + pagePool: pool + pageStack: mainWindow.pageStack + page: "TestPage.qml?action=loadPageAction" + } + + function test_loadPage () { + var expectedUrl = "TestPage.qml?action=loadPageAction" + compare(mainWindow.pageStack.depth, 0) + loadPageAction.trigger() + compare(mainWindow.pageStack.depth, 1) + verify(pool.lastLoadedUrl.toString().endsWith(expectedUrl)) + compare(mainWindow.pageStack.currentItem.title, "INITIAL TITLE") + } + + Kirigami.PagePoolAction { + id: loadPageActionWithProps + pagePool: pool + pageStack: mainWindow.pageStack + page: "TestPage.qml?action=loadPageActionWithProps" + initialProperties: { + return {title: "NEW TITLE" } + } + } + + function test_loadPageInitialPropertyOverride () { + var expectedUrl = "TestPage.qml?action=loadPageActionWithProps" + compare(mainWindow.pageStack.depth, 0) + loadPageActionWithProps.trigger() + compare(mainWindow.pageStack.depth, 1) + verify(pool.lastLoadedUrl.toString().endsWith(expectedUrl)) + compare(mainWindow.pageStack.currentItem.title, "NEW TITLE") + compare(pool.lastLoadedItem.title, "NEW TITLE") + } + + Kirigami.PagePoolAction { + id: loadPageActionPropsNotObject + pagePool: pool + pageStack: mainWindow.pageStack + page: "TestPage.qml?action=loadPageActionPropsNotObject" + initialProperties: "This is a string not an object..." + } + + function test_loadPageInitialPropertiesWrongType () { + var expectedUrl = "TestPage.qml?action=loadPageAction" + compare(mainWindow.pageStack.depth, 0) + loadPageAction.trigger() + loadPageActionPropsNotObject.trigger() + compare(mainWindow.pageStack.depth, 1) + verify(pool.lastLoadedUrl.toString().endsWith(expectedUrl)) + } + + Kirigami.PagePoolAction { + id: loadPageActionPropDoesNotExist + pagePool: pool + pageStack: mainWindow.pageStack + page: "TestPage.qml?action=loadPageActionPropDoesNotExist" + initialProperties: { + return { propDoesNotExist: "PROP-NON-EXISTANT" } + } + } + + function test_loadPageInitialPropertyNotExistOkay () { + var expectedUrl = "TestPage.qml?action=loadPageActionPropDoesNotExist" + loadPageActionPropDoesNotExist.trigger() + verify(pool.lastLoadedUrl.toString().endsWith(expectedUrl)) + } +} diff --git a/src/controls/PagePoolAction.qml b/src/controls/PagePoolAction.qml --- a/src/controls/PagePoolAction.qml +++ b/src/controls/PagePoolAction.qml @@ -62,6 +62,11 @@ return; } + if (initialProperties && typeof(initialProperties) !== "object") { + console.warn("initialProperties must be of type object"); + return; + } + if (pagePool.resolvedUrl(page) == pagePool.lastLoadedUrl) { return; } diff --git a/src/pagepool.h b/src/pagepool.h --- a/src/pagepool.h +++ b/src/pagepool.h @@ -27,6 +27,11 @@ */ Q_PROPERTY(QUrl lastLoadedUrl READ lastLoadedUrl NOTIFY lastLoadedUrlChanged) + /** + * The last item that was loaded with @loadPage. + */ + Q_PROPERTY(QQuickItem *lastLoadedItem READ lastLoadedItem NOTIFY lastLoadedItemChanged) + /** * If true (default) the pages will be kept around, will have C++ ownership and only one instance per page will be created. * If false the pages will have Javascript ownership (thus deleted on pop by the page stacks) and each call to loadPage will create a new page instance. When cachePages is false, Components gets cached never the less @@ -38,6 +43,7 @@ ~PagePool(); QUrl lastLoadedUrl() const; + QQuickItem *lastLoadedItem() const; void setCachePages(bool cache); bool cachePages() const; @@ -87,8 +93,14 @@ */ Q_INVOKABLE bool isLocalUrl(const QUrl &url); + /** + * Deletes all pages managed by the pool. + */ + Q_INVOKABLE void clear(); + Q_SIGNALS: void lastLoadedUrlChanged(); + void lastLoadedItemChanged(); void cachePagesChanged(); private: diff --git a/src/pagepool.cpp b/src/pagepool.cpp --- a/src/pagepool.cpp +++ b/src/pagepool.cpp @@ -26,6 +26,11 @@ return m_lastLoadedUrl; } +QQuickItem *PagePool::lastLoadedItem() const +{ + return m_lastLoadedItem; +} + void PagePool::setCachePages(bool cache) { if (cache == m_cachePages) { @@ -168,10 +173,17 @@ return nullptr; } - auto it = properties.constBegin(); - while (it != properties.constEnd()) { - obj->setProperty(it.key().toUtf8().data(), it.value()); - ++it; + for (auto it = properties.constBegin(); it != properties.constEnd(); ++it) { + + QQmlProperty p(obj, it.key(), ctx); + if (!p.isValid()) { + qWarning() << "Invalid property " << it.key(); + continue; + } + if (!p.write(it.value())) { + qWarning() << "Could not set property " << it.key(); + continue; + } } component->completeCreate(); @@ -192,6 +204,8 @@ QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); } + emit lastLoadedItemChanged(); + return item; } @@ -266,5 +280,16 @@ item->deleteLater(); } +void PagePool::clear() +{ + for (const auto& url : m_urlForItem) { + deletePage(url); + } + m_lastLoadedUrl = QUrl(); + m_lastLoadedItem = nullptr; + + emit lastLoadedUrlChanged(); + emit lastLoadedItemChanged(); +} #include "moc_pagepool.cpp"