Handle materials which don't have any quality profiles of their own. Moved the quality_type computation code into the QualityManager.

Contributes to CURA-2477 Profile menu should only contain valid options for all materials
This commit is contained in:
Simon Edwards 2016-09-29 16:30:35 +02:00
parent f909ffca2e
commit cd45ef496b
3 changed files with 94 additions and 65 deletions

View file

@ -44,6 +44,29 @@ class QualityManager:
criteria = {"type": "quality_changes", "name": quality_changes_name} criteria = {"type": "quality_changes", "name": quality_changes_name}
return self._getFilteredContainersForStack(machine_definition, [], **criteria) return self._getFilteredContainersForStack(machine_definition, [], **criteria)
## Fetch the list of available quality types for this combination of machine definition and materials.
#
# \param machine_definition \type{DefinitionContainer}
# \param material_containers \type{List[InstanceContainer]}
# \return \type{List[str]}
def findAllQualityTypesForMachineAndMaterials(self, machine_definition, material_containers):
# Determine the common set of quality types which can be
# applied to all of the materials for this machine.
quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_containers[0])
common_quality_types = set(quality_type_dict.keys())
for material_container in material_containers[1:]:
next_quality_type_dict = self.__fetchQualityTypeDictForMaterial(machine_definition, material_container)
common_quality_types.intersection_update(set(next_quality_type_dict.keys()))
return list(common_quality_types)
def __fetchQualityTypeDictForMaterial(self, machine_definition, material):
qualities = self.findAllQualitiesForMachineMaterial(machine_definition, material)
quality_type_dict = {}
for quality in qualities:
quality_type_dict[quality.getMetaDataEntry("quality_type")] = quality
return quality_type_dict
## Find a quality container by quality type. ## Find a quality container by quality type.
# #
# \param quality_type \type{str} the name of the quality type to search for. # \param quality_type \type{str} the name of the quality type to search for.
@ -51,12 +74,36 @@ class QualityManager:
# specified then the currently selected machine definition is used. # specified then the currently selected machine definition is used.
# \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then # \param material_containers (Optional) \type{List[ContainerInstance]} If nothing is specified then
# the current set of selected materials is used. # the current set of selected materials is used.
# \return the matching quality containers \type{List[ContainerInstance]} # \return the matching quality container \type{ContainerInstance}
def findQualityByQualityType(self, quality_type, machine_definition=None, material_containers=None): def findQualityByQualityType(self, quality_type, machine_definition=None, material_containers=None):
criteria = {"type": "quality"} criteria = {"type": "quality"}
if quality_type: if quality_type:
criteria["quality_type"] = quality_type criteria["quality_type"] = quality_type
return self._getFilteredContainersForStack(machine_definition, material_containers, **criteria) result = self._getFilteredContainersForStack(machine_definition, material_containers, **criteria)
# Fall back to using generic materials and qualities if nothing could be found.
if not result and material_containers and len(material_containers) == 1:
basic_material = self._getBasicMaterial(material_containers[0])
result = self._getFilteredContainersForStack(machine_definition, [basic_material], **criteria)
return result[0] if result else None
def findAllQualitiesForMachineMaterial(self, machine_definition, material_container):
criteria = {"type": "quality" }
result = self._getFilteredContainersForStack(machine_definition, [material_container], **criteria)
if not result:
basic_material = self._getBasicMaterial(material_container)
result = self._getFilteredContainersForStack(machine_definition, [basic_material], **criteria)
return result
def _getBasicMaterial(self, material_container):
base_material = material_container.getMetaDataEntry("material")
if base_material:
# There is a basic material specified
criteria = { "type": "material", "name": base_material, "definition": "fdmprinter" }
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
return containers[0] if containers else None
return None
def _getFilteredContainers(self, **kwargs): def _getFilteredContainers(self, **kwargs):
return self._getFilteredContainersForStack(None, None, **kwargs) return self._getFilteredContainersForStack(None, None, **kwargs)

View file

