Now loading user settings

CURA-11561
This commit is contained in:
Erwan MATHIEU 2024-02-02 16:05:36 +01:00
parent 733ef4d3d8
commit ab0a52063d
4 changed files with 178 additions and 90 deletions

View file

@ -5,6 +5,7 @@ from configparser import ConfigParser
import zipfile
import os
import json
import re
from typing import cast, Dict, List, Optional, Tuple, Any, Set
import xml.etree.ElementTree as ET
@ -141,10 +142,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._old_new_materials: Dict[str, str] = {}
self._machine_info = None
self._load_profile = False
def _clearState(self):
self._id_mapping = {}
self._old_new_materials = {}
self._machine_info = None
self._load_profile = False
def getNewId(self, old_id: str):
"""Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
@ -228,7 +232,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._resolve_strategies = {k: None for k in resolve_strategy_keys}
containers_found_dict = {k: False for k in resolve_strategy_keys}
# Check whether the file is a PCB
# Check whether the file is a PCB, which changes some import options
is_pcb = file_name.endswith('.pcb')
#
@ -621,6 +625,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
self._dialog.setMissingPackagesMetadata(missing_package_metadata)
self._dialog.setHasVisibleSelectSameProfileChanged(is_pcb)
self._dialog.setAllowCreatemachine(not is_pcb)
self._dialog.show()
# Choosing the initially selected printer in MachineSelector
@ -652,6 +657,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._dialog.setIsNetworkedMachine(is_networked_machine)
self._dialog.setIsAbstractMachine(is_abstract_machine)
self._dialog.setMachineName(machine_name)
self._dialog.updateCompatibleMachine()
self._dialog.setSelectSameProfileChecked(self._dialog.isCompatibleMachine)
# Block until the dialog is closed.
self._dialog.waitForClose()
@ -659,6 +666,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._dialog.getResult() == {}:
return WorkspaceReader.PreReadResult.cancelled
self._load_profile = not is_pcb or self._dialog.selectSameProfileChecked
self._resolve_strategies = self._dialog.getResult()
#
# There can be 3 resolve strategies coming from the dialog:
@ -781,6 +790,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
for stack in extruder_stacks:
stack.setNextStack(global_stack, connect_signals = False)
user_settings = {}
if self._load_profile:
Logger.log("d", "Workspace loading is checking definitions...")
# Get all the definition files & check if they exist. If not, add them.
definition_container_files = [name for name in cura_file_names if name.endswith(self._definition_container_suffix)]
@ -852,13 +864,33 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
self._container_registry.addContainer(material_container)
Job.yieldThread()
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
else:
Logger.log("d", "Workspace loading user settings...")
try:
user_settings = json.loads(archive.open("Cura/user-settings.json").read().decode("utf-8"))
except KeyError as e:
# If there is no user settings file, it's not a PCB, so notify user of failure.
Logger.log("w", "File %s is not a valid PCB.", file_name)
message = Message(
i18n_catalog.i18nc("@info:error Don't translate the XML tags <filename> or <message>!",
"Project file <filename>{0}</filename> is corrupt: <message>{1}</message>.",
file_name, str(e)),
title=i18n_catalog.i18nc("@info:title", "Can't Open Project File"),
message_type=Message.MessageType.ERROR)
message.show()
self.setWorkspaceName("")
return [], {}
if global_stack:
if self._load_profile:
# Handle quality changes if any
self._processQualityChanges(global_stack)
# Prepare the machine
self._applyChangesToMachine(global_stack, extruder_stack_dict)
else:
self._applyUserSettings(global_stack, extruder_stack_dict, user_settings)
Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
# Actually change the active machine.
@ -1181,21 +1213,47 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
extruder_stack.material = material_node.container
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
# Clear all first
def _clearMachineSettings(self, global_stack, extruder_stack_dict):
self._clearStack(global_stack)
for extruder_stack in extruder_stack_dict.values():
self._clearStack(extruder_stack)
self._quality_changes_to_apply = None
self._quality_type_to_apply = None
self._intent_category_to_apply = None
self._user_settings_to_apply = None
def _applyUserSettings(self, global_stack, extruder_stack_dict, user_settings):
# Clear all first
self._clearMachineSettings(global_stack, extruder_stack_dict)
for stack_name, settings in user_settings.items():
if stack_name == 'global':
ThreeMFWorkspaceReader._applyUserSettingsOnStack(global_stack, settings)
else:
extruder_match = re.fullmatch('extruder_([0-9]+)', stack_name)
if extruder_match is not None:
extruder_nr = extruder_match.group(1)
if extruder_nr in extruder_stack_dict:
ThreeMFWorkspaceReader._applyUserSettingsOnStack(extruder_stack_dict[extruder_nr], settings)
@staticmethod
def _applyUserSettingsOnStack(stack, user_settings):
user_settings_container = stack.userChanges
for setting_to_import, setting_value in user_settings.items():
user_settings_container.setProperty(setting_to_import, 'value', setting_value)
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
# Clear all first
self._clearMachineSettings(global_stack, extruder_stack_dict)
self._applyDefinitionChanges(global_stack, extruder_stack_dict)
self._applyUserChanges(global_stack, extruder_stack_dict)
self._applyVariants(global_stack, extruder_stack_dict)
self._applyMaterials(global_stack, extruder_stack_dict)
# prepare the quality to select
self._quality_changes_to_apply = None
self._quality_type_to_apply = None
self._intent_category_to_apply = None
if self._machine_info.quality_changes_info is not None:
self._quality_changes_to_apply = self._machine_info.quality_changes_info.name
else:

View file

@ -73,6 +73,8 @@ class WorkspaceDialog(QObject):
self._is_networked_machine = False
self._is_compatible_machine = False
self._has_visible_select_same_profile = False
self._select_same_profile_checked = True
self._allow_create_machine = True
machineConflictChanged = pyqtSignal()
qualityChangesConflictChanged = pyqtSignal()
@ -98,6 +100,7 @@ class WorkspaceDialog(QObject):
missingPackagesChanged = pyqtSignal()
isCompatibleMachineChanged = pyqtSignal()
hasVisibleSelectSameProfileChanged = pyqtSignal()
selectSameProfileCheckedChanged = pyqtSignal()
@pyqtProperty(bool, notify = isPrinterGroupChanged)
def isPrinterGroup(self) -> bool:
@ -295,17 +298,19 @@ class WorkspaceDialog(QObject):
@pyqtSlot(str)
def setMachineToOverride(self, machine_name: str) -> None:
self._override_machine = machine_name
self.updateCompatibleMachine()
def updateCompatibleMachine(self):
registry = ContainerRegistry.getInstance()
containers_expected = registry.findDefinitionContainers(name = self._machine_type)
containers_selected = registry.findContainerStacks(id = machine_name)
containers_expected = registry.findDefinitionContainers(name=self._machine_type)
containers_selected = registry.findContainerStacks(id=self._override_machine)
if len(containers_expected) == 1 and len(containers_selected) == 1:
new_compatible_machine = (containers_expected[0] == containers_selected[0].definition)
if new_compatible_machine != self._is_compatible_machine:
self._is_compatible_machine = new_compatible_machine
self.isCompatibleMachineChanged.emit()
self._override_machine = machine_name
@pyqtProperty(bool, notify = isCompatibleMachineChanged)
def isCompatibleMachine(self) -> bool:
return self._is_compatible_machine
@ -319,6 +324,22 @@ class WorkspaceDialog(QObject):
def hasVisibleSelectSameProfile(self):
return self._has_visible_select_same_profile
def setSelectSameProfileChecked(self, select_same_profile_checked):
if select_same_profile_checked != self._select_same_profile_checked:
self._select_same_profile_checked = select_same_profile_checked
self.selectSameProfileCheckedChanged.emit()
@pyqtProperty(bool, notify = selectSameProfileCheckedChanged, fset = setSelectSameProfileChecked)
def selectSameProfileChecked(self):
return self._select_same_profile_checked
def setAllowCreatemachine(self, allow_create_machine):
self._allow_create_machine = allow_create_machine
@pyqtProperty(bool, constant = True)
def allowCreateMachine(self):
return self._allow_create_machine
@pyqtSlot()
def closeBackend(self) -> None:
"""Close the backend: otherwise one could end up with "Slicing..."""

