diff options
Diffstat (limited to 'cura/Machines')
-rw-r--r-- | cura/Machines/Models/GlobalStacksModel.py | 48 | ||||
-rw-r--r-- | cura/Machines/Models/MaterialManagementModel.py | 64 |
2 files changed, 57 insertions, 55 deletions
diff --git a/cura/Machines/Models/GlobalStacksModel.py b/cura/Machines/Models/GlobalStacksModel.py index 712597c2e7..586bd11819 100644 --- a/cura/Machines/Models/GlobalStacksModel.py +++ b/cura/Machines/Models/GlobalStacksModel.py @@ -1,7 +1,8 @@ -# Copyright (c) 2018 Ultimaker B.V. +# Copyright (c) 2021 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import Qt, QTimer +from PyQt5.QtCore import Qt, QTimer, pyqtProperty, pyqtSignal +from typing import Optional from UM.Qt.ListModel import ListModel from UM.i18n import i18nCatalog @@ -20,6 +21,7 @@ class GlobalStacksModel(ListModel): MetaDataRole = Qt.UserRole + 5 DiscoverySourceRole = Qt.UserRole + 6 # For separating local and remote printers in the machine management page RemovalWarningRole = Qt.UserRole + 7 + IsOnlineRole = Qt.UserRole + 8 def __init__(self, parent = None) -> None: super().__init__(parent) @@ -31,18 +33,49 @@ class GlobalStacksModel(ListModel): self.addRoleName(self.HasRemoteConnectionRole, "hasRemoteConnection") self.addRoleName(self.MetaDataRole, "metadata") self.addRoleName(self.DiscoverySourceRole, "discoverySource") + self.addRoleName(self.IsOnlineRole, "isOnline") self._change_timer = QTimer() self._change_timer.setInterval(200) self._change_timer.setSingleShot(True) self._change_timer.timeout.connect(self._update) + self._filter_connection_type = None # type: Optional[ConnectionType] + self._filter_online_only = False + # Listen to changes CuraContainerRegistry.getInstance().containerAdded.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerMetaDataChanged.connect(self._onContainerChanged) CuraContainerRegistry.getInstance().containerRemoved.connect(self._onContainerChanged) self._updateDelayed() + filterConnectionTypeChanged = pyqtSignal() + def setFilterConnectionType(self, new_filter: Optional[ConnectionType]) -> None: + self._filter_connection_type = new_filter + + @pyqtProperty(int, fset = setFilterConnectionType, notify = filterConnectionTypeChanged) + def filterConnectionType(self) -> int: + """ + The connection type to filter the list of printers by. + + Only printers that match this connection type will be listed in the + model. + """ + if self._filter_connection_type is None: + return -1 + return self._filter_connection_type.value + + filterOnlineOnlyChanged = pyqtSignal() + def setFilterOnlineOnly(self, new_filter: bool) -> None: + self._filter_online_only = new_filter + + @pyqtProperty(bool, fset = setFilterOnlineOnly, notify = filterOnlineOnlyChanged) + def filterOnlineOnly(self) -> bool: + """ + Whether to filter the global stacks to show only printers that are online. + """ + return self._filter_online_only + def _onContainerChanged(self, container) -> None: """Handler for container added/removed events from registry""" @@ -58,6 +91,10 @@ class GlobalStacksModel(ListModel): container_stacks = CuraContainerRegistry.getInstance().findContainerStacks(type = "machine") for container_stack in container_stacks: + if self._filter_connection_type is not None: # We want to filter on connection types. + if not any((connection_type == self._filter_connection_type for connection_type in container_stack.configuredConnectionTypes)): + continue # No connection type on this printer matches the filter. + has_remote_connection = False for connection_type in container_stack.configuredConnectionTypes: @@ -67,6 +104,10 @@ class GlobalStacksModel(ListModel): if parseBool(container_stack.getMetaDataEntry("hidden", False)): continue + is_online = container_stack.getMetaDataEntry("is_online", False) + if self._filter_online_only and not is_online: + continue + device_name = container_stack.getMetaDataEntry("group_name", container_stack.getName()) section_name = "Connected printers" if has_remote_connection else "Preset printers" section_name = self._catalog.i18nc("@info:title", section_name) @@ -82,6 +123,7 @@ class GlobalStacksModel(ListModel): "hasRemoteConnection": has_remote_connection, "metadata": container_stack.getMetaData().copy(), "discoverySource": section_name, - "removalWarning": removal_warning}) + "removalWarning": removal_warning, + "isOnline": is_online}) items.sort(key=lambda i: (not i["hasRemoteConnection"], i["name"])) self.setItems(items) diff --git a/cura/Machines/Models/MaterialManagementModel.py b/cura/Machines/Models/MaterialManagementModel.py index 802f2559f8..76b2c5b444 100644 --- a/cura/Machines/Models/MaterialManagementModel.py +++ b/cura/Machines/Models/MaterialManagementModel.py @@ -2,21 +2,21 @@ # 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 pyqtSignal, pyqtSlot, QObject, QUrl +from PyQt5.QtGui import QDesktopServices 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 PyQt5.QtGui import QDesktopServices +from UM.Message import Message from UM.i18n import i18nCatalog from UM.Logger import Logger -from UM.Message import Message +from UM.Resources import Resources # To find QML files. from UM.Signal import postponeSignals, CompressTechnique -import cura.CuraApplication # Imported like this to prevent circular imports. +import cura.CuraApplication # Imported like this to prevent cirmanagecular imports. from cura.Machines.ContainerTree import ContainerTree from cura.Settings.CuraContainerRegistry import CuraContainerRegistry # To find the sets of materials belonging to each other, and currently loaded extruder stacks. +from cura.UltimakerCloud.CloudMaterialSync import CloudMaterialSync if TYPE_CHECKING: from cura.Machines.MaterialNode import MaterialNode @@ -33,6 +33,7 @@ class MaterialManagementModel(QObject): def __init__(self, parent: Optional[QObject] = None) -> None: super().__init__(parent = parent) + self._material_sync = CloudMaterialSync(parent=self) self._checkIfNewMaterialsWereInstalled() def _checkIfNewMaterialsWereInstalled(self) -> None: @@ -89,6 +90,7 @@ class MaterialManagementModel(QObject): elif sync_message_action == "learn_more": QDesktopServices.openUrl(QUrl("https://support.ultimaker.com/hc/en-us/articles/360013137919?utm_source=cura&utm_medium=software&utm_campaign=sync-material-printer-message")) + @pyqtSlot("QVariant", result = bool) def canMaterialBeRemoved(self, material_node: "MaterialNode") -> bool: """Can a certain material be deleted, or is it still in use in one of the container stacks anywhere? @@ -323,52 +325,10 @@ class MaterialManagementModel(QObject): 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)) - @pyqtSlot(result = QUrl) - def getPreferredExportAllPath(self) -> QUrl: + @pyqtSlot() + def openSyncAllWindow(self) -> None: """ - 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. - """ - cura_application = cura.CuraApplication.CuraApplication.getInstance() - device_manager = cura_application.getOutputDeviceManager() - devices = device_manager.getOutputDevices() - for device in devices: - if device.__class__.__name__ == "RemovableDriveOutputDevice": - return QUrl.fromLocalFile(device.getId()) - else: # No removable drives? Use local path. - return cura_application.getDefaultPath("dialog_material_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. + Opens the window to sync all materials. """ - registry = CuraContainerRegistry.getInstance() + self._material_sync.openSyncAllWindow() - try: - archive = zipfile.ZipFile(file_path.toLocalFile(), "w", compression = zipfile.ZIP_DEFLATED) - except OSError as e: - Logger.log("e", f"Can't write to destination {file_path.toLocalFile()}: {type(e)} - {str(e)}") - error_message = Message( - text = catalog.i18nc("@message:text", "Could not save material archive to {}:").format(file_path.toLocalFile()) + " " + str(e), - title = catalog.i18nc("@message:title", "Failed to save material archive"), - message_type = Message.MessageType.ERROR - ) - error_message.show() - return - 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 - try: - archive.writestr(filename, material.serialize()) - except OSError as e: - Logger.log("e", f"An error has occurred while writing the material \'{metadata['id']}\' in the file \'{filename}\': {e}.") |