Merge branch 'feature_intent' of github.com:Ultimaker/Cura into feature_intent

This commit is contained in:
Jaime van Kessel 2019-09-23 11:19:19 +02:00
commit 08ffafa475
No known key found for this signature in database
GPG key ID: 3710727397403C91
17 changed files with 95 additions and 102 deletions

View file

@ -255,7 +255,7 @@ class MaterialManager(QObject):
for result in results:
container_registry.removeContainer(result.getMetaDataEntry("id", ""))
@pyqtSlot("QVariant", result=bool)
@pyqtSlot("QVariant", result = bool)
def canMaterialBeRemoved(self, material_node: "MaterialNode"):
# Check if the material is active in any extruder train. In that case, the material shouldn't be removed!
# In the future we might enable this again, but right now, it's causing a ton of issues if we do (since it

View file

@ -45,6 +45,7 @@ class BaseMaterialsModel(ListModel):
# Update this model when switching machines, when adding materials or changing their metadata.
self._machine_manager.activeStackChanged.connect(self._update)
ContainerTree.getInstance().materialsChanged.connect(self._materialsListChanged)
self._application.getMaterialManagementModel().favoritesChanged.connect(self._update)
self.addRoleName(Qt.UserRole + 1, "root_material_id")
self.addRoleName(Qt.UserRole + 2, "id")
@ -115,6 +116,11 @@ class BaseMaterialsModel(ListModel):
return
self._update()
## Triggered when the list of favorite materials is changed.
def _favoritesChanged(self, material_base_file: str) -> None:
if material_base_file in self._available_materials:
self._update()
## This is an abstract method that needs to be implemented by the specific
# models themselves.
def _update(self):

View file

@ -2,7 +2,7 @@
# Cura is released under the terms of the LGPLv3 or higher.
import copy # To duplicate materials.
from PyQt5.QtCore import QObject, pyqtSlot # To allow the preference page proxy to be used from the actual preferences page.
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot # To allow the preference page proxy to be used from the actual preferences page.
from typing import Any, Dict, Optional, TYPE_CHECKING
import uuid # To generate new GUIDs for new materials.
@ -23,6 +23,11 @@ catalog = i18nCatalog("cura")
# This class handles the actions in that page, such as creating new materials,
# renaming them, etc.
class MaterialManagementModel(QObject):
## Triggered when a favorite is added or removed.
# \param The base file of the material is provided as parameter when this
# emits.
favoritesChanged = pyqtSignal(str)
## Can a certain material be deleted, or is it still in use in one of the
# container stacks anywhere?
#
@ -34,7 +39,7 @@ class MaterialManagementModel(QObject):
# \param material_node The ContainerTree node of the material to check.
# \return Whether or not the material can be removed.
@pyqtSlot("QVariant", result = bool)
def canMaterialBeRemoved(self, material_node: "MaterialNode"):
def canMaterialBeRemoved(self, material_node: "MaterialNode") -> bool:
container_registry = CuraContainerRegistry.getInstance()
ids_to_remove = {metadata.get("id", "") for metadata in container_registry.findInstanceContainersMetadata(base_file = material_node.base_file)}
for extruder_stack in container_registry.findContainerStacks(type = "extruder_train"):
@ -80,7 +85,8 @@ class MaterialManagementModel(QObject):
# \param new_metadata Metadata for the new material. If not provided, this
# will be duplicated from the original material.
# \return The root material ID of the duplicate material.
def duplicateMaterialByBaseFile(self, base_file: str, new_base_id: Optional[str] = None, new_metadata: Dict[str, Any] = None) -> Optional[str]:
def duplicateMaterialByBaseFile(self, base_file: str, new_base_id: Optional[str] = None,
new_metadata: Optional[Dict[str, Any]] = None) -> Optional[str]:
container_registry = CuraContainerRegistry.getInstance()
root_materials = container_registry.findContainers(id = base_file)
@ -144,7 +150,8 @@ class MaterialManagementModel(QObject):
# will be duplicated from the original material.
# \return The root material ID of the duplicate material.
@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) -> Optional[str]:
return self.duplicateMaterialByBaseFile(material_node.base_file, new_base_id, new_metadata)
## Create a new material by cloning the preferred material for the current
@ -178,4 +185,31 @@ class MaterialManagementModel(QObject):
}
self.duplicateMaterial(preferred_material_node, new_base_id = new_id, new_metadata = new_metadata)
return new_id
return new_id
## Adds a certain material to the favorite materials.
# \param material_base_file The base file of the material to add.
@pyqtSlot(str)
def addFavorite(self, material_base_file: str) -> None:
application = cura.CuraApplication.CuraApplication.getInstance()
favorites = application.getPreferences().getValue("cura/favorite_materials").split(";")
if material_base_file not in favorites:
favorites.append(material_base_file)
application.getPreferences().setValue("cura/favorite_materials", ";".join(favorites))
application.saveSettings()
self.favoritesChanged.emit(material_base_file)
## Removes a certain material from the favorite materials.
#
# If the material was not in the favorite materials, nothing happens.
@pyqtSlot(str)
def removeFavorite(self, material_base_file: str) -> None:
application = cura.CuraApplication.CuraApplication.getInstance()
favorites = application.getPreferences().getValue("cura/favorite_materials").split(";")
try:
favorites.remove(material_base_file)
application.getPreferences().setValue("cura/favorite_materials", ";".join(favorites))
application.saveSettings()
self.favoritesChanged.emit(material_base_file)
except ValueError: # Material was not in the favorites list.
Logger.log("w", "Material {material_base_file} was already not a favorite material.".format(material_base_file = material_base_file))

