Merge branch 'master' into CURA-7509_plugin_versions_on_crash

This commit is contained in:
Kostas Karmas 2020-06-18 09:13:28 +02:00
commit 039823e68e
57 changed files with 10668 additions and 239 deletions

View file

@ -103,6 +103,11 @@ class Account(QObject):
self._authorization_service.accessTokenChanged.connect(self._onAccessTokenChanged)
self._authorization_service.loadAuthDataFromPreferences()
@pyqtProperty(int, notify=syncStateChanged)
def syncState(self):
return self._sync_state
def setSyncState(self, service_name: str, state: int) -> None:
""" Can be used to register sync services and update account sync states

View file

@ -1,22 +1,21 @@
from typing import Optional
from PyQt5.QtCore import QObject, pyqtSignal, QTimer, pyqtProperty
from PyQt5.QtNetwork import QNetworkReply
from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
from cura.UltimakerCloud import UltimakerCloudConstants
class ConnectionStatus(QObject):
"""Status info for some web services"""
"""Provides an estimation of whether internet is reachable
UPDATE_INTERVAL = 10.0 # seconds
ULTIMAKER_CLOUD_STATUS_URL = UltimakerCloudConstants.CuraCloudAPIRoot + "/connect/v1/"
Estimation is updated with every request through HttpRequestManager.
Acts as a proxy to HttpRequestManager.internetReachableChanged without
exposing the HttpRequestManager in its entirety.
"""
__instance = None # type: Optional[ConnectionStatus]
internetReachableChanged = pyqtSignal()
umCloudReachableChanged = pyqtSignal()
@classmethod
def getInstance(cls, *args, **kwargs) -> "ConnectionStatus":
@ -24,41 +23,19 @@ class ConnectionStatus(QObject):
cls.__instance = cls(*args, **kwargs)
return cls.__instance
def __init__(self, parent: Optional["QObject"] = None):
def __init__(self, parent: Optional["QObject"] = None) -> None:
super().__init__(parent)
self._http = HttpRequestManager.getInstance()
self._statuses = {
self.ULTIMAKER_CLOUD_STATUS_URL: True,
"http://example.com": True
}
manager = HttpRequestManager.getInstance()
self._is_internet_reachable = manager.isInternetReachable # type: bool
manager.internetReachableChanged.connect(self._onInternetReachableChanged)
# Create a timer for automatic updates
self._update_timer = QTimer()
self._update_timer.setInterval(int(self.UPDATE_INTERVAL * 1000))
# The timer is restarted automatically
self._update_timer.setSingleShot(False)
self._update_timer.timeout.connect(self._update)
self._update_timer.start()
@pyqtProperty(bool, notify=internetReachableChanged)
@pyqtProperty(bool, notify = internetReachableChanged)
def isInternetReachable(self) -> bool:
# Is any of the test urls reachable?
return any(self._statuses.values())
return self._is_internet_reachable
def _update(self):
for url in self._statuses.keys():
self._http.get(
url = url,
callback = self._statusCallback,
error_callback = self._statusCallback,
timeout = 5
)
def _statusCallback(self, reply: QNetworkReply, error: QNetworkReply.NetworkError = None):
url = reply.request().url().toString()
prev_statuses = self._statuses.copy()
self._statuses[url] = HttpRequestManager.replyIndicatesSuccess(reply, error)
if any(self._statuses.values()) != any(prev_statuses.values()):
def _onInternetReachableChanged(self, reachable: bool):
if reachable != self._is_internet_reachable:
self._is_internet_reachable = reachable
self.internetReachableChanged.emit()

View file

@ -207,6 +207,7 @@ class CuraApplication(QtApplication):
self._first_start_machine_actions_model = None
self._welcome_pages_model = WelcomePagesModel(self, parent = self)
self._add_printer_pages_model = AddPrinterPagesModel(self, parent = self)
self._add_printer_pages_model_without_cancel = AddPrinterPagesModel(self, parent = self)
self._whats_new_pages_model = WhatsNewPagesModel(self, parent = self)
self._text_manager = TextManager(parent = self)
@ -261,6 +262,10 @@ class CuraApplication(QtApplication):
def ultimakerCloudAccountRootUrl(self) -> str:
return UltimakerCloudConstants.CuraCloudAccountAPIRoot
@pyqtProperty(str, constant=True)
def ultimakerDigitalFactoryUrl(self) -> str:
return UltimakerCloudConstants.CuraDigitalFactoryURL
def addCommandLineOptions(self):
"""Adds command line options to the command line parser.
@ -647,7 +652,7 @@ class CuraApplication(QtApplication):
return self._global_container_stack
@override(Application)
def setGlobalContainerStack(self, stack: "GlobalStack") -> None:
def setGlobalContainerStack(self, stack: Optional["GlobalStack"]) -> None:
self._setLoadingHint(self._i18n_catalog.i18nc("@info:progress", "Initializing Active Machine..."))
super().setGlobalContainerStack(stack)
@ -812,6 +817,7 @@ class CuraApplication(QtApplication):
self._output_device_manager.start()
self._welcome_pages_model.initialize()
self._add_printer_pages_model.initialize()
self._add_printer_pages_model_without_cancel.initialize(cancellable = False)
self._whats_new_pages_model.initialize()
# Detect in which mode to run and execute that mode
@ -849,6 +855,7 @@ class CuraApplication(QtApplication):
self.callLater(self._openFile, file_name)
initializationFinished = pyqtSignal()
showAddPrintersUncancellableDialog = pyqtSignal() # Used to show the add printers dialog with a greyed background
def runWithoutGUI(self):
"""Run Cura without GUI elements and interaction (server mode)."""
@ -939,6 +946,10 @@ class CuraApplication(QtApplication):
def getAddPrinterPagesModel(self, *args) -> "AddPrinterPagesModel":
return self._add_printer_pages_model
@pyqtSlot(result = QObject)
def getAddPrinterPagesModelWithoutCancel(self, *args) -> "AddPrinterPagesModel":
return self._add_printer_pages_model_without_cancel
@pyqtSlot(result = QObject)
def getWhatsNewPagesModel(self, *args) -> "WhatsNewPagesModel":
return self._whats_new_pages_model

