WelcomePagesModel.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from collections import deque
  4. import os
  5. from typing import TYPE_CHECKING, Optional, List, Dict, Any, Deque
  6. from PyQt5.QtCore import QUrl, Qt, pyqtSlot, pyqtProperty, pyqtSignal
  7. from UM.Logger import Logger
  8. from UM.Qt.ListModel import ListModel
  9. from UM.Resources import Resources
  10. if TYPE_CHECKING:
  11. from PyQt5.QtCore import QObject
  12. class WelcomePagesModel(ListModel):
  13. IdRole = Qt.UserRole + 1 # Page ID
  14. PageUrlRole = Qt.UserRole + 2 # URL to the page's QML file
  15. NextPageIdRole = Qt.UserRole + 3 # The next page ID it should go to
  16. def __init__(self, parent: Optional["QObject"] = None) -> None:
  17. super().__init__(parent)
  18. self.addRoleName(self.IdRole, "id")
  19. self.addRoleName(self.PageUrlRole, "page_url")
  20. self.addRoleName(self.NextPageIdRole, "next_page_id")
  21. self._pages = [] # type: List[Dict[str, Any]]
  22. self._current_page_index = 0
  23. # Store all the previous page indices so it can go back.
  24. self._previous_page_indices_stack = deque() # type: Deque[int]
  25. allFinished = pyqtSignal() # emitted when all steps have been finished
  26. currentPageIndexChanged = pyqtSignal()
  27. @pyqtProperty(int, notify = currentPageIndexChanged)
  28. def currentPageIndex(self) -> int:
  29. return self._current_page_index
  30. # Returns a float number in [0, 1] which indicates the current progress.
  31. @pyqtProperty(float, notify = currentPageIndexChanged)
  32. def currentProgress(self) -> float:
  33. return self._current_page_index / len(self._items)
  34. # Indicates if the current page is the last page.
  35. @pyqtProperty(bool, notify = currentPageIndexChanged)
  36. def isCurrentPageLast(self) -> bool:
  37. return self._current_page_index == len(self._items) - 1
  38. def _setCurrentPageIndex(self, page_index: int) -> None:
  39. if page_index != self._current_page_index:
  40. self._previous_page_indices_stack.append(self._current_page_index)
  41. self._current_page_index = page_index
  42. self.currentPageIndexChanged.emit()
  43. # Goes to the next page.
  44. @pyqtSlot()
  45. def goToNextPage(self) -> None:
  46. page_item = self._items[self._current_page_index]
  47. # Check if there's a "next_page_id" assigned. If so, go to that page. Otherwise, go to the page with the
  48. # current index + 1.
  49. next_page_id = page_item.get("next_page_id")
  50. next_page_index = self._current_page_index + 1
  51. if next_page_id:
  52. idx = self.getPageIndexById(next_page_id)
  53. if idx is None:
  54. # FIXME: If we cannot find the next page, we cannot do anything here.
  55. Logger.log("e", "Cannot find page with ID [%s]", next_page_id)
  56. return
  57. next_page_index = idx
  58. # If we have reached the last page, emit allFinished signal and reset.
  59. if next_page_index == len(self._items):
  60. self.allFinished.emit()
  61. self.resetState()
  62. # Move to the next page
  63. self._setCurrentPageIndex(next_page_index)
  64. # Goes to the previous page. If there's no previous page, do nothing.
  65. @pyqtSlot()
  66. def goToPreviousPage(self) -> None:
  67. if len(self._previous_page_indices_stack) == 0:
  68. Logger.log("i", "No previous page, do nothing")
  69. return
  70. previous_page_index = self._previous_page_indices_stack.pop()
  71. self._current_page_index = previous_page_index
  72. self.currentPageIndexChanged.emit()
  73. # Sets the current page to the given page ID. If the page ID is not found, do nothing.
  74. @pyqtSlot(str)
  75. def goToPage(self, page_id: str) -> None:
  76. page_index = self.getPageIndexById(page_id)
  77. if page_index is None:
  78. # FIXME: If we cannot find the next page, we cannot do anything here.
  79. Logger.log("e", "Cannot find page with ID [%s]", page_index)
  80. return
  81. # Move to that page
  82. self._setCurrentPageIndex(page_index)
  83. # Resets the state of the WelcomePagesModel. This functions does the following:
  84. # - Resets current_page_index to 0
  85. # - Clears the previous page indices stack
  86. @pyqtSlot()
  87. def resetState(self) -> None:
  88. self._current_page_index = 0
  89. self._previous_page_indices_stack.clear()
  90. self.currentPageIndexChanged.emit()
  91. # Gets the page index with the given page ID. If the page ID doesn't exist, returns None.
  92. def getPageIndexById(self, page_id: str) -> Optional[int]:
  93. page_idx = None
  94. for idx, page_item in enumerate(self._items):
  95. if page_item["id"] == page_id:
  96. page_idx = idx
  97. break
  98. return page_idx
  99. # Convenience function to get QUrl path to pages that's located in "resources/qml/WelcomePages".
  100. def _getBuiltinWelcomePagePath(self, page_filename: str) -> "QUrl":
  101. from cura.CuraApplication import CuraApplication
  102. return QUrl.fromLocalFile(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles,
  103. os.path.join("WelcomePages", page_filename)))
  104. def initialize(self) -> None:
  105. # Add default welcome pages
  106. self._pages.append({"id": "welcome",
  107. "page_url": self._getBuiltinWelcomePagePath("WelcomeContent.qml"),
  108. })
  109. self._pages.append({"id": "user_agreement",
  110. "page_url": self._getBuiltinWelcomePagePath("UserAgreementContent.qml"),
  111. })
  112. self._pages.append({"id": "whats_new",
  113. "page_url": self._getBuiltinWelcomePagePath("WhatsNewContent.qml"),
  114. })
  115. self._pages.append({"id": "data_collections",
  116. "page_url": self._getBuiltinWelcomePagePath("DataCollectionsContent.qml"),
  117. })
  118. self._pages.append({"id": "add_network_or_local_printer",
  119. "page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
  120. "next_page_id": "cloud",
  121. })
  122. self._pages.append({"id": "add_printer_by_ip",
  123. "page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
  124. "next_page_id": "cloud",
  125. })
  126. self._pages.append({"id": "cloud",
  127. "page_url": self._getBuiltinWelcomePagePath("CloudContent.qml"),
  128. })
  129. self.setItems(self._pages)
  130. def addPage(self) -> None:
  131. pass
  132. __all__ = ["WelcomePagesModel"]