Merge branch 'master' into layer_view3_cleanup

This commit is contained in:
Jack Ha 2017-02-15 10:57:24 +01:00
commit 78de5412a2
95 changed files with 3279 additions and 683 deletions

View file

@ -2,6 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher.
from cura.Settings.ExtruderManager import ExtruderManager
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog
from UM.Scene.Platform import Platform
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
@ -25,9 +26,6 @@ import numpy
import copy
import math
import UM.Settings.ContainerRegistry
# Setting for clearance around the prime
PRIME_CLEARANCE = 6.5
@ -796,7 +794,7 @@ class BuildVolume(SceneNode):
stack = self._global_container_stack
else:
extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)]
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
stack = ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
value = stack.getProperty(setting_key, property)
setting_type = stack.getProperty(setting_key, "type")

View file

@ -1,13 +1,13 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Application import Application
from cura.Settings.ExtruderManager import ExtruderManager
from UM.Math.Polygon import Polygon
from . import ConvexHullNode
from UM.Scene.SceneNodeDecorator import SceneNodeDecorator
from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Settings.ContainerRegistry
from cura.Settings.ExtruderManager import ExtruderManager
from . import ConvexHullNode
import numpy
@ -308,11 +308,11 @@ class ConvexHullDecorator(SceneNodeDecorator):
extruder_stack_id = self._node.callDecoration("getActiveExtruder")
if not extruder_stack_id: #Decoration doesn't exist.
extruder_stack_id = ExtruderManager.getInstance().extruderIds["0"]
extruder_stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
extruder_stack = ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
return extruder_stack.getProperty(setting_key, property)
else: #Limit_to_extruder is set. Use that one.
extruder_stack_id = ExtruderManager.getInstance().extruderIds[str(extruder_index)]
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
stack = ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
return stack.getProperty(setting_key, property)
## Returns true if node is a descendant or the same as the root node.

View file

@ -12,10 +12,14 @@ from UM.Logger import Logger
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
try:
from cura.CuraVersion import CuraDebugMode
except ImportError:
CuraDebugMode = False # [CodeStyle: Reflecting imported value]
MYPY = False
if MYPY:
CuraDebugMode = False
else:
try:
from cura.CuraVersion import CuraDebugMode
except ImportError:
CuraDebugMode = False # [CodeStyle: Reflecting imported value]
# List of exceptions that should be considered "fatal" and abort the program.
# These are primarily some exception types that we simply cannot really recover from

View file

