mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-08 07:27:29 -06:00

Should be completely transparent. It'll fail the unit tests though because it now pretends that all printers have machine nodes. Contributes to issue CURA-6793.
126 lines
No EOL
6.5 KiB
Python
126 lines
No EOL
6.5 KiB
Python
# Copyright (c) 2019 Ultimaker B.V.
|
|
# Cura is released under the terms of the LGPLv3 or higher.
|
|
|
|
from UM.Logger import Logger
|
|
from UM.Settings.ContainerRegistry import ContainerRegistry # To listen to containers being added.
|
|
from UM.Signal import Signal
|
|
import cura.CuraApplication # Imported like this to prevent circular dependencies.
|
|
from cura.Machines.MachineNode import MachineNode
|
|
from cura.Settings.GlobalStack import GlobalStack # To listen only to global stacks being added.
|
|
|
|
from typing import Dict, List, TYPE_CHECKING
|
|
import time
|
|
|
|
if TYPE_CHECKING:
|
|
from cura.Machines.QualityGroup import QualityGroup
|
|
from cura.Machines.QualityChangesGroup import QualityChangesGroup
|
|
|
|
|
|
## This class contains a look-up tree for which containers are available at
|
|
# which stages of configuration.
|
|
#
|
|
# The tree starts at the machine definitions. For every distinct definition
|
|
# there will be one machine node here.
|
|
#
|
|
# All of the fallbacks for material choices, quality choices, etc. should be
|
|
# encoded in this tree. There must always be at least one child node (for
|
|
# nodes that have children) but that child node may be a node representing the
|
|
# empty instance container.
|
|
class ContainerTree:
|
|
__instance = None
|
|
|
|
@classmethod
|
|
def getInstance(cls):
|
|
if cls.__instance is None:
|
|
cls.__instance = ContainerTree()
|
|
return cls.__instance
|
|
|
|
def __init__(self) -> None:
|
|
self.machines = self.MachineNodeMap() # Mapping from definition ID to machine nodes with lazy loading.
|
|
self.materialsChanged = Signal() # Emitted when any of the material nodes in the tree got changed.
|
|
|
|
## Get the quality groups available for the currently activated printer.
|
|
#
|
|
# This contains all quality groups, enabled or disabled. To check whether
|
|
# the quality group can be activated, test for the
|
|
# ``QualityGroup.is_available`` property.
|
|
# \return For every quality type, one quality group.
|
|
def getCurrentQualityGroups(self) -> Dict[str, "QualityGroup"]:
|
|
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
|
if global_stack is None:
|
|
return {}
|
|
variant_names = [extruder.variant.getName() for extruder in global_stack.extruderList]
|
|
material_bases = [extruder.material.getMetaDataEntry("base_file") for extruder in global_stack.extruderList]
|
|
extruder_enabled = [extruder.isEnabled for extruder in global_stack.extruderList]
|
|
return self.machines[global_stack.definition.getId()].getQualityGroups(variant_names, material_bases, extruder_enabled)
|
|
|
|
## Get the quality changes groups available for the currently activated
|
|
# printer.
|
|
#
|
|
# This contains all quality changes groups, enabled or disabled. To check
|
|
# whether the quality changes group can be activated, test for the
|
|
# ``QualityChangesGroup.is_available`` property.
|
|
# \return A list of all quality changes groups.
|
|
def getCurrentQualityChangesGroups(self) -> List["QualityChangesGroup"]:
|
|
global_stack = cura.CuraApplication.CuraApplication.getInstance().getGlobalContainerStack()
|
|
if global_stack is None:
|
|
return []
|
|
variant_names = [extruder.variant.getName() for extruder in global_stack.extruderList]
|
|
material_bases = [extruder.material.getMetaDataEntry("base_file") for extruder in global_stack.extruderList]
|
|
extruder_enabled = [extruder.isEnabled for extruder in global_stack.extruderList]
|
|
return self.machines[global_stack.definition.getId()].getQualityChangesGroups(variant_names, material_bases, extruder_enabled)
|
|
|
|
## Builds the initial container tree.
|
|
def _loadAll(self):
|
|
Logger.log("i", "Building container tree.")
|
|
start_time = time.time()
|
|
all_stacks = ContainerRegistry.getInstance().findContainerStacks()
|
|
for stack in all_stacks:
|
|
if not isinstance(stack, GlobalStack):
|
|
continue # Only want to load global stacks. We don't need to create a tree for extruder definitions.
|
|
_ = self.machines[stack.definition.getId()] # TODO: Load this lazily.
|
|
|
|
Logger.log("d", "Building the container tree took %s seconds", time.time() - start_time)
|
|
|
|
## For debugging purposes, visualise the entire container tree as it stands
|
|
# now.
|
|
def _visualise_tree(self) -> str:
|
|
lines = ["% CONTAINER TREE"] # Start with array and then combine into string, for performance.
|
|
for machine in self.machines.machines.values():
|
|
lines.append(" # " + machine.container_id)
|
|
for variant in machine.variants.values():
|
|
lines.append(" * " + variant.container_id)
|
|
for material in variant.materials.values():
|
|
lines.append(" + " + material.container_id)
|
|
for quality in material.qualities.values():
|
|
lines.append(" - " + quality.container_id)
|
|
for intent in quality.intents.values():
|
|
lines.append(" . " + intent.container_id)
|
|
return "\n".join(lines)
|
|
|
|
## Dictionary-like object that contains the machines.
|
|
#
|
|
# This handles the lazy loading of MachineNodes.
|
|
class MachineNodeMap:
|
|
def __init__(self):
|
|
self.machines = {}
|
|
|
|
## Returns whether a printer with a certain definition ID exists. This
|
|
# is regardless of whether or not the printer is loaded yet.
|
|
# \param definition_id The definition to look for.
|
|
# \return Whether or not a printer definition exists with that name.
|
|
def __contains__(self, definition_id: str) -> bool:
|
|
return len(ContainerRegistry.getInstance().findInstanceContainersMetadata(id = definition_id)) == 0
|
|
|
|
## Returns a machine node for the specified definition ID.
|
|
#
|
|
# If the machine node wasn't loaded yet, this will load it lazily.
|
|
# \param definition_id The definition to look for.
|
|
# \return A machine node for that definition.
|
|
def __getitem__(self, definition_id: str) -> MachineNode:
|
|
if definition_id not in self.machines:
|
|
start_time = time.time()
|
|
self.machines[definition_id] = MachineNode(definition_id)
|
|
self.machines[definition_id].materialsChanged.connect(ContainerTree.getInstance().materialsChanged)
|
|
Logger.log("d", "Adding container tree for {definition_id} took {duration} seconds.".format(definition_id = definition_id, duration = time.time() - start_time))
|
|
return self.machines[definition_id] |