MachineSettingsAction.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. # Copyright (c) 2016 Ultimaker B.V.
  2. # Cura is released under the terms of the AGPLv3 or higher.
  3. from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
  4. from cura.MachineAction import MachineAction
  5. import cura.Settings.CuraContainerRegistry
  6. import UM.Application
  7. import UM.Settings.InstanceContainer
  8. import UM.Settings.DefinitionContainer
  9. import UM.Logger
  10. import UM.i18n
  11. catalog = UM.i18n.i18nCatalog("cura")
  12. class MachineSettingsAction(MachineAction):
  13. def __init__(self, parent = None):
  14. super().__init__("MachineSettingsAction", catalog.i18nc("@action", "Machine Settings"))
  15. self._qml_url = "MachineSettingsAction.qml"
  16. self._container_index = 0
  17. self._container_registry = UM.Settings.ContainerRegistry.getInstance()
  18. self._container_registry.containerAdded.connect(self._onContainerAdded)
  19. def _reset(self):
  20. global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
  21. if not global_container_stack:
  22. return
  23. # First check if there is a variant previously generated by this machine
  24. machine_settings_variant = global_container_stack.findContainer({"type": "variant", "subtype": "machine_settings"})
  25. if not machine_settings_variant:
  26. # There may be a variant created by the UMOUpgradeSelection machine action
  27. machine_settings_variant = global_container_stack.findContainer({"type": "variant", "id": global_container_stack.getName() + "_variant"})
  28. if not machine_settings_variant:
  29. variant = global_container_stack.findContainer({"type": "variant"})
  30. if variant and variant.getId() == "empty_variant":
  31. # There is an empty variant that we can use to store the machine settings
  32. container_index = global_container_stack.getContainerIndex(variant)
  33. machine_settings_variant = self._createMachineVariant(global_container_stack, container_index)
  34. else:
  35. # Add a second variant before the current variant to store the machine settings
  36. machine_settings_variant = self._createMachineVariant(global_container_stack)
  37. # Notify the UI in which container to store the machine settings data
  38. container_index = global_container_stack.getContainerIndex(machine_settings_variant)
  39. if container_index != self._container_index:
  40. self._container_index = container_index
  41. self.containerIndexChanged.emit()
  42. def _createMachineSettingsVariant(self, global_container_stack, container_index = None):
  43. machine_settings_variant = UM.Settings.InstanceContainer(global_container_stack.getName() + "_variant")
  44. if global_container_stack.getMetaDataEntry("has_variants", False):
  45. # If the current machine uses visible variants (eg for nozzle selection), make sure
  46. # not to add this variant to the list.
  47. definition = self._container_registry.findDefinitionContainers(id="fdmprinter")[0]
  48. else:
  49. definition = global_container_stack.getBottom()
  50. machine_settings_variant.setDefinition(definition)
  51. machine_settings_variant.addMetaDataEntry("type", "variant")
  52. machine_settings_variant.addMetaDataEntry("subtype", "machine_settings")
  53. self._container_registry.addContainer(machine_settings_variant)
  54. if container_index:
  55. global_container_stack.replaceContainer(container_index, machine_settings_variant)
  56. else:
  57. index = len(global_container_stack.getContainers()) - 1
  58. global_container_stack.addContainer(machine_settings_variant, index)
  59. return machine_settings_variant
  60. containerIndexChanged = pyqtSignal()
  61. @pyqtProperty(int, notify = containerIndexChanged)
  62. def containerIndex(self):
  63. return self._container_index
  64. def _onContainerAdded(self, container):
  65. # Add this action as a supported action to all machine definitions
  66. if isinstance(container, UM.Settings.DefinitionContainer) and container.getMetaDataEntry("type") == "machine":
  67. if container.getProperty("machine_extruder_count", "value") > 1:
  68. # Multiextruder printers are not currently supported
  69. UM.Logger.log("d", "Not attaching MachineSettingsAction to %s; Multi-extrusion printers are not supported", container.getId())
  70. return
  71. UM.Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey())
  72. @pyqtSlot()
  73. def forceUpdate(self):
  74. # Force rebuilding the build volume by reloading the global container stack.
  75. # This is a bit of a hack, but it seems quick enough.
  76. UM.Application.getInstance().globalContainerStackChanged.emit()
  77. @pyqtSlot()
  78. def updateHasMaterialsMetadata(self):
  79. # Updates the has_materials metadata flag after switching gcode flavor
  80. global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
  81. if global_container_stack:
  82. definition = global_container_stack.getBottom()
  83. if definition.getProperty("machine_gcode_flavor", "value") == "UltiGCode" and not definition.getMetaDataEntry("has_materials", False):
  84. has_materials = global_container_stack.getProperty("machine_gcode_flavor", "value") != "UltiGCode"
  85. material_container = global_container_stack.findContainer({"type": "material"})
  86. material_index = global_container_stack.getContainerIndex(material_container)
  87. if has_materials:
  88. if "has_materials" in global_container_stack.getMetaData():
  89. global_container_stack.setMetaDataEntry("has_materials", True)
  90. else:
  91. global_container_stack.addMetaDataEntry("has_materials", True)
  92. # Set the material container to a sane default
  93. if material_container.getId() == "empty_material":
  94. search_criteria = { "type": "material", "definition": "fdmprinter", "id": "*pla*" }
  95. containers = self._container_registry.findInstanceContainers(**search_criteria)
  96. if containers:
  97. global_container_stack.replaceContainer(material_index, containers[0])
  98. else:
  99. # The metadata entry is stored in an ini, and ini files are parsed as strings only.
  100. # Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
  101. if "has_materials" in global_container_stack.getMetaData():
  102. global_container_stack.removeMetaDataEntry("has_materials")
  103. empty_material = self._container_registry.findInstanceContainers(id = "empty_material")[0]
  104. global_container_stack.replaceContainer(material_index, empty_material)
  105. UM.Application.getInstance().globalContainerStackChanged.emit()