@ -8,7 +8,6 @@ from UM.Application import Application
from UM.Preferences import Preferences from UM.Preferences import Preferences
from UM.Logger import Logger from UM.Logger import Logger
from UM.Message import Message from UM.Message import Message
from UM.Settings.SettingRelation import RelationType
import UM.Settings import UM.Settings
@ -562,26 +561,18 @@ class MachineManager(QObject):
# See if the requested quality type is available in the new situation. # See if the requested quality type is available in the new situation.
machine_definition = self._active_container_stack.getBottom() machine_definition = self._active_container_stack.getBottom()
quality_manager = QualityManager.getInstance() quality_manager = QualityManager.getInstance()
candidate_qualities = quality_manager.findQualityByQualityType(quality_type, candidate_quality = quality_manager.findQualityByQualityType(quality_type,
quality_manager.getWholeMachineDefinition(machine_definition), quality_manager.getWholeMachineDefinition(machine_definition),
[material_container]) [material_container])
if not candidate_qualities: if not candidate_quality:
# Fall back to normal quality # Fall back to a quality
quality_containers = quality_manager.findQualityByQualityType("normal", new_quality_id = quality_manager.findQualityByQualityType(None,
quality_manager.getWholeMachineDefinition(machine_definition), quality_manager.getWholeMachineDefinition(machine_definition),
[material_container]) [material_container])
if quality_containers:
new_quality_id = quality_containers[0].getId()
else:
# There is no normal quality for this machine/variant/material combination
quality_containers = quality_manager.findQualityByQualityType(None,
quality_manager.getWholeMachineDefinition(machine_definition),
[material_container])
new_quality_id = quality_containers[0].getId()
else: else:
if not old_quality_changes: if not old_quality_changes:
new_quality_id = candidate_qualities[0].getId() new_quality_id = candidate_quality.getId()
self.setActiveQuality(new_quality_id) self.setActiveQuality(new_quality_id)
@ -622,10 +613,11 @@ class MachineManager(QObject):
# If we found a quality_changes profile then look up its parent quality profile. # If we found a quality_changes profile then look up its parent quality profile.
container_type = containers[0].getMetaDataEntry("type") container_type = containers[0].getMetaDataEntry("type")
quality_name = containers[0].getName() quality_name = containers[0].getName()
quality_type = containers[0].getMetaDataEntry("quality_type")
# Get quality container and optionally the quality_changes container. # Get quality container and optionally the quality_changes container.
if container_type == "quality": if container_type == "quality":
new_quality_settings_list = self._determineQualityAndQualityChangesForQuality(quality_name) new_quality_settings_list = self._determineQualityAndQualityChangesForQualityType(quality_type)
elif container_type == "quality_changes": elif container_type == "quality_changes":
new_quality_settings_list = self._determineQualityAndQualityChangesForQualityChanges(quality_name) new_quality_settings_list = self._determineQualityAndQualityChangesForQualityChanges(quality_name)
else: else:
@ -661,26 +653,28 @@ class MachineManager(QObject):
# #
# \param quality_name \type{str} the name of the quality. # \param quality_name \type{str} the name of the quality.
# \return \type{List[Dict]} with keys "stack", "quality" and "quality_changes". # \return \type{List[Dict]} with keys "stack", "quality" and "quality_changes".
def _determineQualityAndQualityChangesForQuality(self, quality_name): def _determineQualityAndQualityChangesForQualityType(self, quality_type):
quality_manager = QualityManager.getInstance()
result = [] result = []
empty_quality_changes = self._empty_quality_changes_container empty_quality_changes = self._empty_quality_changes_container
# Find the values for the global stack.
global_container_stack = self._global_container_stack global_container_stack = self._global_container_stack
global_machine_definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom()) global_machine_definition = quality_manager.getParentMachineDefinition(global_container_stack.getBottom())
material = global_container_stack.findContainer(type="material")
global_quality = QualityManager.getInstance().findQualityByName(quality_name, global_machine_definition, [material])[0]
result.append({"stack": global_container_stack, "quality": global_quality, "quality_changes": empty_quality_changes})
# Find the values for each extruder. extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
for stack in ExtruderManager.getInstance().getActiveExtruderStacks(): if extruder_stacks:
stacks = extruder_stacks
else:
stacks = [global_container_stack]
for stack in stacks:
material = stack.findContainer(type="material") material = stack.findContainer(type="material")
stack_qualities = QualityManager.getInstance().findQualityByName(quality_name, global_machine_definition, [material]) quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
if not stack_qualities: result.append({"stack": stack, "quality": quality, "quality_changes": empty_quality_changes})
# Fall back on the values used for the global stack.
result.append({"stack": stack, "quality": global_quality, "quality_changes": empty_quality_changes}) if extruder_stacks:
else: # Add an extra entry for the global stack.
result.append({"stack": stack, "quality": stack_qualities[0], "quality_changes": empty_quality_changes}) result.append({"stack": global_container_stack, "quality": result[0]["quality"],
"quality_changes": empty_quality_changes})
return result return result
## Determine the quality and quality changes settings for the current machine for a quality changes name. ## Determine the quality and quality changes settings for the current machine for a quality changes name.
@ -699,12 +693,11 @@ class MachineManager(QObject):
# For the global stack, find a quality which matches the quality_type in # For the global stack, find a quality which matches the quality_type in
# the quality changes profile and also satisfies any material constraints. # the quality changes profile and also satisfies any material constraints.
quality_type = global_quality_changes.getMetaDataEntry("quality_type") quality_type = global_quality_changes.getMetaDataEntry("quality_type")
global_quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])[0] global_quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
result.append({"stack": global_container_stack, "quality": global_quality, "quality_changes": global_quality_changes})
# Find the values for each extruder. # Find the values for each extruder.
for stack in ExtruderManager.getInstance().getActiveExtruderStacks(): extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
for stack in extruder_stacks:
machine_definition = quality_manager.getParentMachineDefinition(stack.getBottom()) machine_definition = quality_manager.getParentMachineDefinition(stack.getBottom())
quality_changes_profiles = quality_manager.findQualityChangesByName(quality_changes_name, machine_definition) quality_changes_profiles = quality_manager.findQualityChangesByName(quality_changes_name, machine_definition)
if quality_changes_profiles: if quality_changes_profiles:
@ -713,10 +706,17 @@ class MachineManager(QObject):
quality_changes = global_quality_changes quality_changes = global_quality_changes
material = stack.findContainer(type="material") material = stack.findContainer(type="material")
quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])[0] quality = quality_manager.findQualityByQualityType(quality_type, global_machine_definition, [material])
result.append({"stack": stack, "quality": quality, "quality_changes": quality_changes}) result.append({"stack": stack, "quality": quality, "quality_changes": quality_changes})
if extruder_stacks:
# Duplicate the quality from the 1st extruder into the global stack. If anyone
# then looks in the global stack, they should get a reasonable view.
result.append({"stack": global_container_stack, "quality": result[0]["quality"], "quality_changes": global_quality_changes})
else:
result.append({"stack": global_container_stack, "quality": global_quality, "quality_changes": global_quality_changes})
return result return result
def _replaceQualityOrQualityChangesInStack(self, stack, container, postpone_emit = False): def _replaceQualityOrQualityChangesInStack(self, stack, container, postpone_emit = False):

View file

@ -3,8 +3,8 @@
from UM.Application import Application from UM.Application import Application
from UM.Settings.Models.InstanceContainersModel import InstanceContainersModel from UM.Settings.Models.InstanceContainersModel import InstanceContainersModel
from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.QualityManager import QualityManager
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
## QML Model for listing the current list of valid quality profiles. ## QML Model for listing the current list of valid quality profiles.
@ -28,36 +28,18 @@ class ProfilesModel(InstanceContainersModel):
extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks() extruder_stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
if extruder_stacks: if extruder_stacks:
# Multi-extruder machine detected. # Multi-extruder machine detected.
materials = [stack.findContainer(type="material") for stack in extruder_stacks]
# Determine the common set of quality types which can be
# applied to all of the materials for this machine.
quality_type_dict = self.__fetchQualityTypeDictForStack(extruder_stacks[0], global_machine_definition)
common_quality_types = set(quality_type_dict.keys())
for stack in extruder_stacks[1:]:
next_quality_type_dict = self.__fetchQualityTypeDictForStack(stack, global_machine_definition)
common_quality_types.intersection_update(set(next_quality_type_dict.keys()))
return [quality_type_dict[quality_type] for quality_type in common_quality_types]
else: else:
# Machine with one extruder. # Machine with one extruder.
quality_type_dict = self.__fetchQualityTypeDictForStack(global_container_stack, global_machine_definition) materials = [global_container_stack.findContainer(type="material")]
return list(quality_type_dict.values())
return []
def __fetchQualityTypeDictForStack(self, stack, global_machine_definition):
criteria = {"type": "quality" }
if global_machine_definition.getMetaDataEntry("has_machine_quality", False):
criteria["definition"] = global_machine_definition.getId()
if global_machine_definition.getMetaDataEntry("has_materials", False):
material = stack.findContainer(type="material")
criteria["material"] = material.getId()
else:
criteria["definition"] = "fdmprinter"
qualities = ContainerRegistry.getInstance().findInstanceContainers(**criteria)
quality_types = QualityManager.getInstance().findAllQualityTypesForMachineAndMaterials(global_machine_definition,
materials)
# Map the list of quality_types to InstanceContainers
qualities = QualityManager.getInstance().findAllQualitiesForMachineMaterial(global_machine_definition,
materials[0])
quality_type_dict = {} quality_type_dict = {}
for quality in qualities: for quality in qualities:
quality_type_dict[quality.getMetaDataEntry("quality_type")] = quality quality_type_dict[quality.getMetaDataEntry("quality_type")] = quality
return quality_type_dict
return [quality_type_dict[quality_type] for quality_type in quality_types]