diff options
author | Jaime van Kessel <nallath@gmail.com> | 2019-11-20 18:48:00 +0300 |
---|---|---|
committer | Jaime van Kessel <nallath@gmail.com> | 2019-11-20 18:48:00 +0300 |
commit | 50d72692d8163d3e0cd5c577246a2eb024273dc6 (patch) | |
tree | 3e1e6ed85c8753f43a35e0fdc087f05c83b7df7a /cura | |
parent | 266f7d1f74c860eb80433ea248cc6da1d864c190 (diff) | |
parent | 9aeb9912c8d0d37db11bb11372c982d065b56c16 (diff) |
Merge branch 'master' of github.com:Ultimaker/Cura into CURA-6522_one_at_a_time_overlapping_build_area
Diffstat (limited to 'cura')
23 files changed, 152 insertions, 85 deletions
diff --git a/cura/ApplicationMetadata.py b/cura/ApplicationMetadata.py index daa937197c..427cc77e65 100644 --- a/cura/ApplicationMetadata.py +++ b/cura/ApplicationMetadata.py @@ -9,7 +9,11 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura" DEFAULT_CURA_VERSION = "master" DEFAULT_CURA_BUILD_TYPE = "" DEFAULT_CURA_DEBUG_MODE = False -DEFAULT_CURA_SDK_VERSION = "7.0.0" + +# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for +# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the +# CuraVersion.py.in template. +CuraSDKVersion = "7.0.0" try: from cura.CuraVersion import CuraAppName # type: ignore @@ -32,6 +36,9 @@ try: except ImportError: CuraVersion = DEFAULT_CURA_VERSION # [CodeStyle: Reflecting imported value] +# CURA-6569 +# This string indicates what type of version it is. For example, "enterprise". By default it's empty which indicates +# a default/normal Cura build. try: from cura.CuraVersion import CuraBuildType # type: ignore except ImportError: @@ -42,7 +49,7 @@ try: except ImportError: CuraDebugMode = DEFAULT_CURA_DEBUG_MODE -# Each release has a fixed SDK version coupled with it. It doesn't make sense to make it configurable because, for -# example Cura 3.2 with SDK version 6.1 will not work. So the SDK version is hard-coded here and left out of the -# CuraVersion.py.in template. -CuraSDKVersion = "7.0.0" +# CURA-6569 +# Various convenience flags indicating what kind of Cura build it is. +__ENTERPRISE_VERSION_TYPE = "enterprise" +IsEnterpriseVersion = CuraBuildType.lower() == __ENTERPRISE_VERSION_TYPE diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 7928b0243a..809d392c10 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -26,7 +26,6 @@ catalog = i18nCatalog("cura") import numpy import math -import copy from typing import List, Optional, TYPE_CHECKING, Any, Set, cast, Iterable, Dict diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 11784718ca..ef5f987b85 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -720,6 +720,8 @@ class CuraApplication(QtApplication): ## Handle loading of all plugin types (and the backend explicitly) # \sa PluginRegistry def _loadPlugins(self) -> None: + self._plugin_registry.setCheckIfTrusted(ApplicationMetadata.IsEnterpriseVersion) + self._plugin_registry.addType("profile_reader", self._addProfileReader) self._plugin_registry.addType("profile_writer", self._addProfileWriter) @@ -1368,16 +1370,19 @@ class CuraApplication(QtApplication): for node in nodes: mesh_data = node.getMeshData() - if mesh_data and mesh_data.getFileName(): - job = ReadMeshJob(mesh_data.getFileName()) - job._node = node # type: ignore - job.finished.connect(self._reloadMeshFinished) - if has_merged_nodes: - job.finished.connect(self.updateOriginOfMergedMeshes) - - job.start() - else: - Logger.log("w", "Unable to reload data because we don't have a filename.") + + if mesh_data: + file_name = mesh_data.getFileName() + if file_name: + job = ReadMeshJob(file_name) + job._node = node # type: ignore + job.finished.connect(self._reloadMeshFinished) + if has_merged_nodes: + job.finished.connect(self.updateOriginOfMergedMeshes) + + job.start() + else: + Logger.log("w", "Unable to reload data because we don't have a filename.") @pyqtSlot("QStringList") def setExpandedCategories(self, categories: List[str]) -> None: @@ -1796,7 +1801,7 @@ class CuraApplication(QtApplication): try: result = workspace_reader.preRead(file_path, show_dialog=False) return result == WorkspaceReader.PreReadResult.accepted - except Exception as e: + except Exception: Logger.logException("e", "Could not check file %s", file_url) return False @@ -1892,3 +1897,7 @@ class CuraApplication(QtApplication): op.push() from UM.Scene.Selection import Selection Selection.clear() + + @classmethod + def getInstance(cls, *args, **kwargs) -> "CuraApplication": + return cast(CuraApplication, super().getInstance(**kwargs)) diff --git a/cura/LayerPolygon.py b/cura/LayerPolygon.py index a62083945b..0d6489aaa2 100644 --- a/cura/LayerPolygon.py +++ b/cura/LayerPolygon.py @@ -1,7 +1,7 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Application import Application +from UM.Qt.QtApplication import QtApplication from typing import Any, Optional import numpy @@ -232,7 +232,7 @@ class LayerPolygon: @classmethod def getColorMap(cls): if cls.__color_map is None: - theme = Application.getInstance().getTheme() + theme = QtApplication.getInstance().getTheme() cls.__color_map = numpy.array([ theme.getColor("layerview_none").getRgbF(), # NoneType theme.getColor("layerview_inset_0").getRgbF(), # Inset0Type diff --git a/cura/Machines/MachineNode.py b/cura/Machines/MachineNode.py index 72652f2987..8d69ffdc8d 100644 --- a/cura/Machines/MachineNode.py +++ b/cura/Machines/MachineNode.py @@ -140,7 +140,7 @@ class MachineNode(ContainerNode): elif groups_by_name[name].intent_category == "default": # Intent category should be stored as "default" if everything is default or as the intent if any of the extruder have an actual intent. groups_by_name[name].intent_category = quality_changes.get("intent_category", "default") - if "position" in quality_changes: # An extruder profile. + if quality_changes.get("position") is not None: # An extruder profile. groups_by_name[name].metadata_per_extruder[int(quality_changes["position"])] = quality_changes else: # Global profile. groups_by_name[name].metadata_for_global = quality_changes diff --git a/cura/Machines/Models/BaseMaterialsModel.py b/cura/Machines/Models/BaseMaterialsModel.py index 73d9d48b22..db660704b5 100644 --- a/cura/Machines/Models/BaseMaterialsModel.py +++ b/cura/Machines/Models/BaseMaterialsModel.py @@ -6,6 +6,7 @@ from typing import Dict, Set from PyQt5.QtCore import Qt, QTimer, pyqtSignal, pyqtProperty from UM.Qt.ListModel import ListModel +from UM.Logger import Logger import cura.CuraApplication # Imported like this to prevent a circular reference. from cura.Machines.ContainerTree import ContainerTree @@ -153,7 +154,12 @@ class BaseMaterialsModel(ListModel): if not extruder_stack: return nozzle_name = extruder_stack.variant.getName() - materials = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants[nozzle_name].materials + machine_node = ContainerTree.getInstance().machines[global_stack.definition.getId()] + if nozzle_name not in machine_node.variants: + Logger.log("w", "Unable to find variant %s in container tree", nozzle_name) + self._available_materials = {} + return + materials = machine_node.variants[nozzle_name].materials approximate_material_diameter = extruder_stack.getApproximateMaterialDiameter() self._available_materials = {key: material for key, material in materials.items() if float(material.getMetaDataEntry("approximate_diameter", -1)) == approximate_material_diameter} diff --git a/cura/Machines/Models/BuildPlateModel.py b/cura/Machines/Models/BuildPlateModel.py index c52228cf76..3697dd2762 100644 --- a/cura/Machines/Models/BuildPlateModel.py +++ b/cura/Machines/Models/BuildPlateModel.py @@ -2,13 +2,8 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import Qt - -from UM.Application import Application from UM.Logger import Logger from UM.Qt.ListModel import ListModel -from UM.Util import parseBool - -from cura.Machines.VariantType import VariantType class BuildPlateModel(ListModel): @@ -26,4 +21,4 @@ class BuildPlateModel(ListModel): def _update(self): Logger.log("d", "Updating {model_class_name}.".format(model_class_name = self.__class__.__name__)) self.setItems([]) - return
\ No newline at end of file + return diff --git a/cura/Machines/Models/DiscoveredPrintersModel.py b/cura/Machines/Models/DiscoveredPrintersModel.py index a1b68ee1ae..c662334470 100644 --- a/cura/Machines/Models/DiscoveredPrintersModel.py +++ b/cura/Machines/Models/DiscoveredPrintersModel.py @@ -11,7 +11,6 @@ from UM.Util import parseBool from UM.OutputDevice.OutputDeviceManager import ManualDeviceAdditionAttempt if TYPE_CHECKING: - from PyQt5.QtCore import QObject from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from cura.CuraApplication import CuraApplication from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice diff --git a/cura/Machines/Models/IntentCategoryModel.py b/cura/Machines/Models/IntentCategoryModel.py index 0ff52b325a..202d79bb15 100644 --- a/cura/Machines/Models/IntentCategoryModel.py +++ b/cura/Machines/Models/IntentCategoryModel.py @@ -1,9 +1,10 @@ #Copyright (c) 2019 Ultimaker B.V. #Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, QTimer import collections +from PyQt5.QtCore import Qt, QTimer from typing import TYPE_CHECKING, Optional, Dict +from cura.Machines.Models.IntentTranslations import intent_translations from cura.Machines.Models.IntentModel import IntentModel from cura.Settings.IntentManager import IntentManager @@ -29,21 +30,29 @@ class IntentCategoryModel(ListModel): modelUpdated = pyqtSignal() + _translations = collections.OrderedDict() # type: "collections.OrderedDict[str,Dict[str,Optional[str]]]" + # Translations to user-visible string. Ordered by weight. # TODO: Create a solution for this name and weight to be used dynamically. - _translations = collections.OrderedDict() # type: "collections.OrderedDict[str,Dict[str,Optional[str]]]" - _translations["default"] = { - "name": catalog.i18nc("@label", "Default") - } - _translations["engineering"] = { - "name": catalog.i18nc("@label", "Engineering"), - "description": catalog.i18nc("@text", "Suitable for engineering work") - - } - _translations["smooth"] = { - "name": catalog.i18nc("@label", "Smooth"), - "description": catalog.i18nc("@text", "Optimized for a smooth surfaces") - } + @classmethod + def _get_translations(cls): + if len(cls._translations) == 0: + cls._translations["default"] = { + "name": catalog.i18nc("@label", "Default") + } + cls._translations["visual"] = { + "name": catalog.i18nc("@label", "Visual"), + "description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality.") + } + cls._translations["engineering"] = { + "name": catalog.i18nc("@label", "Engineering"), + "description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances.") + } + cls._translations["quick"] = { + "name": catalog.i18nc("@label", "Draft"), + "description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.") + } + return cls._translations ## Creates a new model for a certain intent category. # \param The category to list the intent profiles for. @@ -95,15 +104,15 @@ class IntentCategoryModel(ListModel): "name": IntentCategoryModel.translation(category, "name", catalog.i18nc("@label", "Unknown")), "description": IntentCategoryModel.translation(category, "description", None), "intent_category": category, - "weight": list(self._translations.keys()).index(category), + "weight": list(IntentCategoryModel._get_translations().keys()).index(category), "qualities": qualities }) result.sort(key = lambda k: k["weight"]) self.setItems(result) - ## Get a display value for a category. See IntenCategoryModel._translations + ## Get a display value for a category. ## for categories and keys @staticmethod def translation(category: str, key: str, default: Optional[str] = None): - display_strings = IntentCategoryModel._translations.get(category, {}) + display_strings = IntentCategoryModel._get_translations().get(category, {}) return display_strings.get(key, default) diff --git a/cura/Machines/Models/IntentTranslations.py b/cura/Machines/Models/IntentTranslations.py new file mode 100644 index 0000000000..050fb1de56 --- /dev/null +++ b/cura/Machines/Models/IntentTranslations.py @@ -0,0 +1,24 @@ +import collections +from typing import Dict, Optional + +from UM.i18n import i18nCatalog +from typing import Dict, Optional +catalog = i18nCatalog("cura") + + +intent_translations = collections.OrderedDict() # type: collections.OrderedDict[str, Dict[str, Optional[str]]] +intent_translations["default"] = { + "name": catalog.i18nc("@label", "Default") +} +intent_translations["visual"] = { + "name": catalog.i18nc("@label", "Visual"), + "description": catalog.i18nc("@text", "The visual profile is designed to print visual prototypes and models with the intent of high visual and surface quality.") +} +intent_translations["engineering"] = { + "name": catalog.i18nc("@label", "Engineering"), + "description": catalog.i18nc("@text", "The engineering profile is designed to print functional prototypes and end-use parts with the intent of better accuracy and for closer tolerances.") +} +intent_translations["quick"] = { + "name": catalog.i18nc("@label", "Draft"), + "description": catalog.i18nc("@text", "The draft profile is designed to print initial prototypes and concept validation with the intent of significant print time reduction.") +} diff --git a/cura/Machines/Models/QualityManagementModel.py b/cura/Machines/Models/QualityManagementModel.py index d8b0785778..74dc8649d0 100644 --- a/cura/Machines/Models/QualityManagementModel.py +++ b/cura/Machines/Models/QualityManagementModel.py @@ -14,6 +14,7 @@ from cura.Machines.ContainerTree import ContainerTree from cura.Settings.cura_empty_instance_containers import empty_quality_changes_container from cura.Settings.IntentManager import IntentManager from cura.Machines.Models.MachineModelUtils import fetchLayerHeight +from cura.Machines.Models.IntentTranslations import intent_translations from UM.i18n import i18nCatalog catalog = i18nCatalog("cura") @@ -336,10 +337,11 @@ class QualityManagementModel(ListModel): "quality_type": quality_type, "quality_changes_group": None, "intent_category": intent_category, - "section_name": catalog.i18nc("@label", intent_category.capitalize()), + "section_name": catalog.i18nc("@label", intent_translations.get(intent_category, {}).get("name", catalog.i18nc("@label", "Unknown"))), }) # Sort by quality_type for each intent category - result = sorted(result, key = lambda x: (x["intent_category"], x["quality_type"])) + + result = sorted(result, key = lambda x: (list(intent_translations).index(x["intent_category"]), x["quality_type"])) item_list += result # Create quality_changes group items diff --git a/cura/Machines/VariantNode.py b/cura/Machines/VariantNode.py index 334a01158b..c9e3ec4913 100644 --- a/cura/Machines/VariantNode.py +++ b/cura/Machines/VariantNode.py @@ -1,13 +1,12 @@ # Copyright (c) 2019 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional, TYPE_CHECKING +from typing import TYPE_CHECKING from UM.Logger import Logger from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import ContainerInterface from UM.Signal import Signal -from cura.Settings.cura_empty_instance_containers import empty_variant_container from cura.Machines.ContainerNode import ContainerNode from cura.Machines.MaterialNode import MaterialNode @@ -83,12 +82,22 @@ class VariantNode(ContainerNode): # if there is no match. def preferredMaterial(self, approximate_diameter: int) -> MaterialNode: for base_material, material_node in self.materials.items(): - if self.machine.preferred_material in base_material and approximate_diameter == int(material_node.getMetaDataEntry("approximate_diameter")): + if self.machine.preferred_material == base_material and approximate_diameter == int(material_node.getMetaDataEntry("approximate_diameter")): return material_node - # First fallback: Choose any material with matching diameter. + + # First fallback: Check if we should be checking for the 175 variant. + if approximate_diameter == 2: + preferred_material = self.machine.preferred_material + "_175" + for base_material, material_node in self.materials.items(): + if preferred_material == base_material and approximate_diameter == int(material_node.getMetaDataEntry("approximate_diameter")): + return material_node + + # Second fallback: Choose any material with matching diameter. for material_node in self.materials.values(): if material_node.getMetaDataEntry("approximate_diameter") and approximate_diameter == int(material_node.getMetaDataEntry("approximate_diameter")): + Logger.log("w", "Could not find preferred material %s, falling back to whatever works", self.machine.preferred_material) return material_node + fallback = next(iter(self.materials.values())) # Should only happen with empty material node. Logger.log("w", "Could not find preferred material {preferred_material} with diameter {diameter} for variant {variant_id}, falling back to {fallback}.".format( preferred_material = self.machine.preferred_material, diff --git a/cura/OAuth2/AuthorizationHelpers.py b/cura/OAuth2/AuthorizationHelpers.py index 08309fa30e..9fc01ba50b 100644 --- a/cura/OAuth2/AuthorizationHelpers.py +++ b/cura/OAuth2/AuthorizationHelpers.py @@ -99,7 +99,7 @@ class AuthorizationHelpers: }) except requests.exceptions.ConnectionError: # Connection was suddenly dropped. Nothing we can do about that. - Logger.log("w", "Something failed while attempting to parse the JWT token") + Logger.logException("w", "Something failed while attempting to parse the JWT token") return None if token_request.status_code not in (200, 201): Logger.log("w", "Could not retrieve token data from auth server: %s", token_request.text) diff --git a/cura/OAuth2/AuthorizationService.py b/cura/OAuth2/AuthorizationService.py index 68756f8df6..0848623410 100644 --- a/cura/OAuth2/AuthorizationService.py +++ b/cura/OAuth2/AuthorizationService.py @@ -3,7 +3,6 @@ import json from datetime import datetime, timedelta -import os from typing import Optional, TYPE_CHECKING from urllib.parse import urlencode @@ -14,7 +13,6 @@ from PyQt5.QtGui import QDesktopServices from UM.Logger import Logger from UM.Message import Message -from UM.Platform import Platform from UM.Signal import Signal from cura.OAuth2.LocalAuthorizationServer import LocalAuthorizationServer diff --git a/cura/PlatformPhysics.py b/cura/PlatformPhysics.py index d084c0dbf4..a411478b16 100755 --- a/cura/PlatformPhysics.py +++ b/cura/PlatformPhysics.py @@ -17,6 +17,7 @@ from cura.Scene import ZOffsetDecorator import random # used for list shuffling + class PlatformPhysics: def __init__(self, controller, volume): super().__init__() diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 3f20e0f3c4..56e260a7f0 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -20,7 +20,7 @@ class FirmwareUpdater(QObject): self._output_device = output_device - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True, name = "FirmwareUpdateThread") self._firmware_file = "" self._firmware_progress = 0 @@ -43,7 +43,7 @@ class FirmwareUpdater(QObject): ## Cleanup after a succesful update def _cleanupAfterUpdate(self) -> None: # Clean up for next attempt. - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True, name = "FirmwareUpdateThread") self._firmware_file = "" self._onFirmwareProgress(100) self._setFirmwareUpdateState(FirmwareUpdateState.completed) diff --git a/cura/Scene/BuildPlateDecorator.py b/cura/Scene/BuildPlateDecorator.py index dfb465b7ad..cff9f88f62 100644 --- a/cura/Scene/BuildPlateDecorator.py +++ b/cura/Scene/BuildPlateDecorator.py @@ -4,12 +4,12 @@ from cura.Scene.CuraSceneNode import CuraSceneNode ## Make a SceneNode build plate aware CuraSceneNode objects all have this decorator. class BuildPlateDecorator(SceneNodeDecorator): - def __init__(self, build_plate_number = -1): + def __init__(self, build_plate_number: int = -1) -> None: super().__init__() - self._build_plate_number = None + self._build_plate_number = build_plate_number self.setBuildPlateNumber(build_plate_number) - def setBuildPlateNumber(self, nr): + def setBuildPlateNumber(self, nr: int) -> None: # Make sure that groups are set correctly # setBuildPlateForSelection in CuraActions makes sure that no single childs are set. self._build_plate_number = nr @@ -19,7 +19,7 @@ class BuildPlateDecorator(SceneNodeDecorator): for child in self._node.getChildren(): child.callDecoration("setBuildPlateNumber", nr) - def getBuildPlateNumber(self): + def getBuildPlateNumber(self) -> int: return self._build_plate_number def __deepcopy__(self, memo): diff --git a/cura/Scene/ConvexHullNode.py b/cura/Scene/ConvexHullNode.py index 6aa71223e5..da2713a522 100644 --- a/cura/Scene/ConvexHullNode.py +++ b/cura/Scene/ConvexHullNode.py @@ -1,6 +1,6 @@ # Copyright (c) 2015 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import Optional +from typing import Optional, TYPE_CHECKING from UM.Application import Application from UM.Math.Polygon import Polygon @@ -11,6 +11,9 @@ from UM.Math.Color import Color from UM.Mesh.MeshBuilder import MeshBuilder # To create a mesh to display the convex hull with. from UM.View.GL.OpenGL import OpenGL +if TYPE_CHECKING: + from UM.Mesh.MeshData import MeshData + class ConvexHullNode(SceneNode): shader = None # To prevent the shader from being re-built over and over again, only load it once. @@ -44,7 +47,7 @@ class ConvexHullNode(SceneNode): # The node this mesh is "watching" self._node = node # Area of the head + fans for display as a shadow on the buildplate - self._convex_hull_head_mesh = None + self._convex_hull_head_mesh = None # type: Optional[MeshData] self._node.decoratorsChanged.connect(self._onNodeDecoratorsChanged) self._onNodeDecoratorsChanged(self._node) diff --git a/cura/Settings/ContainerManager.py b/cura/Settings/ContainerManager.py index 4a4a7b64dd..92f06929d2 100644 --- a/cura/Settings/ContainerManager.py +++ b/cura/Settings/ContainerManager.py @@ -247,7 +247,7 @@ class ContainerManager(QObject): try: with open(file_url, "rt", encoding = "utf-8") as f: - container.deserialize(f.read()) + container.deserialize(f.read(), file_url) except PermissionError: return {"status": "error", "message": "Permission denied when trying to read the file."} except ContainerFormatError: @@ -339,11 +339,11 @@ class ContainerManager(QObject): # \return A list of names of materials with the same GUID. @pyqtSlot("QVariant", bool, result = "QStringList") def getLinkedMaterials(self, material_node: "MaterialNode", exclude_self: bool = False) -> List[str]: - same_guid = ContainerRegistry.getInstance().findInstanceContainersMetadata(guid = material_node.guid) + same_guid = ContainerRegistry.getInstance().findInstanceContainersMetadata(GUID = material_node.guid) if exclude_self: - return [metadata["name"] for metadata in same_guid if metadata["base_file"] != material_node.base_file] + return list({meta["name"] for meta in same_guid if meta["base_file"] != material_node.base_file}) else: - return [metadata["name"] for metadata in same_guid] + return list({meta["name"] for meta in same_guid}) ## Unlink a material from all other materials by creating a new GUID # \param material_id \type{str} the id of the material to create a new GUID for. diff --git a/cura/Settings/ExtruderManager.py b/cura/Settings/ExtruderManager.py index b3d108e1aa..62bf396878 100755 --- a/cura/Settings/ExtruderManager.py +++ b/cura/Settings/ExtruderManager.py @@ -12,7 +12,6 @@ from UM.Scene.SceneNode import SceneNode from UM.Scene.Selection import Selection from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator from UM.Settings.ContainerRegistry import ContainerRegistry # Finding containers by ID. -from UM.Decorators import deprecated from typing import Any, cast, Dict, List, Optional, TYPE_CHECKING, Union @@ -369,7 +368,7 @@ class ExtruderManager(QObject): printer = global_stack.getId(), expected = expected_extruder_definition_0_id, got = extruder_stack_0.definition.getId())) try: extruder_definition = container_registry.findDefinitionContainers(id = expected_extruder_definition_0_id)[0] - except IndexError as e: + except IndexError: # It still needs to break, but we want to know what extruder ID made it break. msg = "Unable to find extruder definition with the id [%s]" % expected_extruder_definition_0_id Logger.logException("e", msg) diff --git a/cura/Settings/IntentManager.py b/cura/Settings/IntentManager.py index c1d59fb84a..732e22d1bd 100644 --- a/cura/Settings/IntentManager.py +++ b/cura/Settings/IntentManager.py @@ -1,13 +1,15 @@ -#Copyright (c) 2019 Ultimaker B.V. -#Cura is released under the terms of the LGPLv3 or higher. +# Copyright (c) 2019 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot from typing import Any, Dict, List, Optional, Set, Tuple, TYPE_CHECKING -import cura.CuraApplication + from UM.Logger import Logger +from UM.Settings.InstanceContainer import InstanceContainer + +import cura.CuraApplication from cura.Machines.ContainerTree import ContainerTree from cura.Settings.cura_empty_instance_containers import empty_intent_container -from UM.Settings.InstanceContainer import InstanceContainer if TYPE_CHECKING: from UM.Settings.InstanceContainer import InstanceContainer @@ -36,8 +38,12 @@ class IntentManager(QObject): # \return A list of metadata dictionaries matching the search criteria, or # an empty list if nothing was found. def intentMetadatas(self, definition_id: str, nozzle_name: str, material_base_file: str) -> List[Dict[str, Any]]: - material_node = ContainerTree.getInstance().machines[definition_id].variants[nozzle_name].materials[material_base_file] - intent_metadatas = [] + intent_metadatas = [] # type: List[Dict[str, Any]] + materials = ContainerTree.getInstance().machines[definition_id].variants[nozzle_name].materials + if material_base_file not in materials: + return intent_metadatas + + material_node = materials[material_base_file] for quality_node in material_node.qualities.values(): for intent_node in quality_node.intents.values(): intent_metadatas.append(intent_node.getMetadata()) @@ -116,7 +122,7 @@ class IntentManager(QObject): ## The intent that gets selected by default when no intent is available for # the configuration, an extruder can't match the intent that the user # selects, or just when creating a new printer. - def getDefaultIntent(self) -> InstanceContainer: + def getDefaultIntent(self) -> "InstanceContainer": return empty_intent_container @pyqtProperty(str, notify = intentCategoryChanged) diff --git a/cura/Settings/SettingInheritanceManager.py b/cura/Settings/SettingInheritanceManager.py index 8be0813d0a..7db579bf3f 100644 --- a/cura/Settings/SettingInheritanceManager.py +++ b/cura/Settings/SettingInheritanceManager.py @@ -28,20 +28,21 @@ if TYPE_CHECKING: class SettingInheritanceManager(QObject): def __init__(self, parent = None) -> None: super().__init__(parent) - Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + self._global_container_stack = None # type: Optional[ContainerStack] self._settings_with_inheritance_warning = [] # type: List[str] self._active_container_stack = None # type: Optional[ExtruderStack] - self._onGlobalContainerChanged() - - ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) - self._onActiveExtruderChanged() self._update_timer = QTimer() self._update_timer.setInterval(500) self._update_timer.setSingleShot(True) self._update_timer.timeout.connect(self._update) + Application.getInstance().globalContainerStackChanged.connect(self._onGlobalContainerChanged) + ExtruderManager.getInstance().activeExtruderChanged.connect(self._onActiveExtruderChanged) + self._onGlobalContainerChanged() + self._onActiveExtruderChanged() + settingsWithIntheritanceChanged = pyqtSignal() ## Get the keys of all children settings with an override. @@ -106,7 +107,7 @@ class SettingInheritanceManager(QObject): if self._active_container_stack is not None: self._active_container_stack.propertyChanged.connect(self._onPropertyChanged) self._active_container_stack.containersChanged.connect(self._onContainersChanged) - self._update() # Ensure that the settings_with_inheritance_warning list is populated. + self._update_timer.start() # Ensure that the settings_with_inheritance_warning list is populated. def _onPropertyChanged(self, key: str, property_name: str) -> None: if (property_name == "value" or property_name == "enabled") and self._global_container_stack: diff --git a/cura/UI/CuraSplashScreen.py b/cura/UI/CuraSplashScreen.py index 77c9ad1427..05231c106d 100644 --- a/cura/UI/CuraSplashScreen.py +++ b/cura/UI/CuraSplashScreen.py @@ -56,11 +56,11 @@ class CuraSplashScreen(QSplashScreen): if buildtype: version[0] += " (%s)" % buildtype - # draw version text + # Draw version text font = QFont() # Using system-default font here font.setPixelSize(37) painter.setFont(font) - painter.drawText(215, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0]) + painter.drawText(60, 66, 330 * self._scale, 230 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[0]) if len(version) > 1: font.setPixelSize(16) painter.setFont(font) @@ -68,14 +68,14 @@ class CuraSplashScreen(QSplashScreen): painter.drawText(247, 105, 330 * self._scale, 255 * self._scale, Qt.AlignLeft | Qt.AlignTop, version[1]) painter.setPen(QColor(255, 255, 255, 255)) - # draw the loading image + # Draw the loading image pen = QPen() pen.setWidth(6 * self._scale) pen.setColor(QColor(32, 166, 219, 255)) painter.setPen(pen) painter.drawArc(60, 150, 32 * self._scale, 32 * self._scale, self._loading_image_rotation_angle * 16, 300 * 16) - # draw message text + # Draw message text if self._current_message: font = QFont() # Using system-default font here font.setPixelSize(13) |