SettingInheritanceManager.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal
  2. import UM.Settings
  3. from UM.Signal import signalemitter
  4. from UM.Application import Application
  5. import cura.Settings
  6. class SettingInheritanceManager(QObject):
  7. def __init__(self, parent = None):
  8. super().__init__(parent)
  9. Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
  10. self._global_container_stack = None
  11. self._onGlobalContainerChanged()
  12. self._settings_with_inheritance_warning = []
  13. self._active_container_stack = None
  14. cura.Settings.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
  15. self._onActiveExtruderChanged()
  16. settingsWithIntheritanceChanged = pyqtSignal()
  17. @pyqtSlot()
  18. def test(self):
  19. pass
  20. def _onActiveExtruderChanged(self):
  21. if self._active_container_stack:
  22. self._active_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
  23. new_active_stack = cura.Settings.ExtruderManager.getInstance().getActiveExtruderStack()
  24. if not new_active_stack:
  25. new_active_stack = self._global_container_stack
  26. if new_active_stack != self._active_container_stack:
  27. # Check if changed
  28. self._active_container_stack = new_active_stack
  29. self._update() # Ensure that the settings_with_inheritance_warning list is populated.
  30. self._active_container_stack.propertyChanged.connect(self._onPropertyChanged)
  31. def _onPropertyChanged(self, key, property_name):
  32. if property_name == "value" and self._global_container_stack:
  33. definitions = self._global_container_stack.getBottom().findDefinitions(key = key)
  34. if not definitions:
  35. return
  36. has_overwritten_inheritance = self._settingIsOverwritingInheritance(key)
  37. settings_with_inheritance_warning_changed = False
  38. # Check if the setting needs to be in the list.
  39. if key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
  40. self._settings_with_inheritance_warning.append(key)
  41. settings_with_inheritance_warning_changed = True
  42. elif key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
  43. self._settings_with_inheritance_warning.remove(key)
  44. settings_with_inheritance_warning_changed = True
  45. # Find the topmost parent & add that to the list as well
  46. parent = definitions[0].parent
  47. while parent.parent is not None:
  48. parent = parent.parent
  49. if parent.key not in self._settings_with_inheritance_warning and has_overwritten_inheritance:
  50. self._settings_with_inheritance_warning.append(parent.key)
  51. settings_with_inheritance_warning_changed = True
  52. elif parent.key in self._settings_with_inheritance_warning and not has_overwritten_inheritance:
  53. if not self._recursiveCheck(parent):
  54. self._settings_with_inheritance_warning.remove(parent.key)
  55. settings_with_inheritance_warning_changed = True
  56. # Emit the signal if there was any change to the list.
  57. if settings_with_inheritance_warning_changed:
  58. self.settingsWithIntheritanceChanged.emit()
  59. def _recursiveCheck(self, definition):
  60. for child in definition.children:
  61. if child.key in self._settings_with_inheritance_warning:
  62. return True
  63. if child.children:
  64. if self._recursiveCheck(child):
  65. return True
  66. return False
  67. @pyqtProperty("QVariantList", notify = settingsWithIntheritanceChanged)
  68. def settingsWithInheritanceWarning(self):
  69. return self._settings_with_inheritance_warning
  70. # Check if a setting is being overwritten.
  71. def _settingIsOverwritingInheritance(self, key):
  72. has_setting_function = False
  73. stack = self._active_container_stack
  74. containers = []
  75. has_user_state = self._active_container_stack.getProperty(key, "state") == UM.Settings.InstanceState.User
  76. if not has_user_state:
  77. return False
  78. while stack:
  79. containers.extend(stack.getContainers())
  80. stack = stack.getNextStack()
  81. for container in containers:
  82. try:
  83. has_setting_function = isinstance(container.getProperty(key, "value"), UM.Settings.SettingFunction)
  84. except AttributeError:
  85. continue
  86. if has_setting_function:
  87. break
  88. return has_setting_function and not isinstance(self._active_container_stack.getTop().getProperty(key, "value"), UM.Settings.SettingFunction)
  89. def _update(self):
  90. self._settings_with_inheritance_warning = []
  91. for setting_key in self._global_container_stack.getAllKeys():
  92. override = self._settingIsOverwritingInheritance(setting_key)
  93. if override:
  94. self._settings_with_inheritance_warning.append(setting_key)
  95. definitions = self._global_container_stack.getBottom().findDefinitions(key=setting_key)
  96. parent = definitions[0].parent
  97. if parent is not None and override:
  98. while parent.parent is not None:
  99. parent = parent.parent
  100. # Add the topmost container as well (if this wasn't already the case)
  101. if parent.key not in self._settings_with_inheritance_warning:
  102. self._settings_with_inheritance_warning.append(parent.key)
  103. self.settingsWithIntheritanceChanged.emit()
  104. def _onGlobalContainerChanged(self):
  105. self._global_container_stack = Application.getInstance().getGlobalContainerStack()
  106. @staticmethod
  107. def createSettingInheritanceManager(engine=None, script_engine=None):
  108. return SettingInheritanceManager()