Move page index logic into WelcomePagesModel

This commit is contained in:
Lipu Fei 2019-03-26 11:34:44 +01:00
parent 20bd9ea501
commit 418ad73a63
5 changed files with 126 additions and 73 deletions

View file

@ -1,10 +1,12 @@
# Copyright (c) 2019 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from collections import deque
import os import os
from typing import TYPE_CHECKING, Optional, List, Dict, Any from typing import TYPE_CHECKING, Optional, List, Dict, Any, Deque
from PyQt5.QtCore import QUrl, Qt from PyQt5.QtCore import QUrl, Qt, pyqtSlot, pyqtProperty, pyqtSignal
from UM.Logger import Logger
from UM.Qt.ListModel import ListModel from UM.Qt.ListModel import ListModel
from UM.Resources import Resources from UM.Resources import Resources
@ -18,7 +20,6 @@ class WelcomePagesModel(ListModel):
PageUrlRole = Qt.UserRole + 2 # URL to the page's QML file PageUrlRole = Qt.UserRole + 2 # URL to the page's QML file
NextPageIdRole = Qt.UserRole + 3 # The next page ID it should go to NextPageIdRole = Qt.UserRole + 3 # The next page ID it should go to
def __init__(self, parent: Optional["QObject"] = None) -> None: def __init__(self, parent: Optional["QObject"] = None) -> None:
super().__init__(parent) super().__init__(parent)
@ -28,6 +29,99 @@ class WelcomePagesModel(ListModel):
self._pages = [] # type: List[Dict[str, Any]] self._pages = [] # type: List[Dict[str, Any]]
self._current_page_index = 0
# Store all the previous page indices so it can go back.
self._previous_page_indices_stack = deque() # type: Deque[int]
allFinished = pyqtSignal() # emitted when all steps have been finished
currentPageIndexChanged = pyqtSignal()
@pyqtProperty(int, notify = currentPageIndexChanged)
def currentPageIndex(self) -> int:
return self._current_page_index
# Returns a float number in [0, 1] which indicates the current progress.
@pyqtProperty(float, notify = currentPageIndexChanged)
def currentProgress(self) -> float:
return self._current_page_index / len(self._items)
# Indicates if the current page is the last page.
@pyqtProperty(bool, notify = currentPageIndexChanged)
def isCurrentPageLast(self) -> bool:
return self._current_page_index == len(self._items) - 1
def _setCurrentPageIndex(self, page_index: int) -> None:
if page_index != self._current_page_index:
self._previous_page_indices_stack.append(self._current_page_index)
self._current_page_index = page_index
self.currentPageIndexChanged.emit()
# Goes to the next page.
@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
# If we have reached the last page, emit allFinished signal and reset.
if next_page_index == len(self._items):
self.allFinished.emit()
self.resetState()
# Move to the next page
self._setCurrentPageIndex(next_page_index)
# Goes to the previous page. If there's no previous page, do nothing.
@pyqtSlot()
def goToPreviousPage(self) -> None:
if len(self._previous_page_indices_stack) == 0:
Logger.log("i", "No previous page, do nothing")
return
previous_page_index = self._previous_page_indices_stack.pop()
self._current_page_index = previous_page_index
self.currentPageIndexChanged.emit()
# Sets the current page to the given page ID. If the page ID is not found, do nothing.
@pyqtSlot(str)
def goToPage(self, page_id: str) -> None:
page_index = self.getPageIndexById(page_id)
if page_index is None:
# FIXME: If we cannot find the next page, we cannot do anything here.
Logger.log("e", "Cannot find page with ID [%s]", page_index)
return
# Move to that page
self._setCurrentPageIndex(page_index)
# Resets the state of the WelcomePagesModel. This functions does the following:
# - Resets current_page_index to 0
# - Clears the previous page indices stack
@pyqtSlot()
def resetState(self) -> None:
self._current_page_index = 0
self._previous_page_indices_stack.clear()
self.currentPageIndexChanged.emit()
# Gets the page index with the given page ID. If the page ID doesn't exist, returns None.
def getPageIndexById(self, page_id: str) -> Optional[int]:
page_idx = None
for idx, page_item in enumerate(self._items):
if page_item["id"] == page_id:
page_idx = idx
break
return page_idx
# Convenience function to get QUrl path to pages that's located in "resources/qml/WelcomePages". # Convenience function to get QUrl path to pages that's located in "resources/qml/WelcomePages".
def _getBuiltinWelcomePagePath(self, page_filename: str) -> "QUrl": def _getBuiltinWelcomePagePath(self, page_filename: str) -> "QUrl":
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
@ -35,7 +129,6 @@ class WelcomePagesModel(ListModel):
os.path.join("WelcomePages", page_filename))) os.path.join("WelcomePages", page_filename)))
def initialize(self) -> None: def initialize(self) -> None:
# Add default welcome pages # Add default welcome pages
self._pages.append({"id": "welcome", self._pages.append({"id": "welcome",
"page_url": self._getBuiltinWelcomePagePath("WelcomeContent.qml"), "page_url": self._getBuiltinWelcomePagePath("WelcomeContent.qml"),
@ -51,9 +144,11 @@ class WelcomePagesModel(ListModel):
}) })
self._pages.append({"id": "add_network_or_local_printer", self._pages.append({"id": "add_network_or_local_printer",
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"), "page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
"next_page_id": "cloud",
}) })
self._pages.append({"id": "add_printer_by_ip", self._pages.append({"id": "add_printer_by_ip",
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"), "page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
"next_page_id": "cloud",
}) })
self._pages.append({"id": "cloud", self._pages.append({"id": "cloud",
"page_url": self._getBuiltinWelcomePagePath("CloudContent.qml"), "page_url": self._getBuiltinWelcomePagePath("CloudContent.qml"),

View file

@ -76,12 +76,11 @@ UM.MainWindow
if (CuraApplication.needToShowUserAgreement) if (CuraApplication.needToShowUserAgreement)
{ {
welcomeDialog.visible = true; welcomeDialog.show()
welcomeDialog.currentStep = 0;
} }
else else
{ {
welcomeDialog.visible = false; welcomeDialog.close()
} }
// TODO: While the new onboarding process contains the user-agreement, // TODO: While the new onboarding process contains the user-agreement,
// it should probably not entirely rely on 'needToShowUserAgreement' for show/hide. // it should probably not entirely rely on 'needToShowUserAgreement' for show/hide.

View file

@ -247,7 +247,7 @@ Item
text: catalog.i18nc("@button", "Cancel") text: catalog.i18nc("@button", "Cancel")
width: UM.Theme.getSize("action_button").width width: UM.Theme.getSize("action_button").width
fixedWidthMode: true fixedWidthMode: true
onClicked: base.goToPage("add_printer_by_selection") onClicked: base.showPreviousPage()
} }
Cura.PrimaryButton Cura.PrimaryButton

View file

@ -14,6 +14,7 @@ Window
{ {
UM.I18nCatalog { id: catalog; name: "cura" } UM.I18nCatalog { id: catalog; name: "cura" }
id: dialog
title: catalog.i18nc("@title", "Welcome to Ultimaker Cura") title: catalog.i18nc("@title", "Welcome to Ultimaker Cura")
modality: Qt.ApplicationModal modality: Qt.ApplicationModal
flags: Qt.Window | Qt.FramelessWindowHint flags: Qt.Window | Qt.FramelessWindowHint
@ -24,14 +25,21 @@ Window
property int shadowOffset: 1 * screenScaleFactor property int shadowOffset: 1 * screenScaleFactor
property alias currentStep: stepPanel.currentStep property var model: CuraApplication.getWelcomePagesModel()
onVisibleChanged:
{
if (visible)
{
model.resetState()
}
}
WizardPanel WizardPanel
{ {
id: stepPanel id: stepPanel
anchors.fill: parent anchors.fill: parent
currentStep: 0 model: dialog.model
model: CuraApplication.getWelcomePagesModel()
} }
// Drop shadow around the panel // Drop shadow around the panel
@ -50,7 +58,7 @@ Window
// Close this dialog when there's no more page to show // Close this dialog when there's no more page to show
Connections Connections
{ {
target: stepPanel target: model
onPassLastPage: close() onAllFinished: close()
} }
} }

View file

@ -20,70 +20,21 @@ Item
clip: true clip: true
property int currentStep: 0 property var currentItem: (model == null) ? null : model.getItem(model.currentPageIndex)
property int totalStepCount: (model == null) ? 0 : model.count
property real progressValue: (totalStepCount == 0) ? 0 : (currentStep / totalStepCount)
property var currentItem: (model == null) ? null : model.getItem(currentStep)
property var model: null property var model: null
// Convenience properties
property var progressValue: model == null ? 0 : model.currentProgress
property string pageUrl: currentItem == null ? null : currentItem.page_url
signal showNextPage() signal showNextPage()
signal showPreviousPage() signal showPreviousPage()
signal passLastPage() // Emitted when there is no more page to show
signal goToPage(string page_id) // Go to a specific page by the given page_id. signal goToPage(string page_id) // Go to a specific page by the given page_id.
onShowNextPage: // Call the corresponding functions in the model
{ onShowNextPage: model.goToNextPage()
if (currentStep < totalStepCount - 1) onShowPreviousPage: model.goToPreviousPage()
{ onGoToPage: model.goToPage(page_id)
currentStep++
}
else
{
passLastPage()
}
}
onShowPreviousPage:
{
if (currentStep > 0)
{
currentStep--
}
}
onGoToPage:
{
// find the page index
var page_index = -1
for (var i = 0; i < base.model.count; i++)
{
const item = base.model.getItem(i)
if (item.id == page_id)
{
page_index = i
break
}
}
if (page_index > 0)
{
currentStep = page_index
}
}
onVisibleChanged:
{
if (visible)
{
base.currentStep = 0
base.currentItem = base.model.getItem(base.currentStep)
}
}
onModelChanged:
{
base.currentStep = 0
}
Rectangle // Panel background Rectangle // Panel background
{ {
@ -108,13 +59,13 @@ Item
id: contentLoader id: contentLoader
anchors anchors
{ {
margins: base.contentMargins margins: UM.Theme.getSize("default_margin").width
top: progressBar.bottom top: progressBar.bottom
bottom: parent.bottom bottom: parent.bottom
left: parent.left left: parent.left
right: parent.right right: parent.right
} }
source: base.currentItem.page_url source: base.pageUrl
} }
} }
} }