Make intents work on quality management page

CURA-6706
This commit is contained in:
Lipu Fei 2019-10-04 13:36:03 +02:00
parent 1981a7c65b
commit c42feae11c
6 changed files with 114 additions and 40 deletions

View file

@ -74,21 +74,7 @@ class IntentModel(ListModel):
new_items.append(intent) new_items.append(intent)
layer_heights_added.append(intent["layer_height"]) 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) new_items = sorted(new_items, key = lambda x: x["layer_height"])
# for all groups that we don't have anything for (and set it to not available)
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 = fetchLayerHeight(quality_group)
if layer_height not in layer_heights_added:
new_items.append({"name": "Unavailable",
"quality_type": "",
"layer_height": layer_height,
"intent_category": self._intent_category,
"available": False})
layer_heights_added.append(layer_height)
new_items = sorted(new_items, key=lambda x: x["layer_height"])
self.setItems(new_items) self.setItems(new_items)
## Get the active materials for all extruders. No duplicates will be returned ## Get the active materials for all extruders. No duplicates will be returned

View file

@ -12,6 +12,11 @@ import cura.CuraApplication # Imported this way to prevent circular imports.
from cura.Settings.ContainerManager import ContainerManager from cura.Settings.ContainerManager import ContainerManager
from cura.Machines.ContainerTree import ContainerTree from cura.Machines.ContainerTree import ContainerTree
from cura.Settings.cura_empty_instance_containers import empty_quality_changes_container from cura.Settings.cura_empty_instance_containers import empty_quality_changes_container
from cura.Settings.IntentManager import IntentManager
from cura.Machines.Models.IntentCategoryModel import IntentCategoryModel
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
if TYPE_CHECKING: if TYPE_CHECKING:
from UM.Settings.Interfaces import ContainerInterface from UM.Settings.Interfaces import ContainerInterface
@ -19,6 +24,7 @@ if TYPE_CHECKING:
from cura.Settings.ExtruderStack import ExtruderStack from cura.Settings.ExtruderStack import ExtruderStack
from cura.Settings.GlobalStack import GlobalStack from cura.Settings.GlobalStack import GlobalStack
# #
# This the QML model for the quality management page. # This the QML model for the quality management page.
# #
@ -26,15 +32,21 @@ class QualityManagementModel(ListModel):
NameRole = Qt.UserRole + 1 NameRole = Qt.UserRole + 1
IsReadOnlyRole = Qt.UserRole + 2 IsReadOnlyRole = Qt.UserRole + 2
QualityGroupRole = Qt.UserRole + 3 QualityGroupRole = Qt.UserRole + 3
QualityChangesGroupRole = Qt.UserRole + 4 QualityTypeRole = Qt.UserRole + 4
QualityChangesGroupRole = Qt.UserRole + 5
IntentCategoryRole = Qt.UserRole + 6
SectionNameRole = Qt.UserRole + 7
def __init__(self, parent = None): def __init__(self, parent: Optional["QObject"] = None) -> None:
super().__init__(parent) super().__init__(parent)
self.addRoleName(self.NameRole, "name") self.addRoleName(self.NameRole, "name")
self.addRoleName(self.IsReadOnlyRole, "is_read_only") self.addRoleName(self.IsReadOnlyRole, "is_read_only")
self.addRoleName(self.QualityGroupRole, "quality_group") self.addRoleName(self.QualityGroupRole, "quality_group")
self.addRoleName(self.QualityTypeRole, "quality_type")
self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group") self.addRoleName(self.QualityChangesGroupRole, "quality_changes_group")
self.addRoleName(self.IntentCategoryRole, "intent_category")
self.addRoleName(self.SectionNameRole, "section_name")
application = cura.CuraApplication.CuraApplication.getInstance() application = cura.CuraApplication.CuraApplication.getInstance()
container_registry = application.getContainerRegistry() container_registry = application.getContainerRegistry()
@ -127,11 +139,13 @@ class QualityManagementModel(ListModel):
container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry() container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry()
new_name = container_registry.uniqueName(new_name) new_name = container_registry.uniqueName(new_name)
intent_category = quality_model_item["intent_category"]
quality_group = quality_model_item["quality_group"] quality_group = quality_model_item["quality_group"]
quality_changes_group = quality_model_item["quality_changes_group"] quality_changes_group = quality_model_item["quality_changes_group"]
if quality_changes_group is None: if quality_changes_group is None:
# Create global quality changes only. # Create global quality changes only.
new_quality_changes = self._createQualityChanges(quality_group.quality_type, None, new_name, global_stack, extruder_stack = None) new_quality_changes = self._createQualityChanges(quality_group.quality_type, intent_category, new_name,
global_stack, extruder_stack = None)
container_registry.addContainer(new_quality_changes) container_registry.addContainer(new_quality_changes)
else: else:
for metadata in [quality_changes_group.metadata_for_global] + list(quality_changes_group.metadata_per_extruder.values()): for metadata in [quality_changes_group.metadata_for_global] + list(quality_changes_group.metadata_per_extruder.values()):
@ -233,6 +247,31 @@ class QualityManagementModel(ListModel):
if container.getMetaDataEntry("type") == "quality_changes": if container.getMetaDataEntry("type") == "quality_changes":
self._update() self._update()
@pyqtSlot("QVariantMap", result = str)
def getQualityItemDisplayName(self, quality_model_item: Dict[str, Any]) -> str:
display_name = quality_model_item["name"]
quality_group = quality_model_item["quality_group"]
is_read_only = quality_model_item["is_read_only"]
intent_category = quality_model_item["intent_category"]
# Not a custom quality
if is_read_only:
return display_name
# A custom quality
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)
quality_level_name = "Not Supported"
if quality_group is not None:
quality_level_name = quality_group.name
display_name += " - {quality_level_name}".format(quality_level_name = quality_level_name)
return display_name
def _update(self): def _update(self):
Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__))
@ -253,7 +292,7 @@ class QualityManagementModel(ListModel):
return return
item_list = [] item_list = []
# Create quality group items # Create quality group items (intent category = "default")
for quality_group in quality_group_dict.values(): for quality_group in quality_group_dict.values():
if not quality_group.is_available: if not quality_group.is_available:
continue continue
@ -261,11 +300,33 @@ class QualityManagementModel(ListModel):
item = {"name": quality_group.name, item = {"name": quality_group.name,
"is_read_only": True, "is_read_only": True,
"quality_group": quality_group, "quality_group": quality_group,
"quality_changes_group": None} "quality_type": quality_group.quality_type,
"quality_changes_group": None,
"intent_category": "default",
"section_name": catalog.i18nc("@label", "Default"),
}
item_list.append(item) item_list.append(item)
# Sort by quality names # Sort by quality names
item_list = sorted(item_list, key = lambda x: x["name"].upper()) item_list = sorted(item_list, key = lambda x: x["name"].upper())
# Create intent items (non-default)
available_intent_list = IntentManager.getInstance().getCurrentAvailableIntents()
available_intent_list = [i for i in available_intent_list if i[0] != "default"]
result = []
for intent_category, quality_type in available_intent_list:
result.append({
"name": quality_group_dict[quality_type].name, # Use the quality name as the display name
"is_read_only": True,
"quality_group": quality_group_dict[quality_type],
"quality_type": quality_type,
"quality_changes_group": None,
"intent_category": intent_category,
"section_name": IntentCategoryModel.name_translation.get(intent_category, catalog.i18nc("@label", "Unknown")),
})
# Sort by quality_type for each intent category
result = sorted(result, key = lambda x: (x["intent_category"], x["quality_type"]))
item_list += result
# Create quality_changes group items # Create quality_changes group items
quality_changes_item_list = [] quality_changes_item_list = []
for quality_changes_group in quality_changes_group_list: for quality_changes_group in quality_changes_group_list:
@ -273,7 +334,11 @@ class QualityManagementModel(ListModel):
item = {"name": quality_changes_group.name, item = {"name": quality_changes_group.name,
"is_read_only": False, "is_read_only": False,
"quality_group": quality_group, "quality_group": quality_group,
"quality_changes_group": quality_changes_group} "quality_type": quality_group.quality_type,
"quality_changes_group": quality_changes_group,
"intent_category": quality_changes_group.intent_category,
"section_name": catalog.i18nc("@label", "Custom profiles"),
}
quality_changes_item_list.append(item) quality_changes_item_list.append(item)
# Sort quality_changes items by names and append to the item list # Sort quality_changes items by names and append to the item list