@ -1,5 +1,7 @@
# Copyright (c) 2015 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from PyQt5.QtNetwork import QLocalServer
from PyQt5.QtNetwork import QLocalSocket
from UM.Qt.QtApplication import QtApplication
from UM.Scene.SceneNode import SceneNode
@ -26,7 +28,6 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
from UM.Operations.GroupedOperation import GroupedOperation
from UM.Operations.SetTransformOperation import SetTransformOperation
from UM.Operations.TranslateOperation import TranslateOperation
from cura.SetParentOperation import SetParentOperation
from cura.SliceableObjectDecorator import SliceableObjectDecorator
from cura.BlockSlicingDecorator import BlockSlicingDecorator
@ -34,6 +35,11 @@ from cura.BlockSlicingDecorator import BlockSlicingDecorator
from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.SettingFunction import SettingFunction
from cura.Settings.MachineNameValidator import MachineNameValidator
from cura.Settings.ProfilesModel import ProfilesModel
from cura.Settings.QualityAndUserProfilesModel import QualityAndUserProfilesModel
from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
from cura.Settings.UserProfilesModel import UserProfilesModel
from . import PlatformPhysics
from . import BuildVolume
@ -45,7 +51,14 @@ from . import CuraSplashScreen
from . import CameraImageProvider
from . import MachineActionManager
import cura.Settings
from cura.Settings.MachineManager import MachineManager
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry
from cura.Settings.ExtrudersModel import ExtrudersModel
from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from cura.Settings.QualitySettingsModel import QualitySettingsModel
from cura.Settings.ContainerManager import ContainerManager
from PyQt5.QtCore import QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
from UM.FlameProfiler import pyqtSlot
@ -59,15 +72,18 @@ import numpy
import copy
import urllib.parse
import os
import argparse
import json
numpy.seterr(all="ignore")
try:
from cura.CuraVersion import CuraVersion, CuraBuildType
except ImportError:
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
CuraBuildType = ""
MYPY = False
if not MYPY:
try:
from cura.CuraVersion import CuraVersion, CuraBuildType
except ImportError:
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
CuraBuildType = ""
class CuraApplication(QtApplication):
class ResourceTypes:
@ -83,6 +99,7 @@ class CuraApplication(QtApplication):
Q_ENUMS(ResourceTypes)
def __init__(self):
Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources"))
if not hasattr(sys, "frozen"):
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources"))
@ -107,9 +124,9 @@ class CuraApplication(QtApplication):
SettingDefinition.addSettingType("extruder", None, str, Validator)
SettingFunction.registerOperator("extruderValues", cura.Settings.ExtruderManager.getExtruderValues)
SettingFunction.registerOperator("extruderValue", cura.Settings.ExtruderManager.getExtruderValue)
SettingFunction.registerOperator("resolveOrValue", cura.Settings.ExtruderManager.getResolveOrValue)
SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues)
SettingFunction.registerOperator("extruderValue", ExtruderManager.getExtruderValue)
SettingFunction.registerOperator("resolveOrValue", ExtruderManager.getResolveOrValue)
## Add the 4 types of profiles to storage.
Resources.addStorageType(self.ResourceTypes.QualityInstanceContainer, "quality")
@ -128,13 +145,14 @@ class CuraApplication(QtApplication):
## Initialise the version upgrade manager with Cura's storage paths.
import UM.VersionUpgradeManager #Needs to be here to prevent circular dependencies.
UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions(
{
("quality", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"),
("machine_stack", UM.Settings.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"),
("extruder_train", UM.Settings.ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"),
("preferences", UM.Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"),
("user", UM.Settings.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer")
("quality", UM.Settings.InstanceContainer.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"),
("machine_stack", UM.Settings.ContainerStack.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"),
("extruder_train", UM.Settings.ContainerStack.ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"),
("preferences", Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"),
("user", UM.Settings.InstanceContainer.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer")
}
)
@ -401,7 +419,11 @@ class CuraApplication(QtApplication):
@pyqtSlot(str, str)
def setDefaultPath(self, key, default_path):
Preferences.getInstance().setValue("local_file/%s" % key, default_path)
Preferences.getInstance().setValue("local_file/%s" % key, QUrl(default_path).toLocalFile())
@classmethod
def getStaticVersion(cls):
return CuraVersion
## Handle loading of all plugin types (and the backend explicitly)
# \sa PluginRegistery
@ -421,13 +443,107 @@ class CuraApplication(QtApplication):
self._plugins_loaded = True
@classmethod
def addCommandLineOptions(self, parser):
super().addCommandLineOptions(parser)
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
parser.add_argument("--single-instance", action="store_true", default=False)
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
def _setUpSingleInstanceServer(self):
if self.getCommandLineOption("single_instance", False):
self.__single_instance_server = QLocalServer()
self.__single_instance_server.newConnection.connect(self._singleInstanceServerNewConnection)
self.__single_instance_server.listen("ultimaker-cura")
def _singleInstanceServerNewConnection(self):
Logger.log("i", "New connection recevied on our single-instance server")
remote_cura_connection = self.__single_instance_server.nextPendingConnection()
if remote_cura_connection is not None:
def readCommands():
line = remote_cura_connection.readLine()
while len(line) != 0: # There is also a .canReadLine()
try:
payload = json.loads(str(line, encoding="ASCII").strip())
command = payload["command"]
# Command: Remove all models from the build plate.
if command == "clear-all":
self.deleteAll()
# Command: Load a model file
elif command == "open":
self._openFile(payload["filePath"])
# WARNING ^ this method is async and we really should wait until
# the file load is complete before processing more commands.
# Command: Activate the window and bring it to the top.
elif command == "focus":
# Operating systems these days prevent windows from moving around by themselves.
# 'alert' or flashing the icon in the taskbar is the best thing we do now.
self.getMainWindow().alert(0)
# Command: Close the socket connection. We're done.
elif command == "close-connection":
remote_cura_connection.close()
else:
Logger.log("w", "Received an unrecognized command " + str(command))
except json.decoder.JSONDecodeError as ex:
Logger.log("w", "Unable to parse JSON command in _singleInstanceServerNewConnection(): " + repr(ex))
line = remote_cura_connection.readLine()
remote_cura_connection.readyRead.connect(readCommands)
## Perform any checks before creating the main application.
#
# This should be called directly before creating an instance of CuraApplication.
# \returns \type{bool} True if the whole Cura app should continue running.
@classmethod
def preStartUp(cls):
# Peek the arguments and look for the 'single-instance' flag.
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
CuraApplication.addCommandLineOptions(parser)
parsed_command_line = vars(parser.parse_args())
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
single_instance_socket = QLocalSocket()
Logger.log("d", "preStartUp(): full server name: " + single_instance_socket.fullServerName())
single_instance_socket.connectToServer("ultimaker-cura")
single_instance_socket.waitForConnected()
if single_instance_socket.state() == QLocalSocket.ConnectedState:
Logger.log("i", "Connection has been made to the single-instance Cura socket.")
# Protocol is one line of JSON terminated with a carriage return.
# "command" field is required and holds the name of the command to execute.
# Other fields depend on the command.
payload = {"command": "clear-all"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
payload = {"command": "focus"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
if len(parsed_command_line["file"]) != 0:
for filename in parsed_command_line["file"]:
payload = {"command": "open", "filePath": filename}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
payload = {"command": "close-connection"}
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
single_instance_socket.flush()
single_instance_socket.waitForDisconnected()
return False
return True
def run(self):
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
self._setUpSingleInstanceServer()
controller = self.getController()
controller.setActiveView("SolidView")
@ -464,9 +580,11 @@ class CuraApplication(QtApplication):
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Loading interface..."))
# Initialise extruder so as to listen to global container stack changes before the first global container stack is set.
cura.Settings.ExtruderManager.getInstance()
qmlRegisterSingletonType(cura.Settings.MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager)
qmlRegisterSingletonType(cura.Settings.SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager", self.getSettingInheritanceManager)
ExtruderManager.getInstance()
qmlRegisterSingletonType(MachineManager, "Cura", 1, 0, "MachineManager", self.getMachineManager)
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, "SettingInheritanceManager",
self.getSettingInheritanceManager)
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, "MachineActionManager", self.getMachineActionManager)
self.setMainQml(Resources.getPath(self.ResourceTypes.QmlFiles, "Cura.qml"))
self._qml_import_paths.append(Resources.getPath(self.ResourceTypes.QmlFiles))
@ -486,12 +604,12 @@ class CuraApplication(QtApplication):
def getMachineManager(self, *args):
if self._machine_manager is None:
self._machine_manager = cura.Settings.MachineManager.createMachineManager()
self._machine_manager = MachineManager.createMachineManager()
return self._machine_manager
def getSettingInheritanceManager(self, *args):
if self._setting_inheritance_manager is None:
self._setting_inheritance_manager = cura.Settings.SettingInheritanceManager.createSettingInheritanceManager()
self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager()
return self._setting_inheritance_manager
## Get the machine action manager
@ -527,23 +645,23 @@ class CuraApplication(QtApplication):
qmlRegisterUncreatableType(CuraApplication, "Cura", 1, 0, "ResourceTypes", "Just an Enum type")
qmlRegisterType(cura.Settings.ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(ExtrudersModel, "Cura", 1, 0, "ExtrudersModel")
qmlRegisterType(cura.Settings.ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterSingletonType(cura.Settings.ProfilesModel, "Cura", 1, 0, "ProfilesModel", cura.Settings.ProfilesModel.createProfilesModel)
qmlRegisterType(cura.Settings.QualityAndUserProfilesModel, "Cura", 1, 0, "QualityAndUserProfilesModel")
qmlRegisterType(cura.Settings.UserProfilesModel, "Cura", 1, 0, "UserProfilesModel")
qmlRegisterType(cura.Settings.MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(cura.Settings.QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterType(cura.Settings.MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(ContainerSettingsModel, "Cura", 1, 0, "ContainerSettingsModel")
qmlRegisterSingletonType(ProfilesModel, "Cura", 1, 0, "ProfilesModel", ProfilesModel.createProfilesModel)
qmlRegisterType(QualityAndUserProfilesModel, "Cura", 1, 0, "QualityAndUserProfilesModel")
qmlRegisterType(UserProfilesModel, "Cura", 1, 0, "UserProfilesModel")
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterSingletonType(cura.Settings.ContainerManager, "Cura", 1, 0, "ContainerManager", cura.Settings.ContainerManager.createContainerManager)
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
# As of Qt5.7, it is necessary to get rid of any ".." in the path for the singleton to work.
actions_url = QUrl.fromLocalFile(os.path.abspath(Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "Actions.qml")))
qmlRegisterSingletonType(actions_url, "Cura", 1, 0, "Actions")
engine.rootContext().setContextProperty("ExtruderManager", cura.Settings.ExtruderManager.getInstance())
engine.rootContext().setContextProperty("ExtruderManager", ExtruderManager.getInstance())
for path in Resources.getAllResourcesOfType(CuraApplication.ResourceTypes.QmlFiles):
type_name = os.path.splitext(os.path.basename(path))[0]

View file

@ -1,6 +1,6 @@
from UM.Math.Color import Color
from UM.Application import Application
from typing import Any
import numpy
@ -198,7 +198,7 @@ class LayerPolygon:
return normals
__color_map = None
__color_map = None # type: numpy.ndarray[Any]
## Gets the instance of the VersionUpgradeManager, or creates one.
@classmethod

View file

@ -7,9 +7,9 @@ from UM.FlameProfiler import pyqtSlot
from UM.Application import Application
from UM.Qt.Duration import Duration
from UM.Preferences import Preferences
from UM.Settings import ContainerRegistry
from UM.Settings.ContainerRegistry import ContainerRegistry
import cura.Settings.ExtruderManager
from cura.Settings.ExtruderManager import ExtruderManager
import math
import os.path
@ -124,7 +124,7 @@ class PrintInformation(QObject):
material_preference_values = json.loads(Preferences.getInstance().getValue("cura/material_settings"))
extruder_stacks = list(cura.Settings.ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId()))
extruder_stacks = list(ExtruderManager.getInstance().getMachineExtruders(Application.getInstance().getGlobalContainerStack().getId()))
for index, amount in enumerate(self._material_amounts):
## Find the right extruder stack. As the list isn't sorted because it's a annoying generator, we do some
# list comprehension filtering to solve this for us.

View file

@ -1,12 +1,15 @@
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from UM.i18n import i18nCatalog
from UM.OutputDevice.OutputDevice import OutputDevice
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtWidgets import QMessageBox
import UM.Settings.ContainerRegistry
from UM.Settings.ContainerRegistry import ContainerRegistry
from enum import IntEnum # For the connection state tracking.
from UM.Logger import Logger
from UM.Application import Application
from UM.Signal import signalemitter
i18n_catalog = i18nCatalog("cura")
@ -25,7 +28,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
def __init__(self, device_id, parent = None):
super().__init__(device_id = device_id, parent = parent)
self._container_registry = UM.Settings.ContainerRegistry.getInstance()
self._container_registry = ContainerRegistry.getInstance()
self._target_bed_temperature = 0
self._bed_temperature = 0
self._num_extruders = 1
@ -45,6 +48,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = ""
self._error_text = ""
self._accepts_commands = True
self._preheat_bed_timeout = 900 #Default time-out for pre-heating the bed, in seconds.
self._printer_state = ""
self._printer_type = "unknown"
@ -161,6 +165,17 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = name
self.jobNameChanged.emit()
## Gives a human-readable address where the device can be found.
@pyqtProperty(str, constant = True)
def address(self):
Logger.log("w", "address is not implemented by this output device.")
## A human-readable name for the device.
@pyqtProperty(str, constant = True)
def name(self):
Logger.log("w", "name is not implemented by this output device.")
return ""
@pyqtProperty(str, notify = errorTextChanged)
def errorText(self):
return self._error_text
@ -199,6 +214,13 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._target_bed_temperature = temperature
self.targetBedTemperatureChanged.emit()
## The duration of the time-out to pre-heat the bed, in seconds.
#
# \return The duration of the time-out to pre-heat the bed, in seconds.
@pyqtProperty(int)
def preheatBedTimeout(self):
return self._preheat_bed_timeout
## Time the print has been printing.
# Note that timeTotal - timeElapsed should give time remaining.
@pyqtProperty(float, notify = timeElapsedChanged)
@ -254,6 +276,22 @@ class PrinterOutputDevice(QObject, OutputDevice):
def _setTargetBedTemperature(self, temperature):
Logger.log("w", "_setTargetBedTemperature is not implemented by this output device")
## Pre-heats the heated bed of the printer.
#
# \param temperature The temperature to heat the bed to, in degrees
# Celsius.
# \param duration How long the bed should stay warm, in seconds.
@pyqtSlot(float, float)
def preheatBed(self, temperature, duration):
Logger.log("w", "preheatBed is not implemented by this output device.")
## Cancels pre-heating the heated bed of the printer.
#
# If the bed is not pre-heated, nothing happens.
@pyqtSlot()
def cancelPreheatBed(self):
Logger.log("w", "cancelPreheatBed is not implemented by this output device.")
## Protected setter for the current bed temperature.
# This simply sets the bed temperature, but ensures that a signal is emitted.
# /param temperature temperature of the bed.
@ -323,6 +361,28 @@ class PrinterOutputDevice(QObject, OutputDevice):
result.append(i18n_catalog.i18nc("@item:material", "Unknown material"))
return result
## List of the colours of the currently loaded materials.
#
# The list is in order of extruders. If there is no material in an
# extruder, the colour is shown as transparent.
#
# The colours are returned in hex-format AARRGGBB or RRGGBB
# (e.g. #800000ff for transparent blue or #00ff00 for pure green).
@pyqtProperty("QVariantList", notify = materialIdChanged)
def materialColors(self):
result = []
for material_id in self._material_ids:
if material_id is None:
result.append("#00000000") #No material.
continue
containers = self._container_registry.findInstanceContainers(type = "material", GUID = material_id)
if containers:
result.append(containers[0].getMetaDataEntry("color_code"))
else:
result.append("#00000000") #Unknown material.
return result
## Protected setter for the current material id.
# /param index Index of the extruder
# /param material_id id of the material

View file

@ -1,12 +1,16 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
import UM.Application
import cura.Settings.ExtruderManager
import UM.Settings.ContainerRegistry
# This collects a lot of quality and quality changes related code which was split between ContainerManager
# and the MachineManager and really needs to usable from both.
from typing import List
from UM.Application import Application
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.InstanceContainer import InstanceContainer
from cura.Settings.ExtruderManager import ExtruderManager
class QualityManager:
@ -18,7 +22,7 @@ class QualityManager:
QualityManager.__instance = cls()
return QualityManager.__instance
__instance = None
__instance = None # type: "QualityManager"
## Find a quality by name for a specific machine definition and materials.
#
@ -121,14 +125,14 @@ class QualityManager:
#
# \param machine_definition \type{DefinitionContainer} the machine definition.
# \return \type{List[InstanceContainer]} the list of quality changes
def findAllQualityChangesForMachine(self, machine_definition):
def findAllQualityChangesForMachine(self, machine_definition: DefinitionContainer) -> List[InstanceContainer]:
if machine_definition.getMetaDataEntry("has_machine_quality"):
definition_id = machine_definition.getId()
else:
definition_id = "fdmprinter"
filter_dict = { "type": "quality_changes", "extruder": None, "definition": definition_id }
quality_changes_list = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**filter_dict)
quality_changes_list = ContainerRegistry.getInstance().findInstanceContainers(**filter_dict)
return quality_changes_list
## Find all usable qualities for a machine and extruders.
@ -177,7 +181,7 @@ class QualityManager:
if base_material:
# There is a basic material specified
criteria = { "type": "material", "name": base_material, "definition": definition_id }
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**criteria)
containers = [basic_material for basic_material in containers if
basic_material.getMetaDataEntry("variant") == material_container.getMetaDataEntry(
"variant")]
@ -191,13 +195,13 @@ class QualityManager:
def _getFilteredContainersForStack(self, machine_definition=None, material_containers=None, **kwargs):
# Fill in any default values.
if machine_definition is None:
machine_definition = UM.Application.getInstance().getGlobalContainerStack().getBottom()
machine_definition = Application.getInstance().getGlobalContainerStack().getBottom()
quality_definition_id = machine_definition.getMetaDataEntry("quality_definition")
if quality_definition_id is not None:
machine_definition = UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id=quality_definition_id)[0]
machine_definition = ContainerRegistry.getInstance().findDefinitionContainers(id=quality_definition_id)[0]
if material_containers is None:
active_stacks = cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
material_containers = [stack.findContainer(type="material") for stack in active_stacks]
criteria = kwargs
@ -225,7 +229,7 @@ class QualityManager:
material_ids.add(basic_material.getId())
material_ids.add(material_instance.getId())
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**criteria)
result = []
for container in containers:
@ -241,8 +245,8 @@ class QualityManager:
# an extruder definition.
# \return \type{DefinitionContainer} the parent machine definition. If the given machine
# definition doesn't have a parent then it is simply returned.
def getParentMachineDefinition(self, machine_definition):
container_registry = UM.Settings.ContainerRegistry.getInstance()
def getParentMachineDefinition(self, machine_definition: DefinitionContainer) -> DefinitionContainer:
container_registry = ContainerRegistry.getInstance()
machine_entry = machine_definition.getMetaDataEntry("machine")
if machine_entry is None:
@ -277,6 +281,6 @@ class QualityManager:
# This already is a 'global' machine definition.
return machine_definition
else:
container_registry = UM.Settings.ContainerRegistry.getInstance()
container_registry = ContainerRegistry.getInstance()
whole_machine = container_registry.findDefinitionContainers(id=machine_entry)[0]
return whole_machine

View file

@ -8,19 +8,25 @@ from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QUrl, QVariant
from UM.FlameProfiler import pyqtSlot
from PyQt5.QtWidgets import QMessageBox
import UM.PluginRegistry
import UM.Settings
from UM.PluginRegistry import PluginRegistry
import UM.SaveFile
import UM.Platform
import UM.MimeTypeDatabase
import UM.Logger
import cura.Settings
from UM.Logger import Logger
from UM.Application import Application
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.DefinitionContainer import DefinitionContainer
from UM.Settings.InstanceContainer import InstanceContainer
from cura.QualityManager import QualityManager
from UM.MimeTypeDatabase import MimeTypeNotFoundError
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog
from cura.Settings.ExtruderManager import ExtruderManager
catalog = i18nCatalog("cura")
## Manager class that contains common actions to deal with containers in Cura.
@ -32,9 +38,8 @@ class ContainerManager(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._container_registry = UM.Settings.ContainerRegistry.getInstance()
self._machine_manager = UM.Application.getInstance().getMachineManager()
self._container_registry = ContainerRegistry.getInstance()
self._machine_manager = Application.getInstance().getMachineManager()
self._container_name_filters = {}
## Create a duplicate of the specified container
@ -49,7 +54,7 @@ class ContainerManager(QObject):
def duplicateContainer(self, container_id):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could duplicate container %s because it was not found.", container_id)
Logger.log("w", "Could duplicate container %s because it was not found.", container_id)
return ""
container = containers[0]
@ -81,7 +86,7 @@ class ContainerManager(QObject):
def renameContainer(self, container_id, new_id, new_name):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could rename container %s because it was not found.", container_id)
Logger.log("w", "Could rename container %s because it was not found.", container_id)
return False
container = containers[0]
@ -109,7 +114,7 @@ class ContainerManager(QObject):
def removeContainer(self, container_id):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could remove container %s because it was not found.", container_id)
Logger.log("w", "Could remove container %s because it was not found.", container_id)
return False
self._container_registry.removeContainer(containers[0].getId())
@ -129,20 +134,20 @@ class ContainerManager(QObject):
def mergeContainers(self, merge_into_id, merge_id):
containers = self._container_registry.findContainers(None, id = merge_into_id)
if not containers:
UM.Logger.log("w", "Could merge into container %s because it was not found.", merge_into_id)
Logger.log("w", "Could merge into container %s because it was not found.", merge_into_id)
return False
merge_into = containers[0]
containers = self._container_registry.findContainers(None, id = merge_id)
if not containers:
UM.Logger.log("w", "Could not merge container %s because it was not found", merge_id)
Logger.log("w", "Could not merge container %s because it was not found", merge_id)
return False
merge = containers[0]
if not isinstance(merge, type(merge_into)):
UM.Logger.log("w", "Cannot merge two containers of different types")
Logger.log("w", "Cannot merge two containers of different types")
return False
self._performMerge(merge_into, merge)
@ -158,11 +163,11 @@ class ContainerManager(QObject):
def clearContainer(self, container_id):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could clear container %s because it was not found.", container_id)
Logger.log("w", "Could clear container %s because it was not found.", container_id)
return False
if containers[0].isReadOnly():
UM.Logger.log("w", "Cannot clear read-only container %s", container_id)
Logger.log("w", "Cannot clear read-only container %s", container_id)
return False
containers[0].clear()
@ -173,7 +178,7 @@ class ContainerManager(QObject):
def getContainerMetaDataEntry(self, container_id, entry_name):
containers = self._container_registry.findContainers(None, id=container_id)
if not containers:
UM.Logger.log("w", "Could not get metadata of container %s because it was not found.", container_id)
Logger.log("w", "Could not get metadata of container %s because it was not found.", container_id)
return ""
result = containers[0].getMetaDataEntry(entry_name)
@ -198,13 +203,13 @@ class ContainerManager(QObject):
def setContainerMetaDataEntry(self, container_id, entry_name, entry_value):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could not set metadata of container %s because it was not found.", container_id)
Logger.log("w", "Could not set metadata of container %s because it was not found.", container_id)
return False
container = containers[0]
if container.isReadOnly():
UM.Logger.log("w", "Cannot set metadata of read-only container %s.", container_id)
Logger.log("w", "Cannot set metadata of read-only container %s.", container_id)
return False
entries = entry_name.split("/")
@ -232,13 +237,13 @@ class ContainerManager(QObject):
def setContainerName(self, container_id, new_name):
containers = self._container_registry.findContainers(None, id = container_id)
if not containers:
UM.Logger.log("w", "Could not set name of container %s because it was not found.", container_id)
Logger.log("w", "Could not set name of container %s because it was not found.", container_id)
return False
container = containers[0]
if container.isReadOnly():
UM.Logger.log("w", "Cannot set name of read-only container %s.", container_id)
Logger.log("w", "Cannot set name of read-only container %s.", container_id)
return False
container.setName(new_name)
@ -262,11 +267,11 @@ class ContainerManager(QObject):
@pyqtSlot(str, result = bool)
def isContainerUsed(self, container_id):
UM.Logger.log("d", "Checking if container %s is currently used", container_id)
Logger.log("d", "Checking if container %s is currently used", container_id)
containers = self._container_registry.findContainerStacks()
for stack in containers:
if container_id in [child.getId() for child in stack.getContainers()]:
UM.Logger.log("d", "The container is in use by %s", stack.getId())
Logger.log("d", "The container is in use by %s", stack.getId())
return True
return False
@ -382,7 +387,7 @@ class ContainerManager(QObject):
except MimeTypeNotFoundError:
return { "status": "error", "message": "Could not determine mime type of file" }
container_type = UM.Settings.ContainerRegistry.getContainerForMimeType(mime_type)
container_type = self._container_registry.getContainerForMimeType(mime_type)
if not container_type:
return { "status": "error", "message": "Could not find a container to handle the specified file."}
@ -411,17 +416,17 @@ class ContainerManager(QObject):
# \return \type{bool} True if successful, False if not.
@pyqtSlot(result = bool)
def updateQualityChanges(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return False
self._machine_manager.blurSettings.emit()
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
# Find the quality_changes container for this stack and merge the contents of the top container into it.
quality_changes = stack.findContainer(type = "quality_changes")
if not quality_changes or quality_changes.isReadOnly():
UM.Logger.log("e", "Could not update quality of a nonexistant or read only quality profile in stack %s", stack.getId())
Logger.log("e", "Could not update quality of a nonexistant or read only quality profile in stack %s", stack.getId())
continue
self._performMerge(quality_changes, stack.getTop())
@ -438,7 +443,7 @@ class ContainerManager(QObject):
send_emits_containers = []
# Go through global and extruder stacks and clear their topmost container (the user settings).
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
container = stack.getTop()
container.clear()
send_emits_containers.append(container)
@ -455,13 +460,13 @@ class ContainerManager(QObject):
# \return \type{bool} True if the operation was successfully, False if not.
@pyqtSlot(str, result = bool)
def createQualityChanges(self, base_name):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return False
active_quality_name = self._machine_manager.activeQualityName
if active_quality_name == "":
UM.Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId())
Logger.log("w", "No quality container found in stack %s, cannot create profile", global_stack.getId())
return False
self._machine_manager.blurSettings.emit()
@ -470,17 +475,17 @@ class ContainerManager(QObject):
unique_name = self._container_registry.uniqueName(base_name)
# Go through the active stacks and create quality_changes containers from the user containers.
for stack in cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
for stack in ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks():
user_container = stack.getTop()
quality_container = stack.findContainer(type = "quality")
quality_changes_container = stack.findContainer(type = "quality_changes")
if not quality_container or not quality_changes_container:
UM.Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId())
Logger.log("w", "No quality or quality changes container found in stack %s, ignoring it", stack.getId())
continue
extruder_id = None if stack is global_stack else QualityManager.getInstance().getParentMachineDefinition(stack.getBottom()).getId()
new_changes = self._createQualityChanges(quality_container, unique_name,
UM.Application.getInstance().getGlobalContainerStack().getBottom(),
Application.getInstance().getGlobalContainerStack().getBottom(),
extruder_id)
self._performMerge(new_changes, quality_changes_container, clear_settings = False)
self._performMerge(new_changes, user_container)
@ -502,7 +507,7 @@ class ContainerManager(QObject):
# \return \type{bool} True if successful, False if not.
@pyqtSlot(str, result = bool)
def removeQualityChanges(self, quality_name):
UM.Logger.log("d", "Attempting to remove the quality change containers with name %s", quality_name)
Logger.log("d", "Attempting to remove the quality change containers with name %s", quality_name)
containers_found = False
if not quality_name:
@ -512,7 +517,7 @@ class ContainerManager(QObject):
activate_quality = quality_name == self._machine_manager.activeQualityName
activate_quality_type = None
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack or not quality_name:
return ""
machine_definition = global_stack.getBottom()
@ -524,7 +529,7 @@ class ContainerManager(QObject):
self._container_registry.removeContainer(container.getId())
if not containers_found:
UM.Logger.log("d", "Unable to remove quality containers, as we did not find any by the name of %s", quality_name)
Logger.log("d", "Unable to remove quality containers, as we did not find any by the name of %s", quality_name)
elif activate_quality:
definition_id = "fdmprinter" if not self._machine_manager.filterQualityByMachine else self._machine_manager.activeDefinitionId
@ -547,15 +552,15 @@ class ContainerManager(QObject):
# \return True if successful, False if not.
@pyqtSlot(str, str, result = bool)
def renameQualityChanges(self, quality_name, new_name):
UM.Logger.log("d", "User requested QualityChanges container rename of %s to %s", quality_name, new_name)
Logger.log("d", "User requested QualityChanges container rename of %s to %s", quality_name, new_name)
if not quality_name or not new_name:
return False
if quality_name == new_name:
UM.Logger.log("w", "Unable to rename %s to %s, because they are the same.", quality_name, new_name)
Logger.log("w", "Unable to rename %s to %s, because they are the same.", quality_name, new_name)
return True
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return False
@ -572,7 +577,7 @@ class ContainerManager(QObject):
container_registry.renameContainer(container.getId(), new_name, self._createUniqueId(stack_id, new_name))
if not containers_to_rename:
UM.Logger.log("e", "Unable to rename %s, because we could not find the profile", quality_name)
Logger.log("e", "Unable to rename %s, because we could not find the profile", quality_name)
self._machine_manager.activeQualityChanged.emit()
return True
@ -588,12 +593,12 @@ class ContainerManager(QObject):
# \return A string containing the name of the duplicated containers, or an empty string if it failed.
@pyqtSlot(str, str, result = str)
def duplicateQualityOrQualityChanges(self, quality_name, base_name):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack or not quality_name:
return ""
machine_definition = global_stack.getBottom()
active_stacks = cura.Settings.ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
active_stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
material_containers = [stack.findContainer(type="material") for stack in active_stacks]
result = self._duplicateQualityOrQualityChangesForMachineType(quality_name, base_name,
@ -609,16 +614,16 @@ class ContainerManager(QObject):
# \param material_instances \type{List[InstanceContainer]}
# \return \type{str} the name of the newly created container.
def _duplicateQualityOrQualityChangesForMachineType(self, quality_name, base_name, machine_definition, material_instances):
UM.Logger.log("d", "Attempting to duplicate the quality %s", quality_name)
Logger.log("d", "Attempting to duplicate the quality %s", quality_name)
if base_name is None:
base_name = quality_name
# Try to find a Quality with the name.
container = QualityManager.getInstance().findQualityByName(quality_name, machine_definition, material_instances)
if container:
UM.Logger.log("d", "We found a quality to duplicate.")
Logger.log("d", "We found a quality to duplicate.")
return self._duplicateQualityForMachineType(container, base_name, machine_definition)
UM.Logger.log("d", "We found a quality_changes to duplicate.")
Logger.log("d", "We found a quality_changes to duplicate.")
# Assume it is a quality changes.
return self._duplicateQualityChangesForMachineType(quality_name, base_name, machine_definition)
@ -665,11 +670,11 @@ class ContainerManager(QObject):
def duplicateMaterial(self, material_id):
containers = self._container_registry.findInstanceContainers(id=material_id)
if not containers:
UM.Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id)
Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id)
return ""
# Ensure all settings are saved.
UM.Application.getInstance().saveSettings()
Application.getInstance().saveSettings()
# Create a new ID & container to hold the data.
new_id = self._container_registry.uniqueName(material_id)
@ -692,7 +697,7 @@ class ContainerManager(QObject):
ContainerManager.__instance = cls()
return ContainerManager.__instance
__instance = None
__instance = None # type: "ContainerManager"
# Factory function, used by QML
@staticmethod
@ -713,14 +718,14 @@ class ContainerManager(QObject):
def _updateContainerNameFilters(self):
self._container_name_filters = {}
for plugin_id, container_type in UM.Settings.ContainerRegistry.getContainerTypes():
for plugin_id, container_type in self._container_registry.getContainerTypes():
# Ignore default container types since those are not plugins
if container_type in (UM.Settings.InstanceContainer, UM.Settings.ContainerStack, UM.Settings.DefinitionContainer):
if container_type in (InstanceContainer, ContainerStack, DefinitionContainer):
continue
serialize_type = ""
try:
plugin_metadata = UM.PluginRegistry.getInstance().getMetaData(plugin_id)
plugin_metadata = PluginRegistry.getInstance().getMetaData(plugin_id)
if plugin_metadata:
serialize_type = plugin_metadata["settings_container"]["type"]
else:
@ -728,7 +733,7 @@ class ContainerManager(QObject):
except KeyError as e:
continue
mime_type = UM.Settings.ContainerRegistry.getMimeTypeForContainer(container_type)
mime_type = self._container_registry.getMimeTypeForContainer(container_type)
entry = {
"type": serialize_type,
@ -791,7 +796,7 @@ class ContainerManager(QObject):
base_id = machine_definition.getId() if extruder_id is None else extruder_id
# Create a new quality_changes container for the quality.
quality_changes = UM.Settings.InstanceContainer(self._createUniqueId(base_id, new_name))
quality_changes = InstanceContainer(self._createUniqueId(base_id, new_name))
quality_changes.setName(new_name)
quality_changes.addMetaDataEntry("type", "quality_changes")
quality_changes.addMetaDataEntry("quality_type", quality_container.getMetaDataEntry("quality_type"))
@ -826,7 +831,7 @@ class ContainerManager(QObject):
if not path.endswith(".curaprofile"):
continue
single_result = UM.Settings.ContainerRegistry.getInstance().importProfile(path)
single_result = self._container_registry.importProfile(path)
if single_result["status"] == "error":
status = "error"
results[single_result["status"]].append(single_result["message"])
@ -843,7 +848,7 @@ class ContainerManager(QObject):
path = file_url.toLocalFile()
if not path:
return
return UM.Settings.ContainerRegistry.getInstance().importProfile(path)
return self._container_registry.importProfile(path)
@pyqtSlot("QVariantList", QUrl, str)
def exportProfile(self, instance_id, file_url, file_type):
@ -852,4 +857,4 @@ class ContainerManager(QObject):
path = file_url.toLocalFile()
if not path:
return
UM.Settings.ContainerRegistry.getInstance().exportProfile(instance_id, path, file_type)
self._container_registry.exportProfile(instance_id, path, file_type)

View file

@ -4,13 +4,16 @@
from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant #For communicating data and events to Qt.
from UM.FlameProfiler import pyqtSlot
import UM.Application #To get the global container stack to find the current machine.
import UM.Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator #To find which extruders are used in the scene.
from UM.Scene.SceneNode import SceneNode #To find which extruders are used in the scene.
import UM.Settings.ContainerRegistry #Finding containers by ID.
import UM.Settings.SettingFunction
from UM.Application import Application #To get the global container stack to find the current machine.
from UM.Logger import Logger
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode
from UM.Settings.ContainerRegistry import ContainerRegistry #Finding containers by ID.
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.DefinitionContainer import DefinitionContainer
from typing import Optional
## Manages all existing extruder stacks.
#
@ -31,7 +34,7 @@ class ExtruderManager(QObject):
super().__init__(parent)
self._extruder_trains = { } #Per machine, a dictionary of extruder container stack IDs.
self._active_extruder_index = 0
UM.Application.getInstance().globalContainerStackChanged.connect(self.__globalContainerStackChanged)
Application.getInstance().globalContainerStackChanged.connect(self.__globalContainerStackChanged)
self._global_container_stack_definition_id = None
self._addCurrentMachineExtruders()
@ -42,35 +45,35 @@ class ExtruderManager(QObject):
#
# \return The unique ID of the currently active extruder stack.
@pyqtProperty(str, notify = activeExtruderChanged)
def activeExtruderStackId(self):
if not UM.Application.getInstance().getGlobalContainerStack():
def activeExtruderStackId(self) -> Optional[str]:
if not Application.getInstance().getGlobalContainerStack():
return None # No active machine, so no active extruder.
try:
return self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
return self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][str(self._active_extruder_index)].getId()
except KeyError: # Extruder index could be -1 if the global tab is selected, or the entry doesn't exist if the machine definition is wrong.
return None
## Return extruder count according to extruder trains.
@pyqtProperty(int, notify = extrudersChanged)
def extruderCount(self):
if not UM.Application.getInstance().getGlobalContainerStack():
if not Application.getInstance().getGlobalContainerStack():
return 0 # No active machine, so no extruders.
try:
return len(self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()])
return len(self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()])
except KeyError:
return 0
@pyqtProperty("QVariantMap", notify=extrudersChanged)
def extruderIds(self):
map = {}
for position in self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()]:
map[position] = self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][position].getId()
for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]:
map[position] = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position].getId()
return map
@pyqtSlot(str, result = str)
def getQualityChangesIdByExtruderStackId(self, id):
for position in self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()]:
extruder = self._extruder_trains[UM.Application.getInstance().getGlobalContainerStack().getId()][position]
def getQualityChangesIdByExtruderStackId(self, id: str) -> str:
for position in self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()]:
extruder = self._extruder_trains[Application.getInstance().getGlobalContainerStack().getId()][position]
if extruder.getId() == id:
return extruder.findContainer(type = "quality_changes").getId()
@ -87,7 +90,7 @@ class ExtruderManager(QObject):
#
# \return The extruder manager.
@classmethod
def getInstance(cls):
def getInstance(cls) -> "ExtruderManager":
if not cls.__instance:
cls.__instance = ExtruderManager()
return cls.__instance
@ -96,16 +99,27 @@ class ExtruderManager(QObject):
#
# \param index The index of the new active extruder.
@pyqtSlot(int)
def setActiveExtruderIndex(self, index):
def setActiveExtruderIndex(self, index: int) -> None:
self._active_extruder_index = index
self.activeExtruderChanged.emit()
@pyqtProperty(int, notify = activeExtruderChanged)
def activeExtruderIndex(self):
def activeExtruderIndex(self) -> int:
return self._active_extruder_index
def getActiveExtruderStack(self):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
## Gets the extruder name of an extruder of the currently active machine.
#
# \param index The index of the extruder whose name to get.
@pyqtSlot(int, result = str)
def getExtruderName(self, index):
try:
return list(self.getActiveExtruderStacks())[index].getName()
except IndexError:
return ""
def getActiveExtruderStack(self) -> ContainerStack:
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
if global_container_stack.getId() in self._extruder_trains:
if str(self._active_extruder_index) in self._extruder_trains[global_container_stack.getId()]:
@ -114,7 +128,7 @@ class ExtruderManager(QObject):
## Get an extruder stack by index
def getExtruderStack(self, index):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
if global_container_stack.getId() in self._extruder_trains:
if str(index) in self._extruder_trains[global_container_stack.getId()]:
@ -126,19 +140,19 @@ class ExtruderManager(QObject):
#
# \param machine_definition The machine definition to add the extruders for.
# \param machine_id The machine_id to add the extruders for.
def addMachineExtruders(self, machine_definition, machine_id):
def addMachineExtruders(self, machine_definition: DefinitionContainer, machine_id: str) -> None:
changed = False
machine_definition_id = machine_definition.getId()
if machine_id not in self._extruder_trains:
self._extruder_trains[machine_id] = { }
changed = True
container_registry = UM.Settings.ContainerRegistry.getInstance()
container_registry = ContainerRegistry.getInstance()
if container_registry:
# Add the extruder trains that don't exist yet.
for extruder_definition in container_registry.findDefinitionContainers(machine = machine_definition_id):
position = extruder_definition.getMetaDataEntry("position", None)
if not position:
UM.Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
Logger.log("w", "Extruder definition %s specifies no position metadata entry.", extruder_definition.getId())
if not container_registry.findContainerStacks(machine = machine_id, position = position): # Doesn't exist yet.
self.createExtruderTrain(extruder_definition, machine_definition, position, machine_id)
changed = True
@ -149,7 +163,7 @@ class ExtruderManager(QObject):
self._extruder_trains[machine_id][extruder_train.getMetaDataEntry("position")] = extruder_train
# regardless of what the next stack is, we have to set it again, because of signal routing.
extruder_train.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
extruder_train.setNextStack(Application.getInstance().getGlobalContainerStack())
changed = True
if changed:
self.extrudersChanged.emit(machine_id)
@ -178,14 +192,15 @@ class ExtruderManager(QObject):
# \param machine_definition The machine that the extruder train belongs to.
# \param position The position of this extruder train in the extruder slots of the machine.
# \param machine_id The id of the "global" stack this extruder is linked to.
def createExtruderTrain(self, extruder_definition, machine_definition, position, machine_id):
def createExtruderTrain(self, extruder_definition: DefinitionContainer, machine_definition: DefinitionContainer,
position, machine_id: str) -> None:
# Cache some things.
container_registry = UM.Settings.ContainerRegistry.getInstance()
machine_definition_id = UM.Application.getInstance().getMachineManager().getQualityDefinitionId(machine_definition)
container_registry = ContainerRegistry.getInstance()
machine_definition_id = Application.getInstance().getMachineManager().getQualityDefinitionId(machine_definition)
# Create a container stack for this extruder.
extruder_stack_id = container_registry.uniqueName(extruder_definition.getId())
container_stack = UM.Settings.ContainerStack(extruder_stack_id)
container_stack = ContainerStack(extruder_stack_id)
container_stack.setName(extruder_definition.getName()) # Take over the display name to display the stack with.
container_stack.addMetaDataEntry("type", "extruder_train")
container_stack.addMetaDataEntry("machine", machine_id)
@ -205,7 +220,7 @@ class ExtruderManager(QObject):
if len(preferred_variants) >= 1:
variant = preferred_variants[0]
else:
UM.Logger.log("w", "The preferred variant \"%s\" of machine %s doesn't exist or is not a variant profile.", preferred_variant_id, machine_id)
Logger.log("w", "The preferred variant \"%s\" of machine %s doesn't exist or is not a variant profile.", preferred_variant_id, machine_id)
# And leave it at the default variant.
container_stack.addContainer(variant)
@ -235,7 +250,7 @@ class ExtruderManager(QObject):
if len(preferred_materials) >= 1:
material = preferred_materials[0]
else:
UM.Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
# And leave it at the default material.
container_stack.addContainer(material)
@ -254,11 +269,11 @@ class ExtruderManager(QObject):
if preferred_quality:
search_criteria["id"] = preferred_quality
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if not containers and preferred_quality:
UM.Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality, machine_id)
Logger.log("w", "The preferred quality \"%s\" of machine %s doesn't exist or is not a quality profile.", preferred_quality, machine_id)
search_criteria.pop("id", None)
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
quality = containers[0]
@ -271,7 +286,7 @@ class ExtruderManager(QObject):
if user_profile: # There was already a user profile, loaded from settings.
user_profile = user_profile[0]
else:
user_profile = UM.Settings.InstanceContainer(extruder_stack_id + "_current_settings") # Add an empty user profile.
user_profile = InstanceContainer(extruder_stack_id + "_current_settings") # Add an empty user profile.
user_profile.addMetaDataEntry("type", "user")
user_profile.addMetaDataEntry("extruder", extruder_stack_id)
user_profile.setDefinition(machine_definition)
@ -279,7 +294,7 @@ class ExtruderManager(QObject):
container_stack.addContainer(user_profile)
# regardless of what the next stack is, we have to set it again, because of signal routing.
container_stack.setNextStack(UM.Application.getInstance().getGlobalContainerStack())
container_stack.setNextStack(Application.getInstance().getGlobalContainerStack())
container_registry.addContainer(container_stack)
@ -292,14 +307,14 @@ class ExtruderManager(QObject):
# \param property \type{str} The property to get.
# \return \type{List} the list of results
def getAllExtruderSettings(self, setting_key, property):
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack.getProperty("machine_extruder_count", "value") <= 1:
return [global_container_stack.getProperty(setting_key, property)]
result = []
for index in self.extruderIds:
extruder_stack_id = self.extruderIds[str(index)]
stack = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
stack = ContainerRegistry.getInstance().findContainerStacks(id = extruder_stack_id)[0]
result.append(stack.getProperty(setting_key, property))
return result
@ -314,8 +329,8 @@ class ExtruderManager(QObject):
#
# \return A list of extruder stacks.
def getUsedExtruderStacks(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
container_registry = UM.Settings.ContainerRegistry.getInstance()
global_stack = Application.getInstance().getGlobalContainerStack()
container_registry = ContainerRegistry.getInstance()
if global_stack.getProperty("machine_extruder_count", "value") <= 1: #For single extrusion.
return [global_stack]
@ -325,7 +340,7 @@ class ExtruderManager(QObject):
#Get the extruders of all meshes in the scene.
support_enabled = False
support_interface_enabled = False
scene_root = UM.Application.getInstance().getController().getScene().getRoot()
scene_root = Application.getInstance().getController().getScene().getRoot()
meshes = [node for node in DepthFirstIterator(scene_root) if type(node) is SceneNode and node.isSelectable()] #Only use the nodes that will be printed.
for mesh in meshes:
extruder_stack_id = mesh.callDecoration("getActiveExtruder")
@ -356,7 +371,7 @@ class ExtruderManager(QObject):
try:
return [container_registry.findContainerStacks(id = stack_id)[0] for stack_id in used_extruder_stack_ids]
except IndexError: # One or more of the extruders was not found.
UM.Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids)
Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids)
return []
## Removes the container stack and user profile for the extruders for a specific machine.
@ -364,27 +379,26 @@ class ExtruderManager(QObject):
# \param machine_id The machine to remove the extruders for.
def removeMachineExtruders(self, machine_id):
for extruder in self.getMachineExtruders(machine_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", extruder = extruder.getId())
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", extruder = extruder.getId())
for container in containers:
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
UM.Settings.ContainerRegistry.getInstance().removeContainer(extruder.getId())
ContainerRegistry.getInstance().removeContainer(container.getId())
ContainerRegistry.getInstance().removeContainer(extruder.getId())
## Returns extruders for a specific machine.
#
# \param machine_id The machine to get the extruders of.
def getMachineExtruders(self, machine_id):
if machine_id not in self._extruder_trains:
UM.Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id)
return
for name in self._extruder_trains[machine_id]:
yield self._extruder_trains[machine_id][name]
Logger.log("w", "Tried to get the extruder trains for machine %s, which doesn't exist.", machine_id)
return []
return [self._extruder_trains[machine_id][name] for name in self._extruder_trains[machine_id]]
## Returns a list containing the global stack and active extruder stacks.
#
# The first element is the global container stack, followed by any extruder stacks.
# \return \type{List[ContainerStack]}
def getActiveGlobalAndExtruderStacks(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return None
@ -396,7 +410,7 @@ class ExtruderManager(QObject):
#
# \return \type{List[ContainerStack]} a list of
def getActiveExtruderStacks(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
result = []
if global_stack:
@ -404,17 +418,17 @@ class ExtruderManager(QObject):
result.append(self._extruder_trains[global_stack.getId()][extruder])
return result
def __globalContainerStackChanged(self):
def __globalContainerStackChanged(self) -> None:
self._addCurrentMachineExtruders()
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack and global_container_stack.getBottom() and global_container_stack.getBottom().getId() != self._global_container_stack_definition_id:
self._global_container_stack_definition_id = global_container_stack.getBottom().getId()
self.globalContainerStackDefinitionChanged.emit()
self.activeExtruderChanged.emit()
## Adds the extruders of the currently active machine.
def _addCurrentMachineExtruders(self):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
def _addCurrentMachineExtruders(self) -> None:
global_stack = Application.getInstance().getGlobalContainerStack()
if global_stack and global_stack.getBottom():
self.addMachineExtruders(global_stack.getBottom(), global_stack.getId())
@ -428,7 +442,7 @@ class ExtruderManager(QObject):
# If no extruder has the value, the list will contain the global value.
@staticmethod
def getExtruderValues(key):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
result = []
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
@ -437,7 +451,7 @@ class ExtruderManager(QObject):
if value is None:
continue
if isinstance(value, UM.Settings.SettingFunction):
if isinstance(value, SettingFunction):
value = value(extruder)
result.append(value)
@ -473,10 +487,10 @@ class ExtruderManager(QObject):
if extruder:
value = extruder.getRawProperty(key, "value")
if isinstance(value, UM.Settings.SettingFunction):
if isinstance(value, SettingFunction):
value = value(extruder)
else: #Just a value from global.
value = UM.Application.getInstance().getGlobalContainerStack().getProperty(key, "value")
value = Application.getInstance().getGlobalContainerStack().getProperty(key, "value")
return value
@ -489,7 +503,7 @@ class ExtruderManager(QObject):
# \return The effective value
@staticmethod
def getResolveOrValue(key):
global_stack = UM.Application.getInstance().getGlobalContainerStack()
global_stack = Application.getInstance().getGlobalContainerStack()
resolved_value = global_stack.getProperty(key, "resolve")
if resolved_value is not None:

View file

@ -4,8 +4,9 @@
from PyQt5.QtCore import Qt, pyqtSignal, pyqtProperty
import UM.Qt.ListModel
from UM.Application import Application
from . import ExtruderManager
from cura.Settings.ExtruderManager import ExtruderManager
## Model that holds extruders.
#
@ -55,7 +56,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
self._active_extruder_stack = None
#Listen to changes.
UM.Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders)
Application.getInstance().globalContainerStackChanged.connect(self._updateExtruders)
manager = ExtruderManager.getInstance()
self._updateExtruders()
@ -105,8 +106,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
def _onExtruderStackContainersChanged(self, container):
# The ExtrudersModel needs to be updated when the material-name or -color changes, because the user identifies extruders by material-name
if container.getMetaDataEntry("type") == "material":
self._updateExtruders()
self._updateExtruders()
modelChanged = pyqtSignal()
@ -121,7 +121,7 @@ class ExtrudersModel(UM.Qt.ListModel.ListModel):
items = []
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
global_container_stack = Application.getInstance().getGlobalContainerStack()
if global_container_stack:
if self._add_global:
material = global_container_stack.findContainer({ "type": "material" })

View file

@ -1,5 +1,6 @@
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2017 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from typing import Union
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
from UM.FlameProfiler import pyqtSlot
@ -11,11 +12,17 @@ from UM.Preferences import Preferences
from UM.Logger import Logger
from UM.Message import Message
import UM.Settings
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingDefinition import SettingDefinition
from UM.Settings.SettingFunction import SettingFunction
from UM.Settings.Validator import ValidatorState
from UM.Signal import postponeSignals
from cura.QualityManager import QualityManager
from cura.PrinterOutputDevice import PrinterOutputDevice
from . import ExtruderManager
from cura.Settings.ExtruderManager import ExtruderManager
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
@ -26,8 +33,8 @@ class MachineManager(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self._active_container_stack = None
self._global_container_stack = None
self._active_container_stack = None # type: ContainerStack
self._global_container_stack = None # type: ContainerStack
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged)
## When the global container is changed, active material probably needs to be updated.
@ -36,10 +43,10 @@ class MachineManager(QObject):
self.globalContainerChanged.connect(self.activeQualityChanged)
self._stacks_have_errors = None
self._empty_variant_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_variant")[0]
self._empty_material_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_material")[0]
self._empty_quality_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality")[0]
self._empty_quality_changes_container = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality_changes")[0]
self._empty_variant_container = ContainerRegistry.getInstance().findInstanceContainers(id="empty_variant")[0]
self._empty_material_container = ContainerRegistry.getInstance().findInstanceContainers(id="empty_material")[0]
self._empty_quality_container = ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality")[0]
self._empty_quality_changes_container = ContainerRegistry.getInstance().findInstanceContainers(id="empty_quality_changes")[0]
self._onGlobalContainerChanged()
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderStackChanged)
@ -91,7 +98,7 @@ class MachineManager(QObject):
outputDevicesChanged = pyqtSignal()
def _onOutputDevicesChanged(self):
def _onOutputDevicesChanged(self) -> None:
for printer_output_device in self._printer_output_devices:
printer_output_device.hotendIdChanged.disconnect(self._onHotendIdChanged)
printer_output_device.materialIdChanged.disconnect(self._onMaterialIdChanged)
@ -112,16 +119,17 @@ class MachineManager(QObject):
@pyqtProperty(int, constant=True)
def totalNumberOfSettings(self):
return len(UM.Settings.ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0].getAllKeys())
return len(ContainerRegistry.getInstance().findDefinitionContainers(id="fdmprinter")[0].getAllKeys())
def _onHotendIdChanged(self, index, hotend_id):
def _onHotendIdChanged(self, index: Union[str, int], hotend_id: str) -> None:
if not self._global_container_stack:
return
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type="variant", definition=self._global_container_stack.getBottom().getId(), name=hotend_id)
containers = ContainerRegistry.getInstance().findInstanceContainers(type="variant", definition=self._global_container_stack.getBottom().getId(), name=hotend_id)
if containers: # New material ID is known
extruder_manager = ExtruderManager.getInstance()
extruders = list(extruder_manager.getMachineExtruders(self.activeMachineId))
machine_id = self.activeMachineId
extruders = extruder_manager.getMachineExtruders(machine_id)
matching_extruder = None
for extruder in extruders:
if str(index) == extruder.getMetaDataEntry("position"):
@ -142,7 +150,7 @@ class MachineManager(QObject):
if self._global_container_stack.getMetaDataEntry("has_machine_materials", False):
definition_id = self.activeQualityDefinitionId
extruder_manager = ExtruderManager.getInstance()
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition_id, GUID = material_id)
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "material", definition = definition_id, GUID = material_id)
if containers: # New material ID is known
extruders = list(extruder_manager.getMachineExtruders(self.activeMachineId))
matching_extruder = None
@ -220,6 +228,11 @@ class MachineManager(QObject):
quality = self._global_container_stack.findContainer({"type": "quality"})
quality.nameChanged.disconnect(self._onQualityNameChanged)
if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1:
for extruder_stack in ExtruderManager.getInstance().getActiveExtruderStacks():
extruder_stack.propertyChanged.disconnect(self._onPropertyChanged)
extruder_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._global_container_stack = Application.getInstance().getGlobalContainerStack()
self._active_container_stack = self._global_container_stack
@ -243,6 +256,10 @@ class MachineManager(QObject):
if global_material != self._empty_material_container:
self._global_container_stack.replaceContainer(self._global_container_stack.getContainerIndex(global_material), self._empty_material_container)
for extruder_stack in ExtruderManager.getInstance().getActiveExtruderStacks(): #Listen for changes on all extruder stacks.
extruder_stack.propertyChanged.connect(self._onPropertyChanged)
extruder_stack.containersChanged.connect(self._onInstanceContainersChanged)
else:
material = self._global_container_stack.findContainer({"type": "material"})
material.nameChanged.connect(self._onMaterialNameChanged)
@ -263,14 +280,8 @@ class MachineManager(QObject):
self.blurSettings.emit() # Ensure no-one has focus.
old_active_container_stack = self._active_container_stack
if self._active_container_stack and self._active_container_stack != self._global_container_stack:
self._active_container_stack.containersChanged.disconnect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.disconnect(self._onPropertyChanged)
self._active_container_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if self._active_container_stack:
self._active_container_stack.containersChanged.connect(self._onInstanceContainersChanged)
self._active_container_stack.propertyChanged.connect(self._onPropertyChanged)
else:
if not self._active_container_stack:
self._active_container_stack = self._global_container_stack
self._updateStacksHaveErrors()
@ -282,13 +293,10 @@ class MachineManager(QObject):
def _onInstanceContainersChanged(self, container):
container_type = container.getMetaDataEntry("type")
if container_type == "material":
self.activeMaterialChanged.emit()
elif container_type == "variant":
self.activeVariantChanged.emit()
elif container_type == "quality":
self.activeQualityChanged.emit()
self.activeVariantChanged.emit()
self.activeMaterialChanged.emit()
self.activeQualityChanged.emit()
self._updateStacksHaveErrors()
@ -297,24 +305,29 @@ class MachineManager(QObject):
# Notify UI items, such as the "changed" star in profile pull down menu.
self.activeStackValueChanged.emit()
if property_name == "validationState":
elif property_name == "validationState":
if not self._stacks_have_errors:
# fast update, we only have to look at the current changed property
if self._active_container_stack.getProperty(key, "settable_per_extruder"):
changed_validation_state = self._active_container_stack.getProperty(key, property_name)
if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1 and self._active_container_stack.getProperty(key, "settable_per_extruder"):
extruder_index = int(self._active_container_stack.getProperty(key, "limit_to_extruder"))
if extruder_index >= 0: #We have to look up the value from a different extruder.
stack = ExtruderManager.getInstance().getExtruderStack(str(extruder_index))
else:
stack = self._active_container_stack
else:
changed_validation_state = self._global_container_stack.getProperty(key, property_name)
stack = self._global_container_stack
changed_validation_state = stack.getProperty(key, property_name)
if changed_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 defintions value can be set by a function, which could
# be an invalid setting.
definition = self._active_container_stack.getSettingDefinition(key)
validator_type = UM.Settings.SettingDefinition.getValidatorForType(definition.type)
validator_type = SettingDefinition.getValidatorForType(definition.type)
if validator_type:
validator = validator_type(key)
changed_validation_state = validator(self._active_container_stack)
if changed_validation_state in (UM.Settings.ValidatorState.Exception, UM.Settings.ValidatorState.MaximumError, UM.Settings.ValidatorState.MinimumError):
if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
self._stacks_have_errors = True
self.stacksValidationChanged.emit()
else:
@ -322,20 +335,20 @@ class MachineManager(QObject):
self._updateStacksHaveErrors()
@pyqtSlot(str)
def setActiveMachine(self, stack_id):
def setActiveMachine(self, stack_id: str) -> None:
self.blurSettings.emit() # Ensure no-one has focus.
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
containers = ContainerRegistry.getInstance().findContainerStacks(id = stack_id)
if containers:
Application.getInstance().setGlobalContainerStack(containers[0])
@pyqtSlot(str, str)
def addMachine(self, name, definition_id):
container_registry = UM.Settings.ContainerRegistry.getInstance()
def addMachine(self, name: str, definition_id: str) -> None:
container_registry = ContainerRegistry.getInstance()
definitions = container_registry.findDefinitionContainers(id = definition_id)
if definitions:
definition = definitions[0]
name = self._createUniqueName("machine", "", name, definition.getName())
new_global_stack = UM.Settings.ContainerStack(name)
new_global_stack = ContainerStack(name)
new_global_stack.addMetaDataEntry("type", "machine")
container_registry.addContainer(new_global_stack)
@ -343,7 +356,7 @@ class MachineManager(QObject):
material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
quality_instance_container = self._updateQualityContainer(definition, variant_instance_container, material_instance_container)
current_settings_instance_container = UM.Settings.InstanceContainer(name + "_current_settings")
current_settings_instance_container = InstanceContainer(name + "_current_settings")
current_settings_instance_container.addMetaDataEntry("machine", name)
current_settings_instance_container.addMetaDataEntry("type", "user")
current_settings_instance_container.setDefinition(definitions[0])
@ -371,17 +384,16 @@ class MachineManager(QObject):
# \param new_name \type{string} Base name, which may not be unique
# \param fallback_name \type{string} Name to use when (stripped) new_name is empty
# \return \type{string} Name that is unique for the specified type and name/id
def _createUniqueName(self, container_type, current_name, new_name, fallback_name):
return UM.Settings.ContainerRegistry.getInstance().createUniqueName(container_type, current_name, new_name, fallback_name)
def _createUniqueName(self, container_type: str, current_name: str, new_name: str, fallback_name: str) -> str:
return ContainerRegistry.getInstance().createUniqueName(container_type, current_name, new_name, fallback_name)
def _checkStacksHaveErrors(self):
if self._global_container_stack is not None and self._global_container_stack.hasErrors():
return True
if self._global_container_stack is None:
if self._global_container_stack is None: #No active machine.
return False
stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
for stack in stacks:
if self._global_container_stack.hasErrors():
return True
for stack in ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()):
if stack.hasErrors():
return True
@ -463,35 +475,35 @@ class MachineManager(QObject):
return bool(self._stacks_have_errors)
@pyqtProperty(str, notify = activeStackChanged)
def activeUserProfileId(self):
def activeUserProfileId(self) -> str:
if self._active_container_stack:
return self._active_container_stack.getTop().getId()
return ""
@pyqtProperty(str, notify = globalContainerChanged)
def activeMachineName(self):
def activeMachineName(self) -> str:
if self._global_container_stack:
return self._global_container_stack.getName()
return ""
@pyqtProperty(str, notify = globalContainerChanged)
def activeMachineId(self):
def activeMachineId(self) -> str:
if self._global_container_stack:
return self._global_container_stack.getId()
return ""
@pyqtProperty(str, notify = activeStackChanged)
def activeStackId(self):
def activeStackId(self) -> str:
if self._active_container_stack:
return self._active_container_stack.getId()
return ""
@pyqtProperty(str, notify = activeMaterialChanged)
def activeMaterialName(self):
def activeMaterialName(self) -> str:
if self._active_container_stack:
material = self._active_container_stack.findContainer({"type":"material"})
if material:
@ -521,7 +533,7 @@ class MachineManager(QObject):
return result
@pyqtProperty(str, notify=activeMaterialChanged)
def activeMaterialId(self):
def activeMaterialId(self) -> str:
if self._active_container_stack:
material = self._active_container_stack.findContainer({"type": "material"})
if material:
@ -559,13 +571,13 @@ class MachineManager(QObject):
quality_changes = self._global_container_stack.findContainer({"type": "quality_changes"})
if quality_changes:
value = self._global_container_stack.getRawProperty("layer_height", "value", skip_until_container = quality_changes.getId())
if isinstance(value, UM.Settings.SettingFunction):
if isinstance(value, SettingFunction):
value = value(self._global_container_stack)
return value
quality = self._global_container_stack.findContainer({"type": "quality"})
if quality:
value = self._global_container_stack.getRawProperty("layer_height", "value", skip_until_container = quality.getId())
if isinstance(value, UM.Settings.SettingFunction):
if isinstance(value, SettingFunction):
value = value(self._global_container_stack)
return value
@ -574,7 +586,7 @@ class MachineManager(QObject):
## Get the Material ID associated with the currently active material
# \returns MaterialID (string) if found, empty string otherwise
@pyqtProperty(str, notify=activeQualityChanged)
def activeQualityMaterialId(self):
def activeQualityMaterialId(self) -> str:
if self._active_container_stack:
quality = self._active_container_stack.findContainer({"type": "quality"})
if quality:
@ -664,8 +676,8 @@ class MachineManager(QObject):
## Check if a container is read_only
@pyqtSlot(str, result = bool)
def isReadOnly(self, container_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
def isReadOnly(self, container_id) -> bool:
containers = ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
if not containers or not self._active_container_stack:
return True
return containers[0].isReadOnly()
@ -687,134 +699,137 @@ class MachineManager(QObject):
# Depending on from/to material+current variant, a quality profile is chosen and set.
@pyqtSlot(str)
def setActiveMaterial(self, material_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = material_id)
if not containers or not self._active_container_stack:
return
material_container = containers[0]
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
containers = ContainerRegistry.getInstance().findInstanceContainers(id = material_id)
if not containers or not self._active_container_stack:
return
material_container = containers[0]
Logger.log("d", "Attempting to change the active material to %s", material_id)
Logger.log("d", "Attempting to change the active material to %s", material_id)
old_material = self._active_container_stack.findContainer({"type": "material"})
old_quality = self._active_container_stack.findContainer({"type": "quality"})
old_quality_changes = self._active_container_stack.findContainer({"type": "quality_changes"})
if not old_material:
Logger.log("w", "While trying to set the active material, no material was found to replace it.")
return
old_material = self._active_container_stack.findContainer({"type": "material"})
old_quality = self._active_container_stack.findContainer({"type": "quality"})
old_quality_changes = self._active_container_stack.findContainer({"type": "quality_changes"})
if not old_material:
Logger.log("w", "While trying to set the active material, no material was found to replace it.")
return
if old_quality_changes.getId() == "empty_quality_changes":
old_quality_changes = None
if old_quality_changes.getId() == "empty_quality_changes":
old_quality_changes = None
self.blurSettings.emit()
old_material.nameChanged.disconnect(self._onMaterialNameChanged)
self.blurSettings.emit()
old_material.nameChanged.disconnect(self._onMaterialNameChanged)
material_index = self._active_container_stack.getContainerIndex(old_material)
self._active_container_stack.replaceContainer(material_index, material_container)
Logger.log("d", "Active material changed")
material_index = self._active_container_stack.getContainerIndex(old_material)
self._active_container_stack.replaceContainer(material_index, material_container)
Logger.log("d", "Active material changed")
material_container.nameChanged.connect(self._onMaterialNameChanged)
material_container.nameChanged.connect(self._onMaterialNameChanged)
if material_container.getMetaDataEntry("compatible") == False:
self._material_incompatible_message.show()
else:
self._material_incompatible_message.hide()
if material_container.getMetaDataEntry("compatible") == False:
self._material_incompatible_message.show()
else:
self._material_incompatible_message.hide()
new_quality_id = old_quality.getId()
quality_type = old_quality.getMetaDataEntry("quality_type")
if old_quality_changes:
quality_type = old_quality_changes.getMetaDataEntry("quality_type")
new_quality_id = old_quality_changes.getId()
new_quality_id = old_quality.getId()
quality_type = old_quality.getMetaDataEntry("quality_type")
if old_quality_changes:
quality_type = old_quality_changes.getMetaDataEntry("quality_type")
new_quality_id = old_quality_changes.getId()
# See if the requested quality type is available in the new situation.
machine_definition = self._active_container_stack.getBottom()
quality_manager = QualityManager.getInstance()
candidate_quality = quality_manager.findQualityByQualityType(quality_type,
quality_manager.getWholeMachineDefinition(machine_definition),
[material_container])
if not candidate_quality or candidate_quality.getId() == "empty_quality":
# Fall back to a quality
new_quality = quality_manager.findQualityByQualityType(None,
quality_manager.getWholeMachineDefinition(machine_definition),
[material_container])
if new_quality:
new_quality_id = new_quality.getId()
else:
if not old_quality_changes:
new_quality_id = candidate_quality.getId()
# See if the requested quality type is available in the new situation.
machine_definition = self._active_container_stack.getBottom()
quality_manager = QualityManager.getInstance()
candidate_quality = quality_manager.findQualityByQualityType(quality_type,
quality_manager.getWholeMachineDefinition(machine_definition),
[material_container])
if not candidate_quality or candidate_quality.getId() == "empty_quality":
# Fall back to a quality
new_quality = quality_manager.findQualityByQualityType(None,
quality_manager.getWholeMachineDefinition(machine_definition),
[material_container])
if new_quality:
new_quality_id = new_quality.getId()
else:
if not old_quality_changes:
new_quality_id = candidate_quality.getId()
self.setActiveQuality(new_quality_id)
self.setActiveQuality(new_quality_id)
@pyqtSlot(str)
def setActiveVariant(self, variant_id):
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = variant_id)
if not containers or not self._active_container_stack:
return
Logger.log("d", "Attempting to change the active variant to %s", variant_id)
old_variant = self._active_container_stack.findContainer({"type": "variant"})
old_material = self._active_container_stack.findContainer({"type": "material"})
if old_variant:
self.blurSettings.emit()
variant_index = self._active_container_stack.getContainerIndex(old_variant)
self._active_container_stack.replaceContainer(variant_index, containers[0])
Logger.log("d", "Active variant changed")
preferred_material = None
if old_material:
preferred_material_name = old_material.getName()
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
containers = ContainerRegistry.getInstance().findInstanceContainers(id = variant_id)
if not containers or not self._active_container_stack:
return
Logger.log("d", "Attempting to change the active variant to %s", variant_id)
old_variant = self._active_container_stack.findContainer({"type": "variant"})
old_material = self._active_container_stack.findContainer({"type": "material"})
if old_variant:
self.blurSettings.emit()
variant_index = self._active_container_stack.getContainerIndex(old_variant)
self._active_container_stack.replaceContainer(variant_index, containers[0])
Logger.log("d", "Active variant changed")
preferred_material = None
if old_material:
preferred_material_name = old_material.getName()
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0], preferred_material_name).id)
else:
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0], preferred_material_name).id)
else:
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
## set the active quality
# \param quality_id The quality_id of either a quality or a quality_changes
@pyqtSlot(str)
def setActiveQuality(self, quality_id):
self.blurSettings.emit()
with postponeSignals(*self._getContainerChangedSignals(), compress = True):
self.blurSettings.emit()
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(id = quality_id)
if not containers or not self._global_container_stack:
return
containers = ContainerRegistry.getInstance().findInstanceContainers(id = quality_id)
if not containers or not self._global_container_stack:
return
Logger.log("d", "Attempting to change the active quality to %s", quality_id)
Logger.log("d", "Attempting to change the active quality to %s", quality_id)
# Quality profile come in two flavours: type=quality and type=quality_changes
# If we found a quality_changes profile then look up its parent quality profile.
container_type = containers[0].getMetaDataEntry("type")
quality_name = containers[0].getName()
quality_type = containers[0].getMetaDataEntry("quality_type")
# Quality profile come in two flavours: type=quality and type=quality_changes
# If we found a quality_changes profile then look up its parent quality profile.
container_type = containers[0].getMetaDataEntry("type")
quality_name = containers[0].getName()
quality_type = containers[0].getMetaDataEntry("quality_type")
# Get quality container and optionally the quality_changes container.
if container_type == "quality":
new_quality_settings_list = self.determineQualityAndQualityChangesForQualityType(quality_type)
elif container_type == "quality_changes":
new_quality_settings_list = self._determineQualityAndQualityChangesForQualityChanges(quality_name)
else:
Logger.log("e", "Tried to set quality to a container that is not of the right type")
return
# Get quality container and optionally the quality_changes container.
if container_type == "quality":
new_quality_settings_list = self.determineQualityAndQualityChangesForQualityType(quality_type)
elif container_type == "quality_changes":
new_quality_settings_list = self._determineQualityAndQualityChangesForQualityChanges(quality_name)
else:
Logger.log("e", "Tried to set quality to a container that is not of the right type")
return
name_changed_connect_stacks = [] # Connect these stacks to the name changed callback
for setting_info in new_quality_settings_list:
stack = setting_info["stack"]
stack_quality = setting_info["quality"]
stack_quality_changes = setting_info["quality_changes"]
name_changed_connect_stacks = [] # Connect these stacks to the name changed callback
for setting_info in new_quality_settings_list:
stack = setting_info["stack"]
stack_quality = setting_info["quality"]
stack_quality_changes = setting_info["quality_changes"]
name_changed_connect_stacks.append(stack_quality)
name_changed_connect_stacks.append(stack_quality_changes)
self._replaceQualityOrQualityChangesInStack(stack, stack_quality, postpone_emit = True)
self._replaceQualityOrQualityChangesInStack(stack, stack_quality_changes, postpone_emit = True)
name_changed_connect_stacks.append(stack_quality)
name_changed_connect_stacks.append(stack_quality_changes)
self._replaceQualityOrQualityChangesInStack(stack, stack_quality)
self._replaceQualityOrQualityChangesInStack(stack, stack_quality_changes)
# Send emits that are postponed in replaceContainer.
# Here the stacks are finished replacing and every value can be resolved based on the current state.
for setting_info in new_quality_settings_list:
setting_info["stack"].sendPostponedEmits()
# Send emits that are postponed in replaceContainer.
# Here the stacks are finished replacing and every value can be resolved based on the current state.
for setting_info in new_quality_settings_list:
setting_info["stack"].sendPostponedEmits()
# Connect to onQualityNameChanged
for stack in name_changed_connect_stacks:
stack.nameChanged.connect(self._onQualityNameChanged)
# Connect to onQualityNameChanged
for stack in name_changed_connect_stacks:
stack.nameChanged.connect(self._onQualityNameChanged)
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
self._askUserToKeepOrClearCurrentSettings()
if self.hasUserSettings and Preferences.getInstance().getValue("cura/active_mode") == 1:
self._askUserToKeepOrClearCurrentSettings()
self.activeQualityChanged.emit()
self.activeQualityChanged.emit()
## Determine the quality and quality changes settings for the current machine for a quality name.
#
@ -1057,7 +1072,7 @@ class MachineManager(QObject):
@pyqtSlot(str, str)
def renameMachine(self, machine_id, new_name):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
containers = ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
if containers:
new_name = self._createUniqueName("machine", containers[0].getName(), new_name, containers[0].getBottom().getName())
containers[0].setName(new_name)
@ -1070,13 +1085,13 @@ class MachineManager(QObject):
ExtruderManager.getInstance().removeMachineExtruders(machine_id)
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "user", machine = machine_id)
for container in containers:
UM.Settings.ContainerRegistry.getInstance().removeContainer(container.getId())
UM.Settings.ContainerRegistry.getInstance().removeContainer(machine_id)
ContainerRegistry.getInstance().removeContainer(container.getId())
ContainerRegistry.getInstance().removeContainer(machine_id)
if activate_new_machine:
stacks = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(type = "machine")
stacks = ContainerRegistry.getInstance().findContainerStacks(type = "machine")
if stacks:
Application.getInstance().setGlobalContainerStack(stacks[0])
@ -1117,7 +1132,7 @@ class MachineManager(QObject):
# \returns DefinitionID (string) if found, None otherwise
@pyqtSlot(str, result = str)
def getDefinitionByMachineId(self, machine_id):
containers = UM.Settings.ContainerRegistry.getInstance().findContainerStacks(id=machine_id)
containers = ContainerRegistry.getInstance().findContainerStacks(id=machine_id)
if containers:
return containers[0].getBottom().getId()
@ -1128,13 +1143,13 @@ class MachineManager(QObject):
def _updateVariantContainer(self, definition):
if not definition.getMetaDataEntry("has_variants"):
return self._empty_variant_container
machine_definition_id = UM.Application.getInstance().getMachineManager().getQualityDefinitionId(definition)
machine_definition_id = Application.getInstance().getMachineManager().getQualityDefinitionId(definition)
containers = []
preferred_variant = definition.getMetaDataEntry("preferred_variant")
if preferred_variant:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id, id = preferred_variant)
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id, id = preferred_variant)
if not containers:
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id)
containers = ContainerRegistry.getInstance().findInstanceContainers(type = "variant", definition = machine_definition_id)
if containers:
return containers[0]
@ -1162,23 +1177,23 @@ class MachineManager(QObject):
if preferred_material:
search_criteria["id"] = preferred_material
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
return containers[0]
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if "variant" in search_criteria or "id" in search_criteria:
# If a material by this name can not be found, try a wider set of search criteria
search_criteria.pop("variant", None)
search_criteria.pop("id", None)
containers = UM.Settings.ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
containers = ContainerRegistry.getInstance().findInstanceContainers(**search_criteria)
if containers:
return containers[0]
Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.")
return self._empty_material_container
def _updateQualityContainer(self, definition, variant_container, material_container = None, preferred_quality_name = None):
container_registry = UM.Settings.ContainerRegistry.getInstance()
container_registry = ContainerRegistry.getInstance()
search_criteria = { "type": "quality" }
if definition.getMetaDataEntry("has_machine_quality"):
@ -1261,7 +1276,7 @@ class MachineManager(QObject):
# \param preferred_quality_changes_name The name of the quality-changes to
# pick, if any such quality-changes profile is available.
def _updateQualityChangesContainer(self, quality_type, preferred_quality_changes_name = None):
container_registry = UM.Settings.ContainerRegistry.getInstance() # Cache.
container_registry = ContainerRegistry.getInstance() # Cache.
search_criteria = { "type": "quality_changes" }
search_criteria["quality"] = quality_type
@ -1289,3 +1304,8 @@ class MachineManager(QObject):
def _onQualityNameChanged(self):
self.activeQualityChanged.emit()
def _getContainerChangedSignals(self):
stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
stacks.append(self._global_container_stack)
return [ s.containersChanged for s in stacks ]

