From 68f334e141896e3d9e09e4bd59da28ff4e8bb5cf Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 4 Oct 2019 11:21:25 +0200 Subject: [PATCH 1/5] Fix: Consider all active extruder intent profiles for display. Remove the notion of a singular 'active' extruder from the code. Visibility of intent profiles should consider all enabled extruders. This fix makes sure that it doesn't matter in what order materials are loaded, the available intent profiles will be the same. CURA-6840 --- cura/Machines/Models/IntentModel.py | 91 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/cura/Machines/Models/IntentModel.py b/cura/Machines/Models/IntentModel.py index e105f012cd..c4dd99a533 100644 --- a/cura/Machines/Models/IntentModel.py +++ b/cura/Machines/Models/IntentModel.py @@ -1,18 +1,15 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. - -from typing import Optional, List, Dict, Any +from typing import Optional, Dict, Any, Set, List from PyQt5.QtCore import Qt, QObject, pyqtProperty, pyqtSignal +import cura.CuraApplication from UM.Qt.ListModel import ListModel from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.SettingFunction import SettingFunction - +from cura.Machines import MaterialNode, QualityGroup from cura.Machines.ContainerTree import ContainerTree -from cura.Settings.ExtruderManager import ExtruderManager -from cura.Settings.IntentManager import IntentManager -import cura.CuraApplication class IntentModel(ListModel): @@ -65,47 +62,16 @@ class IntentModel(ListModel): return quality_groups = ContainerTree.getInstance().getCurrentQualityGroups() - container_tree = ContainerTree.getInstance() - machine_node = container_tree.machines[global_stack.definition.getId()] - - # We can't just look at the active extruder, since it is possible for only one extruder to have an intent - # and the other extruders have no intent (eg, default). It is not possible for one extruder to have intent A and - # the other to have B. - # So we will use the first extruder that we find that has an intent that is not default as the "active" extruder - - active_extruder = None - for extruder in global_stack.extruderList: - if not extruder.isEnabled: - continue - if extruder.intent.getMetaDataEntry("intent_category", "default") == "default": - if active_extruder is None: - active_extruder = extruder # If there is no extruder found and the intent is default, use that. - else: # We found an intent, use that extruder as "active" - active_extruder = extruder - - if not active_extruder: - return - active_variant_name = active_extruder.variant.getMetaDataEntry("name") - active_variant_node = machine_node.variants[active_variant_name] - active_material_node = active_variant_node.materials[active_extruder.material.getMetaDataEntry("base_file")] + material_nodes = self._get_active_materials() layer_heights_added = [] - for quality_id, quality_node in active_material_node.qualities.items(): - if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively). - continue - quality_group = quality_groups[quality_node.quality_type] - layer_height = self._fetchLayerHeight(quality_group) - for intent_id, intent_node in quality_node.intents.items(): - if intent_node.intent_category != self._intent_category: - continue - layer_heights_added.append(layer_height) - new_items.append({"name": quality_group.name, - "quality_type": quality_group.quality_type, - "layer_height": layer_height, - "available": quality_group.is_available, - "intent_category": self._intent_category - }) + for material_node in material_nodes: + intents = self._get_intents_for_material(material_node, quality_groups) + for intent in intents: + if intent["layer_height"] not in layer_heights_added: + new_items.append(intent) + layer_heights_added.append(intent["layer_height"]) # Now that we added all intents that we found something for, ensure that we set add ticks (and layer_heights) # for all groups that we don't have anything for (and set it to not available) @@ -124,8 +90,43 @@ class IntentModel(ListModel): new_items = sorted(new_items, key=lambda x: x["layer_height"]) self.setItems(new_items) + ## Get the active materials for all extruders. No duplicates will be returned + def _get_active_materials(self) -> Set[MaterialNode]: + global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() + container_tree = ContainerTree.getInstance() + machine_node = container_tree.machines[global_stack.definition.getId()] + nodes = set([]) + + for extruder in global_stack.extruderList: + active_variant_name = extruder.variant.getMetaDataEntry("name") + active_variant_node = machine_node.variants[active_variant_name] + active_material_node = active_variant_node.materials[extruder.material.getMetaDataEntry("base_file")] + nodes.add(active_material_node) + + return nodes + + def _get_intents_for_material(self, active_material_node: MaterialNode, quality_groups: Dict[str, QualityGroup]) -> List[Dict[str, Any]]: + extruder_intents = [] # type: List[Dict[str, Any]] + + for quality_id, quality_node in active_material_node.qualities.items(): + if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively). + continue + quality_group = quality_groups[quality_node.quality_type] + layer_height = self._fetchLayerHeight(quality_group) + + for intent_id, intent_node in quality_node.intents.items(): + if intent_node.intent_category != self._intent_category: + continue + extruder_intents.append({"name": quality_group.name, + "quality_type": quality_group.quality_type, + "layer_height": layer_height, + "available": quality_group.is_available, + "intent_category": self._intent_category + }) + return extruder_intents + #TODO: Copied this from QualityProfilesDropdownMenuModel for the moment. This code duplication should be fixed. - def _fetchLayerHeight(self, quality_group) -> float: + def _fetchLayerHeight(self, quality_group: QualityGroup) -> float: global_stack = cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMachine if not self._layer_height_unit: unit = global_stack.definition.getProperty("layer_height", "unit") From 88e0a57374c843d91520f55cdcb77b2193c2903e Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 4 Oct 2019 13:25:58 +0200 Subject: [PATCH 2/5] Fix typing and deduplicate fetch_layer_height CURA-6840 --- cura/Machines/Models/IntentModel.py | 41 +++------------- cura/Machines/Models/MachineModelUtils.py | 33 +++++++++++++ .../QualityProfilesDropDownMenuModel.py | 48 ++++--------------- 3 files changed, 49 insertions(+), 73 deletions(-) create mode 100644 cura/Machines/Models/MachineModelUtils.py diff --git a/cura/Machines/Models/IntentModel.py b/cura/Machines/Models/IntentModel.py index c4dd99a533..1daa1096e0 100644 --- a/cura/Machines/Models/IntentModel.py +++ b/cura/Machines/Models/IntentModel.py @@ -7,9 +7,10 @@ from PyQt5.QtCore import Qt, QObject, pyqtProperty, pyqtSignal import cura.CuraApplication from UM.Qt.ListModel import ListModel from UM.Settings.ContainerRegistry import ContainerRegistry -from UM.Settings.SettingFunction import SettingFunction -from cura.Machines import MaterialNode, QualityGroup from cura.Machines.ContainerTree import ContainerTree +from cura.Machines.MaterialNode import MaterialNode +from cura.Machines.Models.MachineModelUtils import fetch_layer_height +from cura.Machines.QualityGroup import QualityGroup class IntentModel(ListModel): @@ -78,7 +79,7 @@ class IntentModel(ListModel): for quality_tuple, quality_group in quality_groups.items(): # Add the intents that are of the correct category if quality_tuple[0] != self._intent_category: - layer_height = self._fetchLayerHeight(quality_group) + layer_height = fetch_layer_height(quality_group) if layer_height not in layer_heights_added: new_items.append({"name": "Unavailable", "quality_type": "", @@ -95,7 +96,7 @@ class IntentModel(ListModel): global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() container_tree = ContainerTree.getInstance() machine_node = container_tree.machines[global_stack.definition.getId()] - nodes = set([]) + nodes = set() # type: Set[MaterialNode] for extruder in global_stack.extruderList: active_variant_name = extruder.variant.getMetaDataEntry("name") @@ -112,7 +113,7 @@ class IntentModel(ListModel): if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively). continue quality_group = quality_groups[quality_node.quality_type] - layer_height = self._fetchLayerHeight(quality_group) + layer_height = fetch_layer_height(quality_group) for intent_id, intent_node in quality_node.intents.items(): if intent_node.intent_category != self._intent_category: @@ -125,35 +126,5 @@ class IntentModel(ListModel): }) return extruder_intents - #TODO: Copied this from QualityProfilesDropdownMenuModel for the moment. This code duplication should be fixed. - def _fetchLayerHeight(self, quality_group: QualityGroup) -> float: - global_stack = cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMachine - if not self._layer_height_unit: - unit = global_stack.definition.getProperty("layer_height", "unit") - if not unit: - unit = "" - self._layer_height_unit = unit - - default_layer_height = global_stack.definition.getProperty("layer_height", "value") - - # Get layer_height from the quality profile for the GlobalStack - if quality_group.node_for_global is None: - return float(default_layer_height) - container = quality_group.node_for_global.container - - layer_height = default_layer_height - if container and container.hasProperty("layer_height", "value"): - layer_height = container.getProperty("layer_height", "value") - else: - # Look for layer_height in the GlobalStack from material -> definition - container = global_stack.definition - if container and container.hasProperty("layer_height", "value"): - layer_height = container.getProperty("layer_height", "value") - - if isinstance(layer_height, SettingFunction): - layer_height = layer_height(global_stack) - - return float(layer_height) - def __repr__(self): return str(self.items) diff --git a/cura/Machines/Models/MachineModelUtils.py b/cura/Machines/Models/MachineModelUtils.py new file mode 100644 index 0000000000..3e94f4f010 --- /dev/null +++ b/cura/Machines/Models/MachineModelUtils.py @@ -0,0 +1,33 @@ +from typing import TYPE_CHECKING + +from UM.Settings.SettingFunction import SettingFunction + +if TYPE_CHECKING: + from cura.Machines.QualityGroup import QualityGroup + +layer_height_unit = "" + +def fetch_layer_height(quality_group: "QualityGroup") -> float: + from cura.CuraApplication import CuraApplication + global_stack = CuraApplication.getInstance().getMachineManager().activeMachine + + default_layer_height = global_stack.definition.getProperty("layer_height", "value") + + # Get layer_height from the quality profile for the GlobalStack + if quality_group.node_for_global is None: + return float(default_layer_height) + container = quality_group.node_for_global.container + + layer_height = default_layer_height + if container and container.hasProperty("layer_height", "value"): + layer_height = container.getProperty("layer_height", "value") + else: + # Look for layer_height in the GlobalStack from material -> definition + container = global_stack.definition + if container and container.hasProperty("layer_height", "value"): + layer_height = container.getProperty("layer_height", "value") + + if isinstance(layer_height, SettingFunction): + layer_height = layer_height(global_stack) + + return float(layer_height) diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index ab40f440ec..78e8568322 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -2,17 +2,12 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import Qt, QTimer -from typing import TYPE_CHECKING - -from UM.Logger import Logger -from UM.Qt.ListModel import ListModel -from UM.Settings.SettingFunction import SettingFunction import cura.CuraApplication # Imported this way to prevent circular dependencies. +from UM.Logger import Logger +from UM.Qt.ListModel import ListModel from cura.Machines.ContainerTree import ContainerTree - -if TYPE_CHECKING: - from cura.Machines.QualityGroup import QualityGroup +from cura.Machines.Models.MachineModelUtils import fetch_layer_height # @@ -76,6 +71,12 @@ class QualityProfilesDropDownMenuModel(ListModel): Logger.log("d", "No active GlobalStack, set quality profile model as empty.") return + if not self._layer_height_unit: + unit = global_stack.definition.getProperty("layer_height", "unit") + if not unit: + unit = "" + self._layer_height_unit = unit + # Check for material compatibility if not cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMaterialsCompatible(): Logger.log("d", "No active material compatibility, set quality profile model as empty.") @@ -86,7 +87,7 @@ class QualityProfilesDropDownMenuModel(ListModel): item_list = [] for quality_group in quality_group_dict.values(): - layer_height = self._fetchLayerHeight(quality_group) + layer_height = fetch_layer_height(quality_group) item = {"name": quality_group.name, "quality_type": quality_group.quality_type, @@ -102,32 +103,3 @@ class QualityProfilesDropDownMenuModel(ListModel): item_list = sorted(item_list, key = lambda x: x["layer_height"]) self.setItems(item_list) - - def _fetchLayerHeight(self, quality_group: "QualityGroup") -> float: - global_stack = cura.CuraApplication.CuraApplication.getInstance().getMachineManager().activeMachine - if not self._layer_height_unit: - unit = global_stack.definition.getProperty("layer_height", "unit") - if not unit: - unit = "" - self._layer_height_unit = unit - - default_layer_height = global_stack.definition.getProperty("layer_height", "value") - - # Get layer_height from the quality profile for the GlobalStack - if quality_group.node_for_global is None: - return float(default_layer_height) - container = quality_group.node_for_global.container - - layer_height = default_layer_height - if container and container.hasProperty("layer_height", "value"): - layer_height = container.getProperty("layer_height", "value") - else: - # Look for layer_height in the GlobalStack from material -> definition - container = global_stack.definition - if container and container.hasProperty("layer_height", "value"): - layer_height = container.getProperty("layer_height", "value") - - if isinstance(layer_height, SettingFunction): - layer_height = layer_height(global_stack) - - return float(layer_height) From 8d223c01d4239d212a06a3633c39bbc2065b9903 Mon Sep 17 00:00:00 2001 From: Nino van Hooff Date: Fri, 4 Oct 2019 14:07:57 +0200 Subject: [PATCH 3/5] Add type annotation for layer_heights_added CURA-6840 --- cura/Machines/Models/IntentModel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/Machines/Models/IntentModel.py b/cura/Machines/Models/IntentModel.py index 1daa1096e0..28713f0c00 100644 --- a/cura/Machines/Models/IntentModel.py +++ b/cura/Machines/Models/IntentModel.py @@ -65,7 +65,7 @@ class IntentModel(ListModel): material_nodes = self._get_active_materials() - layer_heights_added = [] + layer_heights_added = [] # type: List[float] for material_node in material_nodes: intents = self._get_intents_for_material(material_node, quality_groups) From 4579b06f6d2ffb6129572227b27cb687661a4fef Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Fri, 4 Oct 2019 15:10:42 +0200 Subject: [PATCH 4/5] Fix typing --- cura/Machines/Models/IntentModel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cura/Machines/Models/IntentModel.py b/cura/Machines/Models/IntentModel.py index 28713f0c00..25edc0a759 100644 --- a/cura/Machines/Models/IntentModel.py +++ b/cura/Machines/Models/IntentModel.py @@ -94,6 +94,9 @@ class IntentModel(ListModel): ## Get the active materials for all extruders. No duplicates will be returned def _get_active_materials(self) -> Set[MaterialNode]: global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() + if global_stack is None: + return set() + container_tree = ContainerTree.getInstance() machine_node = container_tree.machines[global_stack.definition.getId()] nodes = set() # type: Set[MaterialNode] From 1967dd840407046668848cd2bb7a7273d0755b53 Mon Sep 17 00:00:00 2001 From: Lipu Fei Date: Mon, 7 Oct 2019 08:12:48 +0200 Subject: [PATCH 5/5] Fix code style CURA-6840 --- cura/Machines/Models/IntentModel.py | 14 +++++++------- cura/Machines/Models/MachineModelUtils.py | 6 +++++- .../Models/QualityProfilesDropDownMenuModel.py | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/cura/Machines/Models/IntentModel.py b/cura/Machines/Models/IntentModel.py index 25edc0a759..4e96d8e152 100644 --- a/cura/Machines/Models/IntentModel.py +++ b/cura/Machines/Models/IntentModel.py @@ -9,7 +9,7 @@ from UM.Qt.ListModel import ListModel from UM.Settings.ContainerRegistry import ContainerRegistry from cura.Machines.ContainerTree import ContainerTree from cura.Machines.MaterialNode import MaterialNode -from cura.Machines.Models.MachineModelUtils import fetch_layer_height +from cura.Machines.Models.MachineModelUtils import fetchLayerHeight from cura.Machines.QualityGroup import QualityGroup @@ -63,12 +63,12 @@ class IntentModel(ListModel): return quality_groups = ContainerTree.getInstance().getCurrentQualityGroups() - material_nodes = self._get_active_materials() + material_nodes = self._getActiveMaterials() layer_heights_added = [] # type: List[float] for material_node in material_nodes: - intents = self._get_intents_for_material(material_node, quality_groups) + intents = self._getIntentsForMaterial(material_node, quality_groups) for intent in intents: if intent["layer_height"] not in layer_heights_added: new_items.append(intent) @@ -79,7 +79,7 @@ class IntentModel(ListModel): for quality_tuple, quality_group in quality_groups.items(): # Add the intents that are of the correct category if quality_tuple[0] != self._intent_category: - layer_height = fetch_layer_height(quality_group) + layer_height = fetchLayerHeight(quality_group) if layer_height not in layer_heights_added: new_items.append({"name": "Unavailable", "quality_type": "", @@ -92,7 +92,7 @@ class IntentModel(ListModel): self.setItems(new_items) ## Get the active materials for all extruders. No duplicates will be returned - def _get_active_materials(self) -> Set[MaterialNode]: + def _getActiveMaterials(self) -> Set["MaterialNode"]: global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() if global_stack is None: return set() @@ -109,14 +109,14 @@ class IntentModel(ListModel): return nodes - def _get_intents_for_material(self, active_material_node: MaterialNode, quality_groups: Dict[str, QualityGroup]) -> List[Dict[str, Any]]: + def _getIntentsForMaterial(self, active_material_node: "MaterialNode", quality_groups: Dict[str, "QualityGroup"]) -> List[Dict[str, Any]]: extruder_intents = [] # type: List[Dict[str, Any]] for quality_id, quality_node in active_material_node.qualities.items(): if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively). continue quality_group = quality_groups[quality_node.quality_type] - layer_height = fetch_layer_height(quality_group) + layer_height = fetchLayerHeight(quality_group) for intent_id, intent_node in quality_node.intents.items(): if intent_node.intent_category != self._intent_category: diff --git a/cura/Machines/Models/MachineModelUtils.py b/cura/Machines/Models/MachineModelUtils.py index 3e94f4f010..a23b1ff3a5 100644 --- a/cura/Machines/Models/MachineModelUtils.py +++ b/cura/Machines/Models/MachineModelUtils.py @@ -1,3 +1,6 @@ +# Copyright (c) 2019 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + from typing import TYPE_CHECKING from UM.Settings.SettingFunction import SettingFunction @@ -7,7 +10,8 @@ if TYPE_CHECKING: layer_height_unit = "" -def fetch_layer_height(quality_group: "QualityGroup") -> float: + +def fetchLayerHeight(quality_group: "QualityGroup") -> float: from cura.CuraApplication import CuraApplication global_stack = CuraApplication.getInstance().getMachineManager().activeMachine diff --git a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py index 78e8568322..9bf1cc08a8 100644 --- a/cura/Machines/Models/QualityProfilesDropDownMenuModel.py +++ b/cura/Machines/Models/QualityProfilesDropDownMenuModel.py @@ -7,7 +7,7 @@ import cura.CuraApplication # Imported this way to prevent circular dependencie from UM.Logger import Logger from UM.Qt.ListModel import ListModel from cura.Machines.ContainerTree import ContainerTree -from cura.Machines.Models.MachineModelUtils import fetch_layer_height +from cura.Machines.Models.MachineModelUtils import fetchLayerHeight # @@ -87,7 +87,7 @@ class QualityProfilesDropDownMenuModel(ListModel): item_list = [] for quality_group in quality_group_dict.values(): - layer_height = fetch_layer_height(quality_group) + layer_height = fetchLayerHeight(quality_group) item = {"name": quality_group.name, "quality_type": quality_group.quality_type,