diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 03a248b238..07879f33cf 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -986,7 +986,7 @@ class CuraApplication(QtApplication): return self._i18n_catalog.i18nc("@info 'width', 'depth' and 'height' are variable names that must NOT be translated; just translate the format of ##x##x## mm.", "%(width).1f x %(depth).1f x %(height).1f mm") % {'width' : self._scene_bounding_box.width.item(), 'depth': self._scene_bounding_box.depth.item(), 'height' : self._scene_bounding_box.height.item()} def updatePlatformActivityDelayed(self, node = None): - if node is not None and node.getMeshData() is not None: + if node is not None and (node.getMeshData() is not None or node.callDecoration("getLayerData")): self._update_platform_activity_timer.start() ## Update scene bounding box for current build plate diff --git a/cura/PrintInformation.py b/cura/PrintInformation.py index d0e9e43e3f..1d66916b52 100644 --- a/cura/PrintInformation.py +++ b/cura/PrintInformation.py @@ -323,16 +323,21 @@ class PrintInformation(QObject): # when a file is opened using the terminal; the filename comes from _onFileLoaded and still contains its # extension. This cuts the extension off if necessary. name = os.path.splitext(name)[0] + filename_parts = os.path.basename(base_name).split(".") + + # If it's a gcode, also always update the job name + is_gcode = False + if len(filename_parts) > 1: + # Only check the extension(s) + is_gcode = "gcode" in filename_parts[1:] # if this is a profile file, always update the job name # name is "" when I first had some meshes and afterwards I deleted them so the naming should start again is_empty = name == "" - if is_project_file or (is_empty or (self._base_name == "" and self._base_name != name)): - # remove ".curaproject" suffix from (imported) the file name - if name.endswith(".curaproject"): - name = name[:name.rfind(".curaproject")] - self._base_name = name - self._updateJobName() + if is_gcode or is_project_file or (is_empty or (self._base_name == "" and self._base_name != name)): + # Only take the file name part + self._base_name = filename_parts[0] + self._updateJobName() @pyqtProperty(str, fset = setBaseName, notify = baseNameChanged) def baseName(self): diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index 470848c208..bfa3cfbc82 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -152,3 +152,17 @@ class GenericOutputController(PrinterOutputController): for extruder in self._preheat_hotends: self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) self._preheat_hotends = set() + + # Cancel any ongoing preheating timers, without setting back the temperature to 0 + # This can be used eg at the start of a print + def stopPreheatTimers(self): + if self._preheat_hotends_timer.isActive(): + for extruder in self._preheat_hotends: + extruder.updateIsPreheating(False) + self._preheat_hotends = set() + + self._preheat_hotends_timer.stop() + + if self._preheat_bed_timer.isActive(): + self._preheat_printer.updateIsPreheating(False) + self._preheat_bed_timer.stop() diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index cd50476c73..46ee0096ef 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -310,19 +310,40 @@ class MachineManager(QObject): global_quality_changes = global_stack.qualityChanges global_quality_changes_name = global_quality_changes.getName() + # Try to set the same quality/quality_changes as the machine specified. + # If the quality/quality_changes is not available, switch to the default or the first quality that's available. + same_quality_found = False + quality_groups = self._application.getQualityManager().getQualityGroups(global_stack) + if global_quality_changes.getId() != "empty_quality_changes": - quality_changes_groups = self._application._quality_manager.getQualityChangesGroups(global_stack) - if global_quality_changes_name in quality_changes_groups: - new_quality_changes_group = quality_changes_groups[global_quality_changes_name] + quality_changes_groups = self._application.getQualityManager().getQualityChangesGroups(global_stack) + new_quality_changes_group = quality_changes_groups.get(global_quality_changes_name) + if new_quality_changes_group is not None and new_quality_changes_group.is_available: self._setQualityChangesGroup(new_quality_changes_group) + same_quality_found = True + Logger.log("i", "Machine '%s' quality changes set to '%s'", + global_stack.getName(), new_quality_changes_group.name) else: - quality_groups = self._application._quality_manager.getQualityGroups(global_stack) - if quality_type not in quality_groups: - Logger.log("w", "Quality type [%s] not found in available qualities [%s]", quality_type, ", ".join(quality_groups.keys())) - self._setEmptyQuality() - return - new_quality_group = quality_groups[quality_type] - self._setQualityGroup(new_quality_group, empty_quality_changes = True) + if quality_type in quality_groups: + new_quality_group = quality_groups[quality_type] + self._setQualityGroup(new_quality_group, empty_quality_changes = True) + same_quality_found = True + Logger.log("i", "Machine '%s' quality set to '%s'", + global_stack.getName(), new_quality_group.quality_type) + + # Could not find the specified quality/quality_changes, switch to the preferred quality if available, + # otherwise the first quality that's available, otherwise empty (not supported). + if not same_quality_found: + Logger.log("i", "Machine '%s' could not find quality_type '%s' and quality_changes '%s'. " + "Available quality types are [%s]. Switching to default quality.", + global_stack.getName(), quality_type, global_quality_changes_name, + ", ".join(quality_groups.keys())) + preferred_quality_type = global_stack.getMetaDataEntry("preferred_quality_type") + quality_group = quality_groups.get(preferred_quality_type) + if quality_group is None: + if quality_groups: + quality_group = list(quality_groups.values())[0] + self._setQualityGroup(quality_group, empty_quality_changes = True) @pyqtSlot(str) def setActiveMachine(self, stack_id: str) -> None: @@ -1012,6 +1033,10 @@ class MachineManager(QObject): if empty_quality_changes: self._current_quality_changes_group = None + if quality_group is None: + self._setEmptyQuality() + return + # Set quality and quality_changes for the GlobalStack self._global_container_stack.quality = quality_group.node_for_global.getContainer() if empty_quality_changes: diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index c943454410..7070ad7c3f 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -104,6 +104,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice): if self._is_printing: return # Aleady printing + # cancel any ongoing preheat timer before starting a print + self._printers[0].getController().stopPreheatTimers() + Application.getInstance().getController().setActiveStage("MonitorStage") # find the G-code for the active build plate to print diff --git a/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py b/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py index 972d238921..5a141f1558 100644 --- a/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py +++ b/plugins/VersionUpgrade/VersionUpgrade27to30/VersionUpgrade27to30.py @@ -4,6 +4,8 @@ import configparser #To parse preference files. import io #To serialise the preference files afterwards. import os +import urllib.parse +import re from UM.VersionUpgrade import VersionUpgrade #We're inheriting from this. @@ -118,6 +120,12 @@ class VersionUpgrade27to30(VersionUpgrade): if not parser.has_section("general"): parser.add_section("general") + # Clean up the filename + file_base_name = os.path.basename(filename) + file_base_name = urllib.parse.unquote_plus(file_base_name) + + um2_pattern = re.compile(r"^ultimaker[^a-zA-Z\\d\\s:]2_.*$") + # The ultimaker 2 family ultimaker2_prefix_list = ["ultimaker2_extended_", "ultimaker2_go_", @@ -127,9 +135,8 @@ class VersionUpgrade27to30(VersionUpgrade): "ultimaker2_plus_"] # set machine definition to "ultimaker2" for the custom quality profiles that can be for the ultimaker 2 family - file_base_name = os.path.basename(filename) - is_ultimaker2_family = False - if not any(file_base_name.startswith(ep) for ep in exclude_prefix_list): + is_ultimaker2_family = um2_pattern.match(file_base_name) is not None + if not is_ultimaker2_family and not any(file_base_name.startswith(ep) for ep in exclude_prefix_list): is_ultimaker2_family = any(file_base_name.startswith(ep) for ep in ultimaker2_prefix_list) # ultimaker2 family quality profiles used to set as "fdmprinter" profiles