View file

@ -48,7 +48,6 @@ class QualityManager(QObject):
def __init__(self, parent = None) -> None:
super().__init__(parent)
application = cura.CuraApplication.CuraApplication.getInstance()
self._material_manager = application.getMaterialManager()
self._container_registry = application.getContainerRegistry()
self._empty_quality_container = application.empty_quality_container

View file

@ -23,7 +23,6 @@ from UM.Settings.InstanceContainer import InstanceContainer
import cura.CuraApplication
from cura.Machines.ContainerTree import ContainerTree
from cura.Machines.MaterialManager import MaterialManager
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication

View file

@ -1,7 +1,7 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Any, cast, Dict, List, Optional
from typing import Any, cast, List, Optional
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject
from UM.Application import Application
@ -364,22 +364,3 @@ class _ContainerIndexes:
# Reverse lookup: type -> index
TypeIndexMap = dict([(v, k) for k, v in IndexTypeMap.items()])
# Mapping to old values before Intent introduction. Used for reading older versions of input files.
IndexToOldIndexMap = {
UserChanges: 0,
QualityChanges: 1,
Intent: -1, # Wasn't there in the old 'format'!
Quality: 2,
Material: 3,
Variant: 4,
DefinitionChanges: 5,
Definition: 6,
}
# Reverse lookup: old index -> new index
OldIndexToIndexMap = dict([(v, k) for k, v in IndexToOldIndexMap.items()])
@classmethod
def getIndexMapping(cls, setting_version: int) -> Dict[int, int]:
return dict([(x, x) for x in list(range(99))]) if setting_version >= 10 else cls.IndexToOldIndexMap

View file

@ -10,7 +10,6 @@ from UM.Settings.InstanceContainer import InstanceContainer
from cura.Machines.ContainerTree import ContainerTree
from cura.Machines.MachineNode import MachineNode
from cura.Machines.MaterialManager import MaterialManager
from .GlobalStack import GlobalStack
from .ExtruderStack import ExtruderStack

View file