View file

@ -7,8 +7,8 @@ import os #For statvfs.
import urllib #To escape machine names for how they're saved to file.
import UM.Resources
import UM.Settings.ContainerRegistry
import UM.Settings.InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer
## Are machine names valid?
#
@ -22,7 +22,7 @@ class MachineNameValidator(QObject):
filename_max_length = os.statvfs(UM.Resources.getDataStoragePath()).f_namemax
except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system.
filename_max_length = 255 #Assume it's Windows on NTFS.
machine_name_max_length = filename_max_length - len("_current_settings.") - len(UM.Settings.ContainerRegistry.getMimeTypeForContainer(UM.Settings.InstanceContainer).preferredSuffix)
machine_name_max_length = filename_max_length - len("_current_settings.") - len(ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix)
# Characters that urllib.parse.quote_plus escapes count for 12! So now
# we must devise a regex that allows only 12 normal characters or 1
# special character, and that up to [machine_name_max_length / 12] times.
@ -45,7 +45,7 @@ class MachineNameValidator(QObject):
except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system.
filename_max_length = 255 #Assume it's Windows on NTFS.
escaped_name = urllib.parse.quote_plus(name)
current_settings_filename = escaped_name + "_current_settings." + UM.Settings.ContainerRegistry.getMimeTypeForContainer(UM.Settings.InstanceContainer).preferredSuffix
current_settings_filename = escaped_name + "_current_settings." + ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix
if len(current_settings_filename) > filename_max_length:
return QValidator.Invalid