View file

@ -154,7 +154,7 @@ class BaseMaterialsModel(ListModel):
# Update the available materials (ContainerNode) for the current active machine and extruder setup.
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
if not global_stack.hasMaterials:
if not global_stack or not global_stack.hasMaterials:
return # There are no materials for this machine, so nothing to do.
extruder_list = global_stack.extruderList
if self._extruder_position > len(extruder_list):

View file

@ -7,6 +7,8 @@ from enum import IntEnum
from threading import Thread
from typing import Union
from UM.Logger import Logger
MYPY = False
if MYPY:
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
@ -38,8 +40,10 @@ class FirmwareUpdater(QObject):
return
self._setFirmwareUpdateState(FirmwareUpdateState.updating)
self._update_firmware_thread.start()
try:
self._update_firmware_thread.start()
except RuntimeError:
Logger.warning("Could not start the update thread, since it's still running!")
def _updateFirmware(self) -> None:
raise NotImplementedError("_updateFirmware needs to be implemented")

View file

@ -290,9 +290,15 @@ class MachineManager(QObject):
self.activeStackValueChanged.emit()
@pyqtSlot(str)
def setActiveMachine(self, stack_id: str) -> None:
def setActiveMachine(self, stack_id: Optional[str]) -> None:
self.blurSettings.emit() # Ensure no-one has focus.
if not stack_id:
self._application.setGlobalContainerStack(None)
self.globalContainerChanged.emit()
self._application.showAddPrintersUncancellableDialog.emit()
return
container_registry = CuraContainerRegistry.getInstance()
containers = container_registry.findContainerStacks(id = stack_id)
if not containers:
@ -721,6 +727,8 @@ class MachineManager(QObject):
other_machine_stacks = [s for s in machine_stacks if s["id"] != machine_id]
if other_machine_stacks:
self.setActiveMachine(other_machine_stacks[0]["id"])
else:
self.setActiveMachine(None)
metadatas = CuraContainerRegistry.getInstance().findContainerStacksMetadata(id = machine_id)
if not metadatas:

View file

@ -10,12 +10,11 @@ from .WelcomePagesModel import WelcomePagesModel
#
class AddPrinterPagesModel(WelcomePagesModel):
def initialize(self) -> None:
def initialize(self, cancellable: bool = True) -> None:
self._pages.append({"id": "add_network_or_local_printer",
"page_url": self._getBuiltinWelcomePagePath("AddNetworkOrLocalPrinterContent.qml"),
"next_page_id": "machine_actions",
"next_page_button_text": self._catalog.i18nc("@action:button", "Add"),
"previous_page_button_text": self._catalog.i18nc("@action:button", "Cancel"),
})
self._pages.append({"id": "add_printer_by_ip",
"page_url": self._getBuiltinWelcomePagePath("AddPrinterByIpContent.qml"),
@ -30,6 +29,9 @@ class AddPrinterPagesModel(WelcomePagesModel):
"page_url": self._getBuiltinWelcomePagePath("FirstStartMachineActionsContent.qml"),
"should_show_function": self.shouldShowMachineActions,
})
if cancellable:
self._pages[0]["previous_page_button_text"] = self._catalog.i18nc("@action:button", "Cancel")
self.setItems(self._pages)

View file

@ -7,6 +7,7 @@
DEFAULT_CLOUD_API_ROOT = "https://api.ultimaker.com" # type: str
DEFAULT_CLOUD_API_VERSION = "1" # type: str
DEFAULT_CLOUD_ACCOUNT_API_ROOT = "https://account.ultimaker.com" # type: str
DEFAULT_DIGITAL_FACTORY_URL = "https://digitalfactory.ultimaker.com" # type: str
# Container Metadata keys
META_UM_LINKED_TO_ACCOUNT = "um_linked_to_account"
@ -32,3 +33,10 @@ try:
CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT
except ImportError:
CuraCloudAccountAPIRoot = DEFAULT_CLOUD_ACCOUNT_API_ROOT
try:
from cura.CuraVersion import CuraDigitalFactoryURL # type: ignore
if CuraDigitalFactoryURL == "":
CuraDigitalFactoryURL = DEFAULT_DIGITAL_FACTORY_URL
except ImportError:
CuraDigitalFactoryURL = DEFAULT_DIGITAL_FACTORY_URL