Browse Source

Merge branch '5.7'

Saumya Jain 11 months ago
parent
commit
547f1bb8de

+ 14 - 5
conandata.yml

@@ -1,14 +1,15 @@
-version: "5.7.0-beta.0"
+version: "5.7.0-beta.1"
 requirements:
-  - "uranium/(latest)@ultimaker/stable"
-  - "curaengine/(latest)@ultimaker/stable"
-  - "cura_binary_data/(latest)@ultimaker/stable"
-  - "fdm_materials/(latest)@ultimaker/stable"
+  - "uranium/5.7.0-beta.1"
+  - "curaengine/5.7.0-beta.1"
+  - "cura_binary_data/5.7.0-beta.1"
+  - "fdm_materials/5.7.0-beta.1"
   - "curaengine_plugin_gradual_flow/0.1.0-beta.3"
   - "dulcificum/latest@ultimaker/testing"
   - "pysavitar/5.3.0"
   - "pynest2d/5.3.0"
   - "curaengine_grpc_definitions/0.2.0"
+  - "native_cad_plugin/2.0.0"
 requirements_internal:
   - "fdm_materials/(latest)@internal/testing"
   - "cura_private_data/(latest)@internal/testing"
@@ -41,6 +42,14 @@ pyinstaller:
             package: "curaengine_plugin_gradual_flow"
             src: "res/bundled_packages"
             dst: "share/cura/resources/bundled_packages"
+        native_cad_plugin:
+          package: "native_cad_plugin"
+          src: "res/plugins/NativeCADplugin"
+          dst: "share/cura/plugins/NativeCADplugin"
+        native_cad_plugin_bundled:
+          package: "native_cad_plugin"
+          src: "res/bundled_packages"
+          dst: "share/cura/resources/bundled_packages"
         cura_resources:
             package: "cura"
             src: "resources"

+ 10 - 0
conanfile.py

@@ -231,6 +231,8 @@ class CuraConan(ConanFile):
                     else:
                         src_path = os.path.join(self.source_folder, data["src"])
                 else:
+                    if data["package"] not in self.deps_cpp_info.deps:
+                        continue
                     src_path = os.path.join(self.deps_cpp_info[data["package"]].rootpath, data["src"])
             elif "root" in data:  # get the paths relative from the install folder
                 src_path = os.path.join(self.install_folder, data["root"], data["src"])
@@ -343,6 +345,8 @@ class CuraConan(ConanFile):
         for req in self.conan_data["requirements"]:
             if self._internal and "fdm_materials" in req:
                 continue
+            if not self._enterprise and "native_cad_plugin" in req:
+                continue
             self.requires(req)
         if self._internal:
             for req in self.conan_data["requirements_internal"]:
@@ -393,6 +397,12 @@ class CuraConan(ConanFile):
             copy(self, "*", curaengine_plugin_gradual_flow.bindirs[0], self.source_folder, keep_path = False)
             copy(self, "bundled_*.json", curaengine_plugin_gradual_flow.resdirs[1], str(self.source_path.joinpath("resources", "bundled_packages")), keep_path = False)
 
+            if self._enterprise:
+                rmdir(self, str(self.source_path.joinpath("plugins", "NativeCADplugin")))
+                curaengine_plugin_gradual_flow = self.dependencies["native_cad_plugin"].cpp_info
+                copy(self, "*", curaengine_plugin_gradual_flow.resdirs[0], str(self.source_path.joinpath("plugins", "NativeCADplugin")), keep_path = True)
+                copy(self, "bundled_*.json", curaengine_plugin_gradual_flow.resdirs[1], str(self.source_path.joinpath("resources", "bundled_packages")), keep_path = False)
+
         # Copy resources of cura_binary_data
         cura_binary_data = self.dependencies["cura_binary_data"].cpp_info
         copy(self, "*", cura_binary_data.resdirs[0], str(self._share_dir.joinpath("cura")), keep_path = True)

+ 14 - 0
cura/API/Account.py

@@ -190,6 +190,20 @@ class Account(QObject):
     def isLoggedIn(self) -> bool:
         return self._logged_in
 
