From e785373ee0513662c558ec3b4264c09575eac684 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 12:59:04 +0000 Subject: [PATCH 1/4] Initial plan From 4938c9be973dedfef986d296db422372f707444a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:02:47 +0000 Subject: [PATCH 2/4] Add clear configuration cache menu item with confirmation dialog Co-authored-by: jellespijker <8535734+jellespijker@users.noreply.github.com> --- cura/CuraActions.py | 56 ++++++++++++++++++++++++++++++++ resources/qml/Actions.qml | 7 ++++ resources/qml/Cura.qml | 35 ++++++++++++++++++++ resources/qml/Menus/HelpMenu.qml | 1 + 4 files changed, 99 insertions(+) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 835c46bba81..623f6701f6e 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -31,6 +31,9 @@ from UM.Logger import Logger from UM.Scene.SceneNode import SceneNode +from UM.Resources import Resources +import os +import shutil class CuraActions(QObject): def __init__(self, parent: QObject = None) -> None: @@ -280,3 +283,56 @@ def paste(self) -> None: def _openUrl(self, url: QUrl) -> None: QDesktopServices.openUrl(url) + + @pyqtSlot(bool) + def clearConfigurationCache(self, clear_all_versions: bool = False) -> None: + """Clear the configuration cache folder. + + :param clear_all_versions: If True, also clear cache from previous Cura versions. + """ + from UM.Message import Message + from UM.i18n import i18nCatalog + catalog = i18nCatalog("cura") + + try: + # Get the current version's data storage path + current_data_path = Resources.getDataStoragePath() + cache_path = os.path.join(current_data_path, "cache") + + # Clear current version's cache + if os.path.exists(cache_path): + shutil.rmtree(cache_path) + Logger.log("i", f"Cleared cache at: {cache_path}") + + # Clear previous versions' caches if requested + if clear_all_versions: + # Get the parent directory containing all version folders + data_storage_root = os.path.dirname(current_data_path) + if os.path.exists(data_storage_root): + # Iterate through all directories in the data storage root + for folder_name in os.listdir(data_storage_root): + folder_path = os.path.join(data_storage_root, folder_name) + # Skip if it's not a directory or if it's the current version + if not os.path.isdir(folder_path) or folder_path == current_data_path: + continue + # Check if it looks like a version folder (has a cache subdirectory) + version_cache_path = os.path.join(folder_path, "cache") + if os.path.exists(version_cache_path): + shutil.rmtree(version_cache_path) + Logger.log("i", f"Cleared cache at: {version_cache_path}") + + # Show success message + message_text = catalog.i18nc("@info:status", "Configuration cache cleared successfully.") + if clear_all_versions: + message_text = catalog.i18nc("@info:status", "Configuration cache cleared successfully for all versions.") + message = Message(message_text, lifetime=5, title=catalog.i18nc("@info:title", "Cache Cleared")) + message.show() + + except Exception as e: + Logger.log("e", f"Failed to clear configuration cache: {str(e)}") + error_message = Message( + catalog.i18nc("@info:status", "Failed to clear configuration cache: {0}").format(str(e)), + lifetime=0, + title=catalog.i18nc("@info:title", "Error") + ) + error_message.show() diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index b12699a100e..84c1686e344 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -62,6 +62,7 @@ Item property alias showProfileFolder: showProfileFolderAction property alias openCuraLogFile: openCuraLogFileAction + property alias clearConfigurationCache: clearConfigurationCacheAction property alias documentation: documentationAction property alias openSponsershipPage: openSponsershipPageAction property alias reportBug: reportBugAction @@ -543,6 +544,12 @@ Item text: catalog.i18nc("@action:inmenu menubar:help","Open Cura Log File") } + Action + { + id: clearConfigurationCacheAction + text: catalog.i18nc("@action:inmenu menubar:help", "Clear Configuration Cache...") + } + Action { diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index bb3e56eafa9..6f9136aed13 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -807,6 +807,41 @@ UM.MainWindow } } + Cura.MessageDialog + { + id: clearConfigurationCacheDialog + + title: catalog.i18nc("@title:window", "Clear Configuration Cache") + text: catalog.i18nc("@info:question", "Are you sure you want to clear the configuration cache? This will remove cached data and may improve performance if you're experiencing issues.") + standardButtons: Dialog.Yes | Dialog.No + property bool clearAllVersions: clearAllVersionsCheckBox.checked + + Column + { + spacing: UM.Theme.getSize("default_margin").height + + UM.CheckBox + { + id: clearAllVersionsCheckBox + text: catalog.i18nc("@option:check", "Also clear cache from previous Cura versions") + } + } + + onAccepted: + { + CuraActions.clearConfigurationCache(clearAllVersions) + } + } + + Connections + { + target: Cura.Actions.clearConfigurationCache + function onTriggered() + { + clearConfigurationCacheDialog.visible = true + } + } + Component { id: discardOrKeepProfileChangesDialogComponent diff --git a/resources/qml/Menus/HelpMenu.qml b/resources/qml/Menus/HelpMenu.qml index db189a9ddd0..ca609d892f4 100644 --- a/resources/qml/Menus/HelpMenu.qml +++ b/resources/qml/Menus/HelpMenu.qml @@ -15,6 +15,7 @@ Cura.Menu Cura.MenuItem { action: Cura.Actions.showProfileFolder } Cura.MenuItem { action: Cura.Actions.openCuraLogFile } + Cura.MenuItem { action: Cura.Actions.clearConfigurationCache } Cura.MenuSeparator { } Cura.MenuItem { action: Cura.Actions.documentation } Cura.MenuItem { action: Cura.Actions.reportBug } From 7ee86724e134ec1fcbda3ae5cff807dd76e60da5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:03:58 +0000 Subject: [PATCH 3/4] Fix dialog to use UM.Dialog instead of MessageDialog for custom content Co-authored-by: jellespijker <8535734+jellespijker@users.noreply.github.com> --- resources/qml/Cura.qml | 50 +++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/resources/qml/Cura.qml b/resources/qml/Cura.qml index 6f9136aed13..02fe5448d12 100644 --- a/resources/qml/Cura.qml +++ b/resources/qml/Cura.qml @@ -807,29 +807,63 @@ UM.MainWindow } } - Cura.MessageDialog + UM.Dialog { id: clearConfigurationCacheDialog title: catalog.i18nc("@title:window", "Clear Configuration Cache") - text: catalog.i18nc("@info:question", "Are you sure you want to clear the configuration cache? This will remove cached data and may improve performance if you're experiencing issues.") - standardButtons: Dialog.Yes | Dialog.No - property bool clearAllVersions: clearAllVersionsCheckBox.checked - + width: UM.Theme.getSize("small_popup_dialog").width + height: UM.Theme.getSize("small_popup_dialog").height + backgroundColor: UM.Theme.getColor("main_background") + + maximumHeight: height + maximumWidth: width + minimumHeight: maximumHeight + minimumWidth: maximumWidth + + modality: Qt.ApplicationModal + Column { + anchors.fill: parent spacing: UM.Theme.getSize("default_margin").height - + + UM.Label + { + width: parent.width + text: catalog.i18nc("@info:question", "Are you sure you want to clear the configuration cache? This will remove cached data and may improve performance if you're experiencing issues.") + wrapMode: Text.WordWrap + } + UM.CheckBox { id: clearAllVersionsCheckBox text: catalog.i18nc("@option:check", "Also clear cache from previous Cura versions") } } - + + rightButtons: + [ + Cura.SecondaryButton + { + text: catalog.i18nc("@action:button", "Cancel") + onClicked: clearConfigurationCacheDialog.reject() + }, + Cura.PrimaryButton + { + text: catalog.i18nc("@action:button", "Clear Cache") + onClicked: clearConfigurationCacheDialog.accept() + } + ] + onAccepted: { - CuraActions.clearConfigurationCache(clearAllVersions) + CuraActions.clearConfigurationCache(clearAllVersionsCheckBox.checked) + clearConfigurationCacheDialog.hide() + } + onRejected: + { + clearConfigurationCacheDialog.hide() } } From c1515da1165d056b6077c22e5b21e55c342418a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:06:10 +0000 Subject: [PATCH 4/4] Address code review feedback: fix logging and add version pattern validation Co-authored-by: jellespijker <8535734+jellespijker@users.noreply.github.com> --- cura/CuraActions.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 623f6701f6e..e5615ba6cbb 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -33,6 +33,7 @@ from UM.Scene.SceneNode import SceneNode from UM.Resources import Resources import os +import re import shutil class CuraActions(QObject): @@ -302,7 +303,7 @@ def clearConfigurationCache(self, clear_all_versions: bool = False) -> None: # Clear current version's cache if os.path.exists(cache_path): shutil.rmtree(cache_path) - Logger.log("i", f"Cleared cache at: {cache_path}") + Logger.log("i", "Cleared cache at: %s", cache_path) # Clear previous versions' caches if requested if clear_all_versions: @@ -310,7 +311,13 @@ def clearConfigurationCache(self, clear_all_versions: bool = False) -> None: data_storage_root = os.path.dirname(current_data_path) if os.path.exists(data_storage_root): # Iterate through all directories in the data storage root + version_pattern = re.compile(r'^\d+\.\d+$') # Pattern to match version folders like "5.0", "5.1" + for folder_name in os.listdir(data_storage_root): + # Only process folders that look like version numbers + if not version_pattern.match(folder_name): + continue + folder_path = os.path.join(data_storage_root, folder_name) # Skip if it's not a directory or if it's the current version if not os.path.isdir(folder_path) or folder_path == current_data_path: @@ -319,7 +326,7 @@ def clearConfigurationCache(self, clear_all_versions: bool = False) -> None: version_cache_path = os.path.join(folder_path, "cache") if os.path.exists(version_cache_path): shutil.rmtree(version_cache_path) - Logger.log("i", f"Cleared cache at: {version_cache_path}") + Logger.log("i", "Cleared cache at: %s", version_cache_path) # Show success message message_text = catalog.i18nc("@info:status", "Configuration cache cleared successfully.") @@ -329,7 +336,7 @@ def clearConfigurationCache(self, clear_all_versions: bool = False) -> None: message.show() except Exception as e: - Logger.log("e", f"Failed to clear configuration cache: {str(e)}") + Logger.log("e", "Failed to clear configuration cache: %s", str(e)) error_message = Message( catalog.i18nc("@info:status", "Failed to clear configuration cache: {0}").format(str(e)), lifetime=0,