@ -2,11 +2,12 @@
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Optional, TYPE_CHECKING
from PyQt5.QtCore import QObject, pyqtSlot
from UM.i18n import i18nCatalog
from cura.Machines.ContainerTree import ContainerTree
if TYPE_CHECKING:
from cura.CuraApplication import CuraApplication
@ -42,7 +43,7 @@ class MachineSettingsManager(QObject):
# it was moved to the machine manager instead. Now this method just calls the machine manager.
self._application.getMachineManager().setActiveMachineExtruderCount(extruder_count)
# Function for the Machine Settings panel (QML) to update after the usre changes "Number of Extruders".
# Function for the Machine Settings panel (QML) to update after the user changes "Number of Extruders".
#
# fieldOfView: The Ultimaker 2 family (not 2+) does not have materials in Cura by default, because the material is
# to be set on the printer. But when switching to Marlin flavor, the printer firmware can not change/insert material
@ -51,8 +52,6 @@ class MachineSettingsManager(QObject):
@pyqtSlot()
def updateHasMaterialsMetadata(self):
machine_manager = self._application.getMachineManager()
material_manager = self._application.getMaterialManager()
global_stack = machine_manager.activeMachine
definition = global_stack.definition
@ -76,7 +75,10 @@ class MachineSettingsManager(QObject):
# set materials
for position in extruder_positions:
if has_materials:
material_node = material_manager.getDefaultMaterial(global_stack, position, None)
extruder = global_stack.extruderList[int(position)]
approximate_diameter = extruder.getApproximateMaterialDiameter()
variant_node = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[extruder.variant.getName()]
material_node = variant_node.preferredMaterial(approximate_diameter)
machine_manager.setMaterial(position, material_node)
self.forceUpdate()

View file

@ -371,8 +371,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
# Get quality type
parser = ConfigParser(interpolation = None)
parser.read_string(serialized)
index_map_version = _ContainerIndexes.getIndexMapping(int(parser["metadata"]["setting_version"]))
quality_container_id = parser["containers"][str(index_map_version[_ContainerIndexes.Quality])]
quality_container_id = parser["containers"][str(_ContainerIndexes.Quality)]
quality_type = "empty_quality"
if quality_container_id not in ("empty", "empty_quality"):
quality_type = instance_container_info_dict[quality_container_id].parser["metadata"]["quality_type"]
@ -382,11 +381,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
serialized = GlobalStack._updateSerialized(serialized, global_stack_file)
parser = ConfigParser(interpolation = None)
parser.read_string(serialized)
index_map_version = _ContainerIndexes.getIndexMapping(int(parser["metadata"]["setting_version"]))
definition_changes_id = parser["containers"][str(index_map_version[_ContainerIndexes.DefinitionChanges])]
definition_changes_id = parser["containers"][str(_ContainerIndexes.DefinitionChanges)]
if definition_changes_id not in ("empty", "empty_definition_changes"):
self._machine_info.definition_changes_info = instance_container_info_dict[definition_changes_id]
user_changes_id = parser["containers"][str(index_map_version[_ContainerIndexes.UserChanges])]
user_changes_id = parser["containers"][str(_ContainerIndexes.UserChanges)]
if user_changes_id not in ("empty", "empty_user_changes"):
self._machine_info.user_changes_info = instance_container_info_dict[user_changes_id]
@ -396,8 +394,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
extruder_info = ExtruderInfo()
extruder_info.position = position
variant_id = parser["containers"][str(index_map_version[_ContainerIndexes.Variant])]
material_id = parser["containers"][str(index_map_version[_ContainerIndexes.Material])]
variant_id = parser["containers"][str(_ContainerIndexes.Variant)]
material_id = parser["containers"][str(_ContainerIndexes.Material)]
if variant_id not in ("empty", "empty_variant"):
extruder_info.variant_info = instance_container_info_dict[variant_id]
if material_id not in ("empty", "empty_material"):
@ -405,7 +403,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
extruder_info.root_material_id = root_material_id
self._machine_info.extruder_info_dict[position] = extruder_info
else:
variant_id = parser["containers"][str(index_map_version[_ContainerIndexes.Variant])]
variant_id = parser["containers"][str(_ContainerIndexes.Variant)]
if variant_id not in ("empty", "empty_variant"):
self._machine_info.variant_info = instance_container_info_dict[variant_id]
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
@ -417,14 +415,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
serialized = ExtruderStack._updateSerialized(serialized, extruder_stack_file)
parser = ConfigParser(interpolation = None)
parser.read_string(serialized)
index_map_version = _ContainerIndexes.getIndexMapping(int(parser["metadata"]["setting_version"]))
# The check should be done for the extruder stack that's associated with the existing global stack,
# and those extruder stacks may have different IDs.
# So we check according to the positions
position = parser["metadata"]["position"]
variant_id = parser["containers"][str(index_map_version[_ContainerIndexes.Variant])]
material_id = parser["containers"][str(index_map_version[_ContainerIndexes.Material])]
variant_id = parser["containers"][str(_ContainerIndexes.Variant)]
material_id = parser["containers"][str(_ContainerIndexes.Material)]
extruder_info = ExtruderInfo()
extruder_info.position = position
@ -438,11 +435,11 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
root_material_id = reverse_material_id_dict[material_id]
extruder_info.root_material_id = root_material_id
definition_changes_id = parser["containers"][str(index_map_version[_ContainerIndexes.DefinitionChanges])]
definition_changes_id = parser["containers"][str(_ContainerIndexes.DefinitionChanges)]
if definition_changes_id not in ("empty", "empty_definition_changes"):
extruder_info.definition_changes_info = instance_container_info_dict[definition_changes_id]
user_changes_id = parser["containers"][str(index_map_version[_ContainerIndexes.UserChanges])]
user_changes_id = parser["containers"][str(_ContainerIndexes.UserChanges)]
if user_changes_id not in ("empty", "empty_user_changes"):
extruder_info.user_changes_info = instance_container_info_dict[user_changes_id]
self._machine_info.extruder_info_dict[position] = extruder_info
@ -575,7 +572,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
@call_on_qt_thread
def read(self, file_name):
application = CuraApplication.getInstance()
material_manager = application.getMaterialManager()
archive = zipfile.ZipFile(file_name, "r")
@ -673,7 +669,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._resolve_strategies["material"] == "override":
# Remove the old materials and then deserialize the one from the project
root_material_id = material_container.getMetaDataEntry("base_file")
material_manager.removeMaterialByRootId(root_material_id)
application.getContainerRegistry().removeContainer(root_material_id)
elif self._resolve_strategies["material"] == "new":
# Note that we *must* deserialize it with a new ID, as multiple containers will be
# auto created & added.
@ -727,8 +723,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
if self._machine_info.quality_changes_info is None:
return
application = CuraApplication.getInstance()
# If we have custom profiles, load them
quality_changes_name = self._machine_info.quality_changes_info.name
if self._machine_info.quality_changes_info is not None:
@ -923,43 +917,27 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
extruder_stack.userChanges.setProperty(key, "value", value)
def _applyVariants(self, global_stack, extruder_stack_dict):
application = CuraApplication.getInstance()
variant_manager = application.getVariantManager()
machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()]
# Take the global variant from the machine info if available.
if self._machine_info.variant_info is not None:
parser = self._machine_info.variant_info.parser
variant_name = parser["general"]["name"]
variant_type = VariantType.BUILD_PLATE
node = variant_manager.getVariantNode(global_stack.definition.getId(), variant_name, variant_type)
if node is not None and node.container is not None:
global_stack.variant = node.container
variant_name = self._machine_info.variant_info.parser["general"]["name"]
global_stack.variant = machine_node.variants[variant_name].container
for position, extruder_stack in extruder_stack_dict.items():
if position not in self._machine_info.extruder_info_dict:
continue
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.
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
parser = extruder_info.variant_info.parser
variant_name = parser["general"]["name"]
variant_type = VariantType.NOZZLE
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
# If there is no variant_info, try to use the default variant. Otherwise, any available variant.
node = machine_node.variants.get(machine_node.preferred_variant_name, next(iter(machine_node.variants.values())))
else:
variant_name = extruder_info.variant_info.parser["general"]["name"]
node = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[variant_name]
extruder_stack.variant = node.container
def _applyMaterials(self, global_stack, extruder_stack_dict):
application = CuraApplication.getInstance()
material_manager = application.getMaterialManager()
machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()]
for position, extruder_stack in extruder_stack_dict.items():
if position not in self._machine_info.extruder_info_dict:
continue
@ -970,18 +948,8 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
root_material_id = extruder_info.root_material_id
root_material_id = self._old_new_materials.get(root_material_id, root_material_id)
build_plate_id = global_stack.variant.getId()
# get material diameter of this extruder
machine_material_diameter = extruder_stack.getCompatibleMaterialDiameter()
material_node = material_manager.getMaterialNode(global_stack.definition.getId(),
extruder_stack.variant.getName(),
build_plate_id,
machine_material_diameter,
root_material_id)
if material_node is not None and material_node.container is not None:
extruder_stack.material = material_node.container # type: InstanceContainer
material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
extruder_stack.material = material_node.container # type: InstanceContainer
def _applyChangesToMachine(self, global_stack, extruder_stack_dict):
# Clear all first