+    @pyqtSlot()
+    def stopSyncing(self) -> None:
+        Logger.debug(f"Stopping sync of cloud printers")
+        self._setManualSyncEnabled(True)
+        if self._update_timer.isActive():
+            self._update_timer.stop()
+
+    @pyqtSlot()
+    def startSyncing(self) -> None:
+        Logger.debug(f"Starting sync of cloud printers")
+        self._setManualSyncEnabled(False)
+        if not self._update_timer.isActive():
+            self._update_timer.start()
+
     def _onLoginStateChanged(self, logged_in: bool = False, error_message: Optional[str] = None) -> None:
         if error_message:
             if self._error_message:

+ 2 - 2
cura/BackendPlugin.py

@@ -18,8 +18,8 @@ class BackendPlugin(AdditionalSettingDefinitionsAppender, PluginObject):
     catalog = i18nCatalog("cura")
     settings_catalog = i18nCatalog("fdmprinter.def.json")
 
-    def __init__(self) -> None:
-        super().__init__(self.settings_catalog)
+    def __init__(self, catalog_i18n = settings_catalog) -> None:
+        super().__init__(catalog_i18n)
         self.__port: int = 0
         self._plugin_address: str = "127.0.0.1"
         self._plugin_command: Optional[List[str]] = None

+ 6 - 1
cura/CuraApplication.py

@@ -33,6 +33,7 @@ from UM.Message import Message
 from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
 from UM.Operations.GroupedOperation import GroupedOperation
 from UM.Operations.SetTransformOperation import SetTransformOperation
+from UM.OutputDevice.ProjectOutputDevice import ProjectOutputDevice
 from UM.Platform import Platform
 from UM.PluginError import PluginNotFoundError
 from UM.Preferences import Preferences
@@ -1457,7 +1458,11 @@ class CuraApplication(QtApplication):
             self._scene_bounding_box = scene_bounding_box
             self.sceneBoundingBoxChanged.emit()
 
-        self._platform_activity = True if count > 0 else False
+        if count > 0:
+            self._platform_activity = True
+        else:
+            ProjectOutputDevice.setLastOutputName(None)
+            self._platform_activity = False
         self.activityChanged.emit()
 
     @pyqtSlot()

+ 1 - 1
cura/Machines/MachineErrorChecker.py

@@ -49,7 +49,7 @@ class MachineErrorChecker(QObject):
 
         self._keys_to_check = set()  # type: Set[str]
 
-        self._num_keys_to_check_per_update = 10
+        self._num_keys_to_check_per_update = 1
 
     def initialize(self) -> None:
         self._error_check_timer.timeout.connect(self._rescheduleCheck)

+ 2 - 2
cura/PrinterOutput/Models/MaterialOutputModel.py

