aboutsummaryrefslogtreecommitdiffstats
path: root/examples/demos/colorpaletteclient/paginatedresource.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/demos/colorpaletteclient/paginatedresource.py')
-rw-r--r--examples/demos/colorpaletteclient/paginatedresource.py278
1 files changed, 278 insertions, 0 deletions
diff --git a/examples/demos/colorpaletteclient/paginatedresource.py b/examples/demos/colorpaletteclient/paginatedresource.py
new file mode 100644
index 000000000..b7f036c4e
--- /dev/null
+++ b/examples/demos/colorpaletteclient/paginatedresource.py
@@ -0,0 +1,278 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import sys
+from dataclasses import dataclass
+from PySide6.QtCore import (QAbstractListModel, QByteArray,
+ QUrlQuery, Property, Signal, Slot, Qt)
+from PySide6.QtQml import QmlAnonymous, QmlElement
+
+from abstractresource import AbstractResource
+
+
+QML_IMPORT_NAME = "ColorPalette"
+QML_IMPORT_MAJOR_VERSION = 1
+
+
+totalPagesField = "total_pages"
+currentPageField = "page"
+
+
+@dataclass
+class ColorUser:
+ id: int
+ email: str
+ avatar: str # URL
+
+
+@QmlElement
+class ColorUserModel (QAbstractListModel):
+ IdRole = Qt.UserRole + 1
+ EmailRole = Qt.UserRole + 2
+ AvatarRole = Qt.UserRole + 3
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._users = []
+
+ def clear(self):
+ self.set_data([])
+
+ def set_data(self, json_list):
+ if not self._users and not json_list:
+ return
+ self.beginResetModel()
+ self._users.clear()
+ for e in json_list:
+ self._users.append(ColorUser(int(e["id"]), e["email"], e["avatar"]))
+ self.endResetModel()
+
+ def roleNames(self):
+ roles = {
+ ColorUserModel.IdRole: QByteArray(b'id'),
+ ColorUserModel.EmailRole: QByteArray(b'email'),
+ ColorUserModel.AvatarRole: QByteArray(b'avatar')
+ }
+ return roles
+
+ def rowCount(self, index):
+ return len(self._users)
+
+ def data(self, index, role):
+ if index.isValid():
+ d = self._users[index.row()]
+ if role == ColorUserModel.IdRole:
+ return d.id
+ if role == ColorUserModel.EmailRole:
+ return d.email
+ if role == ColorUserModel.AvatarRole:
+ return d.avatar
+ return None
+
+ def avatarForEmail(self, email):
+ for e in self._users:
+ if e.email == email:
+ return e.avatar
+ return ""
+
+
+@dataclass
+class Color:
+ id: int
+ color: str
+ name: str
+ pantone_value: str
+
+
+@QmlElement
+class ColorModel (QAbstractListModel):
+ IdRole = Qt.UserRole + 1
+ ColorRole = Qt.UserRole + 2
+ NameRole = Qt.UserRole + 3
+ PantoneValueRole = Qt.UserRole + 4
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self._colors = []
+
+ def clear(self):
+ self.set_data([])
+
+ def set_data(self, json_list):
+ if not self._colors and not json_list:
+ return
+ self.beginResetModel()
+ self._colors.clear()
+ for e in json_list:
+ self._colors.append(Color(int(e["id"]), e["color"],
+ e["name"], e["pantone_value"]))
+ self.endResetModel()
+
+ def roleNames(self):
+ roles = {
+ ColorModel.IdRole: QByteArray(b'color_id'),
+ ColorModel.ColorRole: QByteArray(b'color'),
+ ColorModel.NameRole: QByteArray(b'name'),
+ ColorModel.PantoneValueRole: QByteArray(b'pantone_value')
+ }
+ return roles
+
+ def rowCount(self, index):
+ return len(self._colors)
+
+ def data(self, index, role):
+ if index.isValid():
+ d = self._colors[index.row()]
+ if role == ColorModel.IdRole:
+ return d.id
+ if role == ColorModel.ColorRole:
+ return d.color
+ if role == ColorModel.NameRole:
+ return d.name
+ if role == ColorModel.PantoneValueRole:
+ return d.pantone_value
+ return None
+
+
+@QmlAnonymous
+class PaginatedResource(AbstractResource):
+ """This class manages a simple paginated Crud resource,
+ where the resource is a paginated list of JSON items."""
+
+ dataUpdated = Signal()
+ pageUpdated = Signal()
+ pagesUpdated = Signal()
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ # The total number of pages as reported by the server responses
+ self.m_pages = 0
+ # The default page we request if the user hasn't set otherwise
+ self.m_currentPage = 1
+ self.m_path = ""
+
+ def _clearModel(self):
+ pass
+
+ def _populateModel(self, json_list):
+ pass
+
+ @Property(str)
+ def path(self):
+ return self.m_path
+
+ @path.setter
+ def path(self, p):
+ self.m_path = p
+
+ @Property(int, notify=pagesUpdated)
+ def pages(self):
+ return self.m_pages
+
+ @Property(int, notify=pageUpdated)
+ def page(self):
+ return self.m_currentPage
+
+ @page.setter
+ def page(self, page):
+ if self.m_currentPage == page or page < 1:
+ return
+ self.m_currentPage = page
+ self.pageUpdated.emit()
+ self.refreshCurrentPage()
+
+ @Slot()
+ def refreshCurrentPage(self):
+ query = QUrlQuery()
+ query.addQueryItem("page", str(self.m_currentPage))
+ request = self.m_api.createRequest(self.m_path, query)
+ self.m_manager.get(request, self, self.refreshCurrentPageReply)
+
+ def refreshCurrentPageReply(self, reply):
+ if not reply.isSuccess():
+ print("PaginatedResource: ", reply.errorString(), file=sys.stderr)
+ (json, error) = reply.readJson()
+ if json:
+ self.refreshRequestFinished(json)
+ else:
+ self.refreshRequestFailed()
+
+ def refreshRequestFinished(self, json):
+ json_object = json.object()
+ self._populateModel(json_object["data"])
+ self.m_pages = int(json_object[totalPagesField])
+ self.m_currentPage = int(json_object[currentPageField])
+ self.pageUpdated.emit()
+ self.pagesUpdated.emit()
+ self.dataUpdated.emit()
+
+ def refreshRequestFailed(self):
+ if self.m_currentPage != 1:
+ # A failed refresh. If we weren't on page 1, try that.
+ # Last resource on currentPage might have been deleted, causing a failure
+ self.setPage(1)
+ else:
+ # Refresh failed and we we're already on page 1 => clear data
+ self.m_pages = 0
+ self.pagesUpdated.emit()
+ self._clearModel()
+ self.dataUpdated.emit()
+
+ @Slot("QVariantMap", int)
+ def update(self, data, id):
+ request = self.m_api.createRequest(f"{self.m_path}/{id}")
+ self.m_manager.put(request, self, self.updateReply)
+
+ def updateReply(self, reply):
+ if reply.isSuccess():
+ self.refreshCurrentPage()
+
+ @Slot("QVariantMap")
+ def add(self, data):
+ request = self.m_api.createRequest(self.m_path)
+ self.m_manager.post(request, data, self, self.updateReply)
+
+ @Slot(int)
+ def remove(self, id):
+ request = self.m_api.createRequest(f"{self.m_path}/{id}")
+ self.m_manager.deleteResource(request, self, self.updateReply)
+
+
+@QmlElement
+class PaginatedColorUsersResource(PaginatedResource):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.m_model = ColorUserModel(self)
+
+ @Property(ColorUserModel, constant=True)
+ def model(self):
+ return self.m_model
+
+ def _clearModel(self):
+ self.m_model.clear()
+
+ def _populateModel(self, json_list):
+ self.m_model.set_data(json_list)
+
+ @Slot(str, result=str)
+ def avatarForEmail(self, email):
+ return self.m_model.avatarForEmail(email)
+
+
+@QmlElement
+class PaginatedColorsResource(PaginatedResource):
+
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.m_model = ColorModel(self)
+
+ @Property(ColorModel, constant=True)
+ def model(self):
+ return self.m_model
+
+ def _clearModel(self):
+ self.m_model.clear()
+
+ def _populateModel(self, json_list):
+ self.m_model.set_data(json_list)