WIP: Cleanup MachineSettingsAction

This commit is contained in:
Lipu Fei 2019-03-20 08:41:01 +01:00
parent a92971d80e
commit a106a9ddb9
6 changed files with 76 additions and 83 deletions

View file

@ -12,17 +12,20 @@ from UM.Qt.ListModel import ListModel
# This model holds all first-start machine actions for the currently active machine. It has 2 roles: # This model holds all first-start machine actions for the currently active machine. It has 2 roles:
# - title : the title/name of the action # - title : the title/name of the action
# - content : the QObject of the QML content of the action # - content : the QObject of the QML content of the action
# - action : the MachineAction object itself
# #
class FirstStartMachineActionsModel(ListModel): class FirstStartMachineActionsModel(ListModel):
TitleRole = Qt.UserRole + 1 TitleRole = Qt.UserRole + 1
ContentRole = Qt.UserRole + 2 ContentRole = Qt.UserRole + 2
ActionRole = Qt.UserRole + 3
def __init__(self, parent: Optional[QObject] = None) -> None: def __init__(self, parent: Optional[QObject] = None) -> None:
super().__init__(parent) super().__init__(parent)
self.addRoleName(self.TitleRole, "title") self.addRoleName(self.TitleRole, "title")
self.addRoleName(self.ContentRole, "content") self.addRoleName(self.ContentRole, "content")
self.addRoleName(self.ActionRole, "action")
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
self._application = CuraApplication.getInstance() self._application = CuraApplication.getInstance()
@ -46,6 +49,7 @@ class FirstStartMachineActionsModel(ListModel):
for item in first_start_actions: for item in first_start_actions:
item_list.append({"title": item.label, item_list.append({"title": item.label,
"content": item.displayItem, "content": item.displayItem,
"action": item,
}) })
self.setItems(item_list) self.setItems(item_list)

View file