@@ -25,9 +25,9 @@ class MaterialOutputModel(QObject):
     def getMaterialFromDefinition(guid, type, brand, name):
 
         _MATERIAL_MAP = {	"abs"       :{"name" :"ABS"           ,"guid": "2780b345-577b-4a24-a2c5-12e6aad3e690"},
-                             "abs-cf10": {"name": "ABS-CF", "guid": "495a0ce5-9daf-4a16-b7b2-06856d82394d"},
+                            "abs-cf10"  :{"name": "ABS-CF"        ,"guid": "495a0ce5-9daf-4a16-b7b2-06856d82394d"},
                             "abs-wss1"  :{"name" :"ABS-R"         ,"guid": "88c8919c-6a09-471a-b7b6-e801263d862d"},
-                            "asa"       :{"name" :"ASA"           ,"guid": "416eead4-0d8e-4f0b-8bfc-a91a519befa5"},
+                            "asa"       :{"name" :"ASA"           ,"guid": "f79bc612-21eb-482e-ad6c-87d75bdde066"},
                             "nylon12-cf":{"name": "Nylon 12 CF"   ,"guid": "3c6f2877-71cc-4760-84e6-4b89ab243e3b"},
                             "nylon"     :{"name" :"Nylon"         ,"guid": "283d439a-3490-4481-920c-c51d8cdecf9c"},
                             "pc"        :{"name" :"PC"            ,"guid": "62414577-94d1-490d-b1e4-7ef3ec40db02"},

+ 30 - 23
cura/Settings/SettingInheritanceManager.py

@@ -1,6 +1,6 @@
 # Copyright (c) 2017 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
-from typing import List, Optional, TYPE_CHECKING
+from typing import List, Optional, Set, TYPE_CHECKING
 
 from PyQt6.QtCore import QObject, QTimer, pyqtProperty, pyqtSignal
 from UM.FlameProfiler import pyqtSlot
@@ -168,37 +168,26 @@ class SettingInheritanceManager(QObject):
     def settingsWithInheritanceWarning(self) -> List[str]:
         return self._settings_with_inheritance_warning
 
-    def _settingIsOverwritingInheritance(self, key: str, stack: ContainerStack = None) -> bool:
-        """Check if a setting has an inheritance function that is overwritten"""
+    def _userSettingIsOverwritingInheritance(self, key: str, stack: ContainerStack, all_keys: Set[str] = set()) -> bool:
+        """Check if a setting known as having a User state has an inheritance function that is overwritten"""
 
         has_setting_function = False
-        if not stack:
-            stack = self._active_container_stack
-        if not stack:  # No active container stack yet!
-            return False
-
-        if self._active_container_stack is None:
-            return False
-        all_keys = self._active_container_stack.getAllKeys()
 
         containers = []  # type: List[ContainerInterface]
 
-        has_user_state = stack.getProperty(key, "state") == InstanceState.User
-        """Check if the setting has a user state. If not, it is never overwritten."""
-
-        if not has_user_state:
-            return False
-
         # If a setting is not enabled, don't label it as overwritten (It's never visible anyway).
         if not stack.getProperty(key, "enabled"):
             return False
 
         user_container = stack.getTop()
-        """Also check if the top container is not a setting function (this happens if the inheritance is restored)."""
+        # Also check if the top container is not a setting function (this happens if the inheritance is restored).
 
         if user_container and isinstance(user_container.getProperty(key, "value"), SettingFunction):
             return False
 
+        if not all_keys:
+            all_keys = self._active_container_stack.getAllKeys()
+
         ##  Mash all containers for all the stacks together.
         while stack:
             containers.extend(stack.getContainers())
@@ -229,17 +218,35 @@ class SettingInheritanceManager(QObject):
                 break  # There is a setting function somewhere, stop looking deeper.
         return has_setting_function and has_non_function_value
 
+    def _settingIsOverwritingInheritance(self, key: str, stack: ContainerStack = None) -> bool:
+        """Check if a setting has an inheritance function that is overwritten"""
+
+        if not stack:
+            stack = self._active_container_stack
+        if not stack:  # No active container stack yet!
+            return False
+
+        if self._active_container_stack is None:
+            return False
+
+        has_user_state = stack.getProperty(key, "state") == InstanceState.User
+
+        if not has_user_state:
+            return False
+
+        return self._userSettingIsOverwritingInheritance(key, stack)
+
     def _update(self) -> None:
         self._settings_with_inheritance_warning = []  # Reset previous data.
 
         # Make sure that the GlobalStack is not None. sometimes the globalContainerChanged signal gets here late.
-        if self._global_container_stack is None:
+        if self._global_container_stack is None or self._active_container_stack is None:
             return
 
-        # Check all setting keys that we know of and see if they are overridden.
-        for setting_key in self._global_container_stack.getAllKeys():
-            override = self._settingIsOverwritingInheritance(setting_key)
-            if override:
+        # Check all user setting keys that we know of and see if they are overridden.
+        all_keys = self._active_container_stack.getAllKeys()
+        for setting_key in self._active_container_stack.getAllKeysWithUserState():
+            if self._userSettingIsOverwritingInheritance(setting_key, self._active_container_stack, all_keys):
                 self._settings_with_inheritance_warning.append(setting_key)
 
         # Check all the categories if any of their children have their inheritance overwritten.

+ 20 - 4
plugins/3MFReader/SpecificSettingsModel.py

@@ -1,8 +1,9 @@
 # Copyright (c) 2024 Ultimaker B.V.
 # Cura is released under the terms of the LGPLv3 or higher.
 
-from PyQt6.QtCore import Qt
+from PyQt6.QtCore import Qt, pyqtSignal
 
+from UM import i18nCatalog
 from UM.Logger import Logger
 from UM.Settings.SettingDefinition import SettingDefinition
 from UM.Qt.ListModel import ListModel
@@ -19,9 +20,11 @@ class SpecificSettingsModel(ListModel):
         self.addRoleName(self.LabelRole, "label")
         self.addRoleName(self.ValueRole, "value")
 
-        self._i18n_catalog = None
+        self._settings_catalog = i18nCatalog("fdmprinter.def.json")
         self._update()
 
+    modelChanged = pyqtSignal()
+
 
     def addSettingsFromStack(self, stack, category, settings):
         for setting, value in settings.items():
@@ -30,17 +33,30 @@ class SpecificSettingsModel(ListModel):
             setting_type = stack.getProperty(setting, "type")
             if setting_type is not None:
                 # This is not very good looking, but will do for now
-                value = str(SettingDefinition.settingValueToString(setting_type, value)) + " " + str(unit)
+                value = str(SettingDefinition.settingValueToString(setting_type, value))
+                if unit:
+                    value += " " + str(unit)
+                if setting_type  == "enum":
+                    options = stack.getProperty(setting, "options")
+                    value_msgctxt = f"{str(setting)} option {str(value)}"
+                    value_msgid = options[stack.getProperty(setting, "value")]
+                    value = self._settings_catalog.i18nc(value_msgctxt, value_msgid)
             else:
                 value = str(value)
 
+            label_msgctxt = f"{str(setting)} label"
+            label_msgid = stack.getProperty(setting, "label")
+            label = self._settings_catalog.i18nc(label_msgctxt, label_msgid)
+
             self.appendItem({
                 "category": category,
-                "label": stack.getProperty(setting, "label"),
+                "label": label,
                 "value": value
             })
+        self.modelChanged.emit()
 
     def _update(self):
         Logger.debug(f"Updating {self.__class__.__name__}")
         self.setItems([])
+        self.modelChanged.emit()
         return

+ 25 - 2
plugins/3MFReader/ThreeMFWorkspaceReader.py

@@ -10,6 +10,8 @@ from typing import cast, Dict, List, Optional, Tuple, Any, Set
 
 import xml.etree.ElementTree as ET
 
+from UM.Math.AxisAlignedBox import AxisAlignedBox
+from UM.Math.Vector import Vector
 from UM.Util import parseBool
 from UM.Workspace.WorkspaceReader import WorkspaceReader
 from UM.Application import Application
@@ -936,6 +938,24 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
         if nodes is None:
             nodes = []
 
+        if self._is_ucp:
+            # We might be on a different printer than the one this project was made on.
+            # The offset to the printers' center isn't saved; instead, try to just fit everything on the buildplate.
+            full_extents = None
+            for node in nodes:
+                extents = node.getMeshData().getExtents() if node.getMeshData() else None
+                if extents is not None:
+                    pos = node.getPosition()
+                    node_box = AxisAlignedBox(extents.minimum + pos, extents.maximum + pos)
+                    if full_extents is None:
+                        full_extents = node_box
+                    else:
+                        full_extents = full_extents + node_box
+            if full_extents and full_extents.isValid():
+                for node in nodes:
+                    pos = node.getPosition()
+                    node.setPosition(Vector(pos.x - full_extents.center.x, pos.y, pos.z - full_extents.center.z))
+
         base_file_name = os.path.basename(file_name)
         self.setWorkspaceName(base_file_name)
 
@@ -1225,7 +1245,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
                 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]
+                node = ContainerTree.getInstance().machines[global_stack.definition.getId()].variants.get(variant_name, next(iter(machine_node.variants.values())))
             extruder_stack.variant = node.container
 
     def _applyMaterials(self, global_stack, extruder_stack_dict):
@@ -1240,7 +1260,10 @@ 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)
 
-            material_node = machine_node.variants[extruder_stack.variant.getName()].materials[root_material_id]
+            available_materials = machine_node.variants[extruder_stack.variant.getName()].materials
+            if root_material_id not in available_materials:
+                continue
+            material_node = available_materials[root_material_id]
             extruder_stack.material = material_node.container
 
     def _clearMachineSettings(self, global_stack, extruder_stack_dict):

Some files were not shown because too many files changed in this diff