MachineSettingsAction.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. # Copyright (c) 2017 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from PyQt5.QtCore import pyqtProperty, pyqtSignal
  4. import UM.i18n
  5. from UM.FlameProfiler import pyqtSlot
  6. from UM.Application import Application
  7. from UM.Settings.ContainerRegistry import ContainerRegistry
  8. from UM.Settings.DefinitionContainer import DefinitionContainer
  9. from cura.MachineAction import MachineAction
  10. from cura.Settings.CuraStackBuilder import CuraStackBuilder
  11. catalog = UM.i18n.i18nCatalog("cura")
  12. ## This action allows for certain settings that are "machine only") to be modified.
  13. # It automatically detects machine definitions that it knows how to change and attaches itself to those.
  14. class MachineSettingsAction(MachineAction):
  15. def __init__(self, parent = None):
  16. super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
  17. self._qml_url = "MachineSettingsAction.qml"
  18. self._application = Application.getInstance()
  19. self._global_container_stack = None
  20. from cura.Settings.CuraContainerStack import _ContainerIndexes
  21. self._container_index = _ContainerIndexes.DefinitionChanges
  22. self._container_registry = ContainerRegistry.getInstance()
  23. self._container_registry.containerAdded.connect(self._onContainerAdded)
  24. self._container_registry.containerRemoved.connect(self._onContainerRemoved)
  25. self._application.globalContainerStackChanged.connect(self._onGlobalContainerChanged)
  26. self._backend = self._application.getBackend()
  27. self._empty_definition_container_id_list = []
  28. def _isEmptyDefinitionChanges(self, container_id: str):
  29. if not self._empty_definition_container_id_list:
  30. self._empty_definition_container_id_list = [self._application.empty_container.getId(),
  31. self._application.empty_definition_changes_container.getId()]
  32. return container_id in self._empty_definition_container_id_list
  33. def _onContainerAdded(self, container):
  34. # Add this action as a supported action to all machine definitions
  35. if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
  36. self._application.getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
  37. def _onContainerRemoved(self, container):
  38. # Remove definition_changes containers when a stack is removed
  39. if container.getMetaDataEntry("type") in ["machine", "extruder_train"]:
  40. definition_changes_id = container.definitionChanges.getId()
  41. if self._isEmptyDefinitionChanges(definition_changes_id):
  42. return
  43. def _reset(self):
  44. if not self._global_container_stack:
  45. return
  46. # Make sure there is a definition_changes container to store the machine settings
  47. definition_changes_id = self._global_container_stack.definitionChanges.getId()
  48. if self._isEmptyDefinitionChanges(definition_changes_id):
  49. CuraStackBuilder.createDefinitionChangesContainer(self._global_container_stack,
  50. self._global_container_stack.getName() + "_settings")
  51. # Notify the UI in which container to store the machine settings data
  52. from cura.Settings.CuraContainerStack import _ContainerIndexes
  53. container_index = _ContainerIndexes.DefinitionChanges
  54. if container_index != self._container_index:
  55. self._container_index = container_index
  56. self.containerIndexChanged.emit()
  57. # Disable auto-slicing while the MachineAction is showing
  58. if self._backend: # This sometimes triggers before backend is loaded.
  59. self._backend.disableTimer()
  60. @pyqtSlot()
  61. def onFinishAction(self):
  62. # Restore autoslicing when the machineaction is dismissed
  63. if self._backend and self._backend.determineAutoSlicing():
  64. self._backend.tickle()
  65. containerIndexChanged = pyqtSignal()
  66. @pyqtProperty(int, notify = containerIndexChanged)
  67. def containerIndex(self):
  68. return self._container_index
  69. def _onGlobalContainerChanged(self):
  70. self._global_container_stack = Application.getInstance().getGlobalContainerStack()
  71. # This additional emit is needed because we cannot connect a UM.Signal directly to a pyqtSignal
  72. self.globalContainerChanged.emit()
  73. globalContainerChanged = pyqtSignal()
  74. @pyqtProperty(int, notify = globalContainerChanged)
  75. def definedExtruderCount(self):
  76. if not self._global_container_stack:
  77. return 0
  78. return len(self._global_container_stack.getMetaDataEntry("machine_extruder_trains"))
  79. @pyqtSlot(int)
  80. def setMachineExtruderCount(self, extruder_count):
  81. # Note: this method was in this class before, but since it's quite generic and other plugins also need it
  82. # it was moved to the machine manager instead. Now this method just calls the machine manager.
  83. self._application.getMachineManager().setActiveMachineExtruderCount(extruder_count)
  84. @pyqtSlot()
  85. def forceUpdate(self):
  86. # Force rebuilding the build volume by reloading the global container stack.
  87. # This is a bit of a hack, but it seems quick enough.
  88. self._application.globalContainerStackChanged.emit()
  89. @pyqtSlot()
  90. def updateHasMaterialsMetadata(self):
  91. # Updates the has_materials metadata flag after switching gcode flavor
  92. if not self._global_container_stack:
  93. return
  94. definition = self._global_container_stack.getBottom()
  95. if definition.getProperty("machine_gcode_flavor", "value") != "UltiGCode" or definition.getMetaDataEntry("has_materials", False):
  96. # In other words: only continue for the UM2 (extended), but not for the UM2+
  97. return
  98. machine_manager = self._application.getMachineManager()
  99. material_manager = self._application.getMaterialManager()
  100. extruder_positions = list(self._global_container_stack.extruders.keys())
  101. has_materials = self._global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
  102. material_node = None
  103. if has_materials:
  104. self._global_container_stack.setMetaDataEntry("has_materials", True)
  105. else:
  106. # The metadata entry is stored in an ini, and ini files are parsed as strings only.
  107. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
  108. if "has_materials" in self._global_container_stack.getMetaData():
  109. self._global_container_stack.removeMetaDataEntry("has_materials")
  110. # set materials
  111. for position in extruder_positions:
  112. if has_materials:
  113. material_node = material_manager.getDefaultMaterial(self._global_container_stack, position, None)
  114. machine_manager.setMaterial(position, material_node)
  115. self._application.globalContainerStackChanged.emit()
  116. @pyqtSlot(int)
  117. def updateMaterialForDiameter(self, extruder_position: int):
  118. # Updates the material container to a material that matches the material diameter set for the printer
  119. self._application.getMachineManager().updateMaterialWithVariant(str(extruder_position))