diff --git a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py index 2536f5dacb..1b24e59309 100644 --- a/plugins/3MFWriter/ThreeMFWorkspaceWriter.py +++ b/plugins/3MFWriter/ThreeMFWorkspaceWriter.py @@ -8,9 +8,12 @@ from io import StringIO from threading import Lock import zipfile from typing import Dict, Any +from pathlib import Path +from zipfile import ZipFile from UM.Application import Application from UM.Logger import Logger +from UM.PluginRegistry import PluginRegistry from UM.Preferences import Preferences from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Workspace.WorkspaceWriter import WorkspaceWriter @@ -33,7 +36,7 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): if self._ucp_model != model: self._ucp_model = model - def _write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode): + def _write(self, stream, nodes, mode, include_log): application = Application.getInstance() machine_manager = application.getMachineManager() @@ -79,6 +82,11 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): if self._ucp_model is not None: user_settings_data = self._getUserSettings(self._ucp_model) ThreeMFWriter._storeMetadataJson(user_settings_data, archive, USER_SETTINGS_PATH) + + # Write log file + if include_log: + ThreeMFWorkspaceWriter._writeLogFile(archive) + except PermissionError: self.setInformation(catalog.i18nc("@error:zip", "No permission to write the workspace here.")) Logger.error("No permission to write workspace to this stream.") @@ -125,8 +133,8 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): return True - def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode): - success = self._write(stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode) + def write(self, stream, nodes, mode=WorkspaceWriter.OutputMode.BinaryMode, **kwargs): + success = self._write(stream, nodes, WorkspaceWriter.OutputMode.BinaryMode, kwargs.get("include_log", False)) self._ucp_model = None return success @@ -191,6 +199,17 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter): Logger.error("File became inaccessible while writing to it: {archive_filename}".format(archive_filename = archive.fp.name)) return + @staticmethod + def _writeLogFile(archive: ZipFile) -> None: + """Helper function that writes the Cura log file to the archive. + + :param archive: The archive to write to. + """ + file_logger = PluginRegistry.getInstance().getPluginObject("FileLogger") + file_logger.flush() + for file_path in file_logger.getFilesPaths(): + archive.write(file_path, arcname=f"log/{Path(file_path).name}") + @staticmethod def _getUserSettings(model: SettingsExportModel) -> Dict[str, Dict[str, Any]]: user_settings = {} diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 0c673a9409..1ae0802be7 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -77,6 +77,7 @@ Item property alias paste: pasteAction property alias copy: copyAction property alias cut: cutAction + property alias exportProjectForSupport: exportProjectForSupportAction readonly property bool copy_paste_enabled: { const all_enabled_packages = CuraApplication.getPackageManager().allEnabledPackages; @@ -549,4 +550,25 @@ Item text: "&Marketplace" icon.name: "plugins_browse" } + + Action + { + id: exportProjectForSupportAction + text: catalog.i18nc("@action:inmenu menubar:help", "Export Package For Technical Support") + onTriggered: + { + var exportName = Qt.formatDateTime(new Date(), "'export-'yyyyMMdd-HHmmss") + var args = { + "filter_by_machine": false, + "file_type": "workspace", + "preferred_mimetypes": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml", + "limit_mimetypes": ["application/vnd.ms-package.3dmanufacturing-3dmodel+xml"], + "silent_save": true, + "writer_args": { + "include_log": true + } + }; + UM.OutputDeviceManager.requestWriteToDevice("local_file", exportName, args) + } + } } diff --git a/resources/qml/Menus/HelpMenu.qml b/resources/qml/Menus/HelpMenu.qml index c257db0527..473649a964 100644 --- a/resources/qml/Menus/HelpMenu.qml +++ b/resources/qml/Menus/HelpMenu.qml @@ -18,6 +18,8 @@ Cura.Menu Cura.MenuItem { action: Cura.Actions.reportBug } Cura.MenuItem { action: Cura.Actions.openSponsershipPage } Cura.MenuSeparator { } + Cura.MenuItem { action: Cura.Actions.exportProjectForSupport } + Cura.MenuSeparator { } Cura.MenuItem { action: Cura.Actions.whatsNew } Cura.MenuItem { action: Cura.Actions.about } } \ No newline at end of file