View file

@ -80,7 +80,7 @@ class IntentManager(QObject):
for extruder_stack in global_stack.extruderList: for extruder_stack in global_stack.extruderList:
nozzle_name = extruder_stack.variant.getMetaDataEntry("name") nozzle_name = extruder_stack.variant.getMetaDataEntry("name")
material_id = extruder_stack.material.getMetaDataEntry("base_file") material_id = extruder_stack.material.getMetaDataEntry("base_file")
final_intent_ids |= {metadata["id"] for metadata in self.intentMetadatas(current_definition_id, nozzle_name, material_id) if metadata["quality_type"] in available_quality_types} final_intent_ids |= {metadata["id"] for metadata in self.intentMetadatas(current_definition_id, nozzle_name, material_id) if metadata.get("quality_type") in available_quality_types}
result = set() # type: Set[Tuple[str, str]] result = set() # type: Set[Tuple[str, str]]
for intent_id in final_intent_ids: for intent_id in final_intent_ids:

View file

@ -636,6 +636,7 @@ class MachineManager(QObject):
category = extruder.intent.getMetaDataEntry("intent_category", "default") category = extruder.intent.getMetaDataEntry("intent_category", "default")
if category != "default" and category != intent_category: if category != "default" and category != intent_category:
intent_category = category intent_category = category
return intent_category return intent_category
# Provies a list of extruder positions that have a different intent from the active one. # Provies a list of extruder positions that have a different intent from the active one.
@ -1625,6 +1626,7 @@ class MachineManager(QObject):
# Otherwise the intent profile will be left to the empty profile, which # Otherwise the intent profile will be left to the empty profile, which
# represents the "default" intent category. # represents the "default" intent category.
# \param intent_category The intent category to change to. # \param intent_category The intent category to change to.
@pyqtSlot(str)
def setIntentByCategory(self, intent_category: str) -> None: def setIntentByCategory(self, intent_category: str) -> None:
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack() global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
if global_stack is None: if global_stack is None:

View file

@ -7,7 +7,7 @@ import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import UM 1.2 as UM import UM 1.2 as UM
import Cura 1.0 as Cura import Cura 1.6 as Cura
Item Item
@ -43,6 +43,7 @@ Item
} }
property var currentItemName: hasCurrentItem ? base.currentItem.name : "" property var currentItemName: hasCurrentItem ? base.currentItem.name : ""
property var currentItemDisplayName: hasCurrentItem ? base.qualityManagementModel.getQualityItemDisplayName(base.currentItem) : ""
property var isCurrentItemActivated: property var isCurrentItemActivated:
{ {
@ -50,8 +51,15 @@ Item
{ {
return false; return false;
} }
if (base.currentItem.is_read_only)
{
return (base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName) && (base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory);
}
else
{
return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName; return base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName;
} }
}
property var canCreateProfile: property var canCreateProfile:
{ {
@ -80,7 +88,7 @@ Item
{ {
if (base.currentItem.is_read_only) if (base.currentItem.is_read_only)
{ {
Cura.MachineManager.setQualityGroup(base.currentItem.quality_group); Cura.IntentManager.selectIntent(base.currentItem.intent_category, base.currentItem.quality_type);
} }
else else
{ {
@ -434,7 +442,7 @@ Item
} }
} }
section.property: "is_read_only" section.property: "section_name"
section.delegate: Rectangle section.delegate: Rectangle
{ {
height: childrenRect.height height: childrenRect.height
@ -443,7 +451,7 @@ Item
{ {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_lining").width anchors.leftMargin: UM.Theme.getSize("default_lining").width
text: section == "true" ? catalog.i18nc("@label", "Default profiles") : catalog.i18nc("@label", "Custom profiles") text: section
font.bold: true font.bold: true
} }
} }
@ -467,7 +475,19 @@ Item
width: Math.floor((parent.width * 0.8)) width: Math.floor((parent.width * 0.8))
text: model.name text: model.name
elide: Text.ElideRight elide: Text.ElideRight
font.italic: model.name == Cura.MachineManager.activeQualityOrQualityChangesName font.italic:
{
if (model.is_read_only)
{
// For built-in qualities, it needs to match both the intent category and the quality name
return model.name == Cura.MachineManager.activeQualityOrQualityChangesName && model.intent_category == Cura.MachineManager.activeIntentCategory
}
else
{
// For custom qualities, it only needs to match the name
return model.name == Cura.MachineManager.activeQualityOrQualityChangesName
}
}
color: parent.isCurrentItem ? palette.highlightedText : palette.text color: parent.isCurrentItem ? palette.highlightedText : palette.text
} }
@ -511,7 +531,7 @@ Item
Label Label
{ {
text: base.currentItemName text: base.currentItemDisplayName
font: UM.Theme.getFont("large_bold") font: UM.Theme.getFont("large_bold")
} }
} }
@ -519,7 +539,7 @@ Item
Flow Flow
{ {
id: currentSettingsActions id: currentSettingsActions
visible: base.hasCurrentItem && base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName visible: base.hasCurrentItem && base.currentItem.name == Cura.MachineManager.activeQualityOrQualityChangesName && base.currentItem.intent_category == Cura.MachineManager.activeIntentCategory
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.top: profileName.bottom anchors.top: profileName.bottom
@ -567,7 +587,6 @@ Item
} }
} }
TabView TabView
{ {
anchors.left: parent.left anchors.left: parent.left

View file

@ -118,10 +118,12 @@ def test_duplicateQualityChanges(quality_mocked_application):
quality_group.getAllNodes = MagicMock(return_value = mocked_quality) quality_group.getAllNodes = MagicMock(return_value = mocked_quality)
quality_changes_group = MagicMock() quality_changes_group = MagicMock()
mocked_quality_changes = MagicMock() mocked_quality_changes = MagicMock()
quality_changes_group.getAllNodes = MagicMock(return_value=[mocked_quality_changes]) quality_changes_group.getAllNodes = MagicMock(return_value = [mocked_quality_changes])
mocked_quality_changes.duplicate = MagicMock(return_value = mocked_quality_changes) mocked_quality_changes.duplicate = MagicMock(return_value = mocked_quality_changes)
manager._container_registry.addContainer = MagicMock() # Side effect we want to check. manager._container_registry.addContainer = MagicMock() # Side effect we want to check.
manager.duplicateQualityChanges("zomg", {"quality_group": quality_group, "quality_changes_group": quality_changes_group}) manager.duplicateQualityChanges("zomg", {"intent_category": "default",
"quality_group": quality_group,
"quality_changes_group": quality_changes_group})
assert manager._container_registry.addContainer.called_once_with(mocked_quality_changes) assert manager._container_registry.addContainer.called_once_with(mocked_quality_changes)