@ -41,6 +41,22 @@ empty_quality_changes_container.setMetaDataEntry("type", "quality_changes")
empty_quality_changes_container.setMetaDataEntry("quality_type", "not_supported") empty_quality_changes_container.setMetaDataEntry("quality_type", "not_supported")
# All empty container IDs set
ALL_EMPTY_CONTAINER_ID_SET = {
EMPTY_CONTAINER_ID,
EMPTY_DEFINITION_CHANGES_CONTAINER_ID,
EMPTY_VARIANT_CONTAINER_ID,
EMPTY_MATERIAL_CONTAINER_ID,
EMPTY_QUALITY_CONTAINER_ID,
EMPTY_QUALITY_CHANGES_CONTAINER_ID,
}
# Convenience function to check if a container ID represents an empty container.
def isEmptyContainer(container_id: str) -> bool:
return container_id in ALL_EMPTY_CONTAINER_ID_SET
__all__ = ["EMPTY_CONTAINER_ID", __all__ = ["EMPTY_CONTAINER_ID",
"empty_container", # For convenience "empty_container", # For convenience
"EMPTY_DEFINITION_CHANGES_CONTAINER_ID", "EMPTY_DEFINITION_CHANGES_CONTAINER_ID",
@ -52,5 +68,7 @@ __all__ = ["EMPTY_CONTAINER_ID",
"EMPTY_QUALITY_CHANGES_CONTAINER_ID", "EMPTY_QUALITY_CHANGES_CONTAINER_ID",
"empty_quality_changes_container", "empty_quality_changes_container",
"EMPTY_QUALITY_CONTAINER_ID", "EMPTY_QUALITY_CONTAINER_ID",
"empty_quality_container" "empty_quality_container",
"ALL_EMPTY_CONTAINER_ID_SET",
"isEmptyContainer",
] ]

View file

@ -1,16 +1,21 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from PyQt5.QtCore import pyqtProperty, pyqtSignal from typing import Optional, TYPE_CHECKING
from PyQt5.QtCore import pyqtProperty
import UM.i18n import UM.i18n
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
from UM.Application import Application
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.DefinitionContainer import DefinitionContainer from UM.Settings.DefinitionContainer import DefinitionContainer
from cura.MachineAction import MachineAction from cura.MachineAction import MachineAction
from cura.Settings.CuraStackBuilder import CuraStackBuilder from cura.Settings.CuraStackBuilder import CuraStackBuilder
from cura.Settings.cura_empty_instance_containers import isEmptyContainer
if TYPE_CHECKING:
from PyQt5.QtCore import QObject
catalog = UM.i18n.i18nCatalog("cura") catalog = UM.i18n.i18nCatalog("cura")
@ -18,139 +23,102 @@ catalog = UM.i18n.i18nCatalog("cura")
## This action allows for certain settings that are "machine only") to be modified. ## This action allows for certain settings that are "machine only") to be modified.
# It automatically detects machine definitions that it knows how to change and attaches itself to those. # It automatically detects machine definitions that it knows how to change and attaches itself to those.
class MachineSettingsAction(MachineAction): class MachineSettingsAction(MachineAction):
def __init__(self, parent = None): def __init__(self, parent: Optional["QObject"] = None) -> None:
super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings")) super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
self._qml_url = "MachineSettingsAction.qml" self._qml_url = "MachineSettingsAction.qml"
self._application = Application.getInstance() from cura.CuraApplication import CuraApplication
self._application = CuraApplication.getInstance()
self._global_container_stack = None
from cura.Settings.CuraContainerStack import _ContainerIndexes from cura.Settings.CuraContainerStack import _ContainerIndexes
self._container_index = _ContainerIndexes.DefinitionChanges self._store_container_index = _ContainerIndexes.DefinitionChanges
self._container_registry = ContainerRegistry.getInstance() self._container_registry = ContainerRegistry.getInstance()
self._container_registry.containerAdded.connect(self._onContainerAdded) self._container_registry.containerAdded.connect(self._onContainerAdded)
self._container_registry.containerRemoved.connect(self._onContainerRemoved)
self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged)
# The machine settings dialog blocks auto-slicing when it's shown, and re-enables it when it's finished.
self._backend = self._application.getBackend() self._backend = self._application.getBackend()
self.onFinished.connect(self._onFinished)
self._empty_definition_container_id_list = [] # Which container index in a stack to store machine setting changes.
@pyqtProperty(int, constant = True)
def _isEmptyDefinitionChanges(self, container_id: str): def storeContainerIndex(self) -> int:
if not self._empty_definition_container_id_list: return self._store_container_index
self._empty_definition_container_id_list = [self._application.empty_container.getId(),
self._application.empty_definition_changes_container.getId()]
return container_id in self._empty_definition_container_id_list
def _onContainerAdded(self, container): def _onContainerAdded(self, container):
# Add this action as a supported action to all machine definitions # Add this action as a supported action to all machine definitions
if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine": if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
def _onContainerRemoved(self, container):
# Remove definition_changes containers when a stack is removed
if container.getMetaDataEntry("type") in ["machine", "extruder_train"]:
definition_changes_id = container.definitionChanges.getId()
if self._isEmptyDefinitionChanges(definition_changes_id):
return
def _reset(self): def _reset(self):
if not self._global_container_stack: global_stack = self._application.getMachineManager().activeMachine
if not global_stack:
return return
# Make sure there is a definition_changes container to store the machine settings # Make sure there is a definition_changes container to store the machine settings
definition_changes_id = self._global_container_stack.definitionChanges.getId() definition_changes_id = global_stack.definitionChanges.getId()
if self._isEmptyDefinitionChanges(definition_changes_id): if isEmptyContainer(definition_changes_id):
CuraStackBuilder.createDefinitionChangesContainer(self._global_container_stack, CuraStackBuilder.createDefinitionChangesContainer(global_stack,
self._global_container_stack.getName() + "_settings") global_stack.getName() + "_settings")
# Notify the UI in which container to store the machine settings data
from cura.Settings.CuraContainerStack import _ContainerIndexes
container_index = _ContainerIndexes.DefinitionChanges
if container_index != self._container_index:
self._container_index = container_index
self.containerIndexChanged.emit()
# Disable auto-slicing while the MachineAction is showing # Disable auto-slicing while the MachineAction is showing
if self._backend: # This sometimes triggers before backend is loaded. if self._backend: # This sometimes triggers before backend is loaded.
self._backend.disableTimer() self._backend.disableTimer()
@pyqtSlot() def _onFinished(self):
def onFinishAction(self): # Restore auto-slicing when the machine action is dismissed
# Restore autoslicing when the machineaction is dismissed
if self._backend and self._backend.determineAutoSlicing(): if self._backend and self._backend.determineAutoSlicing():
self._backend.enableTimer()
self._backend.tickle() self._backend.tickle()
containerIndexChanged = pyqtSignal()
@pyqtProperty(int, notify = containerIndexChanged)
def containerIndex(self):
return self._container_index
def _onGlobalContainerChanged(self):
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
# This additional emit is needed because we cannot connect a UM.Signal directly to a pyqtSignal
self.globalContainerChanged.emit()
globalContainerChanged = pyqtSignal()
@pyqtProperty(int, notify = globalContainerChanged)
def definedExtruderCount(self):
if not self._global_container_stack:
return 0
return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
@pyqtSlot(int) @pyqtSlot(int)
def setMachineExtruderCount(self, extruder_count): def setMachineExtruderCount(self, extruder_count: int) -> None:
# Note: this method was in this class before, but since it's quite generic and other plugins also need it # Note: this method was in this class before, but since it's quite generic and other plugins also need it
# it was moved to the machine manager instead. Now this method just calls the machine manager. # it was moved to the machine manager instead. Now this method just calls the machine manager.
self._application.getMachineManager().setActiveMachineExtruderCount(extruder_count) self._application.getMachineManager().setActiveMachineExtruderCount(extruder_count)
@pyqtSlot() @pyqtSlot()
def forceUpdate(self): def forceUpdate(self) -> None:
# Force rebuilding the build volume by reloading the global container stack. # Force rebuilding the build volume by reloading the global container stack.
# This is a bit of a hack, but it seems quick enough. # This is a bit of a hack, but it seems quick enough.
self._application.globalContainerStackChanged.emit() self._application.getMachineManager().globalContainerChanged.emit()
@pyqtSlot() @pyqtSlot()
def updateHasMaterialsMetadata(self): def updateHasMaterialsMetadata(self) -> None:
global_stack = self._application.getMachineManager().activeMachine
# Updates the has_materials metadata flag after switching gcode flavor # Updates the has_materials metadata flag after switching gcode flavor
if not self._global_container_stack: if not global_stack:
return return
definition = self._global_container_stack.getBottom() definition = global_stack.getDefinition()
if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry("has_materials", False): if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry("has_materials", False):
# In other words: only continue for the UM2 (extended), but not for the UM2+ # In other words: only continue for the UM2 (extended), but not for the UM2+
return return
machine_manager = self._application.getMachineManager() machine_manager = self._application.getMachineManager()
material_manager = self._application.getMaterialManager() material_manager = self._application.getMaterialManager()
extruder_positions = list(self._global_container_stack.extruders.keys()) extruder_positions = list(global_stack.extruders.keys())
has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode" has_materials = global_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
material_node = None material_node = None
if has_materials: if has_materials:
self._global_container_stack.setMetaDataEntry("has_materials", True) global_stack.setMetaDataEntry("has_materials", True)
else: else:
# The metadata entry is stored in an ini, and ini files are parsed as strings only. # The metadata entry is stored in an ini, and ini files are parsed as strings only.
# Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
if "has_materials" in self._global_container_stack.getMetaData(): if "has_materials" in global_stack.getMetaData():
self._global_container_stack.removeMetaDataEntry("has_materials") global_stack.removeMetaDataEntry("has_materials")
# set materials # set materials
for position in extruder_positions: for position in extruder_positions:
if has_materials: if has_materials:
material_node = material_manager.getDefaultMaterial(self._global_container_stack, position, None) material_node = material_manager.getDefaultMaterial(global_stack, position, None)
machine_manager.setMaterial(position, material_node) machine_manager.setMaterial(position, material_node)
self._application.globalContainerStackChanged.emit() self._application.globalContainerStackChanged.emit()
@pyqtSlot(int) @pyqtSlot(int)
def updateMaterialForDiameter(self, extruder_position: int): def updateMaterialForDiameter(self, extruder_position: int) -> None:
# Updates the material container to a material that matches the material diameter set for the printer # Updates the material container to a material that matches the material diameter set for the printer
self._application.getMachineManager().updateMaterialWithVariant(str(extruder_position)) self._application.getMachineManager().updateMaterialWithVariant(str(extruder_position))

