diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 54abaca86e..c25b58fbcf 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -597,6 +597,18 @@ class MachineManager(QObject): if extruder_stack != self._active_container_stack and extruder_stack.getProperty(key, "value") != new_value: extruder_stack.userChanges.setProperty(key, "value", new_value) # TODO: nested property access, should be improved + ## Copy the value of all manually changed settings of the current extruder to all other extruders. + @pyqtSlot() + def copyAllValuesToExtruders(self): + extruder_stacks = list(self._global_container_stack.extruders.values()) + for extruder_stack in extruder_stacks: + if extruder_stack != self._active_container_stack: + for key in self._active_container_stack.userChanges.getAllKeys(): + new_value = self._active_container_stack.getProperty(key, "value") + + # check if the value has to be replaced + extruder_stack.userChanges.setProperty(key, "value", new_value) + @pyqtProperty(str, notify = activeVariantChanged) def activeVariantName(self) -> str: if self._active_container_stack: diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index e55abe59a2..9873d91c05 100755 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -119,6 +119,7 @@ class CuraEngineBackend(QObject, Backend): self._postponed_scene_change_sources = [] # scene change is postponed (by a tool) self._slice_start_time = None + self._is_disabled = False Preferences.getInstance().addPreference("general/auto_slice", True) @@ -405,6 +406,7 @@ class CuraEngineBackend(QObject, Backend): # - decorator isBlockSlicing is found (used in g-code reader) def determineAutoSlicing(self): enable_timer = True + self._is_disabled = False if not Preferences.getInstance().getValue("general/auto_slice"): enable_timer = False @@ -412,6 +414,7 @@ class CuraEngineBackend(QObject, Backend): if node.callDecoration("isBlockSlicing"): enable_timer = False self.backendStateChange.emit(BackendState.Disabled) + self._is_disabled = True gcode_list = node.callDecoration("getGCodeList") if gcode_list is not None: self._scene.gcode_dict[node.callDecoration("getBuildPlateNumber")] = gcode_list @@ -545,6 +548,10 @@ class CuraEngineBackend(QObject, Backend): self._change_timer.stop() def _onStackErrorCheckFinished(self): + self.determineAutoSlicing() + if self._is_disabled: + return + if not self._slicing and self._build_plates_to_be_sliced: self.needsSlicing() self._onChanged() diff --git a/plugins/GCodeGzReader/GCodeGzReader.py b/plugins/GCodeGzReader/GCodeGzReader.py index 5736fd2fec..0843f8f3c0 100644 --- a/plugins/GCodeGzReader/GCodeGzReader.py +++ b/plugins/GCodeGzReader/GCodeGzReader.py @@ -8,13 +8,13 @@ from io import TextIOWrapper from UM.Mesh.MeshReader import MeshReader #The class we're extending/implementing. from UM.PluginRegistry import PluginRegistry -## A file writer that writes gzipped g-code. +## A file reader that reads gzipped g-code. # # If you're zipping g-code, you might as well use gzip! class GCodeGzReader(MeshReader): def __init__(self): - super(GCodeGzReader, self).__init__() + super().__init__() self._supported_extensions = [".gcode.gz"] def read(self, file_name): diff --git a/plugins/GCodeGzReader/__init__.py b/plugins/GCodeGzReader/__init__.py index 67424a7d45..98965c00aa 100644 --- a/plugins/GCodeGzReader/__init__.py +++ b/plugins/GCodeGzReader/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Aleph Objects, Inc. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from . import GCodeGzReader diff --git a/plugins/PluginBrowser/PluginBrowser.py b/plugins/PluginBrowser/PluginBrowser.py index c8a5e1e545..bb4d5fb395 100644 --- a/plugins/PluginBrowser/PluginBrowser.py +++ b/plugins/PluginBrowser/PluginBrowser.py @@ -1,11 +1,10 @@ # Copyright (c) 2017 Ultimaker B.V. # PluginBrowser is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import QUrl, QObject, Qt, pyqtProperty, pyqtSignal, pyqtSlot +from PyQt5.QtCore import QUrl, QObject, pyqtProperty, pyqtSignal, pyqtSlot from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from UM.Application import Application -from UM.Qt.ListModel import ListModel from UM.Logger import Logger from UM.PluginRegistry import PluginRegistry from UM.Qt.Bindings.PluginsModel import PluginsModel @@ -20,7 +19,6 @@ import os import tempfile import platform import zipfile -import shutil from cura.CuraApplication import CuraApplication @@ -44,7 +42,7 @@ class PluginBrowser(QObject, Extension): self._plugins_metadata = [] self._plugins_model = None - # Can be 'installed' or 'availble' + # Can be 'installed' or 'available' self._view = "available" self._restart_required = False diff --git a/plugins/PluginBrowser/PluginEntry.qml b/plugins/PluginBrowser/PluginEntry.qml index eff9eb8943..9dbcb96e79 100644 --- a/plugins/PluginBrowser/PluginEntry.qml +++ b/plugins/PluginBrowser/PluginEntry.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // PluginBrowser is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -129,6 +129,18 @@ Component { return catalog.i18nc("@action:button", "Install"); } } + enabled: + { + if ( manager.isDownloading ) + { + return pluginList.activePlugin == model ? true : false + } + else + { + return true + } + } + opacity: enabled ? 1.0 : 0.5 visible: model.external && ((model.status !== "installed") || model.can_upgrade) style: ButtonStyle { background: Rectangle { diff --git a/plugins/SimulationView/SimulationView.py b/plugins/SimulationView/SimulationView.py index 3697e38661..85849efb2f 100644 --- a/plugins/SimulationView/SimulationView.py +++ b/plugins/SimulationView/SimulationView.py @@ -74,7 +74,7 @@ class SimulationView(View): self._global_container_stack = None self._proxy = SimulationViewProxy() - self._controller.getScene().sceneChanged.connect(self._onSceneChanged) + self._controller.getScene().getRoot().childrenChanged.connect(self._onSceneChanged) self._resetSettings() self._legend_items = None @@ -160,10 +160,10 @@ class SimulationView(View): def _onSceneChanged(self, node): if node.getMeshData() is None: self.resetLayerData() - else: - self.setActivity(False) - self.calculateMaxLayers() - self.calculateMaxPathsOnLayer(self._current_layer_num) + + self.setActivity(False) + self.calculateMaxLayers() + self.calculateMaxPathsOnLayer(self._current_layer_num) def isBusy(self): return self._busy diff --git a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py index 72f5260249..f3667fc2f3 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3OutputDevice.py @@ -127,10 +127,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._sending_job.send("") #No specifically selected printer. is_job_sent = self._sending_job.send(None) - # Notify the UI that a switch to the print monitor should happen - if is_job_sent: - Application.getInstance().getController().setActiveStage("MonitorStage") - def _spawnPrinterSelectionDialog(self): if self._printer_selection_dialog is None: path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "PrintWindow.qml") @@ -242,6 +238,19 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): if new_progress > self._progress_message.getProgress(): self._progress_message.show() # Ensure that the message is visible. self._progress_message.setProgress(bytes_sent / bytes_total * 100) + + # If successfully sent: + if bytes_sent == bytes_total: + # Show a confirmation to the user so they know the job was sucessful and provide the option to switch to the + # monitor tab. + self._success_message = Message( + i18n_catalog.i18nc("@info:status", "Print job was successfully sent to the printer."), + lifetime=5, dismissable=True, + title=i18n_catalog.i18nc("@info:title", "Data Sent")) + self._success_message.addAction("View", i18n_catalog.i18nc("@action:button", "View in Montior"), icon=None, + description="") + self._success_message.actionTriggered.connect(self._successMessageActionTriggered) + self._success_message.show() else: self._progress_message.setProgress(0) self._progress_message.hide() @@ -260,6 +269,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice): self._latest_reply_handler.disconnect() self._latest_reply_handler = None + def _successMessageActionTriggered(self, message_id: Optional[str]=None, action_id: Optional[str]=None) -> None: + if action_id == "View": + Application.getInstance().getController().setActiveStage("MonitorStage") @pyqtSlot() def openPrintJobControlPanel(self) -> None: diff --git a/resources/i18n/de_DE/cura.po b/resources/i18n/de_DE/cura.po index 250e3e5e1b..f398d1ec4e 100644 --- a/resources/i18n/de_DE/cura.po +++ b/resources/i18n/de_DE/cura.po @@ -194,7 +194,7 @@ msgstr "Vorbereiten" #: /home/ruben/Projects/Cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:23 msgctxt "@action:button Preceded by 'Ready to'." msgid "Save to Removable Drive" -msgstr "Speichern auf Wechseldatenträger" +msgstr "Speichern auf Datenträger" #: /home/ruben/Projects/Cura/plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:24 #, python-brace-format diff --git a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml index 331d78ead9..7aaf87b4df 100644 --- a/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml +++ b/resources/qml/Menus/ConfigurationMenu/ConfigurationListView.qml @@ -21,7 +21,10 @@ Column { // FIXME For now the model should be removed and then created again, otherwise changes in the printer don't automatically update the UI configurationList.model = [] - configurationList.model = outputDevice.uniqueConfigurations + if(outputDevice) + { + configurationList.model = outputDevice.uniqueConfigurations + } } Label diff --git a/resources/qml/Settings/SettingView.qml b/resources/qml/Settings/SettingView.qml index 199db1bbaa..4a919ab9bd 100644 --- a/resources/qml/Settings/SettingView.qml +++ b/resources/qml/Settings/SettingView.qml @@ -533,6 +533,15 @@ Item onTriggered: Cura.MachineManager.copyValueToExtruders(contextMenu.key) } + MenuItem + { + //: Settings context menu action + text: catalog.i18nc("@action:menu", "Copy all changed values to all extruders") + visible: machineExtruderCount.properties.value > 1 + enabled: contextMenu.provider != undefined + onTriggered: Cura.MachineManager.copyAllValuesToExtruders() + } + MenuSeparator { visible: machineExtruderCount.properties.value > 1