mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Now loading user settings
CURA-11561
This commit is contained in:
parent
733ef4d3d8
commit
ab0a52063d
4 changed files with 178 additions and 90 deletions
|
@ -5,6 +5,7 @@ from configparser import ConfigParser
|
||||||
import zipfile
|
import zipfile
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
from typing import cast, Dict, List, Optional, Tuple, Any, Set
|
from typing import cast, Dict, List, Optional, Tuple, Any, Set
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
@ -141,10 +142,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
self._old_new_materials: Dict[str, str] = {}
|
self._old_new_materials: Dict[str, str] = {}
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
|
||||||
|
self._load_profile = False
|
||||||
|
|
||||||
def _clearState(self):
|
def _clearState(self):
|
||||||
self._id_mapping = {}
|
self._id_mapping = {}
|
||||||
self._old_new_materials = {}
|
self._old_new_materials = {}
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
self._load_profile = False
|
||||||
|
|
||||||
def getNewId(self, old_id: str):
|
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.
|
"""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}
|
self._resolve_strategies = {k: None for k in resolve_strategy_keys}
|
||||||
containers_found_dict = {k: False 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')
|
is_pcb = file_name.endswith('.pcb')
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -621,6 +625,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
|
self._dialog.setHasObjectsOnPlate(Application.getInstance().platformActivity)
|
||||||
self._dialog.setMissingPackagesMetadata(missing_package_metadata)
|
self._dialog.setMissingPackagesMetadata(missing_package_metadata)
|
||||||
self._dialog.setHasVisibleSelectSameProfileChanged(is_pcb)
|
self._dialog.setHasVisibleSelectSameProfileChanged(is_pcb)
|
||||||
|
self._dialog.setAllowCreatemachine(not is_pcb)
|
||||||
self._dialog.show()
|
self._dialog.show()
|
||||||
|
|
||||||
# Choosing the initially selected printer in MachineSelector
|
# Choosing the initially selected printer in MachineSelector
|
||||||
|
@ -652,6 +657,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
self._dialog.setIsNetworkedMachine(is_networked_machine)
|
self._dialog.setIsNetworkedMachine(is_networked_machine)
|
||||||
self._dialog.setIsAbstractMachine(is_abstract_machine)
|
self._dialog.setIsAbstractMachine(is_abstract_machine)
|
||||||
self._dialog.setMachineName(machine_name)
|
self._dialog.setMachineName(machine_name)
|
||||||
|
self._dialog.updateCompatibleMachine()
|
||||||
|
self._dialog.setSelectSameProfileChecked(self._dialog.isCompatibleMachine)
|
||||||
|
|
||||||
# Block until the dialog is closed.
|
# Block until the dialog is closed.
|
||||||
self._dialog.waitForClose()
|
self._dialog.waitForClose()
|
||||||
|
@ -659,6 +666,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
if self._dialog.getResult() == {}:
|
if self._dialog.getResult() == {}:
|
||||||
return WorkspaceReader.PreReadResult.cancelled
|
return WorkspaceReader.PreReadResult.cancelled
|
||||||
|
|
||||||
|
self._load_profile = not is_pcb or self._dialog.selectSameProfileChecked
|
||||||
|
|
||||||
self._resolve_strategies = self._dialog.getResult()
|
self._resolve_strategies = self._dialog.getResult()
|
||||||
#
|
#
|
||||||
# There can be 3 resolve strategies coming from the dialog:
|
# There can be 3 resolve strategies coming from the dialog:
|
||||||
|
@ -781,6 +790,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
for stack in extruder_stacks:
|
for stack in extruder_stacks:
|
||||||
stack.setNextStack(global_stack, connect_signals = False)
|
stack.setNextStack(global_stack, connect_signals = False)
|
||||||
|
|
||||||
|
user_settings = {}
|
||||||
|
|
||||||
|
if self._load_profile:
|
||||||
Logger.log("d", "Workspace loading is checking definitions...")
|
Logger.log("d", "Workspace loading is checking definitions...")
|
||||||
# Get all the definition files & check if they exist. If not, add them.
|
# 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)]
|
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)
|
self._container_registry.addContainer(material_container)
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
|
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 global_stack:
|
||||||
|
if self._load_profile:
|
||||||
# Handle quality changes if any
|
# Handle quality changes if any
|
||||||
self._processQualityChanges(global_stack)
|
self._processQualityChanges(global_stack)
|
||||||
|
|
||||||
# Prepare the machine
|
# Prepare the machine
|
||||||
self._applyChangesToMachine(global_stack, extruder_stack_dict)
|
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...")
|
Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
|
||||||
# Actually change the active machine.
|
# 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]
|
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
|
||||||
extruder_stack.material = material_node.container
|
extruder_stack.material = material_node.container
|
||||||
|
|
||||||
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
|
def _clearMachineSettings(self, global_stack, extruder_stack_dict):
|
||||||
# Clear all first
|
|
||||||
self._clearStack(global_stack)
|
self._clearStack(global_stack)
|
||||||
for extruder_stack in extruder_stack_dict.values():
|
for extruder_stack in extruder_stack_dict.values():
|
||||||
self._clearStack(extruder_stack)
|
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._applyDefinitionChanges(global_stack, extruder_stack_dict)
|
||||||
self._applyUserChanges(global_stack, extruder_stack_dict)
|
self._applyUserChanges(global_stack, extruder_stack_dict)
|
||||||
self._applyVariants(global_stack, extruder_stack_dict)
|
self._applyVariants(global_stack, extruder_stack_dict)
|
||||||
self._applyMaterials(global_stack, extruder_stack_dict)
|
self._applyMaterials(global_stack, extruder_stack_dict)
|
||||||
|
|
||||||
# prepare the quality to select
|
# 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:
|
if self._machine_info.quality_changes_info is not None:
|
||||||
self._quality_changes_to_apply = self._machine_info.quality_changes_info.name
|
self._quality_changes_to_apply = self._machine_info.quality_changes_info.name
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -73,6 +73,8 @@ class WorkspaceDialog(QObject):
|
||||||
self._is_networked_machine = False
|
self._is_networked_machine = False
|
||||||
self._is_compatible_machine = False
|
self._is_compatible_machine = False
|
||||||
self._has_visible_select_same_profile = False
|
self._has_visible_select_same_profile = False
|
||||||
|
self._select_same_profile_checked = True
|
||||||
|
self._allow_create_machine = True
|
||||||
|
|
||||||
machineConflictChanged = pyqtSignal()
|
machineConflictChanged = pyqtSignal()
|
||||||
qualityChangesConflictChanged = pyqtSignal()
|
qualityChangesConflictChanged = pyqtSignal()
|
||||||
|
@ -98,6 +100,7 @@ class WorkspaceDialog(QObject):
|
||||||
missingPackagesChanged = pyqtSignal()
|
missingPackagesChanged = pyqtSignal()
|
||||||
isCompatibleMachineChanged = pyqtSignal()
|
isCompatibleMachineChanged = pyqtSignal()
|
||||||
hasVisibleSelectSameProfileChanged = pyqtSignal()
|
hasVisibleSelectSameProfileChanged = pyqtSignal()
|
||||||
|
selectSameProfileCheckedChanged = pyqtSignal()
|
||||||
|
|
||||||
@pyqtProperty(bool, notify = isPrinterGroupChanged)
|
@pyqtProperty(bool, notify = isPrinterGroupChanged)
|
||||||
def isPrinterGroup(self) -> bool:
|
def isPrinterGroup(self) -> bool:
|
||||||
|
@ -295,17 +298,19 @@ class WorkspaceDialog(QObject):
|
||||||
|
|
||||||
@pyqtSlot(str)
|
@pyqtSlot(str)
|
||||||
def setMachineToOverride(self, machine_name: str) -> None:
|
def setMachineToOverride(self, machine_name: str) -> None:
|
||||||
|
self._override_machine = machine_name
|
||||||
|
self.updateCompatibleMachine()
|
||||||
|
|
||||||
|
def updateCompatibleMachine(self):
|
||||||
registry = ContainerRegistry.getInstance()
|
registry = ContainerRegistry.getInstance()
|
||||||
containers_expected = registry.findDefinitionContainers(name = self._machine_type)
|
containers_expected = registry.findDefinitionContainers(name=self._machine_type)
|
||||||
containers_selected = registry.findContainerStacks(id = machine_name)
|
containers_selected = registry.findContainerStacks(id=self._override_machine)
|
||||||
if len(containers_expected) == 1 and len(containers_selected) == 1:
|
if len(containers_expected) == 1 and len(containers_selected) == 1:
|
||||||
new_compatible_machine = (containers_expected[0] == containers_selected[0].definition)
|
new_compatible_machine = (containers_expected[0] == containers_selected[0].definition)
|
||||||
if new_compatible_machine != self._is_compatible_machine:
|
if new_compatible_machine != self._is_compatible_machine:
|
||||||
self._is_compatible_machine = new_compatible_machine
|
self._is_compatible_machine = new_compatible_machine
|
||||||
self.isCompatibleMachineChanged.emit()
|
self.isCompatibleMachineChanged.emit()
|
||||||
|
|
||||||
self._override_machine = machine_name
|
|
||||||
|
|
||||||
@pyqtProperty(bool, notify = isCompatibleMachineChanged)
|
@pyqtProperty(bool, notify = isCompatibleMachineChanged)
|
||||||
def isCompatibleMachine(self) -> bool:
|
def isCompatibleMachine(self) -> bool:
|
||||||
return self._is_compatible_machine
|
return self._is_compatible_machine
|
||||||
|
@ -319,6 +324,22 @@ class WorkspaceDialog(QObject):
|
||||||
def hasVisibleSelectSameProfile(self):
|
def hasVisibleSelectSameProfile(self):
|
||||||
return self._has_visible_select_same_profile
|
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()
|
@pyqtSlot()
|
||||||
def closeBackend(self) -> None:
|
def closeBackend(self) -> None:
|
||||||
"""Close the backend: otherwise one could end up with "Slicing..."""
|
"""Close the backend: otherwise one could end up with "Slicing..."""
|
||||||
|
|
|
@ -120,13 +120,17 @@ UM.Dialog
|
||||||
|
|
||||||
minDropDownWidth: machineSelector.width
|
minDropDownWidth: machineSelector.width
|
||||||
|
|
||||||
buttons: [
|
Component
|
||||||
|
{
|
||||||
|
id: componentNewPrinter
|
||||||
|
|
||||||
Cura.SecondaryButton
|
Cura.SecondaryButton
|
||||||
{
|
{
|
||||||
id: createNewPrinter
|
id: createNewPrinter
|
||||||
text: catalog.i18nc("@button", "Create new")
|
text: catalog.i18nc("@button", "Create new")
|
||||||
fixedWidthMode: true
|
fixedWidthMode: true
|
||||||
width: parent.width - leftPadding * 1.5
|
width: parent.width - leftPadding * 1.5
|
||||||
|
visible: manager.allowCreateMachine
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
toggleContent()
|
toggleContent()
|
||||||
|
@ -136,7 +140,9 @@ UM.Dialog
|
||||||
manager.setIsNetworkedMachine(false)
|
manager.setIsNetworkedMachine(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
|
buttons: manager.allowCreateMachine ? [componentNewPrinter.createObject()] : []
|
||||||
|
|
||||||
onSelectPrinter: function(machine)
|
onSelectPrinter: function(machine)
|
||||||
{
|
{
|
||||||
|
@ -191,9 +197,12 @@ UM.Dialog
|
||||||
{
|
{
|
||||||
text: catalog.i18nc("@action:checkbox", "Select the same profile")
|
text: catalog.i18nc("@action:checkbox", "Select the same profile")
|
||||||
enabled: manager.isCompatibleMachine
|
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")
|
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
|
visible: manager.hasVisibleSelectSameProfile
|
||||||
|
|
||||||
|
checked: manager.selectSameProfileChecked
|
||||||
|
onCheckedChanged: manager.selectSameProfileChecked = checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ class SettingsExportModel(QObject):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _exportSettings(settings_stack):
|
def _exportSettings(settings_stack):
|
||||||
user_settings_container = settings_stack.getTop()
|
user_settings_container = settings_stack.userChanges
|
||||||
user_keys = user_settings_container.getAllKeys()
|
user_keys = user_settings_container.getAllKeys()
|
||||||
|
|
||||||
settings_export = []
|
settings_export = []
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue