diff --git a/cura/Machines/MachineNode.py b/cura/Machines/MachineNode.py index 0c8655070a..3a8a319b0b 100644 --- a/cura/Machines/MachineNode.py +++ b/cura/Machines/MachineNode.py @@ -8,6 +8,7 @@ from UM.Signal import Signal from UM.Util import parseBool from UM.Settings.ContainerRegistry import ContainerRegistry # To find all the variants for this machine. +import cura.CuraApplication # Imported like this to prevent circular dependencies. from cura.Machines.ContainerNode import ContainerNode from cura.Machines.QualityChangesGroup import QualityChangesGroup # To construct groups of quality changes profiles that belong together. from cura.Machines.QualityGroup import QualityGroup # To construct groups of quality profiles that belong together. @@ -74,7 +75,7 @@ class MachineNode(ContainerNode): qualities_per_type_per_extruder[extruder_nr] = self.global_qualities else: # Use the actually specialised quality profiles. - qualities_per_type_per_extruder[extruder_nr] = {node.getMetaDataEntry("quality_type"): node for node in self.variants[variant_name].materials[material_base].qualities.values()} + qualities_per_type_per_extruder[extruder_nr] = {node.quality_type: node for node in self.variants[variant_name].materials[material_base].qualities.values()} # Create the quality group for each available type. quality_groups = {} @@ -82,15 +83,7 @@ class MachineNode(ContainerNode): if not global_quality_node.container: Logger.log("w", "Node {0} doesn't have a container.".format(global_quality_node.container_id)) continue - # CURA-6599 - # Same as QualityChangesGroup. - # For some reason, QML will get null or fail to convert type for MachineManager.activeQualityChangesGroup() to - # a QObject. Setting the object ownership to QQmlEngine.CppOwnership doesn't work, but setting the object - # parent to application seems to work. - from cura.CuraApplication import CuraApplication - quality_groups[quality_type] = QualityGroup(name = global_quality_node.container.getMetaDataEntry("name", "Unnamed profile"), - quality_type = quality_type, - parent = CuraApplication.getInstance()) + quality_groups[quality_type] = QualityGroup(name = global_quality_node.getMetaDataEntry("name", "Unnamed profile"), quality_type = quality_type) quality_groups[quality_type].node_for_global = global_quality_node for extruder, qualities_per_type in enumerate(qualities_per_type_per_extruder): if quality_type in qualities_per_type: @@ -170,7 +163,7 @@ class MachineNode(ContainerNode): ## (Re)loads all variants under this printer. @UM.FlameProfiler.profile - def _loadAll(self): + def _loadAll(self) -> None: container_registry = ContainerRegistry.getInstance() if not self.has_variants: self.variants["empty"] = VariantNode("empty_variant", machine = self) @@ -190,4 +183,4 @@ class MachineNode(ContainerNode): if len(global_qualities) == 0: # This printer doesn't override the global qualities. global_qualities = container_registry.findInstanceContainersMetadata(type = "quality", definition = "fdmprinter", global_quality = "True") # Otherwise pick the global global qualities. for global_quality in global_qualities: - self.global_qualities[global_quality["quality_type"]] = QualityNode(global_quality["id"], parent = self) \ No newline at end of file + self.global_qualities[global_quality["quality_type"]] = QualityNode(global_quality["id"], parent = self) diff --git a/cura/Machines/QualityGroup.py b/cura/Machines/QualityGroup.py index 1ea7ef6903..48047974a9 100644 --- a/cura/Machines/QualityGroup.py +++ b/cura/Machines/QualityGroup.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from typing import Dict, Optional, List, Set @@ -11,24 +11,28 @@ from UM.Util import parseBool from cura.Machines.ContainerNode import ContainerNode +## A QualityGroup represents a group of quality containers that must be applied +# to each ContainerStack when it's used. # -# A QualityGroup represents a group of containers that must be applied to each ContainerStack when it's used. -# Some concrete examples are Quality and QualityChanges: when we select quality type "normal", this quality type -# must be applied to all stacks in a machine, although each stack can have different containers. Use an Ultimaker 3 -# as an example, suppose we choose quality type "normal", the actual InstanceContainers on each stack may look -# as below: -# GlobalStack ExtruderStack 1 ExtruderStack 2 -# quality container: um3_global_normal um3_aa04_pla_normal um3_aa04_abs_normal +# A concrete example: When there are two extruders and the user selects the +# quality type "normal", this quality type must be applied to all stacks in a +# machine, although each stack can have different containers. So one global +# profile gets put on the global stack and one extruder profile gets put on +# each extruder stack. This quality group then contains the following +# profiles (for instance): +# GlobalStack ExtruderStack 1 ExtruderStack 2 +# quality container: um3_global_normal um3_aa04_pla_normal um3_aa04_abs_normal # -# This QualityGroup is mainly used in quality and quality_changes to group the containers that can be applied to -# a machine, so when a quality/custom quality is selected, the container can be directly applied to each stack instead -# of looking them up again. -# -class QualityGroup(QObject): - - def __init__(self, name: str, quality_type: str, parent: Optional["QObject"] = None) -> None: - super().__init__(parent) - +# The purpose of these quality groups is to group the containers that can be +# applied to a configuration, so that when a quality level is selected, the +# container can directly be applied to each stack instead of looking them up +# again. +class QualityGroup: + ## Constructs a new group. + # \param name The user-visible name for the group. + # \param quality_type The quality level that each profile in this group + # has. + def __init__(self, name: str, quality_type: str) -> None: self.name = name self.node_for_global = None # type: Optional[ContainerNode] self.nodes_for_extruders = {} # type: Dict[int, ContainerNode] @@ -36,7 +40,6 @@ class QualityGroup(QObject): self.is_available = False self.is_experimental = False - @pyqtSlot(result = str) def getName(self) -> str: return self.name diff --git a/cura/Machines/QualityManager.py b/cura/Machines/QualityManager.py index 113253f822..4aa88d6775 100644 --- a/cura/Machines/QualityManager.py +++ b/cura/Machines/QualityManager.py @@ -111,14 +111,7 @@ class QualityManager(QObject): quality_group_dict = dict() for node in nodes_to_check: if node and node.quality_type: - # CURA-6599 - # Same as QualityChangesGroup. - # For some reason, QML will get null or fail to convert type for MachineManager.activeQualityChangesGroup() to - # a QObject. Setting the object ownership to QQmlEngine.CppOwnership doesn't work, but setting the object - # parent to application seems to work. - from cura.CuraApplication import CuraApplication - quality_group = QualityGroup(node.getMetaDataEntry("name", ""), node.quality_type, - parent = CuraApplication.getInstance()) + quality_group = QualityGroup(node.getMetaDataEntry("name", ""), node.quality_type) quality_group.setGlobalNode(node) quality_group_dict[node.quality_type] = quality_group diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 49405156e5..d315f2fdb0 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -123,6 +123,14 @@ class MachineManager(QObject): self.globalContainerChanged.connect(self.printerConnectedStatusChanged) self.outputDevicesChanged.connect(self.printerConnectedStatusChanged) + # For updating active quality display name + self.activeQualityChanged.connect(self.activeQualityDisplayNameChanged) + self.activeIntentChanged.connect(self.activeQualityDisplayNameChanged) + self.activeQualityGroupChanged.connect(self.activeQualityDisplayNameChanged) + self.activeQualityChangesGroupChanged.connect(self.activeQualityDisplayNameChanged) + + activeQualityDisplayNameChanged = pyqtSignal() + activeQualityGroupChanged = pyqtSignal() activeQualityChangesGroupChanged = pyqtSignal() @@ -605,9 +613,10 @@ class MachineManager(QObject): global_container_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() if not global_container_stack: return False - if not self.activeQualityGroup: + active_quality_group = self.activeQualityGroup() + if active_quality_group is None: return False - return self.activeQualityGroup.is_available + return active_quality_group.is_available @pyqtProperty(bool, notify = activeQualityGroupChanged) def isActiveQualityExperimental(self) -> bool: @@ -629,16 +638,6 @@ class MachineManager(QObject): intent_category = category return intent_category - # Returns the human-readable name of the active intent category. If the intent category is "default", returns an - # empty string. - @pyqtProperty(str, notify = activeIntentChanged) - def activeIntentName(self) -> str: - intent_category = self.activeIntentCategory - if intent_category == "default": - intent_category = "" - intent_name = intent_category.capitalize() - return intent_name - # Provies a list of extruder positions that have a different intent from the active one. @pyqtProperty("QStringList", notify=activeIntentChanged) def extruderPositionsWithNonActiveIntent(self): @@ -1591,6 +1590,34 @@ class MachineManager(QObject): if not no_dialog and self.hasUserSettings and self._application.getPreferences().getValue("cura/active_mode") == 1: self._application.discardOrKeepProfileChanges() + # The display name of currently active quality. + # This display name is: + # - For built-in qualities (quality/intent): the quality type name, such as "Fine", "Normal", etc. + # - For custom qualities: - - + # Examples: + # - "my_profile - Fine" (only based on a default quality, no intent involved) + # - "my_profile - Engineering - Fine" (based on an intent) + @pyqtProperty(str, notify = activeQualityDisplayNameChanged) + def activeQualityDisplayName(self) -> str: + global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() + if global_stack is None: + return "" + + # Not a custom quality + display_name = self.activeQualityOrQualityChangesName + if global_stack.qualityChanges == empty_quality_changes_container: + return display_name + + # A custom quality + intent_category = self.activeIntentCategory + if intent_category != "default": + from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel + intent_display_name = IntentCategoryModel.name_translation.get(intent_category, catalog.i18nc("@label", "Unknown")) + display_name += " - {intent_name}".format(intent_name = intent_display_name) + + display_name += " - {quality_level_name}".format(quality_level_name = global_stack.quality.getName()) + return display_name + ## Change the intent category of the current printer. # # All extruders can change their profiles. If an intent profile is @@ -1620,13 +1647,26 @@ class MachineManager(QObject): else: # No intent had the correct category. extruder.intent = empty_intent_container - @pyqtProperty(QObject, fset = setQualityGroup, notify = activeQualityGroupChanged) + ## Get the currently activated quality group. + # + # If no printer is added yet or the printer doesn't have quality profiles, + # this returns ``None``. + # \return The currently active quality group. def activeQualityGroup(self) -> Optional["QualityGroup"]: global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() if not global_stack or global_stack.quality == empty_quality_container: return None return ContainerTree.getInstance().getCurrentQualityGroups().get(self.activeQualityType) + ## Get the name of the active quality group. + # \return The name of the active quality group. + @pyqtProperty(str, notify = activeQualityGroupChanged) + def activeQualityGroupName(self) -> str: + quality_group = self.activeQualityGroup() + if quality_group is None: + return "" + return quality_group.getName() + @pyqtSlot(QObject) def setQualityChangesGroup(self, quality_changes_group: "QualityChangesGroup", no_dialog: bool = False) -> None: self.blurSettings.emit() @@ -1642,7 +1682,7 @@ class MachineManager(QObject): if self._global_container_stack is None: return with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): - self._setQualityGroup(self.activeQualityGroup) + self._setQualityGroup(self.activeQualityGroup()) for stack in [self._global_container_stack] + list(self._global_container_stack.extruders.values()): stack.userChanges.clear() diff --git a/resources/intent/um_s5_aa0.4_ABS_Draft_Print_Quick.inst.cfg b/resources/intent/um_s5_aa0.4_ABS_Draft_Print_Quick.inst.cfg index 9075315841..f627fbf74b 100644 --- a/resources/intent/um_s5_aa0.4_ABS_Draft_Print_Quick.inst.cfg +++ b/resources/intent/um_s5_aa0.4_ABS_Draft_Print_Quick.inst.cfg @@ -15,7 +15,8 @@ variant = AA 0.4 speed_infill = =speed_print speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall speed_layer_0 = 20 top_bottom_thickness = =wall_thickness wall_thickness = =line_width * 2 @@ -25,8 +26,9 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall jerk_layer_0 = 5 line_width = =machine_nozzle_size wall_line_width_x = =line_width diff --git a/resources/intent/um_s5_aa0.4_ABS_Fast_Print_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_ABS_Fast_Print_Accurate.inst.cfg index db4a001daf..be622d6cfe 100644 --- a/resources/intent/um_s5_aa0.4_ABS_Fast_Print_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_ABS_Fast_Print_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/intent/um_s5_aa0.4_ABS_Normal_Quality_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_ABS_Normal_Quality_Accurate.inst.cfg index 12ba19a5d2..352c26d312 100644 --- a/resources/intent/um_s5_aa0.4_ABS_Normal_Quality_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_ABS_Normal_Quality_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/intent/um_s5_aa0.4_PLA_Draft_Print_Quick.inst.cfg b/resources/intent/um_s5_aa0.4_PLA_Draft_Print_Quick.inst.cfg index 5ed11ab78e..553a68201d 100644 --- a/resources/intent/um_s5_aa0.4_PLA_Draft_Print_Quick.inst.cfg +++ b/resources/intent/um_s5_aa0.4_PLA_Draft_Print_Quick.inst.cfg @@ -12,21 +12,23 @@ material = generic_pla variant = AA 0.4 [values] +speed_infill = =speed_print +speed_topbottom = =speed_print +speed_wall = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall +speed_layer_0 = 20 top_bottom_thickness = =wall_thickness wall_thickness = =line_width * 2 -infill_sparse_density = 15 fill_perimeter_gaps = nowhere +infill_sparse_density = 15 infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall jerk_layer_0 = 5 line_width = =machine_nozzle_size -speed_infill = =speed_print -speed_topbottom = =speed_print -speed_wall = =speed_print -speed_wall_0 = =speed_print -speed_layer_0 = 20 wall_line_width_x = =line_width diff --git a/resources/intent/um_s5_aa0.4_PLA_Fast_Print_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_PLA_Fast_Print_Accurate.inst.cfg index 87da046a9f..0943bb2032 100644 --- a/resources/intent/um_s5_aa0.4_PLA_Fast_Print_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_PLA_Fast_Print_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/intent/um_s5_aa0.4_PLA_Normal_Quality_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_PLA_Normal_Quality_Accurate.inst.cfg index 8175cd7c4a..053b849aff 100644 --- a/resources/intent/um_s5_aa0.4_PLA_Normal_Quality_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_PLA_Normal_Quality_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/intent/um_s5_aa0.4_TPLA_Draft_Print_Quick.inst.cfg b/resources/intent/um_s5_aa0.4_TPLA_Draft_Print_Quick.inst.cfg index 40cef6653d..458b283dd8 100644 --- a/resources/intent/um_s5_aa0.4_TPLA_Draft_Print_Quick.inst.cfg +++ b/resources/intent/um_s5_aa0.4_TPLA_Draft_Print_Quick.inst.cfg @@ -15,7 +15,8 @@ variant = AA 0.4 speed_infill = =speed_print speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall speed_layer_0 = 20 top_bottom_thickness = =wall_thickness wall_thickness = =line_width * 2 @@ -25,8 +26,9 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall jerk_layer_0 = 5 line_width = =machine_nozzle_size wall_line_width_x = =line_width diff --git a/resources/intent/um_s5_aa0.4_TPLA_Fast_Print_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_TPLA_Fast_Print_Accurate.inst.cfg index 1aed2360e5..d19ad53fae 100644 --- a/resources/intent/um_s5_aa0.4_TPLA_Fast_Print_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_TPLA_Fast_Print_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/intent/um_s5_aa0.4_TPLA_Normal_Quality_Accurate.inst.cfg b/resources/intent/um_s5_aa0.4_TPLA_Normal_Quality_Accurate.inst.cfg index f2246a6d09..23d8b1e39b 100644 --- a/resources/intent/um_s5_aa0.4_TPLA_Normal_Quality_Accurate.inst.cfg +++ b/resources/intent/um_s5_aa0.4_TPLA_Normal_Quality_Accurate.inst.cfg @@ -16,14 +16,18 @@ infill_line_width = =line_width jerk_print = 30 jerk_infill = =jerk_print jerk_topbottom = =jerk_print -jerk_wall_0 = =jerk_print -jerk_wall_x = =jerk_print +jerk_wall = =jerk_print +jerk_wall_0 = =jerk_wall +jerk_wall_x = =jerk_wall +jerk_layer_0 = 5 line_width = =machine_nozzle_size speed_print = 30 +speed_infill = =speed_print speed_layer_0 = 20 speed_topbottom = =speed_print speed_wall = =speed_print -speed_wall_0 = =speed_print +speed_wall_0 = =speed_wall +speed_wall_x = =speed_wall top_bottom_thickness = =wall_thickness wall_line_width_x = =line_width wall_thickness = =line_width * 3 diff --git a/resources/qml/LabelBar.qml b/resources/qml/LabelBar.qml index 9a870811ca..007c5f1f54 100644 --- a/resources/qml/LabelBar.qml +++ b/resources/qml/LabelBar.qml @@ -7,7 +7,7 @@ import QtQuick.Layouts 1.3 import UM 1.2 as UM -// The labelBar shows a set of labels that are evenly spaced from oneother. +// The labelBar shows a set of labels that are evenly spaced from one another. // The first item is aligned to the left, the last is aligned to the right. // It's intended to be used together with RadioCheckBar. As such, it needs // to know what the used itemSize is, so it can ensure the labels are aligned correctly. diff --git a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml index cae34dc5c5..a297b0a769 100644 --- a/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml +++ b/resources/qml/PrintSetupSelector/Custom/CustomPrintSetup.qml @@ -100,17 +100,7 @@ Item function generateActiveQualityText() { - var result = Cura.MachineManager.activeQualityOrQualityChangesName - - // If this is a custom quality, add intent (if present) and quality it is based on - if (Cura.MachineManager.isActiveQualityCustom) - { - if (Cura.MachineManager.activeIntentName != "") - { - result += " - " + Cura.MachineManager.activeIntentName - } - result += " - " + Cura.MachineManager.activeQualityGroup.getName() - } + var result = Cura.MachineManager.activeQualityDisplayName if (Cura.MachineManager.isActiveQualityExperimental) { diff --git a/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml index affe514bd8..bb3a986929 100644 --- a/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml +++ b/resources/qml/PrintSetupSelector/PrintSetupSelectorHeader.qml @@ -20,17 +20,7 @@ RowLayout { if (Cura.MachineManager.activeStack) { - var text = Cura.MachineManager.activeQualityOrQualityChangesName - - // If this is a custom quality, add intent (if present) and quality it is based on - if (Cura.MachineManager.isActiveQualityCustom) - { - if (Cura.MachineManager.activeIntentName != "") - { - text += " - " + Cura.MachineManager.activeIntentName - } - text += " - " + Cura.MachineManager.activeQualityGroup.getName() - } + var text = Cura.MachineManager.activeQualityDisplayName if (!Cura.MachineManager.hasNotSupportedQuality) { diff --git a/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml index 99a1d25138..d1f7dd7de2 100644 --- a/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml +++ b/resources/qml/PrintSetupSelector/Recommended/RecommendedQualityProfileSelector.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Ultimaker B.V. +// Copyright (c) 2019 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.10 @@ -9,6 +9,7 @@ import QtQuick.Controls.Styles 1.4 import UM 1.2 as UM import Cura 1.6 as Cura import ".." + Item { id: qualityRow diff --git a/resources/qml/RadioCheckbar.qml b/resources/qml/RadioCheckbar.qml index 0ce84ad8ca..dfd9ca8628 100644 --- a/resources/qml/RadioCheckbar.qml +++ b/resources/qml/RadioCheckbar.qml @@ -19,7 +19,7 @@ Item property int barSize: UM.Theme.getSize("slider_groove_radius").height property var isCheckedFunction // Function that accepts the modelItem and returns if the item should be active. - implicitWidth: 200 + implicitWidth: 200 * screenScaleFactor implicitHeight: checkboxSize property var dataModel: null @@ -62,7 +62,7 @@ Item Layout.fillHeight: true // The last item of the repeater needs to be shorter, as we don't need another part to fit // the horizontal bar. The others should essentially not be limited. - Layout.maximumWidth: index + 1 === repeater.count ? activeComponent.width: 200000000 + Layout.maximumWidth: index + 1 === repeater.count ? activeComponent.width : 200000000 property bool isEnabled: model.available // The horizontal bar between the checkable options. diff --git a/tests/Machines/TestMachineNode.py b/tests/Machines/TestMachineNode.py index 270c2503e6..8a343c4fe8 100644 --- a/tests/Machines/TestMachineNode.py +++ b/tests/Machines/TestMachineNode.py @@ -23,6 +23,18 @@ def container_registry(): result.findContainersMetadata = MagicMock(return_value = [metadata_dict]) return result +## Creates a machine node without anything underneath it. No sub-nodes. +# +# For testing stuff with machine nodes without testing _loadAll(). You'll need +# to add subnodes manually in your test. +@pytest.fixture +def empty_machine_node(): + empty_container_registry = MagicMock() + empty_container_registry.findContainersMetadata = MagicMock(return_value = [metadata_dict]) # Still contain the MachineNode's own metadata for the constructor. + empty_container_registry.findInstanceContainersMetadata = MagicMock(return_value = []) + with patch("UM.Settings.ContainerRegistry.ContainerRegistry.getInstance", MagicMock(return_value = empty_container_registry)): + with patch("cura.Machines.MachineNode.MachineNode._loadAll", MagicMock()): + return MachineNode("machine_1") def getMetadataEntrySideEffect(*args, **kwargs): return metadata_dict.get(args[0]) @@ -60,4 +72,100 @@ def test_metadataProperties(container_registry): assert node.exclude_materials == metadata_dict["exclude_materials"] assert node.preferred_variant_name == metadata_dict["preferred_variant_name"] assert node.preferred_material == metadata_dict["preferred_material"] - assert node.preferred_quality_type == metadata_dict["preferred_quality_type"] \ No newline at end of file + assert node.preferred_quality_type == metadata_dict["preferred_quality_type"] + +## Test getting quality groups when there are quality profiles available for +# the requested configurations on two extruders. +def test_getQualityGroupsBothExtrudersAvailable(empty_machine_node): + # Prepare a tree inside the machine node. + extruder_0_node = MagicMock(quality_type = "quality_type_1") + extruder_1_node = MagicMock(quality_type = "quality_type_1") # Same quality type, so this is the one that can be returned. + empty_machine_node.variants = { + "variant_1": MagicMock( + materials = { + "material_1": MagicMock( + qualities = { + "quality_1": extruder_0_node + } + ) + } + ), + "variant_2": MagicMock( + materials = { + "material_2": MagicMock( + qualities = { + "quality_2": extruder_1_node + } + ) + } + ) + } + global_node = MagicMock( + container = MagicMock(id = "global_quality_container"), # Needs to exist, otherwise it won't add this quality type. + getMetaDataEntry = lambda _, __: "Global Quality Profile Name" + ) + empty_machine_node.global_qualities = { + "quality_type_1": global_node + } + + # Request the quality groups for the variants in the machine tree. + result = empty_machine_node.getQualityGroups(["variant_1", "variant_2"], ["material_1", "material_2"], [True, True]) + + assert "quality_type_1" in result, "This quality type was available for both extruders." + assert result["quality_type_1"].node_for_global == global_node + assert result["quality_type_1"].nodes_for_extruders[0] == extruder_0_node + assert result["quality_type_1"].nodes_for_extruders[1] == extruder_1_node + assert result["quality_type_1"].name == global_node.getMetaDataEntry("name", "Unnamed Profile") + assert result["quality_type_1"].quality_type == "quality_type_1" + +## Test the "is_available" flag on quality groups. +# +# If a profile is available for a quality type on an extruder but not on all +# extruders, there should be a quality group for it but it should not be made +# available. +def test_getQualityGroupsAvailability(empty_machine_node): + # Prepare a tree inside the machine node. + extruder_0_both = MagicMock(quality_type = "quality_type_both") # This quality type is available for both extruders. + extruder_1_both = MagicMock(quality_type = "quality_type_both") + extruder_0_exclusive = MagicMock(quality_type = "quality_type_0") # These quality types are only available on one of the extruders. + extruder_1_exclusive = MagicMock(quality_type = "quality_type_1") + empty_machine_node.variants = { + "variant_1": MagicMock( + materials = { + "material_1": MagicMock( + qualities = { + "quality_0_both": extruder_0_both, + "quality_0_exclusive": extruder_0_exclusive + } + ) + } + ), + "variant_2": MagicMock( + materials = { + "material_2": MagicMock( + qualities = { + "quality_1_both": extruder_1_both, + "quality_1_exclusive": extruder_1_exclusive + } + ) + } + ) + } + global_both = MagicMock(container = MagicMock(id = "global_quality_both"), getMetaDataEntry = lambda _, __: "Global Quality Both") + global_0 = MagicMock(container = MagicMock(id = "global_quality_0"), getMetaDataEntry = lambda _, __: "Global Quality 0 Exclusive") + global_1 = MagicMock(container = MagicMock(id = "global_quality_1"), getMetaDataEntry = lambda _, __: "Global Quality 1 Exclusive") + empty_machine_node.global_qualities = { + "quality_type_both": global_both, + "quality_type_0": global_0, + "quality_type_1": global_1 + } + + # Request the quality groups for the variants in the machine tree. + result = empty_machine_node.getQualityGroups(["variant_1", "variant_2"], ["material_1", "material_2"], [True, True]) + + assert "quality_type_both" in result, "This quality type was available on both extruders." + assert result["quality_type_both"].is_available, "This quality type was available on both extruders and thus should be made available." + assert "quality_type_0" in result, "This quality type was available for one of the extruders, and so there must be a group for it (even though it's unavailable)." + assert not result["quality_type_0"].is_available, "This quality type was only available for one of the extruders and thus can't be activated." + assert "quality_type_1" in result, "This quality type was available for one of the extruders, and so there must be a group for it (even though it's unavailable)." + assert not result["quality_type_1"].is_available, "This quality type was only available for one of the extruders and thus can't be activated." \ No newline at end of file diff --git a/tests/Machines/TestVariantNode.py b/tests/Machines/TestVariantNode.py index e04c369762..954904908b 100644 --- a/tests/Machines/TestVariantNode.py +++ b/tests/Machines/TestVariantNode.py @@ -13,13 +13,13 @@ material_node_added_test_data = [({"type": "Not a material"}, ["material_1", "ma ({"type": "material", "base_file": "material_3"}, ["material_1", "material_2"]), # material_3 is on the "NOPE" list. ({"type": "material", "base_file": "material_4", "definition": "machine_3"}, ["material_1", "material_2"]), # Wrong machine ({"type": "material", "base_file": "material_4", "definition": "machine_1"}, ["material_1", "material_2"]), # No variant - ({"type": "material", "base_file": "material_4", "definition": "machine_1", "variant": "Variant Three"}, ["material_1", "material_2"]), # Wrong variant - ({"type": "material", "base_file": "material_4", "definition": "machine_1", "variant": "Variant One"}, ["material_1", "material_2", "material_4"]) + ({"type": "material", "base_file": "material_4", "definition": "machine_1", "variant_name": "Variant Three"}, ["material_1", "material_2"]), # Wrong variant + ({"type": "material", "base_file": "material_4", "definition": "machine_1", "variant_name": "Variant One"}, ["material_1", "material_2", "material_4"]) ] -material_node_update_test_data = [({"type": "material", "base_file": "material_1", "definition": "machine_1", "variant": "Variant One"}, ["material_1"], ["material_2"]), - ({"type": "material", "base_file": "material_1", "definition": "fdmprinter", "variant": "Variant One"}, [], ["material_2", "material_1"]), # Too generic - ({"type": "material", "base_file": "material_1", "definition": "machine_2", "variant": "Variant One"}, [], ["material_2", "material_1"]) # Wrong definition +material_node_update_test_data = [({"type": "material", "base_file": "material_1", "definition": "machine_1", "variant_name": "Variant One"}, ["material_1"], ["material_2"]), + ({"type": "material", "base_file": "material_1", "definition": "fdmprinter", "variant_name": "Variant One"}, [], ["material_2", "material_1"]), # Too generic + ({"type": "material", "base_file": "material_1", "definition": "machine_2", "variant_name": "Variant One"}, [], ["material_2", "material_1"]) # Wrong definition ] metadata_dict = {} diff --git a/tests/Settings/TestCuraStackBuilder.py b/tests/Settings/TestCuraStackBuilder.py index cf4496d0a9..aebde3406f 100644 --- a/tests/Settings/TestCuraStackBuilder.py +++ b/tests/Settings/TestCuraStackBuilder.py @@ -56,7 +56,7 @@ def test_createMachine(application, container_registry, definition_container, gl quality_container, intent_container, quality_changes_container): variant_manager = MagicMock(name = "Variant Manager") quality_manager = MagicMock(name = "Quality Manager") - global_variant_node = MagicMock( name = "global variant node") + global_variant_node = MagicMock(name = "global variant node") global_variant_node.container = global_variant variant_manager.getDefaultVariantNode = MagicMock(return_value = global_variant_node) @@ -98,7 +98,7 @@ def test_createExtruderStack(application, definition_container, global_variant, application.empty_quality_container = quality_container application.empty_intent_container = intent_container application.empty_quality_changes_container = quality_changes_container - with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value=application)): + with patch("cura.CuraApplication.CuraApplication.getInstance", MagicMock(return_value = application)): extruder_stack = CuraStackBuilder.createExtruderStack("Whatever", definition_container, "meh", 0, global_variant, material_instance_container, quality_container) assert extruder_stack.variant == global_variant assert extruder_stack.material == material_instance_container