mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 03:04:23 +08:00
WIP: Create VariantManager
This commit is contained in:
parent
86eb9b925f
commit
55bdc0c853
@ -59,6 +59,8 @@ from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||
from cura.Settings.UserProfilesModel import UserProfilesModel
|
||||
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||
|
||||
from cura.Machines.VariantManager import VariantManager
|
||||
|
||||
|
||||
from . import PlatformPhysics
|
||||
from . import BuildVolume
|
||||
@ -233,6 +235,9 @@ class CuraApplication(QtApplication):
|
||||
if kwargs["parsed_command_line"].get("trigger_early_crash", False):
|
||||
assert not "This crash is triggered by the trigger_early_crash command line argument."
|
||||
|
||||
# new stuff
|
||||
self._variant_manager = VariantManager(ContainerRegistry.getInstance())
|
||||
|
||||
self.default_theme = "cura-light"
|
||||
|
||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||
@ -707,6 +712,9 @@ class CuraApplication(QtApplication):
|
||||
return False
|
||||
return True
|
||||
|
||||
def getVariantManager(self):
|
||||
return self._variant_manager
|
||||
|
||||
def preRun(self):
|
||||
# Last check for unknown commandline arguments
|
||||
parser = self.getCommandlineParser()
|
||||
@ -723,6 +731,9 @@ class CuraApplication(QtApplication):
|
||||
def run(self):
|
||||
self.preRun()
|
||||
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
self._variant_manager.initialize()
|
||||
|
||||
# Check if we should run as single instance or not
|
||||
self._setUpSingleInstanceServer()
|
||||
|
||||
|
34
cura/Machines/ContainerNode.py
Normal file
34
cura/Machines/ContainerNode.py
Normal file
@ -0,0 +1,34 @@
|
||||
from typing import Optional
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from UM.Logger import Logger
|
||||
|
||||
|
||||
## A metadata / container combination. Use getContainer to get the container corresponding to the metadata
|
||||
class ContainerNode:
|
||||
def __init__(self, metadata = None):
|
||||
self.metadata = metadata
|
||||
self.container = None
|
||||
self.children_map = OrderedDict()
|
||||
|
||||
def getChildNode(self, child_key: str) -> Optional["QualityNode"]:
|
||||
return self.children_map.get(child_key)
|
||||
|
||||
def getContainer(self) -> "InstanceContainer":
|
||||
if self.metadata is None:
|
||||
raise RuntimeError("Cannot get container for a QualityNode without metadata")
|
||||
|
||||
if self.container is None:
|
||||
container_id = self.metadata["id"]
|
||||
Logger.log("d", "Lazy-loading container [%s]", container_id)
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
container_list = ContainerRegistry.getInstance().findInstanceContainers(id = container_id)
|
||||
if not container_list:
|
||||
raise RuntimeError("Failed to lazy-load container [%s], cannot find it" % container_id)
|
||||
self.container = container_list[0]
|
||||
|
||||
return self.container
|
||||
|
||||
def __str__(self):
|
||||
return "ContainerNode[%s]" % self.metadata.get("id")
|
81
cura/Machines/VariantManager.py
Normal file
81
cura/Machines/VariantManager.py
Normal file
@ -0,0 +1,81 @@
|
||||
from typing import Optional
|
||||
|
||||
from UM.Logger import Logger
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
|
||||
from cura.Machines.ContainerNode import ContainerNode
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
|
||||
|
||||
class VariantType:
|
||||
BUILD_PLATE = "buildplate"
|
||||
NOZZLE = "nozzle"
|
||||
|
||||
|
||||
ALL_VARIANT_TYPES = (VariantType.BUILD_PLATE, VariantType.NOZZLE)
|
||||
|
||||
|
||||
#
|
||||
# VariantManager is THE place to look for a specific variant. It maintains a variant lookup table with the following
|
||||
# structure:
|
||||
#
|
||||
# [machine_definition_id] -> [variant_type] -> [variant_name] -> ContainerNode(metadata / container)
|
||||
# Example: "ultimaker3" -> "buildplate" -> "Glass" (if present) -> ContainerNode
|
||||
# -> ...
|
||||
# -> "nozzle" -> "AA 0.4"
|
||||
# -> "BB 0.8"
|
||||
# -> ...
|
||||
#
|
||||
# Note that the "container" field is not loaded in the beginning because it would defeat the purpose of lazy-loading.
|
||||
# A container is loaded when getVariant() is called to load a variant InstanceContainer.
|
||||
#
|
||||
class VariantManager:
|
||||
|
||||
def __init__(self, container_registry):
|
||||
self._container_registry = container_registry # type: ContainerRegistry
|
||||
|
||||
self._machine_to_variant_dict_map = {} # <machine_type> -> <variant_dict>
|
||||
|
||||
self._exclude_variant_id_list = ["empty_variant"]
|
||||
|
||||
#
|
||||
# Initializes the VariantManager including:
|
||||
# - initializing the variant lookup table based on the metadata in ContainerRegistry.
|
||||
#
|
||||
def initialize(self):
|
||||
# Cache all variants from the container registry to a variant map for better searching and organization.
|
||||
variant_metadata_list = self._container_registry.findContainersMetadata(type = "variant")
|
||||
for variant_metadata in variant_metadata_list:
|
||||
if variant_metadata["id"] in self._exclude_variant_id_list:
|
||||
Logger.log("d", "Exclude variant [%s]", variant_metadata["id"])
|
||||
continue
|
||||
|
||||
variant_name = variant_metadata["name"]
|
||||
variant_definition = variant_metadata["definition"]
|
||||
if variant_definition not in self._machine_to_variant_dict_map:
|
||||
self._machine_to_variant_dict_map[variant_definition] = {}
|
||||
#for variant_type in ALL_VARIANT_TYPES:
|
||||
# self._machine_to_variant_dict_map[variant_definition][variant_type] = {}
|
||||
|
||||
variant_type = variant_metadata["hardware_type"]
|
||||
#variant_dict = self._machine_to_variant_dict_map[variant_definition][variant_type]
|
||||
variant_dict = self._machine_to_variant_dict_map[variant_definition]
|
||||
if variant_name in variant_dict:
|
||||
# ERROR: duplicated variant name.
|
||||
raise RuntimeError("Found duplicated variant name [%s], type [%s] for machine [%s]" %
|
||||
(variant_name, variant_type, variant_definition))
|
||||
|
||||
variant_dict[variant_name] = ContainerNode(metadata = variant_metadata)
|
||||
|
||||
#
|
||||
# Gets the variant InstanceContainer with the given information.
|
||||
# Almost the same as getVariantMetadata() except that this returns an InstanceContainer if present.
|
||||
#
|
||||
def getVariant(self, machine_type_name: str, variant_name: str,
|
||||
variant_type: Optional[str] = None) -> Optional["InstanceContainer"]:
|
||||
return self._machine_to_variant_dict_map[machine_type_name].get(variant_name)
|
||||
|
||||
def getVariantNodes(self, machine: "GlobalStack"):
|
||||
machine_type_name = machine.definition.getId()
|
||||
return self._machine_to_variant_dict_map.get(machine_type_name)
|
0
cura/Machines/__init__.py
Normal file
0
cura/Machines/__init__.py
Normal file
@ -1490,3 +1490,23 @@ class MachineManager(QObject):
|
||||
stacks = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||
stacks.append(self._global_container_stack)
|
||||
return [ s.containersChanged for s in stacks ]
|
||||
|
||||
# New
|
||||
@pyqtSlot(str, "QVariant")
|
||||
def setVariantGroup(self, position, container_node):
|
||||
Logger.log("d", "---------------- container = [%s]", container_node)
|
||||
position = str(position)
|
||||
self.blurSettings.emit()
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||
self._global_container_stack.extruders[position].variant = container_node.getContainer()
|
||||
|
||||
@pyqtSlot("QVariant")
|
||||
def handleQualityGroup(self, quality_group):
|
||||
Logger.log("d", "---------------- qg = [%s]", quality_group.name)
|
||||
self.blurSettings.emit()
|
||||
with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue):
|
||||
self._global_container_stack.quality = quality_group.node_for_global.getContainer()
|
||||
self._global_container_stack.qualityChanges = self._empty_quality_changes_container
|
||||
for position, node in quality_group.nodes_for_extruders.items():
|
||||
self._global_container_stack.extruders[position].quality = node.getContainer()
|
||||
self._global_container_stack.extruders[position].qualityChanges = self._empty_quality_changes_container
|
||||
|
47
cura/Settings/NozzleModel.py
Normal file
47
cura/Settings/NozzleModel.py
Normal file
@ -0,0 +1,47 @@
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Qt.ListModel import ListModel
|
||||
|
||||
|
||||
class NozzleModel(ListModel):
|
||||
IdRole = Qt.UserRole + 1
|
||||
HotendNameRole = Qt.UserRole + 2
|
||||
ContainerNodeRole = Qt.UserRole + 3
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.addRoleName(self.IdRole, "id")
|
||||
self.addRoleName(self.HotendNameRole, "hotend_name")
|
||||
self.addRoleName(self.ContainerNodeRole, "container_node")
|
||||
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._update)
|
||||
Application.getInstance().getMachineManager().activeVariantChanged.connect(self._update)
|
||||
Application.getInstance().getMachineManager().activeStackChanged.connect(self._update)
|
||||
Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._update)
|
||||
|
||||
def _update(self):
|
||||
self.items.clear()
|
||||
|
||||
variant_manager = Application.getInstance()._variant_manager
|
||||
active_global_stack = Application.getInstance().getMachineManager()._global_container_stack
|
||||
if active_global_stack is None:
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
variant_group_dict = variant_manager.getVariantNodes(active_global_stack)
|
||||
if not variant_group_dict:
|
||||
self.setItems([])
|
||||
return
|
||||
|
||||
item_list = []
|
||||
for hotend_name, container_node in sorted(variant_group_dict.items(), key = lambda i: i[0]):
|
||||
item = {"id": hotend_name,
|
||||
"hotend_name": hotend_name,
|
||||
"container_node": container_node
|
||||
}
|
||||
|
||||
item_list.append(item)
|
||||
|
||||
self.setItems(item_list)
|
@ -590,15 +590,14 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
if buildplate_id is None:
|
||||
continue
|
||||
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(
|
||||
id = buildplate_id)
|
||||
if not variant_containers:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(
|
||||
definition = machine_id, name = buildplate_id)
|
||||
|
||||
if not variant_containers:
|
||||
from cura.Machines.VariantManager import VariantType
|
||||
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||
variant_node = variant_manager.getVariant(machine_id, VariantType.BUILD_PLATE, buildplate_id)
|
||||
if not variant_node:
|
||||
continue
|
||||
variant_metadata = variant_node.metadata
|
||||
|
||||
# TODO: check if build plate variant exists
|
||||
|
||||
buildplate_compatibility = machine_compatibility
|
||||
buildplate_recommended = machine_compatibility
|
||||
@ -623,6 +622,11 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
if hotend_name is None:
|
||||
continue
|
||||
|
||||
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||
variant_node = variant_manager.getVariant(machine_id, hotend_name)
|
||||
if not variant_node:
|
||||
continue
|
||||
|
||||
hotend_compatibility = machine_compatibility
|
||||
hotend_setting_values = {}
|
||||
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
||||
|
@ -29,38 +29,33 @@ Menu
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuItem
|
||||
// TODO: single instance??
|
||||
Cura.NozzleModel
|
||||
{
|
||||
id: automaticNozzle
|
||||
text:
|
||||
{
|
||||
if(visible)
|
||||
{
|
||||
var nozzleName = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex];
|
||||
return catalog.i18nc("@title:menuitem %1 is the nozzle currently loaded in the printer", "Automatic: %1").arg(nozzleName);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
visible: printerConnected && Cura.MachineManager.printerOutputDevices[0].hotendIds != undefined && Cura.MachineManager.printerOutputDevices[0].hotendIds.length > extruderIndex && !isClusterPrinter
|
||||
onTriggered:
|
||||
{
|
||||
var activeExtruderIndex = Cura.ExtruderManager.activeExtruderIndex;
|
||||
Cura.ExtruderManager.setActiveExtruderIndex(extruderIndex);
|
||||
var hotendId = Cura.MachineManager.printerOutputDevices[0].hotendIds[extruderIndex];
|
||||
var itemIndex = nozzleInstantiator.model.find("name", hotendId);
|
||||
if(itemIndex > -1)
|
||||
{
|
||||
Cura.MachineManager.setActiveVariant(nozzleInstantiator.model.getItem(itemIndex).id);
|
||||
}
|
||||
Cura.ExtruderManager.setActiveExtruderIndex(activeExtruderIndex);
|
||||
}
|
||||
id: nozzleModel
|
||||
}
|
||||
|
||||
MenuSeparator
|
||||
Instantiator
|
||||
{
|
||||
visible: automaticNozzle.visible
|
||||
}
|
||||
model: nozzleModel
|
||||
|
||||
MenuItem
|
||||
{
|
||||
text: model.hotend_name
|
||||
checkable: true
|
||||
checked: Cura.MachineManager.activeVariantId == model.hotend_name
|
||||
exclusiveGroup: group
|
||||
onTriggered: {
|
||||
var position = Cura.ExtruderManager.activeExtruderIndex;
|
||||
Cura.MachineManager.setVariantGroup(position, model.container_node);
|
||||
}
|
||||
visible: true
|
||||
}
|
||||
|
||||
onObjectAdded: menu.insertItem(index, object);
|
||||
onObjectRemoved: menu.removeItem(object);
|
||||
}
|
||||
/*
|
||||
Instantiator
|
||||
{
|
||||
id: nozzleInstantiator
|
||||
@ -96,7 +91,7 @@ Menu
|
||||
}
|
||||
onObjectAdded: menu.insertItem(index, object)
|
||||
onObjectRemoved: menu.removeItem(object)
|
||||
}
|
||||
} */
|
||||
|
||||
ExclusiveGroup { id: group }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user