mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 11:14:21 +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.UserProfilesModel import UserProfilesModel
|
||||||
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
|
|
||||||
|
from cura.Machines.VariantManager import VariantManager
|
||||||
|
|
||||||
|
|
||||||
from . import PlatformPhysics
|
from . import PlatformPhysics
|
||||||
from . import BuildVolume
|
from . import BuildVolume
|
||||||
@ -233,6 +235,9 @@ class CuraApplication(QtApplication):
|
|||||||
if kwargs["parsed_command_line"].get("trigger_early_crash", False):
|
if kwargs["parsed_command_line"].get("trigger_early_crash", False):
|
||||||
assert not "This crash is triggered by the trigger_early_crash command line argument."
|
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.default_theme = "cura-light"
|
||||||
|
|
||||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||||
@ -707,6 +712,9 @@ class CuraApplication(QtApplication):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def getVariantManager(self):
|
||||||
|
return self._variant_manager
|
||||||
|
|
||||||
def preRun(self):
|
def preRun(self):
|
||||||
# Last check for unknown commandline arguments
|
# Last check for unknown commandline arguments
|
||||||
parser = self.getCommandlineParser()
|
parser = self.getCommandlineParser()
|
||||||
@ -723,6 +731,9 @@ class CuraApplication(QtApplication):
|
|||||||
def run(self):
|
def run(self):
|
||||||
self.preRun()
|
self.preRun()
|
||||||
|
|
||||||
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
self._variant_manager.initialize()
|
||||||
|
|
||||||
# Check if we should run as single instance or not
|
# Check if we should run as single instance or not
|
||||||
self._setUpSingleInstanceServer()
|
self._setUpSingleInstanceServer()
|
||||||
|
|
||||||
|
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 = ExtruderManager.getInstance().getActiveExtruderStacks()
|
||||||
stacks.append(self._global_container_stack)
|
stacks.append(self._global_container_stack)
|
||||||
return [ s.containersChanged for s in stacks ]
|
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:
|
if buildplate_id is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(
|
from cura.Machines.VariantManager import VariantType
|
||||||
id = buildplate_id)
|
variant_manager = CuraApplication.getInstance().getVariantManager()
|
||||||
if not variant_containers:
|
variant_node = variant_manager.getVariant(machine_id, VariantType.BUILD_PLATE, buildplate_id)
|
||||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
if not variant_node:
|
||||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(
|
|
||||||
definition = machine_id, name = buildplate_id)
|
|
||||||
|
|
||||||
if not variant_containers:
|
|
||||||
continue
|
continue
|
||||||
|
variant_metadata = variant_node.metadata
|
||||||
|
|
||||||
|
# TODO: check if build plate variant exists
|
||||||
|
|
||||||
buildplate_compatibility = machine_compatibility
|
buildplate_compatibility = machine_compatibility
|
||||||
buildplate_recommended = machine_compatibility
|
buildplate_recommended = machine_compatibility
|
||||||
@ -623,6 +622,11 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
if hotend_name is None:
|
if hotend_name is None:
|
||||||
continue
|
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_compatibility = machine_compatibility
|
||||||
hotend_setting_values = {}
|
hotend_setting_values = {}
|
||||||
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
settings = hotend.iterfind("./um:setting", self.__namespaces)
|
||||||
|
@ -29,38 +29,33 @@ Menu
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem
|
// TODO: single instance??
|
||||||
|
Cura.NozzleModel
|
||||||
{
|
{
|
||||||
id: automaticNozzle
|
id: nozzleModel
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
Instantiator
|
||||||
{
|
{
|
||||||
id: nozzleInstantiator
|
id: nozzleInstantiator
|
||||||
@ -96,7 +91,7 @@ Menu
|
|||||||
}
|
}
|
||||||
onObjectAdded: menu.insertItem(index, object)
|
onObjectAdded: menu.insertItem(index, object)
|
||||||
onObjectRemoved: menu.removeItem(object)
|
onObjectRemoved: menu.removeItem(object)
|
||||||
}
|
} */
|
||||||
|
|
||||||
ExclusiveGroup { id: group }
|
ExclusiveGroup { id: group }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user