View file

@ -26,15 +26,15 @@ Item
property int columnWidth: (parent.width - 2 * UM.Theme.getSize("default_margin").width) / 2 property int columnWidth: (parent.width - 2 * UM.Theme.getSize("default_margin").width) / 2
property int columnSpacing: 3 property int columnSpacing: 3
property int propertyStoreIndex: 5 // definition_changes property int propertyStoreIndex: manager.storeContainerIndex // definition_changes
property string extruderStackId: "" property string extruderStackId: ""
property int extruderPosition: 0 property int extruderPosition: 0
property var forceUpdateFunction: CuraApplication.getMachineSettingsManager().forceUpdate property var forceUpdateFunction: manager.forceUpdate
function updateMaterialDiameter() function updateMaterialDiameter()
{ {
CuraApplication.getMachineSettingsManager().updateMaterialForDiameter(extruderPosition) manager.updateMaterialForDiameter(extruderPosition)
} }
Item Item

View file

@ -26,11 +26,11 @@ Item
property int columnWidth: (parent.width - 2 * UM.Theme.getSize("default_margin").width) / 2 property int columnWidth: (parent.width - 2 * UM.Theme.getSize("default_margin").width) / 2
property int columnSpacing: 3 property int columnSpacing: 3
property int propertyStoreIndex: 5 // definition_changes property int propertyStoreIndex: manager.storeContainerIndex // definition_changes
property string machineStackId: Cura.MachineManager.activeMachineId property string machineStackId: Cura.MachineManager.activeMachineId
property var forceUpdateFunction: CuraApplication.getMachineSettingsManager().forceUpdate property var forceUpdateFunction: manager.forceUpdate
Item Item
{ {
@ -153,7 +153,7 @@ Item
// FIXME(Lipu): better document this. // FIXME(Lipu): better document this.
// This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings. // This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings.
// I don't remember exactly what. // I don't remember exactly what.
afterOnEditingFinishedFunction: CuraApplication.getMachineSettingsManager().updateHasMaterialsMetadata afterOnEditingFinishedFunction: manager.updateHasMaterialsMetadata
} }
} }
@ -277,8 +277,8 @@ Item
// FIXME(Lipu): better document this. // FIXME(Lipu): better document this.
// This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings. // This has something to do with UM2 and UM2+ regarding "has_material" and the gcode flavor settings.
// I don't remember exactly what. // I don't remember exactly what.
afterOnEditingFinishedFunction: CuraApplication.getMachineSettingsManager().updateHasMaterialsMetadata afterOnEditingFinishedFunction: manager.updateHasMaterialsMetadata
setValueFunction: CuraApplication.getMachineSettingsManager().setMachineExtruderCount setValueFunction: manager.setMachineExtruderCount
optionModel: ListModel optionModel: ListModel
{ {

View file

@ -84,6 +84,9 @@ Item
return return
} }
// notify the current MachineAction that it has finished
currentActionItem.action.setFinished()
// move on to the next MachineAction
currentActionIndex++ currentActionIndex++
} }
} }