Просмотр исходного кода

Revert "Revert CURA-8055 in the 4.10 branch. This should not have been merged in there."

This reverts commit 4d29de45796dc42f76c774a216a0601bb57cf790.
Effectively this re-applies the changes for CURA-8055 / #9957.
Ghostkeeper 3 лет назад
Родитель
Сommit
f82384d93c

+ 56 - 1
cura/Machines/Models/MaterialManagementModel.py

@@ -2,9 +2,10 @@
 # Cura is released under the terms of the LGPLv3 or higher.
 
 import copy  # To duplicate materials.
-from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot  # To allow the preference page proxy to be used from the actual preferences page.
+from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl
 from typing import Any, Dict, Optional, TYPE_CHECKING
 import uuid  # To generate new GUIDs for new materials.
+import zipfile  # To export all materials in a .zip archive.
 
 from UM.i18n import i18nCatalog
 from UM.Logger import Logger
@@ -24,6 +25,11 @@ class MaterialManagementModel(QObject):
 
     This class handles the actions in that page, such as creating new materials, renaming them, etc.
     """
+    def __init__(self, parent: QObject) -> None:
+        super().__init__(parent)
+        cura_application = cura.CuraApplication.CuraApplication.getInstance()
+        self._preferred_export_all_path = None  # type: Optional[QUrl]  # Path to export all materials to. None if not yet initialised.
+        cura_application.getOutputDeviceManager().outputDevicesChanged.connect(self._onOutputDevicesChanged)
 
     favoritesChanged = pyqtSignal(str)
     """Triggered when a favorite is added or removed.
@@ -264,3 +270,52 @@ class MaterialManagementModel(QObject):
             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))
+
+    def _onOutputDevicesChanged(self) -> None:
+        """
+        When the list of output devices changes, we may want to update the
+        preferred export path.
+        """
+        cura_application = cura.CuraApplication.CuraApplication.getInstance()
+        device_manager = cura_application.getOutputDeviceManager()
+        devices = device_manager.getOutputDevices()
+        for device in devices:
+            if device.__class__.__name__ == "RemovableDriveOutputDevice":
+                self._preferred_export_all_path = QUrl.fromLocalFile(device.getId())
+                break
+        else:  # No removable drives? Use local path.
+            self._preferred_export_all_path = cura_application.getDefaultPath("dialog_material_path")
+        self.outputDevicesChanged.emit()
+
+    outputDevicesChanged = pyqtSignal()  # Triggered when adding or removing removable drives.
+    @pyqtProperty(QUrl, notify = outputDevicesChanged)
+    def preferredExportAllPath(self) -> QUrl:
+        """
+        Get the preferred path to export materials to.
+
+        If there is a removable drive, that should be the preferred path. Otherwise it should be the most recent local
+        file path.
+        :return: The preferred path to export all materials to.
+        """
+        if self._preferred_export_all_path is None:  # Not initialised yet. Can happen when output devices changed before class got created.
+            self._onOutputDevicesChanged()
+        return self._preferred_export_all_path
+
+    @pyqtSlot(QUrl)
+    def exportAll(self, file_path: QUrl) -> None:
+        """
+        Export all materials to a certain file path.
+        :param file_path: The path to export the materials to.
+        """
+        registry = CuraContainerRegistry.getInstance()
+
+        archive = zipfile.ZipFile(file_path.toLocalFile(), "w", compression = zipfile.ZIP_DEFLATED)
+        for metadata in registry.findInstanceContainersMetadata(type = "material"):
+            if metadata["base_file"] != metadata["id"]:  # Only process base files.
+                continue
+            if metadata["id"] == "empty_material":  # Don't export the empty material.
+                continue
+            material = registry.findContainers(id = metadata["id"])[0]
+            suffix = registry.getMimeTypeForContainer(type(material)).preferredSuffix
+            filename = metadata["id"] + "." + suffix
+            archive.writestr(filename, material.serialize())

+ 8 - 0
cura/Settings/GlobalStack.py

@@ -86,6 +86,14 @@ class GlobalStack(CuraContainerStack):
     def supportsNetworkConnection(self):
         return self.getMetaDataEntry("supports_network_connection", False)
 
+    @pyqtProperty(bool, constant = True)
+    def supportsMaterialExport(self):
+        """
+        Whether the printer supports Cura's export format of material profiles.
+        :return: ``True`` if it supports it, or ``False`` if not.
+        """
+        return self.getMetaDataEntry("supports_material_export", False)
+
     @classmethod
     def getLoadingPriority(cls) -> int:
         return 2

+ 2 - 1
resources/definitions/ultimaker2_plus_connect.def.json

@@ -22,7 +22,8 @@
             "0": "ultimaker2_plus_connect_extruder_0"
         },
         "supports_usb_connection": false,
-        "supports_network_connection": true
+        "supports_network_connection": true,
+        "supports_material_export": true
     },
 
     "overrides": {

+ 1 - 0
resources/definitions/ultimaker_s3.def.json

@@ -27,6 +27,7 @@
         "first_start_actions": [ "DiscoverUM3Action" ],
         "supported_actions": [ "DiscoverUM3Action" ],
         "supports_usb_connection": false,
+        "supports_material_export": true,
         "weight": -1,
         "firmware_update_info": {
             "id": 213482,

+ 1 - 0
resources/definitions/ultimaker_s5.def.json

@@ -28,6 +28,7 @@
         "supported_actions": [ "DiscoverUM3Action" ],
         "supports_usb_connection": false,
         "supports_network_connection": true,
+        "supports_material_export": true,
         "weight": -2,
         "firmware_update_info": {
             "id": 9051,

+ 30 - 2
resources/qml/Preferences/Materials/MaterialsPage.qml

@@ -1,5 +1,5 @@
-// Copyright (c) 2018 Ultimaker B.V.
-// Uranium is released under the terms of the LGPLv3 or higher.
+// Copyright (c) 2021 Ultimaker B.V.
+// Cura is released under the terms of the LGPLv3 or higher.
 
 import QtQuick 2.7
 import QtQuick.Controls 1.4
@@ -191,6 +191,20 @@ Item
             }
             enabled: base.hasCurrentItem
         }
+
+        //Sync button.
+        Button
+        {
+            id: syncMaterialsButton
+            text: catalog.i18nc("@action:button Sending materials to printers", "Sync with Printers")
+            iconName: "sync-synchronizing"
+            onClicked:
+            {
+                forceActiveFocus();
+                exportAllMaterialsDialog.open();
+            }
+            visible: Cura.MachineManager.activeMachine.supportsMaterialExport
+        }
     }
 
     Item {
@@ -368,6 +382,20 @@ Item
         }
     }
 
+    FileDialog
+    {
+        id: exportAllMaterialsDialog
+        title: catalog.i18nc("@title:window", "Export All Materials")
+        selectExisting: false
+        nameFilters: ["Material archives (*.umm)", "All files (*)"]
+        folder: base.materialManagementModel.preferredExportAllPath
+        onAccepted:
+        {
+            base.materialManagementModel.exportAll(fileUrl);
+            CuraApplication.setDefaultPath("dialog_material_path", folder);
+        }
+    }
+
     MessageDialog
     {
         id: messageDialog