View file

@ -120,13 +120,17 @@ UM.Dialog
minDropDownWidth: machineSelector.width
buttons: [
Component
{
id: componentNewPrinter
Cura.SecondaryButton
{
id: createNewPrinter
text: catalog.i18nc("@button", "Create new")
fixedWidthMode: true
width: parent.width - leftPadding * 1.5
visible: manager.allowCreateMachine
onClicked:
{
toggleContent()
@ -136,7 +140,9 @@ UM.Dialog
manager.setIsNetworkedMachine(false)
}
}
]
}
buttons: manager.allowCreateMachine ? [componentNewPrinter.createObject()] : []
onSelectPrinter: function(machine)
{
@ -191,9 +197,12 @@ UM.Dialog
{
text: catalog.i18nc("@action:checkbox", "Select the same profile")
enabled: manager.isCompatibleMachine
onEnabledChanged: checked = enabled
onEnabledChanged: manager.selectSameProfileChecked = enabled
tooltip: enabled ? "" : catalog.i18nc("@tooltip", "You can use the same profile only if you have the same printer as the project was published with")
visible: manager.hasVisibleSelectSameProfile
checked: manager.selectSameProfileChecked
onCheckedChanged: manager.selectSameProfileChecked = checked
}
}

View file

@ -105,7 +105,7 @@ class SettingsExportModel(QObject):
@staticmethod
def _exportSettings(settings_stack):
user_settings_container = settings_stack.getTop()
user_settings_container = settings_stack.userChanges
user_keys = user_settings_container.getAllKeys()
settings_export = []