mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-23 14:19:37 +08:00
Merge branch 'feature_intent_container_tree' into feature_intent_upgrade
This commit is contained in:
commit
8d21f75c40
@ -287,7 +287,8 @@ class MaterialManager(QObject):
|
||||
if root_material_id is not None:
|
||||
self.removeMaterialByRootId(root_material_id)
|
||||
|
||||
def duplicateMaterialByRootId(self, root_material_id, new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
|
||||
def duplicateMaterialByRootId(self, root_material_id: str, new_base_id: Optional[str] = None,
|
||||
new_metadata: Optional[Dict[str, Any]] = None) -> Optional[str]:
|
||||
container_registry = CuraContainerRegistry.getInstance()
|
||||
results = container_registry.findContainers(id=root_material_id)
|
||||
|
||||
@ -346,12 +347,14 @@ class MaterialManager(QObject):
|
||||
# Returns the root material ID of the duplicated material if successful.
|
||||
#
|
||||
@pyqtSlot("QVariant", result = str)
|
||||
def duplicateMaterial(self, material_node: MaterialNode, new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
|
||||
def duplicateMaterial(self, material_node: MaterialNode, new_base_id: Optional[str] = None,
|
||||
new_metadata: Optional[Dict[str, Any]] = None) -> str:
|
||||
if material_node.container is None:
|
||||
Logger.log("e", "Material node {0} doesn't have container.".format(material_node.container_id))
|
||||
return "ERROR"
|
||||
root_material_id = cast(str, material_node.container.getMetaDataEntry("base_file", ""))
|
||||
return self.duplicateMaterialByRootId(root_material_id, new_base_id, new_metadata)
|
||||
new_material_id = self.duplicateMaterialByRootId(root_material_id, new_base_id, new_metadata)
|
||||
return new_material_id if new_material_id is not None else "ERROR"
|
||||
|
||||
# Create a new material by cloning Generic PLA for the current material diameter and generate a new GUID.
|
||||
# Returns the ID of the newly created material.
|
||||
|
@ -74,6 +74,8 @@ class IntentModel(ListModel):
|
||||
active_material_node = active_variant_node.materials[active_extruder.material.getMetaDataEntry("base_file")]
|
||||
layer_heights_added = []
|
||||
for quality_id, quality_node in active_material_node.qualities.items():
|
||||
if quality_node.quality_type not in quality_groups: # Don't add the empty quality type (or anything else that would crash, defensively).
|
||||
continue
|
||||
quality_group = quality_groups[quality_node.quality_type]
|
||||
layer_height = self._fetchLayerHeight(quality_group)
|
||||
|
||||
|
@ -12,7 +12,7 @@ import cura.CuraApplication # Imported this way to prevent circular dependencie
|
||||
from cura.Machines.ContainerTree import ContainerTree
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from cura.Machines import QualityGroup
|
||||
from cura.Machines.QualityGroup import QualityGroup
|
||||
|
||||
|
||||
#
|
||||
|
@ -87,14 +87,15 @@ class ContainerManager(QObject):
|
||||
Logger.log("w", "Container node {0} doesn't have a container.".format(container_node.container_id))
|
||||
return False
|
||||
root_material_id = container_node.container.getMetaDataEntry("base_file", "")
|
||||
if cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry().isReadOnly(root_material_id):
|
||||
container_registry = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry()
|
||||
if container_registry.isReadOnly(root_material_id):
|
||||
Logger.log("w", "Cannot set metadata of read-only container %s.", root_material_id)
|
||||
return False
|
||||
|
||||
material_group = MaterialManager.getInstance().getMaterialGroup(root_material_id)
|
||||
if material_group is None:
|
||||
Logger.log("w", "Unable to find material group for: %s.", root_material_id)
|
||||
root_material_query = container_registry.findContainers(id = root_material_id)
|
||||
if not root_material_query:
|
||||
Logger.log("w", "Unable to find root material: {root_material}.".format(root_material = root_material_id))
|
||||
return False
|
||||
root_material = root_material_query[0]
|
||||
|
||||
entries = entry_name.split("/")
|
||||
entry_name = entries.pop()
|
||||
@ -102,7 +103,7 @@ class ContainerManager(QObject):
|
||||
sub_item_changed = False
|
||||
if entries:
|
||||
root_name = entries.pop(0)
|
||||
root = material_group.root_material_node.container.getMetaDataEntry(root_name)
|
||||
root = root_material.getMetaDataEntry(root_name)
|
||||
|
||||
item = root
|
||||
for _ in range(len(entries)):
|
||||
@ -115,11 +116,9 @@ class ContainerManager(QObject):
|
||||
entry_name = root_name
|
||||
entry_value = root
|
||||
|
||||
container = material_group.root_material_node.container
|
||||
if container is not None:
|
||||
container.setMetaDataEntry(entry_name, entry_value)
|
||||
if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed.
|
||||
container.metaDataChanged.emit(container)
|
||||
root_material.setMetaDataEntry(entry_name, entry_value)
|
||||
if sub_item_changed: #If it was only a sub-item that has changed then the setMetaDataEntry won't correctly notice that something changed, and we must manually signal that the metadata changed.
|
||||
root_material.metaDataChanged.emit(root_material)
|
||||
return True
|
||||
|
||||
@pyqtSlot(str, result = str)
|
||||
@ -355,11 +354,11 @@ class ContainerManager(QObject):
|
||||
if material_node.container is None:
|
||||
Logger.log("w", "Material node {0} doesn't have a container.".format(material_node.container_id))
|
||||
return
|
||||
material_group = MaterialManager.getInstance().getMaterialGroup(material_node.container.getMetaDataEntry("base_file", ""))
|
||||
|
||||
if material_group is None:
|
||||
root_material_query = cura.CuraApplication.CuraApplication.getInstance().getContainerRegistry().findInstanceContainers(id = material_node.getMetaDataEntry("base_file", ""))
|
||||
if not root_material_query:
|
||||
Logger.log("w", "Unable to find material group for %s", material_node)
|
||||
return
|
||||
root_material = root_material_query[0]
|
||||
|
||||
# Generate a new GUID
|
||||
new_guid = str(uuid.uuid4())
|
||||
@ -367,9 +366,7 @@ class ContainerManager(QObject):
|
||||
# Update the GUID
|
||||
# NOTE: We only need to set the root material container because XmlMaterialProfile.setMetaDataEntry() will
|
||||
# take care of the derived containers too
|
||||
container = material_group.root_material_node.container
|
||||
if container is not None:
|
||||
container.setMetaDataEntry("GUID", new_guid)
|
||||
root_material.setMetaDataEntry("GUID", new_guid)
|
||||
|
||||
def _performMerge(self, merge_into: InstanceContainer, merge: InstanceContainer, clear_settings: bool = True) -> None:
|
||||
if merge == merge_into:
|
||||
|
@ -25,6 +25,9 @@ EMPTY_MATERIAL_CONTAINER_ID = "empty_material"
|
||||
empty_material_container = copy.deepcopy(empty_container)
|
||||
empty_material_container.setMetaDataEntry("id", EMPTY_MATERIAL_CONTAINER_ID)
|
||||
empty_material_container.setMetaDataEntry("type", "material")
|
||||
empty_material_container.setMetaDataEntry("base_file", "empty_material")
|
||||
empty_material_container.setMetaDataEntry("GUID", "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
|
||||
empty_material_container.setMetaDataEntry("material", "empty")
|
||||
|
||||
# Empty quality
|
||||
EMPTY_QUALITY_CONTAINER_ID = "empty_quality"
|
||||
|
@ -942,7 +942,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
extruder_info = self._machine_info.extruder_info_dict[position]
|
||||
if extruder_info.variant_info is None:
|
||||
# If there is no variant_info, try to use the default variant. Otherwise, leave it be.
|
||||
node = variant_manager.getDefaultVariantNode(global_stack.definition, VariantType.NOZZLE, global_stack)
|
||||
machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()]
|
||||
node = machine_node.variants[machine_node.preferred_variant_name]
|
||||
if node is not None and node.container is not None:
|
||||
extruder_stack.variant = node.container
|
||||
continue
|
||||
@ -951,7 +952,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||
variant_name = parser["general"]["name"]
|
||||
variant_type = VariantType.NOZZLE
|
||||
|
||||
node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type)
|
||||
node = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[variant_name]
|
||||
if node is not None and node.container is not None:
|
||||
extruder_stack.variant = node.container
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Copyright (c) 2018 Ultimaker B.V.
|
||||
#Copyright (c) 2019 Ultimaker B.V.
|
||||
#Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import cast
|
||||
@ -7,13 +7,13 @@ from Charon.VirtualFile import VirtualFile #To open UFP files.
|
||||
from Charon.OpenMode import OpenMode #To indicate that we want to write to UFP files.
|
||||
from io import StringIO #For converting g-code to bytes.
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.Mesh.MeshWriter import MeshWriter #The writer we need to implement.
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
from UM.PluginRegistry import PluginRegistry #To get the g-code writer.
|
||||
from PyQt5.QtCore import QBuffer
|
||||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Snapshot import Snapshot
|
||||
from cura.Utils.Threading import call_on_qt_thread
|
||||
|
||||
@ -79,9 +79,9 @@ class UFPWriter(MeshWriter):
|
||||
Logger.log("d", "Thumbnail not created, cannot save it")
|
||||
|
||||
# Store the material.
|
||||
application = Application.getInstance()
|
||||
application = CuraApplication.getInstance()
|
||||
machine_manager = application.getMachineManager()
|
||||
material_manager = application.getMaterialManager()
|
||||
container_registry = application.getContainerRegistry()
|
||||
global_stack = machine_manager.activeMachine
|
||||
|
||||
material_extension = "xml.fdm_material"
|
||||
@ -107,12 +107,12 @@ class UFPWriter(MeshWriter):
|
||||
continue
|
||||
|
||||
material_root_id = material.getMetaDataEntry("base_file")
|
||||
material_group = material_manager.getMaterialGroup(material_root_id)
|
||||
if material_group is None:
|
||||
Logger.log("e", "Cannot find material container with root id [%s]", material_root_id)
|
||||
material_root_query = container_registry.findContainers(id = material_root_id)
|
||||
if not material_root_query:
|
||||
Logger.log("e", "Cannot find material container with root id {root_id}".format(root_id = material_root_id))
|
||||
return False
|
||||
material_container = material_root_query[0]
|
||||
|
||||
material_container = material_group.root_material_node.container
|
||||
try:
|
||||
serialized_material = material_container.serialize()
|
||||
except NotImplementedError:
|
||||
|
@ -1,76 +0,0 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtProperty
|
||||
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Application import Application
|
||||
from UM.Util import parseBool
|
||||
|
||||
from cura.MachineAction import MachineAction
|
||||
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
||||
## The Ultimaker 2 can have a few revisions & upgrades.
|
||||
class UM2UpgradeSelection(MachineAction):
|
||||
def __init__(self):
|
||||
super().__init__("UM2UpgradeSelection", catalog.i18nc("@action", "Select upgrades"))
|
||||
self._qml_url = "UM2UpgradeSelectionMachineAction.qml"
|
||||
|
||||
self._container_registry = ContainerRegistry.getInstance()
|
||||
|
||||
self._current_global_stack = None
|
||||
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._reset()
|
||||
|
||||
def _reset(self):
|
||||
self.hasVariantsChanged.emit()
|
||||
|
||||
def _onGlobalStackChanged(self):
|
||||
if self._current_global_stack:
|
||||
self._current_global_stack.metaDataChanged.disconnect(self._onGlobalStackMetaDataChanged)
|
||||
|
||||
self._current_global_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if self._current_global_stack:
|
||||
self._current_global_stack.metaDataChanged.connect(self._onGlobalStackMetaDataChanged)
|
||||
self._reset()
|
||||
|
||||
def _onGlobalStackMetaDataChanged(self):
|
||||
self._reset()
|
||||
|
||||
hasVariantsChanged = pyqtSignal()
|
||||
|
||||
def setHasVariants(self, has_variants = True):
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
variant_container = global_container_stack.extruders["0"].variant
|
||||
|
||||
if has_variants:
|
||||
global_container_stack.setMetaDataEntry("has_variants", True)
|
||||
|
||||
# Set the variant container to a sane default
|
||||
empty_container = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||
if type(variant_container) == type(empty_container):
|
||||
search_criteria = { "type": "variant", "definition": "ultimaker2", "id": "*0.4*" }
|
||||
containers = self._container_registry.findInstanceContainers(**search_criteria)
|
||||
if containers:
|
||||
global_container_stack.extruders["0"].variant = containers[0]
|
||||
else:
|
||||
# The metadata entry is stored in an ini, and ini files are parsed as strings only.
|
||||
# Because any non-empty string evaluates to a boolean True, we have to remove the entry to make it False.
|
||||
if "has_variants" in global_container_stack.getMetaData():
|
||||
global_container_stack.removeMetaDataEntry("has_variants")
|
||||
|
||||
# Set the variant container to an empty variant
|
||||
global_container_stack.extruders["0"].variant = ContainerRegistry.getInstance().getEmptyInstanceContainer()
|
||||
|
||||
Application.getInstance().globalContainerStackChanged.emit()
|
||||
self._reset()
|
||||
|
||||
@pyqtProperty(bool, fset = setHasVariants, notify = hasVariantsChanged)
|
||||
def hasVariants(self):
|
||||
if self._current_global_stack:
|
||||
return parseBool(self._current_global_stack.getMetaDataEntry("has_variants", "false"))
|
@ -1,55 +0,0 @@
|
||||
// Copyright (c) 2019 Ultimaker B.V.
|
||||
// Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.1 as Cura
|
||||
|
||||
|
||||
Cura.MachineAction
|
||||
{
|
||||
UM.I18nCatalog { id: catalog; name: "cura"; }
|
||||
anchors.fill: parent
|
||||
|
||||
Item
|
||||
{
|
||||
id: upgradeSelectionMachineAction
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").width * 5
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width * 4
|
||||
|
||||
Label
|
||||
{
|
||||
id: pageDescription
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
text: catalog.i18nc("@label", "Please select any upgrades made to this Ultimaker 2.")
|
||||
font: UM.Theme.getFont("medium")
|
||||
color: UM.Theme.getColor("text")
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
|
||||
Cura.CheckBox
|
||||
{
|
||||
id: olssonBlockCheckBox
|
||||
anchors.top: pageDescription.bottom
|
||||
anchors.topMargin: UM.Theme.getSize("default_margin").height
|
||||
|
||||
height: UM.Theme.getSize("setting_control").height
|
||||
|
||||
text: catalog.i18nc("@label", "Olsson Block")
|
||||
checked: manager.hasVariants
|
||||
onClicked: manager.hasVariants = checked
|
||||
|
||||
Connections
|
||||
{
|
||||
target: manager
|
||||
onHasVariantsChanged: olssonBlockCheckBox.checked = manager.hasVariants
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from . import BedLevelMachineAction
|
||||
from . import UMOUpgradeSelection
|
||||
from . import UM2UpgradeSelection
|
||||
|
||||
def getMetaData():
|
||||
return {}
|
||||
@ -11,6 +10,5 @@ def getMetaData():
|
||||
def register(app):
|
||||
return { "machine_action": [
|
||||
BedLevelMachineAction.BedLevelMachineAction(),
|
||||
UMOUpgradeSelection.UMOUpgradeSelection(),
|
||||
UM2UpgradeSelection.UM2UpgradeSelection()
|
||||
UMOUpgradeSelection.UMOUpgradeSelection()
|
||||
]}
|
||||
|
@ -75,37 +75,20 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
if k in self.__material_properties_setting_map:
|
||||
new_setting_values_dict[self.__material_properties_setting_map[k]] = v
|
||||
|
||||
# Prevent recursion
|
||||
if not apply_to_all:
|
||||
super().setMetaDataEntry(key, value)
|
||||
if not apply_to_all: # Historical: If you only want to modify THIS container. We only used that to prevent recursion but with the below code that's no longer necessary.
|
||||
container_query = registry.findContainers(id = self.getId())
|
||||
else:
|
||||
container_query = registry.findContainers(base_file = self.getMetaDataEntry("base_file"))
|
||||
|
||||
for container in container_query:
|
||||
if key not in container.getMetaData() or container.getMetaData()[key] != value:
|
||||
container.getMetaData()[key] = value
|
||||
container.setDirty(True)
|
||||
container.metaDataChanged.emit(container)
|
||||
for k, v in new_setting_values_dict.items():
|
||||
self.setProperty(k, "value", v)
|
||||
return
|
||||
|
||||
# Get the MaterialGroup
|
||||
material_manager = CuraApplication.getInstance().getMaterialManager()
|
||||
root_material_id = self.getMetaDataEntry("base_file") #if basefile is self.getId, this is a basefile.
|
||||
material_group = material_manager.getMaterialGroup(root_material_id)
|
||||
if not material_group: #If the profile is not registered in the registry but loose/temporary, it will not have a base file tree.
|
||||
super().setMetaDataEntry(key, value)
|
||||
for k, v in new_setting_values_dict.items():
|
||||
self.setProperty(k, "value", v)
|
||||
return
|
||||
# Update the root material container
|
||||
root_material_container = material_group.root_material_node.container
|
||||
if root_material_container is not None:
|
||||
root_material_container.setMetaDataEntry(key, value, apply_to_all = False)
|
||||
for k, v in new_setting_values_dict.items():
|
||||
root_material_container.setProperty(k, "value", v)
|
||||
|
||||
# Update all containers derived from it
|
||||
for node in material_group.derived_material_node_list:
|
||||
container = node.container
|
||||
if container is not None:
|
||||
container.setMetaDataEntry(key, value, apply_to_all = False)
|
||||
for k, v in new_setting_values_dict.items():
|
||||
container.setProperty(k, "value", v)
|
||||
|
||||
## Overridden from InstanceContainer, similar to setMetaDataEntry.
|
||||
# without this function the setName would only set the name of the specific nozzle / material / machine combination container
|
||||
# The function is a bit tricky. It will not set the name of all containers if it has the correct name itself.
|
||||
|
@ -14,8 +14,6 @@
|
||||
"has_materials": false,
|
||||
"has_machine_quality": true,
|
||||
"preferred_variant_name": "0.4 mm",
|
||||
"first_start_actions": ["UM2UpgradeSelection"],
|
||||
"supported_actions":["UM2UpgradeSelection"],
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "ultimaker2_extruder_0"
|
||||
|
12
resources/definitions/ultimaker2_extended_olsson.def.json
Normal file
12
resources/definitions/ultimaker2_extended_olsson.def.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Ultimaker 2 Extended with Olsson",
|
||||
"inherits": "ultimaker2_extended",
|
||||
"metadata": {
|
||||
"has_variants": true
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "Ultimaker 2 Extended with Olsson" }
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@
|
||||
"platform": "ultimaker2go_platform.obj",
|
||||
"platform_texture": "Ultimaker2Gobackplate.png",
|
||||
"platform_offset": [0, 0, 0],
|
||||
"first_start_actions": [],
|
||||
"machine_extruder_trains":
|
||||
{
|
||||
"0": "ultimaker2_go_extruder_0"
|
||||
|
13
resources/definitions/ultimaker2_olsson.def.json
Normal file
13
resources/definitions/ultimaker2_olsson.def.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "Ultimaker 2 with Olsson Block",
|
||||
"inherits": "ultimaker2",
|
||||
"metadata": {
|
||||
"has_variants": true,
|
||||
"quality_definition": "ultimaker2"
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "Ultimaker 2 with Olsson Block" }
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
[general]
|
||||
name = 0.25 mm
|
||||
version = 4
|
||||
definition = ultimaker2
|
||||
definition = ultimaker2_olsson
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
@ -1,7 +1,7 @@
|
||||
[general]
|
||||
name = 0.4 mm
|
||||
version = 4
|
||||
definition = ultimaker2
|
||||
definition = ultimaker2_olsson
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
@ -1,7 +1,7 @@
|
||||
[general]
|
||||
name = 0.6 mm
|
||||
version = 4
|
||||
definition = ultimaker2
|
||||
definition = ultimaker2_olsson
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
@ -1,7 +1,7 @@
|
||||
[general]
|
||||
name = 0.8 mm
|
||||
version = 4
|
||||
definition = ultimaker2
|
||||
definition = ultimaker2_olsson
|
||||
|
||||
[metadata]
|
||||
setting_version = 10
|
Loading…
x
Reference in New Issue
Block a user