View file

@ -1,9 +1,9 @@
# Copyright (c) 2016 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.
import UM.Settings.Models
from UM.Settings.Models.SettingVisibilityHandler import SettingVisibilityHandler
class MaterialSettingsVisibilityHandler(UM.Settings.Models.SettingVisibilityHandler):
class MaterialSettingsVisibilityHandler(SettingVisibilityHandler):
def __init__(self, parent = None, *args, **kwargs):
super().__init__(parent = parent, *args, **kwargs)

View file

@ -38,7 +38,7 @@ class ProfilesModel(InstanceContainersModel):
ProfilesModel.__instance = cls()
return ProfilesModel.__instance
__instance = None
__instance = None # type: "ProfilesModel"
## Fetch the list of containers to display.
#

View file

@ -5,15 +5,14 @@ import collections
from PyQt5.QtCore import pyqtProperty, pyqtSignal, Qt
import UM.Application
import UM.Logger
import UM.Qt
import UM.Settings
from UM.i18n import i18nCatalog
from UM.Application import Application
from UM.Settings.ContainerRegistry import ContainerRegistry
import os
from UM.i18n import i18nCatalog
class QualitySettingsModel(UM.Qt.ListModel.ListModel):
KeyRole = Qt.UserRole + 1
@ -27,7 +26,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel):
def __init__(self, parent = None):
super().__init__(parent = parent)
self._container_registry = UM.Settings.ContainerRegistry.getInstance()
self._container_registry = ContainerRegistry.getInstance()
self._extruder_id = None
self._extruder_definition_id = None
@ -94,7 +93,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel):
items = []
settings = collections.OrderedDict()
definition_container = UM.Application.getInstance().getGlobalContainerStack().getBottom()
definition_container = Application.getInstance().getGlobalContainerStack().getBottom()
containers = self._container_registry.findInstanceContainers(id = self._quality_id)
if not containers:
@ -122,7 +121,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel):
quality_container = quality_container[0]
quality_type = quality_container.getMetaDataEntry("quality_type")
definition_id = UM.Application.getInstance().getMachineManager().getQualityDefinitionId(quality_container.getDefinition())
definition_id = Application.getInstance().getMachineManager().getQualityDefinitionId(quality_container.getDefinition())
definition = quality_container.getDefinition()
# Check if the definition container has a translation file.
@ -169,7 +168,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel):
if self._extruder_definition_id != "":
extruder_definitions = self._container_registry.findDefinitionContainers(id = self._extruder_definition_id)
if extruder_definitions:
criteria["extruder"] = UM.Application.getInstance().getMachineManager().getQualityDefinitionId(extruder_definitions[0])
criteria["extruder"] = Application.getInstance().getMachineManager().getQualityDefinitionId(extruder_definitions[0])
criteria["name"] = quality_changes_container.getName()
else:
criteria["extruder"] = None
@ -178,7 +177,7 @@ class QualitySettingsModel(UM.Qt.ListModel.ListModel):
if changes:
containers.extend(changes)
global_container_stack = UM.Application.getInstance().getGlobalContainerStack()
global_container_stack = Application.getInstance().getGlobalContainerStack()
is_multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
current_category = ""

