Merge branch '4.10'

This commit is contained in:
Ghostkeeper 2021-06-24 14:19:40 +02:00
commit 84b5b19584
No known key found for this signature in database
GPG Key ID: D2A8871EE34EC59A
7 changed files with 8 additions and 113 deletions

View File

@ -2,10 +2,9 @@
# Cura is released under the terms of the LGPLv3 or higher.
import copy # To duplicate materials.
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl
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.
import zipfile # To export all materials in a .zip archive.
from UM.i18n import i18nCatalog
from UM.Logger import Logger
@ -25,11 +24,6 @@ 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.
@ -270,52 +264,3 @@ 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())

View File

@ -1,10 +1,10 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Type, TYPE_CHECKING, Optional, List, Union
from typing import Type, TYPE_CHECKING, Optional, List
import keyring
from keyring.backend import KeyringBackend
from keyring.errors import NoKeyringError, PasswordSetError, KeyringError
from keyring.errors import NoKeyringError, PasswordSetError, KeyringLocked
from UM.Logger import Logger
@ -14,24 +14,13 @@ if TYPE_CHECKING:
# Need to do some extra workarounds on windows:
import sys
from UM.Platform import Platform
class _KeychainDenied(Exception):
pass
if Platform.isWindows() and hasattr(sys, "frozen"):
import win32timezone
from keyring.backends.Windows import WinVaultKeyring
keyring.set_keyring(WinVaultKeyring())
if Platform.isOSX() and hasattr(sys, "frozen"):
from keyring.backends.macOS import Keyring
from keyring.backends.macOS.api import KeychainDenied as _KeychainDeniedMacOS
KeychainDenied: Union[Type[_KeychainDenied], Type[_KeychainDeniedMacOS]] = _KeychainDeniedMacOS
keyring.set_keyring(Keyring())
else:
KeychainDenied = _KeychainDenied
# Even if errors happen, we don't want this stored locally:
DONT_EVER_STORE_LOCALLY: List[str] = ["refresh_token"]
@ -50,7 +39,7 @@ class KeyringAttribute:
self._store_secure = False
Logger.logException("w", "No keyring backend present")
return getattr(instance, self._name)
except KeychainDenied:
except KeyringLocked:
self._store_secure = False
Logger.log("i", "Access to the keyring was denied.")
return getattr(instance, self._name)
@ -63,7 +52,7 @@ class KeyringAttribute:
if value is not None:
try:
keyring.set_password("cura", self._keyring_name, value)
except PasswordSetError:
except (PasswordSetError, KeyringLocked):
self._store_secure = False
if self._name not in DONT_EVER_STORE_LOCALLY:
setattr(instance, self._name, value)

View File

@ -86,14 +86,6 @@ 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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
// Copyright (c) 2021 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
// Copyright (c) 2018 Ultimaker B.V.
// Uranium is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Controls 1.4
@ -191,20 +191,6 @@ 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 {
@ -382,20 +368,6 @@ 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