From 6dbae6f088e4c03fee93ee686b5f976877195ed2 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 27 Mar 2019 09:34:48 +0100 Subject: [PATCH] Show machine actions page optionally --- .../Models/FirstStartMachineActionsModel.py | 48 +++++++++- cura/UI/WelcomePagesModel.py | 94 ++++++++++++++----- .../FirstStartMachineActionsContent.qml | 48 ++++------ 3 files changed, 136 insertions(+), 54 deletions(-) diff --git a/cura/Machines/Models/FirstStartMachineActionsModel.py b/cura/Machines/Models/FirstStartMachineActionsModel.py index aabf8b8a8a..73deb6ac24 100644 --- a/cura/Machines/Models/FirstStartMachineActionsModel.py +++ b/cura/Machines/Models/FirstStartMachineActionsModel.py @@ -1,9 +1,9 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional +from typing import Optional, Dict, Any -from PyQt5.QtCore import QObject, Qt +from PyQt5.QtCore import QObject, Qt, pyqtProperty, pyqtSignal, pyqtSlot from UM.Qt.ListModel import ListModel @@ -27,6 +27,8 @@ class FirstStartMachineActionsModel(ListModel): self.addRoleName(self.ContentRole, "content") self.addRoleName(self.ActionRole, "action") + self._current_action_index = 0 + from cura.CuraApplication import CuraApplication self._application = CuraApplication.getInstance() @@ -36,6 +38,47 @@ class FirstStartMachineActionsModel(ListModel): self._application.getMachineManager().globalContainerChanged.connect(self._update) self._update() + currentActionIndexChanged = pyqtSignal() + allFinished = pyqtSignal() # Emitted when all actions have been finished. + + @pyqtProperty(int, notify = currentActionIndexChanged) + def currentActionIndex(self) -> int: + return self._current_action_index + + @pyqtProperty("QVariantMap", notify = currentActionIndexChanged) + def currentItem(self) -> Optional[Dict[str, Any]]: + if self._current_action_index >= self.count: + return dict() + else: + return self.getItem(self._current_action_index) + + @pyqtProperty(bool, notify = currentActionIndexChanged) + def hasMoreActions(self) -> bool: + return self._current_action_index < self.count - 1 + + @pyqtSlot() + def goToNextAction(self) -> None: + # finish the current item + if "action" in self.currentItem: + self.currentItem["action"].setFinished() + + if not self.hasMoreActions: + self.allFinished.emit() + self.reset() + return + + self._current_action_index += 1 + self.currentActionIndexChanged.emit() + + # Resets the current action index to 0 so the wizard panel can show actions from the beginning. + @pyqtSlot() + def reset(self) -> None: + self._current_action_index = 0 + self.currentActionIndexChanged.emit() + + if self.count == 0: + self.allFinished.emit() + def _update(self) -> None: global_stack = self._application.getMachineManager().activeMachine if global_stack is None: @@ -53,6 +96,7 @@ class FirstStartMachineActionsModel(ListModel): }) self.setItems(item_list) + self.reset() __all__ = ["FirstStartMachineActionsModel"] diff --git a/cura/UI/WelcomePagesModel.py b/cura/UI/WelcomePagesModel.py index 6cbe59e349..5cb29436d9 100644 --- a/cura/UI/WelcomePagesModel.py +++ b/cura/UI/WelcomePagesModel.py @@ -13,7 +13,20 @@ from UM.Resources import Resources if TYPE_CHECKING: from PyQt5.QtCore import QObject - +# +# This is the Qt ListModel that contains all welcome pages data. Each page is a page that can be shown as a step in the +# welcome wizard dialog. Each item in this ListModel represents a page, which contains the following fields: +# +# - id : A unique page_id which can be used in function goToPage(page_id) +# - page_url : The QUrl to the QML file that contains the content of this page +# - next_page_id : (OPTIONAL) The next page ID to go to when this page finished. This is optional. If this is not +# provided, it will go to the page with the current index + 1 +# - should_show_function : (OPTIONAL) An optional function that returns True/False indicating if this page should be +# shown. By default all pages should be shown. If a function returns False, that page will +# be skipped and its next page will be shown. +# +# Note that in any case, a page that has its "should_show_function" == False will ALWAYS be skipped. +# class WelcomePagesModel(ListModel): IdRole = Qt.UserRole + 1 # Page ID @@ -57,26 +70,40 @@ class WelcomePagesModel(ListModel): self.currentPageIndexChanged.emit() # Goes to the next page. + # If "from_index" is given, it will look for the next page to show starting from the "from_index" page instead of + # the "self._current_page_index". @pyqtSlot() - def goToNextPage(self) -> None: - page_item = self._items[self._current_page_index] - # Check if there's a "next_page_id" assigned. If so, go to that page. Otherwise, go to the page with the - # current index + 1. - next_page_id = page_item.get("next_page_id") - next_page_index = self._current_page_index + 1 - if next_page_id: - idx = self.getPageIndexById(next_page_id) - if idx is None: - # FIXME: If we cannot find the next page, we cannot do anything here. - Logger.log("e", "Cannot find page with ID [%s]", next_page_id) - return - next_page_index = idx + def goToNextPage(self, from_index: Optional[int] = None) -> None: + # Look for the next page that should be shown + current_index = self._current_page_index if from_index is None else from_index + while True: + page_item = self._items[current_index] - # If we have reached the last page, emit allFinished signal and reset. - if next_page_index == len(self._items): - self.allFinished.emit() - self.resetState() - return + # Check if there's a "next_page_id" assigned. If so, go to that page. Otherwise, go to the page with the + # current index + 1. + next_page_id = page_item.get("next_page_id") + next_page_index = current_index + 1 + if next_page_id: + idx = self.getPageIndexById(next_page_id) + if idx is None: + # FIXME: If we cannot find the next page, we cannot do anything here. + Logger.log("e", "Cannot find page with ID [%s]", next_page_id) + return + next_page_index = idx + + # If we have reached the last page, emit allFinished signal and reset. + if next_page_index == len(self._items): + self.allFinished.emit() + self.resetState() + return + + # Check if the this page should be shown (default yes), if not, keep looking for the next one. + next_page_item = self.getItem(next_page_index) + if self._shouldPageBeShown(next_page_index): + break + + Logger.log("d", "Page [%s] should not be displayed, look for the next page.", next_page_item["id"]) + current_index = next_page_index # Move to the next page self._setCurrentPageIndex(next_page_index) @@ -101,8 +128,19 @@ class WelcomePagesModel(ListModel): Logger.log("e", "Cannot find page with ID [%s]", page_index) return - # Move to that page - self._setCurrentPageIndex(page_index) + if self._shouldPageBeShown(page_index): + # Move to that page if it should be shown + self._setCurrentPageIndex(page_index) + else: + # Find the next page to show starting from the "page_index" + self.goToNextPage(from_index = page_index) + + # Checks if the page with the given index should be shown by calling the "should_show_function" associated with it. + # If the function is not present, returns True (show page by default). + def _shouldPageBeShown(self, page_index: int) -> bool: + next_page_item = self.getItem(page_index) + should_show_function = next_page_item.get("should_show_function", lambda: True) + return should_show_function() # Resets the state of the WelcomePagesModel. This functions does the following: # - Resets current_page_index to 0 @@ -154,6 +192,7 @@ class WelcomePagesModel(ListModel): self._pages.append({"id": "machine_actions", "page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"), "next_page_id": "cloud", + "should_show_function": self.shouldShowMachineActions, }) self._pages.append({"id": "cloud", "page_url": self._getBuiltinWelcomePagePath("CloudContent.qml"), @@ -161,6 +200,19 @@ class WelcomePagesModel(ListModel): self.setItems(self._pages) + # Indicates if the machine action panel should be shown by checking if there's any first start machine actions + # available. + def shouldShowMachineActions(self) -> bool: + from cura.CuraApplication import CuraApplication + application = CuraApplication.getInstance() + global_stack = application.getMachineManager().activeMachine + if global_stack is None: + return False + + definition_id = global_stack.definition.getId() + first_start_actions = application.getMachineActionManager().getFirstStartActions(definition_id) + return len(first_start_actions) > 0 + def addPage(self) -> None: pass diff --git a/resources/qml/WelcomePages/FirstStartMachineActionsContent.qml b/resources/qml/WelcomePages/FirstStartMachineActionsContent.qml index 6b4a79a24a..f1a178e018 100644 --- a/resources/qml/WelcomePages/FirstStartMachineActionsContent.qml +++ b/resources/qml/WelcomePages/FirstStartMachineActionsContent.qml @@ -17,25 +17,19 @@ Item property var machineActionsModel: CuraApplication.getFirstStartMachineActionsModel() - property int currentActionIndex: 0 - property var currentActionItem: currentActionIndex >= machineActionsModel.count - ? null : machineActionsModel.getItem(currentActionIndex) - property bool hasActions: machineActionsModel.count > 0 + Component.onCompleted: + { + // Reset the action to start from the beginning when it is shown. + machineActionsModel.reset() + } - // Reset to the first page if the model gets changed. + // Go to the next page when all machine actions have been finished Connections { target: machineActionsModel - onItemsChanged: currentActionIndex = 0 - } - - onVisibleChanged: - { - if (visible) + onAllFinished: { - // Reset the action to start from the beginning when it is shown. - currentActionIndex = 0 - if (!hasActions) + if (visible) { base.showNextPage() } @@ -49,7 +43,7 @@ Item anchors.topMargin: UM.Theme.getSize("welcome_pages_default_margin").height anchors.horizontalCenter: parent.horizontalCenter horizontalAlignment: Text.AlignHCenter - text: currentActionItem == null ? "" : currentActionItem.title + text: machineActionsModel.currentItem.title == undefined ? "" : machineActionsModel.currentItem.title color: UM.Theme.getColor("primary_button") font: UM.Theme.getFont("large_bold") renderType: Text.NativeRendering @@ -63,7 +57,13 @@ Item anchors.left: parent.left anchors.right: parent.right - data: currentActionItem == undefined ? null : currentActionItem.content + data: machineActionsModel.currentItem.content == undefined ? emptyItem : machineActionsModel.currentItem.content + } + + // An empty item in case there's no currentItem.content to show + Item + { + id: emptyItem } Cura.PrimaryButton @@ -75,20 +75,6 @@ Item text: catalog.i18nc("@button", "Next") width: UM.Theme.getSize("welcome_pages_button").width fixedWidthMode: true - onClicked: - { - // If no more first-start actions to show, go to the next page. - if (currentActionIndex + 1 >= machineActionsModel.count) - { - currentActionIndex = 0 - base.showNextPage() - return - } - - // notify the current MachineAction that it has finished - currentActionItem.action.setFinished() - // move on to the next MachineAction - currentActionIndex++ - } + onClicked: machineActionsModel.goToNextAction() } }