View file

@ -3,9 +3,7 @@
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
from UM.FlameProfiler import pyqtSlot
import UM.Settings
from UM.Application import Application
import cura.Settings
from UM.Logger import Logger
@ -14,6 +12,12 @@ from UM.Logger import Logger
# because some profiles tend to have 'hardcoded' values that break our inheritance. A good example of that are the
# speed settings. If all the children of print_speed have a single value override, changing the speed won't
# actually do anything, as only the 'leaf' settings are used by the engine.
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.SettingFunction import SettingFunction
from UM.Settings.SettingInstance import InstanceState
from cura.Settings.ExtruderManager import ExtruderManager
class SettingInheritanceManager(QObject):
def __init__(self, parent = None):
super().__init__(parent)
@ -23,7 +27,7 @@ class SettingInheritanceManager(QObject):
self._active_container_stack = None
self._onGlobalContainerChanged()
cura.Settings.ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged)
self._onActiveExtruderChanged()
settingsWithIntheritanceChanged = pyqtSignal()
@ -46,7 +50,7 @@ class SettingInheritanceManager(QObject):
multi_extrusion = self._global_container_stack.getProperty("machine_extruder_count", "value") > 1
if not multi_extrusion:
return self._settings_with_inheritance_warning
extruder = cura.Settings.ExtruderManager.getInstance().getExtruderStack(extruder_index)
extruder = ExtruderManager.getInstance().getExtruderStack(extruder_index)
if not extruder:
Logger.log("w", "Unable to find extruder for current machine with index %s", extruder_index)
return []
@ -73,7 +77,7 @@ class SettingInheritanceManager(QObject):
self._update()
def _onActiveExtruderChanged(self):
new_active_stack = cura.Settings.ExtruderManager.getInstance().getActiveExtruderStack()
new_active_stack = ExtruderManager.getInstance().getActiveExtruderStack()
if not new_active_stack:
new_active_stack = self._global_container_stack
@ -139,14 +143,14 @@ class SettingInheritanceManager(QObject):
return self._settings_with_inheritance_warning
## Check if a setting has an inheritance function that is overwritten
def _settingIsOverwritingInheritance(self, key, stack = None):
def _settingIsOverwritingInheritance(self, key: str, stack: ContainerStack = None) -> bool:
has_setting_function = False
if not stack:
stack = self._active_container_stack
containers = []
## Check if the setting has a user state. If not, it is never overwritten.
has_user_state = stack.getProperty(key, "state") == UM.Settings.InstanceState.User
has_user_state = stack.getProperty(key, "state") == InstanceState.User
if not has_user_state:
return False
@ -155,7 +159,7 @@ class SettingInheritanceManager(QObject):
return False
## Also check if the top container is not a setting function (this happens if the inheritance is restored).
if isinstance(stack.getTop().getProperty(key, "value"), UM.Settings.SettingFunction):
if isinstance(stack.getTop().getProperty(key, "value"), SettingFunction):
return False
## Mash all containers for all the stacks together.
@ -170,7 +174,7 @@ class SettingInheritanceManager(QObject):
continue
if value is not None:
# If a setting doesn't use any keys, it won't change it's value, so treat it as if it's a fixed value
has_setting_function = isinstance(value, UM.Settings.SettingFunction)
has_setting_function = isinstance(value, SettingFunction)
if has_setting_function:
for setting_key in value.getUsedSettingKeys():
if setting_key in self._active_container_stack.getAllKeys():

