Merge branch '4.10'

This commit is contained in:
Ghostkeeper 2021-06-10 17:37:35 +02:00
commit f815d15b10
No known key found for this signature in database
GPG key ID: D2A8871EE34EC59A
11 changed files with 4844 additions and 4683 deletions

View file

@ -2,9 +2,10 @@
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
import copy # To duplicate materials. 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 from typing import Any, Dict, Optional, TYPE_CHECKING
import uuid # To generate new GUIDs for new materials. 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.i18n import i18nCatalog
from UM.Logger import Logger 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. 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) favoritesChanged = pyqtSignal(str)
"""Triggered when a favorite is added or removed. """Triggered when a favorite is added or removed.
@ -264,3 +270,52 @@ class MaterialManagementModel(QObject):
self.favoritesChanged.emit(material_base_file) self.favoritesChanged.emit(material_base_file)
except ValueError: # Material was not in the favorites list. 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)) 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

@ -99,7 +99,7 @@ class QualitySettingsModel(ListModel):
if self._selected_position == self.GLOBAL_STACK_POSITION: if self._selected_position == self.GLOBAL_STACK_POSITION:
quality_node = quality_group.node_for_global quality_node = quality_group.node_for_global
else: else:
quality_node = quality_group.nodes_for_extruders.get(str(self._selected_position)) quality_node = quality_group.nodes_for_extruders.get(self._selected_position)
settings_keys = quality_group.getAllKeys() settings_keys = quality_group.getAllKeys()
quality_containers = [] quality_containers = []
if quality_node is not None and quality_node.container is not None: if quality_node is not None and quality_node.container is not None:

View file

@ -86,6 +86,14 @@ class GlobalStack(CuraContainerStack):
def supportsNetworkConnection(self): def supportsNetworkConnection(self):
return self.getMetaDataEntry("supports_network_connection", False) 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 @classmethod
def getLoadingPriority(cls) -> int: def getLoadingPriority(cls) -> int:
return 2 return 2

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Uranium json setting files\n" "Project-Id-Version: Uranium json setting files\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n" "Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2021-04-02 16:09+0000\n" "POT-Creation-Date: 2021-06-10 17:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"

View file

@ -3,7 +3,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Uranium json setting files\n" "Project-Id-Version: Uranium json setting files\n"
"Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n" "Report-Msgid-Bugs-To: r.dulek@ultimaker.com\n"
"POT-Creation-Date: 2021-04-02 16:09+0000\n" "POT-Creation-Date: 2021-06-10 17:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE\n" "Language-Team: LANGUAGE\n"
@ -3656,8 +3656,9 @@ msgstr ""
#: fdmprinter.def.json #: fdmprinter.def.json
msgctxt "retraction_combing_max_distance description" msgctxt "retraction_combing_max_distance description"
msgid "" msgid ""
"When non-zero, combing travel moves that are longer than this distance will " "When greater than zero, combing travel moves that are longer than this "
"use retraction." "distance will use retraction. If set to zero, there is no maximum and "
"combing moves will not use retraction."
msgstr "" msgstr ""
#: fdmprinter.def.json #: fdmprinter.def.json

View file

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

View file

@ -100,7 +100,7 @@ Item
top: subpageImage.bottom top: subpageImage.bottom
topMargin: UM.Theme.getSize("default_margin").height topMargin: UM.Theme.getSize("default_margin").height
bottom: parent.bottom bottom: parent.bottom
bottomMargin: UM.Theme.getSize("thick_margin").height bottomMargin: UM.Theme.getSize("thin_margin").height
left: subpageImage.left left: subpageImage.left
right: subpageImage.right right: subpageImage.right
} }