View file

@ -360,12 +360,14 @@ class Toolbox(QObject, Extension):
@pyqtSlot()
def resetMaterialsQualitiesAndUninstall(self) -> None:
application = CuraApplication.getInstance()
material_manager = application.getMaterialManager()
machine_manager = application.getMachineManager()
container_tree = ContainerTree.getInstance()
for global_stack, extruder_nr, container_id in self._package_used_materials:
default_material_node = material_manager.getDefaultMaterial(global_stack, extruder_nr, global_stack.extruders[extruder_nr].variant.getName())
extruder = global_stack.extruderList[int(extruder_nr)]
approximate_diameter = extruder.getApproximateMaterialDiameter()
variant_node = container_tree.machines[global_stack.definition.getId()].variants[extruder.variant.getName()]
default_material_node = variant_node.preferredMaterial(approximate_diameter)
machine_manager.setMaterial(extruder_nr, default_material_node, global_stack = global_stack)
for global_stack, extruder_nr, container_id in self._package_used_qualities:
variant_names = [extruder.variant.getName() for extruder in global_stack.extruderList]

View file

@ -8,6 +8,10 @@ _renamed_container_id_map = {
"ultimaker2_0.4": "ultimaker2_olsson_0.4",
"ultimaker2_0.6": "ultimaker2_olsson_0.6",
"ultimaker2_0.8": "ultimaker2_olsson_0.8",
"ultimaker2_extended_0.25": "ultimaker2_extended_olsson_0.25",
"ultimaker2_extended_0.4": "ultimaker2_extended_olsson_0.4",
"ultimaker2_extended_0.6": "ultimaker2_extended_olsson_0.6",
"ultimaker2_extended_0.8": "ultimaker2_extended_olsson_0.8",
}

View file

@ -82,11 +82,12 @@ Rectangle
{
if (materialSlot.is_favorite)
{
CuraApplication.getMaterialManager().removeFavorite(material.root_material_id)
return
CuraApplication.getMaterialManagementModel().removeFavorite(material.root_material_id)
}
else
{
CuraApplication.getMaterialManagementModel().addFavorite(material.root_material_id)
}
CuraApplication.getMaterialManager().addFavorite(material.root_material_id)
return
}
style: ButtonStyle
{

View file

@ -1,7 +1,7 @@
[general]
name = 0.25 mm
version = 4
definition = ultimaker2_extended
definition = ultimaker2_extended_olsson
[metadata]
setting_version = 10

View file

@ -1,7 +1,7 @@
[general]
name = 0.4 mm
version = 4
definition = ultimaker2_extended
definition = ultimaker2_extended_olsson
[metadata]
setting_version = 10

View file

@ -1,7 +1,7 @@
[general]
name = 0.6 mm
version = 4
definition = ultimaker2_extended
definition = ultimaker2_extended_olsson
[metadata]
setting_version = 10

View file

@ -1,7 +1,7 @@
[general]
name = 0.8 mm
version = 4
definition = ultimaker2_extended
definition = ultimaker2_extended_olsson
[metadata]
setting_version = 10

View file

@ -66,8 +66,6 @@ def test_createMachine(application, container_registry, definition_container, gl
quality_manager.getQualityGroups = MagicMock(return_value = {"normal": quality_group})
application.getContainerRegistry = MagicMock(return_value=container_registry)
application.getVariantManager = MagicMock(return_value = variant_manager)
application.getQualityManager = MagicMock(return_value = quality_manager)
application.empty_material_container = material_instance_container
application.empty_quality_container = quality_container
application.empty_intent_container = intent_container