From b70e9c90800af9671cfb5c494bd25e965aee4408 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Tue, 29 Jan 2019 08:16:39 +0100 Subject: [PATCH 1/6] Handle empty hotend and material in config syncing CURA-5693 - Disable an extruder if the config states no material or nozzle for it. - Show a warning message if an used extruder gets disabled. --- cura/Settings/ExtrudersModel.py | 7 ++-- cura/Settings/MachineManager.py | 62 +++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/cura/Settings/ExtrudersModel.py b/cura/Settings/ExtrudersModel.py index 076cebf60d..afc2af94b3 100644 --- a/cura/Settings/ExtrudersModel.py +++ b/cura/Settings/ExtrudersModel.py @@ -107,17 +107,19 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): # that signal. Application.globalContainerStackChanged doesn't fill this # signal; it's assumed to be the current printer in that case. def _extrudersChanged(self, machine_id = None): + machine_manager = Application.getInstance().getMachineManager() if machine_id is not None: - if Application.getInstance().getGlobalContainerStack() is None: + if machine_manager.activeMachine is None: # No machine, don't need to update the current machine's extruders return - if machine_id != Application.getInstance().getGlobalContainerStack().getId(): + if machine_id != machine_manager.activeMachine.getId(): # Not the current machine return # Unlink from old extruders for extruder in self._active_machine_extruders: extruder.containersChanged.disconnect(self._onExtruderStackContainersChanged) + extruder.enabledChanged.disconnect(self._updateExtruders) # Link to new extruders self._active_machine_extruders = [] @@ -126,6 +128,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel): if extruder is None: #This extruder wasn't loaded yet. This happens asynchronously while this model is constructed from QML. continue extruder.containersChanged.connect(self._onExtruderStackContainersChanged) + extruder.enabledChanged.connect(self._updateExtruders) self._active_machine_extruders.append(extruder) self._updateExtruders() # Since the new extruders may have different properties, update our own model. diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index ae74d76734..b0192ce9c0 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -117,10 +117,6 @@ class MachineManager(QObject): self._application.callLater(self.setInitialActiveMachine) - self._material_incompatible_message = Message(catalog.i18nc("@info:status", - "The selected material is incompatible with the selected machine or configuration."), - title = catalog.i18nc("@info:title", "Incompatible Material")) # type: Message - containers = CuraContainerRegistry.getInstance().findInstanceContainers(id = self.activeMaterialId) # type: List[InstanceContainer] if containers: containers[0].nameChanged.connect(self._onMaterialNameChanged) @@ -1369,25 +1365,47 @@ class MachineManager(QObject): self.blurSettings.emit() with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.switchPrinterType(configuration.printerType) + + used_extruder_stack_list = ExtruderManager.getInstance().getUsedExtruderStacks() + used_extruder_position_set = {es.getMetaDataEntry("position") for es in used_extruder_stack_list} + disabled_used_extruder_position_set = set() + + # If an extruder that's currently used to print a model gets disabled due to the syncing, we need to show + # a message explaining why. + need_to_show_message = False + for extruder_configuration in configuration.extruderConfigurations: position = str(extruder_configuration.position) - variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), extruder_configuration.hotendID) - material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, - position, - extruder_configuration.hotendID, - configuration.buildplateConfiguration, - extruder_configuration.material.guid) - if variant_container_node: - self._setVariantNode(position, variant_container_node) - else: - self._global_container_stack.extruders[position].variant = empty_variant_container + extruder_has_hotend = extruder_configuration.hotendID != "" + extruder_has_material = extruder_configuration.material.guid != "" + + # If the machine doesn't have a hotend or material, disable this extruder + if not extruder_has_hotend or not extruder_has_material: + self._global_container_stack.extruders[position].setEnabled(False) + if position in used_extruder_position_set: + need_to_show_message = True + disabled_used_extruder_position_set.add(int(position)) - if material_container_node: - self._setMaterial(position, material_container_node) else: - self._global_container_stack.extruders[position].material = empty_material_container - self.updateMaterialWithVariant(position) + variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), + extruder_configuration.hotendID) + material_container_node = self._material_manager.getMaterialNodeByType(self._global_container_stack, + position, + extruder_configuration.hotendID, + configuration.buildplateConfiguration, + extruder_configuration.material.guid) + if variant_container_node: + self._setVariantNode(position, variant_container_node) + else: + self._global_container_stack.extruders[position].variant = empty_variant_container + + if material_container_node: + self._setMaterial(position, material_container_node) + else: + self._global_container_stack.extruders[position].material = empty_material_container + self._global_container_stack.extruders[position].setEnabled(True) + self.updateMaterialWithVariant(position) if configuration.buildplateConfiguration is not None: global_variant_container_node = self._variant_manager.getBuildplateVariantNode(self._global_container_stack.definition.getId(), configuration.buildplateConfiguration) @@ -1399,6 +1417,14 @@ class MachineManager(QObject): self._global_container_stack.variant = empty_variant_container self._updateQualityWithMaterial() + if need_to_show_message: + msg_str = "Extruder {extruders} is disabled because there is no material loaded. Please load a material or use custom configurations." + extruders_str = ", ".join(str(x) for x in sorted(disabled_used_extruder_position_set)) + msg_str = msg_str.format(extruders = extruders_str) + message = Message(catalog.i18nc("@info:status", msg_str), + title = catalog.i18nc("@info:title", "Extruders Disabled")) + message.show() + # See if we need to show the Discard or Keep changes screen if self.hasUserSettings and self._application.getPreferences().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() From b884e46187ea1e95f28be34f335061703b00eaa5 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Wed, 30 Jan 2019 22:02:13 +0100 Subject: [PATCH 2/6] Ensure Cura stores the cloud connection type in the stack file --- .../src/Cloud/CloudOutputDeviceManager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index c9c78caa0f..78944d954b 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -111,7 +111,7 @@ class CloudOutputDeviceManager: stored_cluster_id = active_machine.getMetaDataEntry(self.META_CLUSTER_ID) if stored_cluster_id in self._remote_clusters: device = self._remote_clusters[stored_cluster_id] - self._connectToOutputDevice(device) + self._connectToOutputDevice(device, active_machine) Logger.log("d", "Device connected by metadata cluster ID %s", stored_cluster_id) else: self._connectByNetworkKey(active_machine) @@ -129,12 +129,13 @@ class CloudOutputDeviceManager: Logger.log("i", "Found cluster %s with network key %s", device, local_network_key) active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) - self._connectToOutputDevice(device) + self._connectToOutputDevice(device, active_machine) ## Connects to an output device and makes sure it is registered in the output device manager. - def _connectToOutputDevice(self, device: CloudOutputDevice) -> None: + def _connectToOutputDevice(self, device: CloudOutputDevice, active_machine: GlobalStack) -> None: device.connect() self._output_device_manager.addOutputDevice(device) + active_machine.addConfiguredConnectionType(device.connectionType.value) ## Handles an API error received from the cloud. # \param errors: The errors received From 4f6d53b0097b998ab24ff108532434fbd86d52b3 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 31 Jan 2019 08:30:35 +0100 Subject: [PATCH 3/6] Do not disable all extruders when syncing CURA-5693 When syncing with a machine with no material/nozzle, do not disable all extruders. leave the first one enabled. --- cura/Settings/MachineManager.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index b0192ce9c0..be40f420fc 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1369,19 +1369,29 @@ class MachineManager(QObject): used_extruder_stack_list = ExtruderManager.getInstance().getUsedExtruderStacks() used_extruder_position_set = {es.getMetaDataEntry("position") for es in used_extruder_stack_list} disabled_used_extruder_position_set = set() + extruders_to_disable = set() # If an extruder that's currently used to print a model gets disabled due to the syncing, we need to show # a message explaining why. need_to_show_message = False for extruder_configuration in configuration.extruderConfigurations: - position = str(extruder_configuration.position) - extruder_has_hotend = extruder_configuration.hotendID != "" extruder_has_material = extruder_configuration.material.guid != "" # If the machine doesn't have a hotend or material, disable this extruder if not extruder_has_hotend or not extruder_has_material: + extruders_to_disable.add(extruder_configuration.position) + + # If there's no material and/or nozzle on the printer, enable the first extruder and disable the rest. + if len(extruders_to_disable) == len(self._global_container_stack.extruders): + extruders_to_disable.remove(min(extruders_to_disable)) + + for extruder_configuration in configuration.extruderConfigurations: + position = str(extruder_configuration.position) + + # If the machine doesn't have a hotend or material, disable this extruder + if int(position) in extruders_to_disable: self._global_container_stack.extruders[position].setEnabled(False) if position in used_extruder_position_set: need_to_show_message = True From f0d9aa77c2d6d6a85e73712236acfa62efbc344f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 31 Jan 2019 09:43:31 +0100 Subject: [PATCH 4/6] Make account button non-fixed-width CURA-6132 --- resources/qml/Account/UserOperations.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/Account/UserOperations.qml b/resources/qml/Account/UserOperations.qml index 88a6d9d827..c9fb461696 100644 --- a/resources/qml/Account/UserOperations.qml +++ b/resources/qml/Account/UserOperations.qml @@ -39,7 +39,7 @@ Column height: UM.Theme.getSize("account_button").height text: catalog.i18nc("@button", "Ultimaker account") onClicked: Qt.openUrlExternally(CuraApplication.ultimakerCloudAccountRootUrl) - fixedWidthMode: true + fixedWidthMode: false } Label From 3734b980d8ba5816377222781edebc12e30b5576 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 31 Jan 2019 11:30:37 +0100 Subject: [PATCH 5/6] When disabling an extruder due to sync, always show a message. Originally it would only show a message if the extruder was actually used, but this didn't take the flow into account when you would first sync and then load a model. In that case, the user never got a message and never got any notification that (and why) any of the extruders got disabled. CURA-5693 --- cura/Settings/MachineManager.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index be40f420fc..fbeb2f71e4 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -1367,7 +1367,6 @@ class MachineManager(QObject): self.switchPrinterType(configuration.printerType) used_extruder_stack_list = ExtruderManager.getInstance().getUsedExtruderStacks() - used_extruder_position_set = {es.getMetaDataEntry("position") for es in used_extruder_stack_list} disabled_used_extruder_position_set = set() extruders_to_disable = set() @@ -1393,9 +1392,9 @@ class MachineManager(QObject): # If the machine doesn't have a hotend or material, disable this extruder if int(position) in extruders_to_disable: self._global_container_stack.extruders[position].setEnabled(False) - if position in used_extruder_position_set: - need_to_show_message = True - disabled_used_extruder_position_set.add(int(position)) + + need_to_show_message = True + disabled_used_extruder_position_set.add(int(position)) else: variant_container_node = self._variant_manager.getVariantNode(self._global_container_stack.definition.getId(), @@ -1432,7 +1431,7 @@ class MachineManager(QObject): extruders_str = ", ".join(str(x) for x in sorted(disabled_used_extruder_position_set)) msg_str = msg_str.format(extruders = extruders_str) message = Message(catalog.i18nc("@info:status", msg_str), - title = catalog.i18nc("@info:title", "Extruders Disabled")) + title = catalog.i18nc("@info:title", "Extruder(s) Disabled")) message.show() # See if we need to show the Discard or Keep changes screen From d5e34cc9c99b293c72248989beb088c019802319 Mon Sep 17 00:00:00 2001 From: Jaime van Kessel Date: Thu, 31 Jan 2019 12:59:29 +0100 Subject: [PATCH 6/6] Prevent crash when activePrinter doesn't have a controller Got the crash from the automatic crash reports --- plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 59552775b6..e2b0041674 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -57,7 +57,7 @@ class FirmwareUpdaterMachineAction(MachineAction): outputDeviceCanUpdateFirmwareChanged = pyqtSignal() @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) def firmwareUpdater(self) -> Optional["FirmwareUpdater"]: - if self._active_output_device and self._active_output_device.activePrinter and self._active_output_device.activePrinter.getController().can_update_firmware: + if self._active_output_device and self._active_output_device.activePrinter and self._active_output_device.activePrinter.getController() is not None and self._active_output_device.activePrinter.getController().can_update_firmware: self._active_firmware_updater = self._active_output_device.getFirmwareUpdater() return self._active_firmware_updater