View file

@ -10,10 +10,10 @@ from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Logger
import cura.Settings
from UM.Application import Application
from cura.Settings.ExtruderManager import ExtruderManager
## A decorator that adds a container stack to a Node. This stack should be queried for all settings regarding
# the linked node. The Stack in question will refer to the global stack (so that settings that are not defined by
# this stack still resolve.
@ -29,8 +29,8 @@ class SettingOverrideDecorator(SceneNodeDecorator):
self._instance = InstanceContainer(container_id = "SettingOverrideInstanceContainer")
self._stack.addContainer(self._instance)
if cura.Settings.ExtruderManager.getInstance().extruderCount > 1:
self._extruder_stack = cura.Settings.ExtruderManager.getInstance().getExtruderStack(0).getId()
if ExtruderManager.getInstance().extruderCount > 1:
self._extruder_stack = ExtruderManager.getInstance().getExtruderStack(0).getId()
else:
self._extruder_stack = None

View file

@ -1,18 +1,2 @@
# Copyright (c) 2016 Ultimaker B.V.
# Cura is released under the terms of the AGPLv3 or higher.
from .MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from .ContainerManager import ContainerManager
from .ContainerSettingsModel import ContainerSettingsModel
from .CuraContainerRegistry import CuraContainerRegistry
from .ExtruderManager import ExtruderManager
from .ExtrudersModel import ExtrudersModel
from .MachineManager import MachineManager
from .MachineNameValidator import MachineNameValidator
from .MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
from .SettingOverrideDecorator import SettingOverrideDecorator
from .QualitySettingsModel import QualitySettingsModel
from .SettingInheritanceManager import SettingInheritanceManager
from .ProfilesModel import ProfilesModel
from .QualityAndUserProfilesModel import QualityAndUserProfilesModel
from .UserProfilesModel import UserProfilesModel