1 /*
2  *  SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
3  *
4  *  SPDX-License-Identifier: LGPL-2.0-or-later
5  */
6 #pragma once
7 
8 #include <QObject>
9 #include <QPointer>
10 #include <QQuickItem>
11 
12 /**
13  * A Pool of Page items, pages will be unique per url and the items
14  * will be kept around unless explicitly deleted.
15  * Instances are C++ owned and can be deleted only manually using deletePage()
16  * Instance are unique per url: if you need 2 different instance for a page
17  * url, you should instantiate them in the traditional way
18  * or use a different PagePool instance.
19  *
20  * @see org::kde::kirigami::PagePoolAction
21  */
22 class PagePool : public QObject
23 {
24     Q_OBJECT
25     /**
26      * The last url that was loaded with @loadPage. Useful if you need
27      * to have a "checked" state to buttons or list items that
28      * load the page when clicked.
29      */
30     Q_PROPERTY(QUrl lastLoadedUrl READ lastLoadedUrl NOTIFY lastLoadedUrlChanged)
31 
32     /**
33      * The last item that was loaded with @loadPage.
34      */
35     Q_PROPERTY(QQuickItem *lastLoadedItem READ lastLoadedItem NOTIFY lastLoadedItemChanged)
36 
37     /**
38      * All items loaded/managed by the PagePool.
39      * @since 5.84
40      */
41     Q_PROPERTY(QList<QObject *> items READ items NOTIFY itemsChanged)
42 
43     /**
44      * All page URLs loaded/managed by the PagePool.
45      * @since 5.84
46      */
47     Q_PROPERTY(QList<QUrl> urls READ urls NOTIFY urlsChanged)
48 
49     /**
50      * If true (default) the pages will be kept around, will have C++ ownership and
51      * only one instance per page will be created.
52      * If false the pages will have Javascript ownership (thus deleted on pop by the
53      * page stacks) and each call to loadPage will create a new page instance. When
54      * cachePages is false, Components get cached nevertheless.
55      */
56     Q_PROPERTY(bool cachePages READ cachePages WRITE setCachePages NOTIFY cachePagesChanged)
57 
58 public:
59     PagePool(QObject *parent = nullptr);
60     ~PagePool() override;
61 
62     QUrl lastLoadedUrl() const;
63     QQuickItem *lastLoadedItem() const;
64     QList<QObject *> items() const;
65     QList<QUrl> urls() const;
66 
67     void setCachePages(bool cache);
68     bool cachePages() const;
69 
70     /**
71      * Returns the instance of the item defined in the QML file identified
72      * by url, only one instance will be made per url if cachePAges is true.
73      * If the url is remote (i.e. http) don't rely on the return value but
74      * us the async callback instead.
75      *
76      * @param url full url of the item: it can be a well formed Url, an
77      * absolute path or a relative one to the path of the qml file the
78      * PagePool is instantiated from
79      * @param callback If we are loading a remote url, we can't have the
80      * item immediately but will be passed as a parameter to the provided
81      * callback. Normally, don't set a callback, use it only in case of
82      * remote urls
83      * @returns the page instance that will have been created if necessary.
84      * If the url is remote it will return null, as well will return null
85      * if the callback has been provided
86      */
87     Q_INVOKABLE QQuickItem *loadPage(const QString &url, QJSValue callback = QJSValue());
88 
89     Q_INVOKABLE QQuickItem *loadPageWithProperties(const QString &url, const QVariantMap &properties, QJSValue callback = QJSValue());
90 
91     /**
92      * @returns The url of the page for the given instance, empty if there is no correspondence
93      */
94     Q_INVOKABLE QUrl urlForPage(QQuickItem *item) const;
95 
96     /**
97      * @returns The page associated with a given URL, nullptr if there is no correspondence
98      */
99     Q_INVOKABLE QQuickItem *pageForUrl(const QUrl &url) const;
100 
101     /**
102      * @returns true if the is managed by the PagePool
103      * @param the page can be either a QQuickItem or an url
104      */
105     Q_INVOKABLE bool contains(const QVariant &page) const;
106 
107     /**
108      * Deletes the page (only if is managed by the pool.
109      * @param page either the url or the instance of the page
110      */
111     Q_INVOKABLE void deletePage(const QVariant &page);
112 
113     /**
114      * @returns full url from an absolute or relative path
115      */
116     Q_INVOKABLE QUrl resolvedUrl(const QString &file) const;
117 
118     /**
119      * @returns true if the url identifies a local resource (local file or a file inside Qt's resource system).
120      * False if the url points to a network location
121      */
122     Q_INVOKABLE bool isLocalUrl(const QUrl &url);
123 
124     /**
125      * Deletes all pages managed by the pool.
126      */
127     Q_INVOKABLE void clear();
128 
129 Q_SIGNALS:
130     void lastLoadedUrlChanged();
131     void lastLoadedItemChanged();
132     void itemsChanged();
133     void urlsChanged();
134     void cachePagesChanged();
135 
136 private:
137     QQuickItem *createFromComponent(QQmlComponent *component, const QVariantMap &properties);
138 
139     QUrl m_lastLoadedUrl;
140     QPointer<QQuickItem> m_lastLoadedItem;
141     QHash<QUrl, QQuickItem *> m_itemForUrl;
142     QHash<QUrl, QQmlComponent *> m_componentForUrl;
143     QHash<QQuickItem *, QUrl> m_urlForItem;
144 
145     bool m_cachePages = true;
146 };
147