From 0c4db90b7bc3460a21a9edbe505e639af5313824 Mon Sep 17 00:00:00 2001 From: Ruben D Date: Tue, 28 Nov 2017 00:20:43 +0100 Subject: [PATCH 01/27] Add button to disable sending info directly Convenient and easy. --- plugins/SliceInfoPlugin/SliceInfo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/SliceInfoPlugin/SliceInfo.py b/plugins/SliceInfoPlugin/SliceInfo.py index 79963a4740..4399b0a450 100755 --- a/plugins/SliceInfoPlugin/SliceInfo.py +++ b/plugins/SliceInfoPlugin/SliceInfo.py @@ -40,16 +40,21 @@ class SliceInfo(Extension): Preferences.getInstance().addPreference("info/asked_send_slice_info", False) if not Preferences.getInstance().getValue("info/asked_send_slice_info"): - self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymised slicing statistics. You can disable this in the preferences."), + self.send_slice_info_message = Message(catalog.i18nc("@info", "Cura collects anonymized usage statistics."), lifetime = 0, dismissable = False, title = catalog.i18nc("@info:title", "Collecting Data")) - self.send_slice_info_message.addAction("Dismiss", catalog.i18nc("@action:button", "Dismiss"), None, "") + self.send_slice_info_message.addAction("Dismiss", name = catalog.i18nc("@action:button", "Allow"), icon = None, + description = catalog.i18nc("@action:tooltip", "Allow Cura to send anonymized usage statistics to help prioritize future improvements to Cura. Some of your preferences and settings are sent, the Cura version and a hash of the models you're slicing.")) + self.send_slice_info_message.addAction("Disable", name = catalog.i18nc("@action:button", "Disable"), icon = None, + description = catalog.i18nc("@action:tooltip", "Don't allow Cura to send anonymized usage statistics. You can enable it again in the preferences.")) self.send_slice_info_message.actionTriggered.connect(self.messageActionTriggered) self.send_slice_info_message.show() def messageActionTriggered(self, message_id, action_id): + if action_id == "Disable": + Preferences.getInstance().setValue("info/send_slice_info", False) self.send_slice_info_message.hide() Preferences.getInstance().setValue("info/asked_send_slice_info", True) From b3758be12e7567ccaffcd56d3e607124cf6d46d4 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Tue, 19 Dec 2017 11:55:08 +0100 Subject: [PATCH 02/27] Fix selecting cura connect printer preference --- plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py b/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py index 853ef72f72..7143b462e6 100644 --- a/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/NetworkClusterPrinterOutputDevice.py @@ -234,7 +234,7 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte def spawnPrintView(self): if self._print_view is None: path = os.path.join(self._plugin_path, "PrintWindow.qml") - self._print_view = Application.getInstance().createQmlComponent(path, {"OutputDevice", self}) + self._print_view = Application.getInstance().createQmlComponent(path, {"OutputDevice": self}) if self._print_view is not None: self._print_view.show() From fd6d3e76a3754dae14f83a45d20685b4ddae6062 Mon Sep 17 00:00:00 2001 From: Aleksei S Date: Tue, 19 Dec 2017 13:17:53 +0100 Subject: [PATCH 03/27] Simplified upgrade funtion, typos, check extruder count CURA-4708 --- .../VersionUpgrade30to31.py | 123 +++++++++--------- 1 file changed, 59 insertions(+), 64 deletions(-) diff --git a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py index c01ff158b1..c350dadefe 100644 --- a/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py +++ b/plugins/VersionUpgrade/VersionUpgrade30to31/VersionUpgrade30to31.py @@ -129,12 +129,17 @@ class VersionUpgrade30to31(VersionUpgrade): if parser.has_option("values", "machine_nozzle_size"): machine_nozzle_size = parser["values"]["machine_nozzle_size"] - definition_name = parser["general"]["name"] - machine_extruders = self._getSingleExtrusionMachineExtruders(definition_name) + machine_extruder_count = '1' # by default it is 1 and the value cannot be stored in the global stack + if parser.has_option("values", "machine_extruder_count"): + machine_extruder_count = parser["values"]["machine_extruder_count"] - #For single extuder machine we nee only first extruder - if len(machine_extruders) !=0: - if self._updateSingleExtuderDefinitionFile(machine_extruders, machine_nozzle_size): + if machine_extruder_count == '1': + definition_name = parser["general"]["name"] + machine_extruders = self._getSingleExtrusionMachineExtruders(definition_name) + + # For single extruder machine we need only first extruder + if len(machine_extruders) !=0: + self._updateSingleExtruderDefinitionFile(machine_extruders, machine_nozzle_size) parser.remove_option("values", "machine_nozzle_size") # Update version numbers @@ -219,9 +224,9 @@ class VersionUpgrade30to31(VersionUpgrade): machine_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.MachineStack) - machine_instances = [] + machine_instance_id = None - #Find all machine instances + # Find machine instances for item in os.listdir(machine_instances_dir): file_path = os.path.join(machine_instances_dir, item) if not os.path.isfile(file_path): @@ -242,57 +247,51 @@ class VersionUpgrade30to31(VersionUpgrade): if not parser.has_option("general", "id"): continue - machine_instances.append(parser) - - #Find for extruders - extruders_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack) - #"machine",[extruders] - extruder_instances_per_machine = {} - - #Find all custom extruders for founded machines - for item in os.listdir(extruders_instances_dir): - file_path = os.path.join(extruders_instances_dir, item) - if not os.path.isfile(file_path): + id = parser["general"]["id"] + if id + "_settings" != definition_name: continue - - parser = configparser.ConfigParser(interpolation=None) - try: - parser.read([file_path]) - except: - # skip, it is not a valid stack file - continue - - if not parser.has_option("metadata", "type"): - continue - if "extruder_train" != parser["metadata"]["type"]: - continue - - if not parser.has_option("metadata", "machine"): - continue - if not parser.has_option("metadata", "position"): - continue - - - for machine_instace in machine_instances: - - machine_id = machine_instace["general"]["id"] - if machine_id != parser["metadata"]["machine"]: - continue - - if machine_id + "_settings" != definition_name: - continue - - if extruder_instances_per_machine.get(machine_id) is None: - extruder_instances_per_machine.update({machine_id:[]}) - - extruder_instances_per_machine.get(machine_id).append(parser) - #the extruder can be related only to one machine + else: + machine_instance_id = id break - return extruder_instances_per_machine + if machine_instance_id is not None: - #Find extruder defition at index 0 and update its values - def _updateSingleExtuderDefinitionFile(self, extruder_instances_per_machine, machine_nozzle_size): + extruders_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.ExtruderStack) + #"machine",[extruders] + extruder_instances = [] + + # Find all custom extruders for found machines + for item in os.listdir(extruders_instances_dir): + file_path = os.path.join(extruders_instances_dir, item) + if not os.path.isfile(file_path): + continue + + parser = configparser.ConfigParser(interpolation=None) + try: + parser.read([file_path]) + except: + # skip, it is not a valid stack file + continue + + if not parser.has_option("metadata", "type"): + continue + if "extruder_train" != parser["metadata"]["type"]: + continue + + if not parser.has_option("metadata", "machine"): + continue + if not parser.has_option("metadata", "position"): + continue + + if machine_instance_id != parser["metadata"]["machine"]: + continue + + extruder_instances.append(parser) + + return extruder_instances + + # Find extruder definition at index 0 and update its values + def _updateSingleExtruderDefinitionFile(self, extruder_instances_per_machine, machine_nozzle_size): defintion_instances_dir = Resources.getPath(CuraApplication.ResourceTypes.DefinitionChangesContainer) @@ -312,19 +311,15 @@ class VersionUpgrade30to31(VersionUpgrade): continue name = parser["general"]["name"] custom_extruder_at_0_position = None - for machine_extruders in extruder_instances_per_machine: - for extruder_instance in extruder_instances_per_machine[machine_extruders]: + for extruder_instance in extruder_instances_per_machine: - if extruder_instance["general"]["id"] + "_settings" == name: - defition_position = extruder_instance["metadata"]["position"] + definition_position = extruder_instance["metadata"]["position"] - if defition_position == "0": - custom_extruder_at_0_position = extruder_instance - break - if custom_extruder_at_0_position is not None: + if definition_position == "0": + custom_extruder_at_0_position = extruder_instance break - #If not null, then parsed file is for first extuder and then can be updated. I need to update only + # If not null, then parsed file is for first extuder and then can be updated. I need to update only # first, because this update for single extuder machine if custom_extruder_at_0_position is not None: @@ -374,4 +369,4 @@ class VersionUpgrade30to31(VersionUpgrade): quality_changes_dir = Resources.getPath(CuraApplication.ResourceTypes.QualityInstanceContainer) with open(os.path.join(quality_changes_dir, extruder_quality_changes_filename), "w") as f: - f.write(extruder_quality_changes_output.getvalue()) + f.write(extruder_quality_changes_output.getvalue()) \ No newline at end of file From c5e33e45a427bb25ddb10c632c788d3d8d05d4b7 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 13:24:20 +0100 Subject: [PATCH 04/27] Fix setting definition if importing profile without printer-specific profiles Fixes a crash. --- cura/Settings/CuraContainerRegistry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 43e2e072b0..9a19d35c60 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -305,7 +305,7 @@ class CuraContainerRegistry(ContainerRegistry): quality_type_criteria["definition"] = profile.getDefinition().getId() else: - profile.setDefinition(fdmprinter) + profile.setDefinition("fdmprinter") quality_type_criteria["definition"] = "fdmprinter" machine_definition = Application.getInstance().getGlobalContainerStack().getBottom() From 569715492c67c6659e3950b2399f84398beb5429 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 16:05:42 +0100 Subject: [PATCH 05/27] Correct ID if importing multiple legacy profiles They have to be made unique. Contributes to issue CURA-4715. --- plugins/LegacyProfileReader/LegacyProfileReader.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py index 32cfb5d027..a0d1442ad8 100644 --- a/plugins/LegacyProfileReader/LegacyProfileReader.py +++ b/plugins/LegacyProfileReader/LegacyProfileReader.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015 Ultimaker B.V. +# Copyright (c) 2017 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. import configparser # For reading the legacy profile INI files. @@ -10,6 +10,7 @@ import os.path # For concatenating the path to the plugin and the relative path from UM.Application import Application # To get the machine manager to create the new profile in. from UM.Logger import Logger # Logging errors. from UM.PluginRegistry import PluginRegistry # For getting the path to this plugin's directory. +from UM.Settings.ContainerRegistry import ContainerRegistry #To create unique profile IDs. from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make. from cura.ProfileReader import ProfileReader # The plug-in type to implement. @@ -77,7 +78,9 @@ class LegacyProfileReader(ProfileReader): raise Exception("Unable to import legacy profile. Multi extrusion is not supported") Logger.log("i", "Importing legacy profile from file " + file_name + ".") - profile = InstanceContainer("Imported Legacy Profile") # Create an empty profile. + container_registry = ContainerRegistry.getInstance() + profile_id = container_registry.uniqueName("Imported Legacy Profile") + profile = InstanceContainer(profile_id) # Create an empty profile. parser = configparser.ConfigParser(interpolation = None) try: @@ -120,7 +123,7 @@ class LegacyProfileReader(ProfileReader): if "translation" not in dict_of_doom: Logger.log("e", "Dictionary of Doom has no translation. Is it the correct JSON file?") return None - current_printer_definition = global_container_stack.getBottom() + current_printer_definition = global_container_stack.definition profile.setDefinition(current_printer_definition.getId()) for new_setting in dict_of_doom["translation"]: # Evaluate all new settings that would get a value from the translations. old_setting_expression = dict_of_doom["translation"][new_setting] @@ -139,12 +142,12 @@ class LegacyProfileReader(ProfileReader): if len(profile.getAllKeys()) == 0: Logger.log("i", "A legacy profile was imported but everything evaluates to the defaults, creating an empty profile.") - # We need to downgrade the container to version 1 (in Cura 2.1) so the upgrade system can correctly upgrade # it to the latest version. profile.addMetaDataEntry("type", "profile") # don't know what quality_type it is based on, so use "normal" by default profile.addMetaDataEntry("quality_type", "normal") + profile.setName("Imported Legacy Profile") profile.setDirty(True) parser = configparser.ConfigParser(interpolation=None) From 039c85677a0c8eec71236eaddd52c60b7ef4c94a Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 16:40:03 +0100 Subject: [PATCH 06/27] Also return a global profile Since we always have an extruder now, also for single-extrusion printers, we need to return both a global profile and an extruder profile. Contributes to issue CURA-4713. --- plugins/LegacyProfileReader/LegacyProfileReader.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py index a0d1442ad8..62ac12dc18 100644 --- a/plugins/LegacyProfileReader/LegacyProfileReader.py +++ b/plugins/LegacyProfileReader/LegacyProfileReader.py @@ -162,4 +162,8 @@ class LegacyProfileReader(ProfileReader): data = stream.getvalue() profile.deserialize(data) - return profile + global_container_id = container_registry.uniqueName("Global Imported Legacy Profile") + global_profile = profile.duplicate(new_id = global_container_id, new_name = "Imported Legacy Profile") #Needs to have the same name as the extruder profile. + global_profile.setDirty(True) + + return [global_profile, profile] From c6a2b1b9c9053b30f4820300ad027ec87e616300 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:08:51 +0100 Subject: [PATCH 07/27] Ignore any additional stacks in imported profile When you import a multi-extrusion file into a single-extrusion printer, don't crash but simply ignore the additional stacks. Contributes to issue CURA-4715. --- cura/Settings/CuraContainerRegistry.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 9a19d35c60..f510a9fca9 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -252,6 +252,9 @@ class CuraContainerRegistry(ContainerRegistry): profile.setMetaDataEntry("extruder", extruder_id) profile_id = (extruder_id + "_" + name_seed).lower().replace(" ", "_") + else: #More extruders in the imported file than in the machine. + continue #Delete the additional profiles. + result = self._configureProfile(profile, profile_id, new_name) if result is not None: return {"status": "error", "message": catalog.i18nc( From 05e232b498514f20a11fbbfc0f8ca2fe932d44d9 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:16:32 +0100 Subject: [PATCH 08/27] Move LegacyProfileReader-specific logic into the plug-in itself This had the documentation that it should edit the profiles returned by LegacyProfileReader. Instead, just return correct profiles from the reader... Contributes to issue CURA-4715. --- cura/Settings/CuraContainerRegistry.py | 19 ------------------- .../LegacyProfileReader.py | 16 ++++++++++++++-- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index f510a9fca9..26d3484a9f 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -218,25 +218,6 @@ class CuraContainerRegistry(ContainerRegistry): if type(profile_or_list) is not list: profile_or_list = [profile_or_list] - if len(profile_or_list) == 1: - # If there is only 1 stack file it means we're loading a legacy (pre-3.1) .curaprofile. - # In that case we find the per-extruder settings and put those in a new quality_changes container - # so that it is compatible with the new stack setup. - profile = profile_or_list[0] - extruder_stack_quality_changes_container = ContainerManager.getInstance().duplicateContainerInstance(profile) - extruder_stack_quality_changes_container.addMetaDataEntry("extruder", "fdmextruder") - - for quality_changes_setting_key in extruder_stack_quality_changes_container.getAllKeys(): - settable_per_extruder = extruder_stack_quality_changes_container.getProperty(quality_changes_setting_key, "settable_per_extruder") - if settable_per_extruder: - profile.removeInstance(quality_changes_setting_key, postpone_emit = True) - else: - extruder_stack_quality_changes_container.removeInstance(quality_changes_setting_key, postpone_emit = True) - - # We add the new container to the profile list so things like extruder positions are taken care of - # in the next code segment. - profile_or_list.append(extruder_stack_quality_changes_container) - # Import all profiles for profile_index, profile in enumerate(profile_or_list): if profile_index == 0: diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py index 62ac12dc18..5f80379e49 100644 --- a/plugins/LegacyProfileReader/LegacyProfileReader.py +++ b/plugins/LegacyProfileReader/LegacyProfileReader.py @@ -13,6 +13,7 @@ from UM.PluginRegistry import PluginRegistry # For getting the path to this plu from UM.Settings.ContainerRegistry import ContainerRegistry #To create unique profile IDs. from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make. from cura.ProfileReader import ProfileReader # The plug-in type to implement. +from cura.Settings.ExtruderManager import ExtruderManager #To get the current extruder definition. ## A plugin that reads profile data from legacy Cura versions. @@ -142,14 +143,13 @@ class LegacyProfileReader(ProfileReader): if len(profile.getAllKeys()) == 0: Logger.log("i", "A legacy profile was imported but everything evaluates to the defaults, creating an empty profile.") - # We need to downgrade the container to version 1 (in Cura 2.1) so the upgrade system can correctly upgrade - # it to the latest version. profile.addMetaDataEntry("type", "profile") # don't know what quality_type it is based on, so use "normal" by default profile.addMetaDataEntry("quality_type", "normal") profile.setName("Imported Legacy Profile") profile.setDirty(True) + #Serialise and deserialise in order to perform the version upgrade. parser = configparser.ConfigParser(interpolation=None) data = profile.serialize() parser.read_string(data) @@ -162,8 +162,20 @@ class LegacyProfileReader(ProfileReader): data = stream.getvalue() profile.deserialize(data) + #We need to return one extruder stack and one global stack. global_container_id = container_registry.uniqueName("Global Imported Legacy Profile") global_profile = profile.duplicate(new_id = global_container_id, new_name = "Imported Legacy Profile") #Needs to have the same name as the extruder profile. global_profile.setDirty(True) + #Only the extruder stack has an extruder metadata entry. + profile.addMetaDataEntry("extruder", ExtruderManager.getInstance().getActiveExtruderStack().definition) + + #Split all settings into per-extruder and global settings. + for setting_key in profile.getAllKeys(): + settable_per_extruder = global_container_stack.getProperty(setting_key, "settable_per_extruder") + if settable_per_extruder: + global_profile.removeInstance(setting_key) + else: + profile.removeInstance(setting_key) + return [global_profile, profile] From fc784021460c04d51026a898a173ea7de108855b Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 19 Dec 2017 17:26:30 +0100 Subject: [PATCH 09/27] CURA-4726 Using a string for the per object stack id instead of the id of the instance (that is an integer) because the new ContainerRegistry searches by string --- cura/Settings/SettingOverrideDecorator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index c70d9343cf..acd161c6a6 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -32,14 +32,14 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __init__(self): super().__init__() - self._stack = PerObjectContainerStack(stack_id = id(self)) + self._stack = PerObjectContainerStack(stack_id = "per_object_stack") self._stack.setDirty(False) # This stack does not need to be saved. self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer")) self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() self._stack.propertyChanged.connect(self._onSettingChanged) - ContainerRegistry.getInstance().addContainer(self._stack) + Application.getInstance().getContainerRegistry().addContainer(self._stack) Application.getInstance().globalContainerStackChanged.connect(self._updateNextStack) self.activeExtruderChanged.connect(self._updateNextStack) From d9bc561d7398f95939208fe25d1f9d38663b7db4 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:28:05 +0100 Subject: [PATCH 10/27] Set the extruder metadata to its ID Not the actual extruder! Contributes to issue CURA-4715. --- plugins/LegacyProfileReader/LegacyProfileReader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py index 5f80379e49..84fbeccb50 100644 --- a/plugins/LegacyProfileReader/LegacyProfileReader.py +++ b/plugins/LegacyProfileReader/LegacyProfileReader.py @@ -168,7 +168,7 @@ class LegacyProfileReader(ProfileReader): global_profile.setDirty(True) #Only the extruder stack has an extruder metadata entry. - profile.addMetaDataEntry("extruder", ExtruderManager.getInstance().getActiveExtruderStack().definition) + profile.addMetaDataEntry("extruder", ExtruderManager.getInstance().getActiveExtruderStack().definition.getId()) #Split all settings into per-extruder and global settings. for setting_key in profile.getAllKeys(): From 21d46d73b5e69eb0c3b5143e7a3e57c239c567c0 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:30:10 +0100 Subject: [PATCH 11/27] Add new CAD plugins --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 88c4d5b6eb..510fbfe006 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,8 @@ plugins/CuraLiveScriptingPlugin plugins/CuraPrintProfileCreator plugins/OctoPrintPlugin plugins/CuraCloudPlugin +plugins/CuraBlenderPlugin +plugins/CuraOpenSCADPlugin #Build stuff CMakeCache.txt From 85debb2577ba2493fc59324b3e22ece072a4e798 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:31:36 +0100 Subject: [PATCH 12/27] Sort list of plugins alphabetically --- .gitignore | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 510fbfe006..71e83433cf 100644 --- a/.gitignore +++ b/.gitignore @@ -33,23 +33,23 @@ cura.desktop .settings #Externally located plug-ins. -plugins/CuraSolidWorksPlugin -plugins/Doodle3D-cura-plugin -plugins/GodMode -plugins/PostProcessingPlugin -plugins/X3GWriter -plugins/FlatProfileExporter -plugins/ProfileFlattener -plugins/cura-god-mode-plugin plugins/cura-big-flame-graph +plugins/cura-god-mode-plugin plugins/cura-siemensnx-plugin -plugins/CuraVariSlicePlugin -plugins/CuraLiveScriptingPlugin -plugins/CuraPrintProfileCreator -plugins/OctoPrintPlugin -plugins/CuraCloudPlugin plugins/CuraBlenderPlugin +plugins/CuraCloudPlugin +plugins/CuraLiveScriptingPlugin plugins/CuraOpenSCADPlugin +plugins/CuraPrintProfileCreator +plugins/CuraSolidWorksPlugin +plugins/CuraVariSlicePlugin +plugins/Doodle3D-cura-plugin +plugins/FlatProfileExporter +plugins/GodMode +plugins/OctoPrintPlugin +plugins/PostProcessingPlugin +plugins/ProfileFlattener +plugins/X3GWriter #Build stuff CMakeCache.txt From 8734460aff01d2a6e7e8f24cf22b88e23442c291 Mon Sep 17 00:00:00 2001 From: Ghostkeeper Date: Tue, 19 Dec 2017 17:36:20 +0100 Subject: [PATCH 13/27] Use unique name too if importing multiple legacy profiles Otherwise all of them get the same name and they don't match global/extruder stacks together properly any more. Contributes to issue CURA-4715. --- plugins/LegacyProfileReader/LegacyProfileReader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/LegacyProfileReader/LegacyProfileReader.py b/plugins/LegacyProfileReader/LegacyProfileReader.py index 84fbeccb50..07cd8b0aad 100644 --- a/plugins/LegacyProfileReader/LegacyProfileReader.py +++ b/plugins/LegacyProfileReader/LegacyProfileReader.py @@ -146,7 +146,7 @@ class LegacyProfileReader(ProfileReader): profile.addMetaDataEntry("type", "profile") # don't know what quality_type it is based on, so use "normal" by default profile.addMetaDataEntry("quality_type", "normal") - profile.setName("Imported Legacy Profile") + profile.setName(profile_id) profile.setDirty(True) #Serialise and deserialise in order to perform the version upgrade. @@ -164,7 +164,7 @@ class LegacyProfileReader(ProfileReader): #We need to return one extruder stack and one global stack. global_container_id = container_registry.uniqueName("Global Imported Legacy Profile") - global_profile = profile.duplicate(new_id = global_container_id, new_name = "Imported Legacy Profile") #Needs to have the same name as the extruder profile. + global_profile = profile.duplicate(new_id = global_container_id, new_name = profile_id) #Needs to have the same name as the extruder profile. global_profile.setDirty(True) #Only the extruder stack has an extruder metadata entry. From 8af52fb61b8a3f5efafb827553ae09d682b48485 Mon Sep 17 00:00:00 2001 From: Diego Prado Gesto Date: Tue, 19 Dec 2017 19:44:04 +0100 Subject: [PATCH 14/27] CURA-4726 Creating unique name for the per object stack. Keep the prefix so it is easy to trace when debugging instead of just a number --- cura/Settings/SettingOverrideDecorator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index acd161c6a6..df19f88a26 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -32,7 +32,7 @@ class SettingOverrideDecorator(SceneNodeDecorator): def __init__(self): super().__init__() - self._stack = PerObjectContainerStack(stack_id = "per_object_stack") + self._stack = PerObjectContainerStack(stack_id = "per_object_stack_" + str(id(self))) self._stack.setDirty(False) # This stack does not need to be saved. self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer")) self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() From 1a6a6f74d5e705dc92e776b9b5feaf4430a645b1 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 12:19:01 +0100 Subject: [PATCH 15/27] Fix SettingOverrideDecorator for non printing meshes CURA-4705 - Do not set a "secret" property in the SceneNode to indicate whether a node is a non-printing-mesh because SceneNode will not copy that property during a deepcopy. Store it in the SettingOverrideDecorator and make it accessible through a decorator call - Try to trigger an auto-slice AFTER the non-printing-meshes flag is updated, not before. --- cura/Settings/SettingOverrideDecorator.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index df19f88a26..135b16116f 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -37,6 +37,8 @@ class SettingOverrideDecorator(SceneNodeDecorator): self._stack.addContainer(InstanceContainer(container_id = "SettingOverrideInstanceContainer")) self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId() + self._is_non_printing_mesh = False + self._stack.propertyChanged.connect(self._onSettingChanged) Application.getInstance().getContainerRegistry().addContainer(self._stack) @@ -57,6 +59,8 @@ class SettingOverrideDecorator(SceneNodeDecorator): # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) + deep_copy._is_non_printing_mesh = self._is_non_printing_mesh + return deep_copy ## Gets the currently active extruder to print this object with. @@ -80,14 +84,17 @@ class SettingOverrideDecorator(SceneNodeDecorator): container_stack = containers[0] return container_stack.getMetaDataEntry("position", default=None) + def isNonPrintingMesh(self): + return self._is_non_printing_mesh + def _onSettingChanged(self, instance, property_name): # Reminder: 'property' is a built-in function # Trigger slice/need slicing if the value has changed. if property_name == "value": + self._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) + Application.getInstance().getBackend().needsSlicing() Application.getInstance().getBackend().tickle() - self._node._non_printing_mesh = any(self._stack.getProperty(setting, "value") for setting in self._non_printing_mesh_settings) - ## Makes sure that the stack upon which the container stack is placed is # kept up to date. def _updateNextStack(self): From b2ac2e0fc79b609b22b6412f635673ecc53be4fc Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 12:22:39 +0100 Subject: [PATCH 16/27] Trust the stack values more than the decorator CURA-4705 A SceneNode and its decorators can be deepcopied. However, the data in some decorators will only be updated when a per-object settings stack triggers a property changed event. That event cannot copied. So, it can happen that a deepcopied SceneNode has inconsistent data in some of its decorators than what's in the per-object settings stack. --- plugins/CuraEngineBackend/StartSliceJob.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index efa0e87b9e..f12b8e656f 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -19,6 +19,10 @@ from UM.Settings.SettingRelation import RelationType from cura.OneAtATimeIterator import OneAtATimeIterator from cura.Settings.ExtruderManager import ExtruderManager + +NON_PRINTING_MESH_SETTINGS = ["anti_overhang_mesh", "infill_mesh", "cutting_mesh"] + + class StartJobResult(IntEnum): Finished = 1 Error = 2 @@ -133,11 +137,13 @@ class StartSliceJob(Job): temp_list = [] has_printing_mesh = False for node in DepthFirstIterator(self._scene.getRoot()): - if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None: - _non_printing_mesh = getattr(node, "_non_printing_mesh", False) - if not getattr(node, "_outside_buildarea", False) or _non_printing_mesh: + if node.callDecoration("isSliceable") and type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None: + per_object_stack = node.callDecoration("getStack") + is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) + + if not getattr(node, "_outside_buildarea", False) or not is_non_printing_mesh: temp_list.append(node) - if not _non_printing_mesh: + if not is_non_printing_mesh: has_printing_mesh = True Job.yieldThread() From 61dd1c98fde94a6b1feb8f001aac8c1e02ab8f7f Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:16:29 +0100 Subject: [PATCH 17/27] Fix cases with no per-object settings stack CURA-4705 --- plugins/CuraEngineBackend/StartSliceJob.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index f12b8e656f..4da26aa78f 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -139,7 +139,9 @@ class StartSliceJob(Job): for node in DepthFirstIterator(self._scene.getRoot()): if node.callDecoration("isSliceable") and type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None: per_object_stack = node.callDecoration("getStack") - is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) + is_non_printing_mesh = False + if per_object_stack: + is_non_printing_mesh = any(per_object_stack.getProperty(key, "value") for key in NON_PRINTING_MESH_SETTINGS) if not getattr(node, "_outside_buildarea", False) or not is_non_printing_mesh: temp_list.append(node) From 4f28dec8845d7666b9e920a6f0e0300dcf553f3b Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:19:48 +0100 Subject: [PATCH 18/27] Fix typo --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 16fd2ee93c..26901c3abc 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -583,7 +583,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): if machine_id: new_machine_id = self.getNewId(machine_id) new_id = new_machine_id + "_current_settings" - instance_container.setMetadataEntry("id", new_id) + instance_container.setMetaDataEntry("id", new_id) instance_container.setName(new_id) instance_container.setMetaDataEntry("machine", new_machine_id) containers_to_add.append(instance_container) From 196bffd3ad6fd026a5e9bc5a04ff570160aeff6e Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:20:22 +0100 Subject: [PATCH 19/27] Only try to get a new unique name when it already exists CURA-4704 --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index 26901c3abc..a7dad68519 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -461,7 +461,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader): global_stack_id_new = self.getNewId(global_stack_id_original) global_stack_need_rename = True - global_stack_name_new = self._container_registry.uniqueName(global_stack_name_original) + if self._container_registry.findContainerStacksMetadata(name = global_stack_id_original): + global_stack_name_new = self._container_registry.uniqueName(global_stack_name_original) for each_extruder_stack_file in extruder_stack_files: old_container_id = self._stripFileToId(each_extruder_stack_file) From 588335c6db112e82810bb421832374538221deef Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:42:55 +0100 Subject: [PATCH 20/27] Make sure only single-extrusion machines will be fixed CURA-4713 --- cura/Settings/CuraContainerRegistry.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cura/Settings/CuraContainerRegistry.py b/cura/Settings/CuraContainerRegistry.py index 26d3484a9f..089d513071 100644 --- a/cura/Settings/CuraContainerRegistry.py +++ b/cura/Settings/CuraContainerRegistry.py @@ -406,6 +406,10 @@ class CuraContainerRegistry(ContainerRegistry): if not isinstance(container, ContainerStack) or container.getMetaDataEntry("type") != "machine": return + machine_extruder_trains = container.getMetaDataEntry("machine_extruder_trains") + if machine_extruder_trains is not None and machine_extruder_trains != {"0": "fdmextruder"}: + return + extruder_stacks = self.findContainerStacks(type = "extruder_train", machine = container.getId()) if not extruder_stacks: self.addExtruderStackForSingleExtrusionMachine(container, "fdmextruder") From 49ee2a543e9b1f790db9b7ded62a9b0c05323a04 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:57:48 +0100 Subject: [PATCH 21/27] Fix code style --- plugins/MachineSettingsAction/MachineSettingsAction.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index b36fb989f0..fd1aa2c7b0 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -432,7 +432,7 @@ Cura.MachineAction property int areaHeight: parent.height - y property string settingKey: "machine_extruder_start_code" property bool isExtruderSetting: true - } + } } Column { height: parent.height @@ -714,7 +714,7 @@ Cura.MachineAction width: gcodeArea.width text: _tooltip - property bool _isExtruderSetting: (typeof(isExtruderSetting) === 'undefined') ? false: isExtruderSetting + property bool _isExtruderSetting: (typeof(isExtruderSetting) === 'undefined') ? false : isExtruderSetting property string _tooltip: (typeof(tooltip) === 'undefined') ? propertyProvider.properties.description : tooltip UM.SettingPropertyProvider From 6d06d184076af5174516e61c0a72080c097b28e0 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 13:58:02 +0100 Subject: [PATCH 22/27] Fix Extruder tabs in MachineSettings dialog CURA-4722 The extruder field views should be bound to the actual extruder, not the active extruder. --- plugins/MachineSettingsAction/MachineSettingsAction.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index fd1aa2c7b0..da3de4f4fc 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -726,7 +726,7 @@ Cura.MachineAction { if(settingsTabs.currentIndex > 0) { - return Cura.MachineManager.activeStackId; + return Cura.ExtruderManager.extruderIds[String(settingsTabs.currentIndex - 1)]; } return ""; } From ae86a838e0d228503131d191c621aed06da9dbf6 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 16:23:39 +0100 Subject: [PATCH 23/27] Update extruder count model in MachineSettings dialog CURA-4722 --- .../MachineSettingsAction.qml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/MachineSettingsAction/MachineSettingsAction.qml b/plugins/MachineSettingsAction/MachineSettingsAction.qml index da3de4f4fc..6ff70a1503 100644 --- a/plugins/MachineSettingsAction/MachineSettingsAction.qml +++ b/plugins/MachineSettingsAction/MachineSettingsAction.qml @@ -270,6 +270,20 @@ Cura.MachineAction } } } + + Connections + { + target: manager + onDefinedExtruderCountChanged: + { + extruderCountModel.clear(); + for(var i = 0; i < manager.definedExtruderCount; ++i) + { + extruderCountModel.append({text: String(i + 1), value: i}); + } + } + } + currentIndex: machineExtruderCountProvider.properties.value - 1 onActivated: { From 107f6aff786157016e622964abb2675b09f2c311 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Wed, 20 Dec 2017 16:48:57 +0100 Subject: [PATCH 24/27] Fix SolidView to use isNonPrintingMesh decorator call CURA-4705 --- plugins/SolidView/SolidView.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/SolidView/SolidView.py b/plugins/SolidView/SolidView.py index e96c7e9bda..e156e655ce 100644 --- a/plugins/SolidView/SolidView.py +++ b/plugins/SolidView/SolidView.py @@ -110,7 +110,7 @@ class SolidView(View): except ValueError: pass - if getattr(node, "_non_printing_mesh", False): + if node.callDecoration("isNonPrintingMesh"): if per_mesh_stack and (per_mesh_stack.getProperty("infill_mesh", "value") or per_mesh_stack.getProperty("cutting_mesh", "value")): renderer.queueNode(node, shader = self._non_printing_shader, uniforms = uniforms, transparent = True) else: From 419dc6f59a9aa8148b03ccec03be4adf1fe3eb79 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Thu, 21 Dec 2017 09:14:31 +0100 Subject: [PATCH 25/27] Improve issue template a bit --- .github/ISSUE_TEMPLATE.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7bdf35455c..b78b9b91a2 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,32 +1,36 @@ -Application Version: +**Application Version** -Platform: +**Platform** -Qt: +**Qt** -PyQt: +**PyQt** -Display Driver: +**Display Driver** -Steps to Reproduce: +**Steps to Reproduce** -Actual Results: +**Actual Results** -Expected results: +**Expected results** -Additional Information: +**Additional Information** From 0a0db39f0288afe188cfc66e43a0484bb5b057f7 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 21 Dec 2017 09:27:05 +0100 Subject: [PATCH 26/27] deepcopy value from the stack CURA-4705 --- cura/Settings/SettingOverrideDecorator.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cura/Settings/SettingOverrideDecorator.py b/cura/Settings/SettingOverrideDecorator.py index 135b16116f..b853c06c8e 100644 --- a/cura/Settings/SettingOverrideDecorator.py +++ b/cura/Settings/SettingOverrideDecorator.py @@ -59,7 +59,9 @@ class SettingOverrideDecorator(SceneNodeDecorator): # Properly set the right extruder on the copy deep_copy.setActiveExtruder(self._extruder_stack) - deep_copy._is_non_printing_mesh = self._is_non_printing_mesh + # use value from the stack because there can be a delay in signal triggering and "_is_non_printing_mesh" + # has not been updated yet. + deep_copy._is_non_printing_mesh = any(bool(self._stack.getProperty(setting, "value")) for setting in self._non_printing_mesh_settings) return deep_copy From eaa27114c63101a86d0546d1ff0b1ec336db9164 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Thu, 21 Dec 2017 12:43:50 +0100 Subject: [PATCH 27/27] Fix ID changing in project loading --- plugins/3MFReader/ThreeMFWorkspaceReader.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/3MFReader/ThreeMFWorkspaceReader.py b/plugins/3MFReader/ThreeMFWorkspaceReader.py index a7dad68519..40d64590f5 100755 --- a/plugins/3MFReader/ThreeMFWorkspaceReader.py +++ b/plugins/3MFReader/ThreeMFWorkspaceReader.py @@ -682,12 +682,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): file_name = global_stack_file) # Ensure a unique ID and name - stack._id = global_stack_id_new - - # Extruder stacks are "bound" to a machine. If we add the machine as a new one, the id of the - # bound machine also needs to change. - if stack.getMetaDataEntry("machine", None): - stack.setMetaDataEntry("machine", global_stack_id_new) + stack.setMetaDataEntry("id", global_stack_id_new) # Only machines need a new name, stacks may be non-unique stack.setName(global_stack_name_new) @@ -741,7 +736,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader): stack.deserialize(extruder_file_content, file_name = extruder_stack_file) # Ensure a unique ID and name - stack._id = new_id + stack.setMetaDataEntry("id", new_id) self._container_registry.addContainer(stack) extruder_stacks_added.append(stack)