mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-13 09:47:50 -06:00
Split error checking into smaller sub-tasks
CURA-5059 Split stack error checking into smaller sub-tasks so running them on the Qt thread will not block GUI updates from happening for too long.
This commit is contained in:
parent
40d3e09d90
commit
934d297e6c
4 changed files with 253 additions and 60 deletions
|
@ -67,6 +67,8 @@ from cura.Machines.Models.MaterialManagementModel import MaterialManagementModel
|
||||||
from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel
|
from cura.Machines.Models.GenericMaterialsModel import GenericMaterialsModel
|
||||||
from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel
|
from cura.Machines.Models.BrandMaterialsModel import BrandMaterialsModel
|
||||||
|
|
||||||
|
from cura.Machines.MachineErrorChecker import MachineErrorChecker
|
||||||
|
|
||||||
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||||
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
|
|
||||||
|
@ -142,12 +144,6 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
Q_ENUMS(ResourceTypes)
|
Q_ENUMS(ResourceTypes)
|
||||||
|
|
||||||
# FIXME: This signal belongs to the MachineManager, but the CuraEngineBackend plugin requires on it.
|
|
||||||
# Because plugins are initialized before the ContainerRegistry, putting this signal in MachineManager
|
|
||||||
# will make it initialized before ContainerRegistry does, and it won't find the active machine, thus
|
|
||||||
# Cura will always show the Add Machine Dialog upon start.
|
|
||||||
stacksValidationFinished = pyqtSignal() # Emitted whenever a validation is finished
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
# this list of dir names will be used by UM to detect an old cura directory
|
# this list of dir names will be used by UM to detect an old cura directory
|
||||||
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
for dir_name in ["extruders", "machine_instances", "materials", "plugins", "quality", "user", "variants"]:
|
||||||
|
@ -224,12 +220,14 @@ class CuraApplication(QtApplication):
|
||||||
self._machine_manager = None # This is initialized on demand.
|
self._machine_manager = None # This is initialized on demand.
|
||||||
self._extruder_manager = None
|
self._extruder_manager = None
|
||||||
self._material_manager = None
|
self._material_manager = None
|
||||||
|
self._quality_manager = None
|
||||||
self._object_manager = None
|
self._object_manager = None
|
||||||
self._build_plate_model = None
|
self._build_plate_model = None
|
||||||
self._multi_build_plate_model = None
|
self._multi_build_plate_model = None
|
||||||
self._setting_inheritance_manager = None
|
self._setting_inheritance_manager = None
|
||||||
self._simple_mode_settings_manager = None
|
self._simple_mode_settings_manager = None
|
||||||
self._cura_scene_controller = None
|
self._cura_scene_controller = None
|
||||||
|
self._machine_error_checker = None
|
||||||
|
|
||||||
self._additional_components = {} # Components to add to certain areas in the interface
|
self._additional_components = {} # Components to add to certain areas in the interface
|
||||||
|
|
||||||
|
@ -743,19 +741,28 @@ class CuraApplication(QtApplication):
|
||||||
self.preRun()
|
self.preRun()
|
||||||
|
|
||||||
container_registry = ContainerRegistry.getInstance()
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
|
Logger.log("i", "Initializing variant manager")
|
||||||
self._variant_manager = VariantManager(container_registry)
|
self._variant_manager = VariantManager(container_registry)
|
||||||
self._variant_manager.initialize()
|
self._variant_manager.initialize()
|
||||||
|
|
||||||
|
Logger.log("i", "Initializing material manager")
|
||||||
from cura.Machines.MaterialManager import MaterialManager
|
from cura.Machines.MaterialManager import MaterialManager
|
||||||
self._material_manager = MaterialManager(container_registry, parent = self)
|
self._material_manager = MaterialManager(container_registry, parent = self)
|
||||||
self._material_manager.initialize()
|
self._material_manager.initialize()
|
||||||
|
|
||||||
|
Logger.log("i", "Initializing quality manager")
|
||||||
from cura.Machines.QualityManager import QualityManager
|
from cura.Machines.QualityManager import QualityManager
|
||||||
self._quality_manager = QualityManager(container_registry, parent = self)
|
self._quality_manager = QualityManager(container_registry, parent = self)
|
||||||
self._quality_manager.initialize()
|
self._quality_manager.initialize()
|
||||||
|
|
||||||
|
Logger.log("i", "Initializing machine manager")
|
||||||
self._machine_manager = MachineManager(self)
|
self._machine_manager = MachineManager(self)
|
||||||
|
|
||||||
|
Logger.log("i", "Initializing machine error checker")
|
||||||
|
self._machine_error_checker = MachineErrorChecker(self)
|
||||||
|
self._machine_error_checker.initialize()
|
||||||
|
|
||||||
# Check if we should run as single instance or not
|
# Check if we should run as single instance or not
|
||||||
self._setUpSingleInstanceServer()
|
self._setUpSingleInstanceServer()
|
||||||
|
|
||||||
|
@ -781,8 +788,11 @@ class CuraApplication(QtApplication):
|
||||||
self._openFile(file_name)
|
self._openFile(file_name)
|
||||||
|
|
||||||
self.started = True
|
self.started = True
|
||||||
|
self.initializationFinished.emit()
|
||||||
self.exec_()
|
self.exec_()
|
||||||
|
|
||||||
|
initializationFinished = pyqtSignal()
|
||||||
|
|
||||||
## Run Cura without GUI elements and interaction (server mode).
|
## Run Cura without GUI elements and interaction (server mode).
|
||||||
def runWithoutGUI(self):
|
def runWithoutGUI(self):
|
||||||
self._use_gui = False
|
self._use_gui = False
|
||||||
|
@ -847,6 +857,9 @@ class CuraApplication(QtApplication):
|
||||||
def hasGui(self):
|
def hasGui(self):
|
||||||
return self._use_gui
|
return self._use_gui
|
||||||
|
|
||||||
|
def getMachineErrorChecker(self, *args) -> MachineErrorChecker:
|
||||||
|
return self._machine_error_checker
|
||||||
|
|
||||||
def getMachineManager(self, *args) -> MachineManager:
|
def getMachineManager(self, *args) -> MachineManager:
|
||||||
if self._machine_manager is None:
|
if self._machine_manager is None:
|
||||||
self._machine_manager = MachineManager(self)
|
self._machine_manager = MachineManager(self)
|
||||||
|
|
184
cura/Machines/MachineErrorChecker.py
Normal file
184
cura/Machines/MachineErrorChecker.py
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty
|
||||||
|
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Logger import Logger
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# This class performs setting error checks for the currently active machine.
|
||||||
|
#
|
||||||
|
# The whole error checking process is pretty heavy which can take ~0.5 secs, so it can cause GUI to lag.
|
||||||
|
# The idea here is to split the whole error check into small tasks, each of which only checks a single setting key
|
||||||
|
# in a stack. According to my profiling results, the maximal runtime for such a sub-task is <0.03 secs, which should
|
||||||
|
# be good enough. Moreover, if any changes happened to the machine, we can cancel the check in progress without wait
|
||||||
|
# for it to finish the complete work.
|
||||||
|
#
|
||||||
|
class MachineErrorChecker(QObject):
|
||||||
|
|
||||||
|
def __init__(self, parent = None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self._global_stack = None
|
||||||
|
|
||||||
|
self._has_errors = True # Result of the error check, indicating whether there are errors in the stack
|
||||||
|
self._error_keys = set() # A set of settings keys that have errors
|
||||||
|
self._error_keys_in_progress = set() # The variable that stores the results of the currently in progress check
|
||||||
|
|
||||||
|
self._stacks_to_check = None # a FIFO queue of stacks to check for errors
|
||||||
|
self._keys_to_check = None # a FIFO queue of setting keys to check for errors
|
||||||
|
|
||||||
|
self._need_to_check = False # Whether we need to schedule a new check or not. This flag is set when a new
|
||||||
|
# error check needs to take place while there is already one running at the moment.
|
||||||
|
self._check_in_progress = False # Whether there is an error check running in progress at the moment.
|
||||||
|
|
||||||
|
self._application = Application.getInstance()
|
||||||
|
self._machine_manager = self._application.getMachineManager()
|
||||||
|
|
||||||
|
# This timer delays the starting of error check so we can react less frequently if the user is frequently
|
||||||
|
# changing settings.
|
||||||
|
self._error_check_timer = QTimer(self)
|
||||||
|
self._error_check_timer.setInterval(300)
|
||||||
|
self._error_check_timer.setSingleShot(True)
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self._error_check_timer.timeout.connect(self._rescheduleCheck)
|
||||||
|
|
||||||
|
# Reconnect all signals when the active machine gets changed.
|
||||||
|
self._machine_manager.globalContainerChanged.connect(self._onMachineChanged)
|
||||||
|
|
||||||
|
# Whenever the machine settings get changed, we schedule an error check.
|
||||||
|
self._machine_manager.globalContainerChanged.connect(self.startErrorCheck)
|
||||||
|
self._machine_manager.globalValueChanged.connect(self.startErrorCheck)
|
||||||
|
|
||||||
|
self._onMachineChanged()
|
||||||
|
|
||||||
|
def _onMachineChanged(self):
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.disconnect(self.startErrorCheck)
|
||||||
|
self._global_stack.containersChanged.disconnect(self.startErrorCheck)
|
||||||
|
|
||||||
|
for extruder in self._global_stack.extruders.values():
|
||||||
|
extruder.propertyChanged.disconnect(self.startErrorCheck)
|
||||||
|
extruder.containersChanged.disconnect(self.startErrorCheck)
|
||||||
|
|
||||||
|
self._global_stack = self._machine_manager.activeMachine
|
||||||
|
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.connect(self.startErrorCheck)
|
||||||
|
self._global_stack.containersChanged.connect(self.startErrorCheck)
|
||||||
|
|
||||||
|
for extruder in self._global_stack.extruders.values():
|
||||||
|
extruder.propertyChanged.connect(self.startErrorCheck)
|
||||||
|
extruder.containersChanged.connect(self.startErrorCheck)
|
||||||
|
|
||||||
|
hasErrorUpdated = pyqtSignal()
|
||||||
|
needToWaitForResultChanged = pyqtSignal()
|
||||||
|
errorCheckFinished = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify = hasErrorUpdated)
|
||||||
|
def hasError(self) -> bool:
|
||||||
|
return self._has_errors
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify = needToWaitForResultChanged)
|
||||||
|
def needToWaitForResult(self) -> bool:
|
||||||
|
return self._need_to_check or self._check_in_progress
|
||||||
|
|
||||||
|
# Starts the error check timer to schedule a new error check.
|
||||||
|
def startErrorCheck(self, *args):
|
||||||
|
if not self._check_in_progress:
|
||||||
|
self._need_to_check = True
|
||||||
|
self.needToWaitForResultChanged.emit()
|
||||||
|
self._error_check_timer.start()
|
||||||
|
|
||||||
|
# This function is called by the timer to reschedule a new error check.
|
||||||
|
# If there is no check in progress, it will start a new one. If there is any, it sets the "_need_to_check" flag
|
||||||
|
# to notify the current check to stop and start a new one.
|
||||||
|
def _rescheduleCheck(self):
|
||||||
|
if self._check_in_progress and not self._need_to_check:
|
||||||
|
self._need_to_check = True
|
||||||
|
self.needToWaitForResultChanged.emit()
|
||||||
|
return
|
||||||
|
|
||||||
|
self._error_keys_in_progress = set()
|
||||||
|
self._need_to_check = False
|
||||||
|
self.needToWaitForResultChanged.emit()
|
||||||
|
|
||||||
|
global_stack = self._machine_manager.activeMachine
|
||||||
|
if global_stack is None:
|
||||||
|
Logger.log("i", "No active machine, nothing to check.")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._stacks_to_check = deque([global_stack] + list(global_stack.extruders.values()))
|
||||||
|
self._keys_to_check = deque(global_stack.getAllKeys())
|
||||||
|
|
||||||
|
self._application.callLater(self._checkStack)
|
||||||
|
Logger.log("d", "New error check scheduled.")
|
||||||
|
|
||||||
|
def _checkStack(self):
|
||||||
|
from UM.Settings.SettingDefinition import SettingDefinition
|
||||||
|
from UM.Settings.Validator import ValidatorState
|
||||||
|
|
||||||
|
if self._need_to_check:
|
||||||
|
Logger.log("d", "Need to check for errors again. Discard the current progress and reschedule a check.")
|
||||||
|
self._check_in_progress = False
|
||||||
|
self._application.callLater(self.startErrorCheck)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._check_in_progress = True
|
||||||
|
|
||||||
|
# If there is nothing to check any more, it means there is no error.
|
||||||
|
if not self._stacks_to_check or not self._keys_to_check:
|
||||||
|
# Finish
|
||||||
|
self._setResult(False)
|
||||||
|
return
|
||||||
|
|
||||||
|
stack = self._stacks_to_check[0]
|
||||||
|
key = self._keys_to_check.popleft()
|
||||||
|
|
||||||
|
# If there is no key left in this stack, check the next stack later.
|
||||||
|
if not self._keys_to_check:
|
||||||
|
if len(self._stacks_to_check) == 1:
|
||||||
|
stacks = None
|
||||||
|
keys = None
|
||||||
|
else:
|
||||||
|
stack = self._stacks_to_check.popleft()
|
||||||
|
self._keys_to_check = deque(stack.getAllKeys())
|
||||||
|
|
||||||
|
enabled = stack.getProperty(key, "enabled")
|
||||||
|
if not enabled:
|
||||||
|
self._application.callLater(self._checkStack)
|
||||||
|
return
|
||||||
|
|
||||||
|
validation_state = stack.getProperty(key, "validationState")
|
||||||
|
if validation_state is None:
|
||||||
|
# Setting is not validated. This can happen if there is only a setting definition.
|
||||||
|
# We do need to validate it, because a setting definitions value can be set by a function, which could
|
||||||
|
# be an invalid setting.
|
||||||
|
definition = stack.getSettingDefinition(key)
|
||||||
|
validator_type = SettingDefinition.getValidatorForType(definition.type)
|
||||||
|
if validator_type:
|
||||||
|
validator = validator_type(key)
|
||||||
|
validation_state = validator(stack)
|
||||||
|
if validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
|
||||||
|
# Finish
|
||||||
|
self._setResult(True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Schedule the check for the next key
|
||||||
|
self._application.callLater(self._checkStack)
|
||||||
|
|
||||||
|
def _setResult(self, result: bool):
|
||||||
|
if result != self._has_errors:
|
||||||
|
self._has_errors = result
|
||||||
|
self.hasErrorUpdated.emit()
|
||||||
|
self._machine_manager.stacksValidationChanged.emit()
|
||||||
|
self._need_to_check = False
|
||||||
|
self._check_in_progress = False
|
||||||
|
self.needToWaitForResultChanged.emit()
|
||||||
|
self.errorCheckFinished.emit()
|
||||||
|
Logger.log("i", "Error check finished, result = %s", result)
|
|
@ -4,7 +4,7 @@
|
||||||
import collections
|
import collections
|
||||||
import time
|
import time
|
||||||
#Type hinting.
|
#Type hinting.
|
||||||
from typing import Union, List, Dict, TYPE_CHECKING, Optional
|
from typing import List, Dict, TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
|
@ -20,7 +20,6 @@ from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
|
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
|
||||||
from UM.Settings.SettingFunction import SettingFunction
|
from UM.Settings.SettingFunction import SettingFunction
|
||||||
from UM.Signal import postponeSignals, CompressTechnique
|
from UM.Signal import postponeSignals, CompressTechnique
|
||||||
|
|
||||||
|
@ -56,11 +55,6 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
self.machine_extruder_material_update_dict = collections.defaultdict(list)
|
self.machine_extruder_material_update_dict = collections.defaultdict(list)
|
||||||
|
|
||||||
self._error_check_timer = QTimer()
|
|
||||||
self._error_check_timer.setInterval(250)
|
|
||||||
self._error_check_timer.setSingleShot(True)
|
|
||||||
self._error_check_timer.timeout.connect(self._updateStacksHaveErrors)
|
|
||||||
|
|
||||||
self._instance_container_timer = QTimer()
|
self._instance_container_timer = QTimer()
|
||||||
self._instance_container_timer.setInterval(250)
|
self._instance_container_timer.setInterval(250)
|
||||||
self._instance_container_timer.setSingleShot(True)
|
self._instance_container_timer.setSingleShot(True)
|
||||||
|
@ -228,15 +222,6 @@ class MachineManager(QObject):
|
||||||
del self.machine_extruder_material_update_dict[self._global_container_stack.getId()]
|
del self.machine_extruder_material_update_dict[self._global_container_stack.getId()]
|
||||||
|
|
||||||
self.activeQualityGroupChanged.emit()
|
self.activeQualityGroupChanged.emit()
|
||||||
self._error_check_timer.start()
|
|
||||||
|
|
||||||
## Update self._stacks_valid according to _checkStacksForErrors and emit if change.
|
|
||||||
def _updateStacksHaveErrors(self) -> None:
|
|
||||||
old_stacks_have_errors = self._stacks_have_errors
|
|
||||||
self._stacks_have_errors = self._checkStacksHaveErrors()
|
|
||||||
if old_stacks_have_errors != self._stacks_have_errors:
|
|
||||||
self.stacksValidationChanged.emit()
|
|
||||||
Application.getInstance().stacksValidationFinished.emit()
|
|
||||||
|
|
||||||
def _onActiveExtruderStackChanged(self) -> None:
|
def _onActiveExtruderStackChanged(self) -> None:
|
||||||
self.blurSettings.emit() # Ensure no-one has focus.
|
self.blurSettings.emit() # Ensure no-one has focus.
|
||||||
|
@ -256,8 +241,6 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
self.rootMaterialChanged.emit()
|
self.rootMaterialChanged.emit()
|
||||||
|
|
||||||
self._error_check_timer.start()
|
|
||||||
|
|
||||||
def _onInstanceContainersChanged(self, container) -> None:
|
def _onInstanceContainersChanged(self, container) -> None:
|
||||||
self._instance_container_timer.start()
|
self._instance_container_timer.start()
|
||||||
|
|
||||||
|
@ -266,9 +249,6 @@ class MachineManager(QObject):
|
||||||
# Notify UI items, such as the "changed" star in profile pull down menu.
|
# Notify UI items, such as the "changed" star in profile pull down menu.
|
||||||
self.activeStackValueChanged.emit()
|
self.activeStackValueChanged.emit()
|
||||||
|
|
||||||
elif property_name == "validationState":
|
|
||||||
self._error_check_timer.start()
|
|
||||||
|
|
||||||
## Given a global_stack, make sure that it's all valid by searching for this quality group and applying it again
|
## Given a global_stack, make sure that it's all valid by searching for this quality group and applying it again
|
||||||
def _initMachineState(self, global_stack):
|
def _initMachineState(self, global_stack):
|
||||||
material_dict = {}
|
material_dict = {}
|
||||||
|
@ -832,9 +812,10 @@ class MachineManager(QObject):
|
||||||
|
|
||||||
## This will fire the propertiesChanged for all settings so they will be updated in the front-end
|
## This will fire the propertiesChanged for all settings so they will be updated in the front-end
|
||||||
def forceUpdateAllSettings(self):
|
def forceUpdateAllSettings(self):
|
||||||
property_names = ["value", "resolve"]
|
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||||
for setting_key in self._global_container_stack.getAllKeys():
|
property_names = ["value", "resolve"]
|
||||||
self._global_container_stack.propertiesChanged.emit(setting_key, property_names)
|
for setting_key in self._global_container_stack.getAllKeys():
|
||||||
|
self._global_container_stack.propertiesChanged.emit(setting_key, property_names)
|
||||||
|
|
||||||
@pyqtSlot(int, bool)
|
@pyqtSlot(int, bool)
|
||||||
def setExtruderEnabled(self, position: int, enabled) -> None:
|
def setExtruderEnabled(self, position: int, enabled) -> None:
|
||||||
|
|
|
@ -10,7 +10,6 @@ from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
|
|
||||||
from UM.Platform import Platform
|
from UM.Platform import Platform
|
||||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Qt.Duration import DurationFormat
|
from UM.Qt.Duration import DurationFormat
|
||||||
|
@ -32,6 +31,7 @@ import Arcus
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
class CuraEngineBackend(QObject, Backend):
|
class CuraEngineBackend(QObject, Backend):
|
||||||
|
|
||||||
backendError = Signal()
|
backendError = Signal()
|
||||||
|
@ -62,23 +62,26 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
default_engine_location = execpath
|
default_engine_location = execpath
|
||||||
break
|
break
|
||||||
|
|
||||||
|
self._application = Application.getInstance()
|
||||||
|
self._multi_build_plate_model = None
|
||||||
|
self._machine_error_checker = None
|
||||||
|
|
||||||
if not default_engine_location:
|
if not default_engine_location:
|
||||||
raise EnvironmentError("Could not find CuraEngine")
|
raise EnvironmentError("Could not find CuraEngine")
|
||||||
|
|
||||||
Logger.log("i", "Found CuraEngine at: %s" %(default_engine_location))
|
Logger.log("i", "Found CuraEngine at: %s", default_engine_location)
|
||||||
|
|
||||||
default_engine_location = os.path.abspath(default_engine_location)
|
default_engine_location = os.path.abspath(default_engine_location)
|
||||||
Preferences.getInstance().addPreference("backend/location", default_engine_location)
|
Preferences.getInstance().addPreference("backend/location", default_engine_location)
|
||||||
|
|
||||||
# Workaround to disable layer view processing if layer view is not active.
|
# Workaround to disable layer view processing if layer view is not active.
|
||||||
self._layer_view_active = False
|
self._layer_view_active = False
|
||||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
|
||||||
Application.getInstance().getMultiBuildPlateModel().activeBuildPlateChanged.connect(self._onActiveViewChanged)
|
|
||||||
self._onActiveViewChanged()
|
self._onActiveViewChanged()
|
||||||
|
|
||||||
self._stored_layer_data = []
|
self._stored_layer_data = []
|
||||||
self._stored_optimized_layer_data = {} # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob
|
self._stored_optimized_layer_data = {} # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob
|
||||||
|
|
||||||
self._scene = Application.getInstance().getController().getScene()
|
self._scene = self._application.getController().getScene()
|
||||||
self._scene.sceneChanged.connect(self._onSceneChanged)
|
self._scene.sceneChanged.connect(self._onSceneChanged)
|
||||||
|
|
||||||
# Triggers for auto-slicing. Auto-slicing is triggered as follows:
|
# Triggers for auto-slicing. Auto-slicing is triggered as follows:
|
||||||
|
@ -86,20 +89,10 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
# - whenever there is a value change, we start the timer
|
# - whenever there is a value change, we start the timer
|
||||||
# - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the
|
# - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the
|
||||||
# auto-slicing timer when that error check is finished
|
# auto-slicing timer when that error check is finished
|
||||||
# If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer,
|
# If there is an error check, stop the auto-slicing timer, and only wait for the error check to be finished
|
||||||
# and only wait for the error check to be finished to start the auto-slicing timer again.
|
# to start the auto-slicing timer again.
|
||||||
#
|
#
|
||||||
self._global_container_stack = None
|
self._global_container_stack = None
|
||||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
|
||||||
self._onGlobalStackChanged()
|
|
||||||
|
|
||||||
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
|
||||||
# extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash
|
|
||||||
ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged)
|
|
||||||
|
|
||||||
# A flag indicating if an error check was scheduled
|
|
||||||
# If so, we will stop the auto-slice timer and start upon the error check
|
|
||||||
self._is_error_check_scheduled = False
|
|
||||||
|
|
||||||
# Listeners for receiving messages from the back-end.
|
# Listeners for receiving messages from the back-end.
|
||||||
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
|
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
|
||||||
|
@ -125,13 +118,6 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self._last_num_objects = defaultdict(int) # Count number of objects to see if there is something changed
|
self._last_num_objects = defaultdict(int) # Count number of objects to see if there is something changed
|
||||||
self._postponed_scene_change_sources = [] # scene change is postponed (by a tool)
|
self._postponed_scene_change_sources = [] # scene change is postponed (by a tool)
|
||||||
|
|
||||||
self.backendQuit.connect(self._onBackendQuit)
|
|
||||||
self.backendConnected.connect(self._onBackendConnected)
|
|
||||||
|
|
||||||
# When a tool operation is in progress, don't slice. So we need to listen for tool operations.
|
|
||||||
Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
|
||||||
Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
|
||||||
|
|
||||||
self._slice_start_time = None
|
self._slice_start_time = None
|
||||||
|
|
||||||
Preferences.getInstance().addPreference("general/auto_slice", True)
|
Preferences.getInstance().addPreference("general/auto_slice", True)
|
||||||
|
@ -146,6 +132,30 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self.determineAutoSlicing()
|
self.determineAutoSlicing()
|
||||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
||||||
|
|
||||||
|
self._application.initializationFinished.connect(self.initialize)
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self._multi_build_plate_model = self._application.getMultiBuildPlateModel()
|
||||||
|
|
||||||
|
self._application.getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||||
|
self._multi_build_plate_model.activeBuildPlateChanged.connect(self._onActiveViewChanged)
|
||||||
|
|
||||||
|
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
|
# extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash
|
||||||
|
ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged)
|
||||||
|
|
||||||
|
self.backendQuit.connect(self._onBackendQuit)
|
||||||
|
self.backendConnected.connect(self._onBackendConnected)
|
||||||
|
|
||||||
|
# When a tool operation is in progress, don't slice. So we need to listen for tool operations.
|
||||||
|
self._application.getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
||||||
|
self._application.getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||||
|
|
||||||
|
self._machine_error_checker = self._application.getMachineErrorChecker()
|
||||||
|
self._machine_error_checker.errorCheckFinished.connect(self._onStackErrorCheckFinished)
|
||||||
|
|
||||||
## Terminate the engine process.
|
## Terminate the engine process.
|
||||||
#
|
#
|
||||||
# This function should terminate the engine process.
|
# This function should terminate the engine process.
|
||||||
|
@ -531,11 +541,9 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
|
|
||||||
elif property == "validationState":
|
elif property == "validationState":
|
||||||
if self._use_timer:
|
if self._use_timer:
|
||||||
self._is_error_check_scheduled = True
|
|
||||||
self._change_timer.stop()
|
self._change_timer.stop()
|
||||||
|
|
||||||
def _onStackErrorCheckFinished(self):
|
def _onStackErrorCheckFinished(self):
|
||||||
self._is_error_check_scheduled = False
|
|
||||||
if not self._slicing and self._build_plates_to_be_sliced:
|
if not self._slicing and self._build_plates_to_be_sliced:
|
||||||
self.needsSlicing()
|
self.needsSlicing()
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
|
@ -561,12 +569,15 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self.processingProgress.emit(message.amount)
|
self.processingProgress.emit(message.amount)
|
||||||
self.backendStateChange.emit(BackendState.Processing)
|
self.backendStateChange.emit(BackendState.Processing)
|
||||||
|
|
||||||
# testing
|
|
||||||
def _invokeSlice(self):
|
def _invokeSlice(self):
|
||||||
if self._use_timer:
|
if self._use_timer:
|
||||||
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
||||||
# otherwise business as usual
|
# otherwise business as usual
|
||||||
if self._is_error_check_scheduled:
|
if self._machine_error_checker is None:
|
||||||
|
self._change_timer.stop()
|
||||||
|
return
|
||||||
|
|
||||||
|
if self._machine_error_checker.needToWaitForResult:
|
||||||
self._change_timer.stop()
|
self._change_timer.stop()
|
||||||
else:
|
else:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
@ -632,7 +643,11 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
if self._use_timer:
|
if self._use_timer:
|
||||||
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
||||||
# otherwise business as usual
|
# otherwise business as usual
|
||||||
if self._is_error_check_scheduled:
|
if self._machine_error_checker is None:
|
||||||
|
self._change_timer.stop()
|
||||||
|
return
|
||||||
|
|
||||||
|
if self._machine_error_checker.needToWaitForResult:
|
||||||
self._change_timer.stop()
|
self._change_timer.stop()
|
||||||
else:
|
else:
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
@ -786,7 +801,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
def _extruderChanged(self):
|
def _extruderChanged(self):
|
||||||
for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1):
|
for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1):
|
||||||
if build_plate_number not in self._build_plates_to_be_sliced:
|
if build_plate_number not in self._build_plates_to_be_sliced:
|
||||||
self._build_plates_to_be_sliced.append(build_plate_number)
|
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||||
self._invokeSlice()
|
self._invokeSlice()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue