refactor(settings): Overhaul Reset and Keyfile UI/UX
This commit introduces a major refactoring of the settings and advanced settings panels to improve user experience and code structure. Key Changes: 1. **Reset Functionality Refactored:** - The "Default Settings" logic has been moved from `actions.py` into `settings_frame.py`, where it belongs. - Clicking "Reset" now opens a dedicated view with separate options for a "Default Reset" and a "Hard Reset", each with clear explanations. - A global "Cancel" button was added for this new view, and the layout of the components has been centered and cleaned up. - Error handling for the reset process has been improved to show feedback in the header. 2. **Keyfile Creation UX Overhauled:** - The "Automation Settings" (Keyfile) view in Advanced Settings is completely redesigned for clarity. - It now explicitly displays the currently selected backup destination, so the user knows which container will be affected. - A detailed description has been added to explain the purpose and prerequisites of creating a keyfile. - The redundant "Apply" button is now hidden in this view. - Feedback for keyfile creation (success or failure) is now shown as a temporary message in the header instead of a blocking dialog. - Error messages are more informative, guiding the user on how to proceed (e.g., by creating an encrypted backup first). 3. **String Externalization:** - All new UI text for the keyfile and reset features has been added to `pbp_app_config.py` to support translation.
This commit is contained in:
@@ -257,7 +257,7 @@ class Msg:
|
||||
"log": _("Log"),
|
||||
"full_backup": _("Full backup"),
|
||||
"incremental": _("Incremental"),
|
||||
"incremental_backup": _("Incremental backup"), # New
|
||||
"incremental_backup": _("Incremental backup"),
|
||||
"test_run": _("Test run"),
|
||||
"start": _("Start"),
|
||||
"cancel_backup": _("Cancel"),
|
||||
@@ -280,8 +280,8 @@ class Msg:
|
||||
"system_excludes": _("System Excludes"),
|
||||
"manual_excludes": _("Manual Excludes"),
|
||||
"manual_excludes_info": _("Here, manually add files or folders to be excluded from the backup. Each entry should be on a new line."),
|
||||
"sudoers_info_text": _(f"To run automated backups, an administrator must create a file in /etc/sudoers.d/\n"
|
||||
f"with the following content (replace 'user' with the correct username):\n"
|
||||
"sudoers_info_text": _(f"To run automated backups, an administrator must create a file in /etc/sudoers.d/\n"
|
||||
f"with the following content (replace 'user' with the correct username):\n"
|
||||
f"user ALL=(ALL) NOPASSWD: /path/to/pybackup-cli.py"),
|
||||
|
||||
# Menus
|
||||
@@ -353,9 +353,9 @@ class Msg:
|
||||
"header_subtitle": _("Simple GUI for rsync"),
|
||||
"encrypted_backup_content": _("Encrypted Backups"),
|
||||
"compressed": _("Compressed"),
|
||||
"compression": _("Compression"), # New
|
||||
"compression": _("Compression"),
|
||||
"encrypted": _("Encrypted"),
|
||||
"encryption": _("Encryption"), # New
|
||||
"encryption": _("Encryption"),
|
||||
"bypass_security": _("Bypass security"),
|
||||
"refresh_log": _("Refresh log"),
|
||||
"comment": _("Kommentar"),
|
||||
@@ -370,17 +370,38 @@ class Msg:
|
||||
"sync_mode_trash_bin": _("Sync Mode: Archive. Files deleted from the source will be moved to a trash folder in the backup."),
|
||||
"sync_mode_no_delete": _("Sync Mode: Additive. Files deleted from the source will be kept in the backup."),
|
||||
"encryption_note_system_backup": _("Note: For system backups, encryption only applies to files directly within the /home directory. Folders are not automatically encrypted unless explicitly included in the backup."),
|
||||
"keyfile_settings": _("Keyfile Settings"), # New
|
||||
"backup_defaults_title": _("Backup Defaults"), # New
|
||||
"automation_settings_title": _("Automation Settings"), # New
|
||||
"create_add_key_file": _("Create/Add Key File"), # New
|
||||
"key_file_not_created": _("Key file not created."), # New
|
||||
"backup_options": _("Backup Options"), # New
|
||||
"hard_reset": _("Hard reset"),
|
||||
|
||||
# Advanced Settings - Keyfile
|
||||
"keyfile_settings": _("Keyfile Settings"),
|
||||
"backup_defaults_title": _("Backup Defaults"),
|
||||
"automation_settings_title": _("Automation Settings"),
|
||||
"create_add_key_file": _("Create/Add Key File"),
|
||||
"key_file_not_created": _("Key file not created."),
|
||||
"keyfile_automation_info": _("A keyfile provides an alternative way to unlock an encrypted backup without entering a password, which is useful for automation.\n\n**Prerequisite:** You must first create at least one encrypted backup for a profile. This process will then add a keyfile to that existing encrypted container."),
|
||||
"err_no_encrypted_container": _("No encrypted container found at the destination. Please create an encrypted backup for this profile first."),
|
||||
"enter_existing_password_title": _("Enter Existing Password"),
|
||||
"keyfile_creation_success": _("Keyfile created successfully!"),
|
||||
"keyfile_creation_failed": _("Failed to create keyfile. See log for details."),
|
||||
"keyfile_status_unknown": _("Keyfile status unknown (no destination set)."),
|
||||
"keyfile_exists": _("Keyfile exists: {key_file_path}"),
|
||||
"keyfile_not_found_for_dest": _("Keyfile has not been created for this destination."),
|
||||
"select_profile_first": _("Please select at least one profile from the list."),
|
||||
"current_destination": _("Current Target Destination"),
|
||||
"no_destination_selected": _("None. Please select a destination in the main backup view."),
|
||||
"sudoers_info_text": _(f"To run automated backups, an administrator must create a file in /etc/sudoers.d/\n"
|
||||
f"with the following content (replace 'user' with the correct username):\n"
|
||||
f"user ALL=(ALL) NOPASSWD: /path/to/pybackup-cli.py"),
|
||||
|
||||
# General Settings
|
||||
"backup_options": _("Backup Options"),
|
||||
"reset": _("Reset"),
|
||||
"hard_reset_success": _("Hard reset successful.\nRestarting..."),
|
||||
"hard_reset_info_manual_restart": _("The application must be restarted as drives are still mounted."),
|
||||
"default_reset_success": _("Default reset successful"),
|
||||
"default_reset_failed": _("Default reset failed\nPlease click Delete now on Full_delete_config_settings..."),
|
||||
"default_reset_info": _("Click to restore all settings to their original defaults. Your existing backup schedules and any manually added paths in the exclusion list will be preserved."),
|
||||
"hard_reset_warning": _("This will reset the application to its initial state, as if it were opened for the first time. This can be useful if you are experiencing problems with the app. Clicking 'Delete now' will delete the '.config/py_backup' folder in your home directory without an additional dialog. The application will then automatically restart."),
|
||||
"delete_now": _("Delete now"),
|
||||
"default_config_settings": _("Default config settings"),
|
||||
"full_delete_config_settings": _("Full delete config settings"),
|
||||
"password_required": _("Password Required"),
|
||||
"enter_password_prompt": _("Please enter the password for the encrypted backup:"),
|
||||
|
@@ -456,8 +456,8 @@ class MainApplication(tk.Tk):
|
||||
self.scheduler_frame.grid_remove()
|
||||
|
||||
def _setup_settings_frame(self):
|
||||
self.settings_frame = SettingsFrame(
|
||||
self.content_frame, self.navigation, self.actions, self.backup_manager.encryption_manager, self.image_manager, self.config_manager, padding=(0, 10))
|
||||
self.settings_frame = SettingsFrame(self.content_frame, self.navigation, self.actions,
|
||||
self.backup_manager.encryption_manager, self.image_manager, self.config_manager, padding=(0, 10))
|
||||
self.settings_frame.grid(row=2, column=0, sticky="nsew")
|
||||
self.settings_frame.grid_remove()
|
||||
|
||||
|
@@ -77,7 +77,7 @@ class Actions:
|
||||
self.app.compressed_cb.config(state="normal")
|
||||
self.app.encrypted_cb.config(state="normal")
|
||||
self.app.test_run_cb.config(state="normal")
|
||||
|
||||
|
||||
# Apply mutual exclusion rules for Option A
|
||||
if self.app.compressed_var.get():
|
||||
self.app.incremental_var.set(False)
|
||||
@@ -85,7 +85,7 @@ class Actions:
|
||||
self.app.incremental_cb.config(state="disabled")
|
||||
self.app.encrypted_var.set(False)
|
||||
self.app.encrypted_cb.config(state="disabled")
|
||||
|
||||
|
||||
if self.app.incremental_var.get() or self.app.encrypted_var.get():
|
||||
self.app.compressed_var.set(False)
|
||||
self.app.compressed_cb.config(state="disabled")
|
||||
@@ -397,47 +397,6 @@ class Actions:
|
||||
MessageDialog(message_type="error",
|
||||
title=Msg.STR["error"], text=Msg.STR["path_not_found"].format(path=path)).show()
|
||||
|
||||
def reset_to_default_settings(self):
|
||||
|
||||
self.app.config_manager.set_setting("backup_destination_path", None)
|
||||
self.app.config_manager.set_setting("restore_source_path", None)
|
||||
self.app.config_manager.set_setting("restore_destination_path", None)
|
||||
|
||||
self.app.config_manager.remove_setting("backup_animation_type")
|
||||
self.app.config_manager.remove_setting("calculation_animation_type")
|
||||
self.app.config_manager.remove_setting("force_full_backup")
|
||||
self.app.config_manager.remove_setting("force_incremental_backup")
|
||||
self.app.config_manager.remove_setting("force_compression")
|
||||
self.app.config_manager.remove_setting("force_encryption")
|
||||
|
||||
self.app.update_backup_options_from_config()
|
||||
|
||||
AppConfig.generate_and_write_final_exclude_list()
|
||||
app_logger.log("Settings have been reset to default values.")
|
||||
|
||||
settings_frame = self.app.settings_frame
|
||||
if settings_frame:
|
||||
settings_frame.load_and_display_excludes()
|
||||
settings_frame._load_hidden_files()
|
||||
self.app.destination_path = None
|
||||
self.app.start_cancel_button.config(state="disabled")
|
||||
|
||||
self.app.backup_left_canvas_data.clear()
|
||||
self.app.backup_right_canvas_data.clear()
|
||||
self.app.restore_left_canvas_data.clear()
|
||||
self.app.restore_right_canvas_data.clear()
|
||||
|
||||
current_source = self.app.left_canvas_data.get('folder')
|
||||
if current_source:
|
||||
self.on_sidebar_button_click(current_source)
|
||||
|
||||
self.app.backup_content_frame.system_backups_frame._load_backup_content()
|
||||
self.app.backup_content_frame.user_backups_frame._load_backup_content()
|
||||
|
||||
with message_box_animation(self.app.animated_icon):
|
||||
MessageDialog(message_type="info",
|
||||
title=Msg.STR["settings_reset_title"], text=Msg.STR["settings_reset_text"])
|
||||
|
||||
def _parse_size_string_to_bytes(self, size_str: str) -> int:
|
||||
if not size_str or size_str == Msg.STR["calculating_size"]:
|
||||
return 0
|
||||
@@ -524,7 +483,8 @@ class Actions:
|
||||
|
||||
self.app.task_progress.stop()
|
||||
self.app.task_progress.config(mode="determinate", value=0)
|
||||
self.app._update_info_label(Msg.STR["incremental_calc_cancelled"], color="#E8740C")
|
||||
self.app._update_info_label(
|
||||
Msg.STR["incremental_calc_cancelled"], color="#E8740C")
|
||||
self.app.start_cancel_button.config(text=Msg.STR["start"])
|
||||
self._set_ui_state(True)
|
||||
return
|
||||
@@ -541,12 +501,14 @@ class Actions:
|
||||
delete_path)
|
||||
app_logger.log(
|
||||
Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
self.app._update_info_label(Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
self.app._update_info_label(
|
||||
Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
else:
|
||||
self.app.backup_manager.cancel_backup()
|
||||
app_logger.log(
|
||||
"Backup cancelled, but directory could not be deleted (path unknown).")
|
||||
self.app._update_info_label("Backup cancelled, but directory could not be deleted (path unknown).")
|
||||
self.app._update_info_label(
|
||||
"Backup cancelled, but directory could not be deleted (path unknown).")
|
||||
else:
|
||||
self.app.backup_manager.cancel_backup()
|
||||
if delete_path:
|
||||
@@ -557,14 +519,17 @@ class Actions:
|
||||
shutil.rmtree(delete_path)
|
||||
app_logger.log(
|
||||
Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
self.app._update_info_label(Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
self.app._update_info_label(
|
||||
Msg.STR["backup_cancelled_and_deleted_msg"])
|
||||
except Exception as e:
|
||||
app_logger.log(f"Error deleting backup directory: {e}")
|
||||
self.app._update_info_label(f"Error deleting backup directory: {e}")
|
||||
self.app._update_info_label(
|
||||
f"Error deleting backup directory: {e}")
|
||||
else:
|
||||
app_logger.log(
|
||||
"Backup cancelled, but no path found to delete.")
|
||||
self.app._update_info_label("Backup cancelled, but no path found to delete.")
|
||||
self.app._update_info_label(
|
||||
"Backup cancelled, but no path found to delete.")
|
||||
|
||||
if hasattr(self.app, 'current_backup_path'):
|
||||
self.app.current_backup_path = None
|
||||
|
@@ -166,28 +166,44 @@ class AdvancedSettingsFrame(ttk.Frame):
|
||||
self.backup_defaults_frame, text=Msg.STR["encryption_note_system_backup"], wraplength=750, justify="left")
|
||||
encryption_note.pack(anchor=tk.W, pady=5)
|
||||
|
||||
# --- Keyfile Settings Frame ---
|
||||
self.keyfile_settings_frame = ttk.LabelFrame(
|
||||
view_container, text=Msg.STR["automation_settings_title"], padding=10)
|
||||
|
||||
keyfile_info_label = ttk.Label(
|
||||
self.keyfile_settings_frame, text=Msg.STR["keyfile_automation_info"], justify="left", wraplength=750)
|
||||
keyfile_info_label.grid(
|
||||
row=0, column=0, columnspan=3, sticky="w", padx=5, pady=(5, 15))
|
||||
|
||||
# Display for current destination
|
||||
dest_frame = ttk.Frame(self.keyfile_settings_frame)
|
||||
dest_frame.grid(row=1, column=0, columnspan=3, sticky="ew", padx=5, pady=5)
|
||||
dest_frame.columnconfigure(1, weight=1)
|
||||
ttk.Label(dest_frame, text=f"{Msg.STR['current_destination']}:", font=("Ubuntu", 11, "bold")).grid(row=0, column=0, sticky="w")
|
||||
self.keyfile_dest_path_label = ttk.Label(dest_frame, text=Msg.STR["no_destination_selected"], foreground="gray")
|
||||
self.keyfile_dest_path_label.grid(row=0, column=1, sticky="w", padx=5)
|
||||
|
||||
# Action Button
|
||||
key_file_button = ttk.Button(
|
||||
self.keyfile_settings_frame, text=Msg.STR["create_add_key_file"], command=self._create_key_file)
|
||||
key_file_button.grid(row=0, column=0, padx=5, pady=5)
|
||||
key_file_button.grid(row=2, column=0, padx=5, pady=10)
|
||||
|
||||
self.key_file_status_var = tk.StringVar(
|
||||
value=Msg.STR["key_file_not_created"])
|
||||
# Status Label
|
||||
self.key_file_status_var = tk.StringVar(value="")
|
||||
key_file_status_label = ttk.Label(
|
||||
self.keyfile_settings_frame, textvariable=self.key_file_status_var, foreground="gray")
|
||||
key_file_status_label.grid(row=0, column=1, padx=5, pady=5, sticky="w")
|
||||
key_file_status_label.grid(
|
||||
row=2, column=1, padx=5, pady=10, sticky="w")
|
||||
|
||||
sudoers_info_text = Msg.STR["sudoers_info_text"]
|
||||
# Sudoers Info
|
||||
sudoers_info_label = ttk.Label(
|
||||
self.keyfile_settings_frame, text=sudoers_info_text, justify="left")
|
||||
|
||||
self.keyfile_settings_frame, text=Msg.STR["sudoers_info_text"], justify="left")
|
||||
sudoers_info_label.grid(
|
||||
row=1, column=0, columnspan=2, sticky="w", padx=5, pady=5)
|
||||
row=3, column=0, columnspan=3, sticky="w", padx=5, pady=10)
|
||||
|
||||
self.keyfile_settings_frame.columnconfigure(1, weight=1)
|
||||
|
||||
# --- Bottom Buttons (for most views) ---
|
||||
self.bottom_button_frame = ttk.Frame(self)
|
||||
self.bottom_button_frame.pack(pady=10)
|
||||
|
||||
@@ -244,60 +260,57 @@ class AdvancedSettingsFrame(ttk.Frame):
|
||||
self.config_manager.set_setting("no_trash_bin", no_trash)
|
||||
|
||||
def _create_key_file(self):
|
||||
if not self.app_instance.destination_path:
|
||||
MessageDialog(message_type="error", title="Error",
|
||||
text="Please select a backup destination first.")
|
||||
header = self.app_instance.header_frame
|
||||
destination = self.app_instance.destination_path
|
||||
|
||||
if not destination:
|
||||
MessageDialog(message_type="error", title=Msg.STR["error"],
|
||||
text=Msg.STR["select_destination_first"]).show()
|
||||
return
|
||||
|
||||
pybackup_dir = os.path.join(
|
||||
self.app_instance.destination_path, "pybackup")
|
||||
pybackup_dir = os.path.join(destination, "pybackup")
|
||||
container_path = os.path.join(pybackup_dir, "pybackup_encrypted.luks")
|
||||
if not os.path.exists(container_path):
|
||||
MessageDialog(message_type="error", title="Error",
|
||||
text="No encrypted container found at the destination.")
|
||||
MessageDialog(message_type="error", title=Msg.STR["error"],
|
||||
text=Msg.STR["err_no_encrypted_container"]).show()
|
||||
return
|
||||
|
||||
password_dialog = PasswordDialog(
|
||||
self, title="Enter Existing Password", confirm=False, translations=Msg.STR)
|
||||
self, title=Msg.STR["enter_existing_password_title"], confirm=False, translations=Msg.STR)
|
||||
password, _ = password_dialog.get_password()
|
||||
|
||||
if not password:
|
||||
return
|
||||
|
||||
key_file_path = self.app_instance.backup_manager.encryption_manager.create_and_add_key_file(
|
||||
self.app_instance.destination_path, password)
|
||||
destination, password)
|
||||
|
||||
if key_file_path:
|
||||
MessageDialog(message_type="info", title="Success",
|
||||
text=f"Key file created and added successfully!\nPath: {key_file_path}")
|
||||
header.show_temporary_message(Msg.STR["keyfile_creation_success"])
|
||||
else:
|
||||
MessageDialog(message_type="error", title="Error",
|
||||
text="Failed to create or add key file. See log for details.")
|
||||
header.show_temporary_message(Msg.STR["keyfile_creation_failed"])
|
||||
|
||||
self._update_key_file_status()
|
||||
|
||||
def _update_key_file_status(self):
|
||||
if not self.app_instance.destination_path:
|
||||
self.key_file_status_var.set(
|
||||
"Key file status unknown (no destination set).")
|
||||
destination = self.app_instance.destination_path
|
||||
if not destination:
|
||||
self.keyfile_dest_path_label.config(text=Msg.STR["no_destination_selected"], foreground="gray")
|
||||
self.key_file_status_var.set(Msg.STR["keyfile_status_unknown"])
|
||||
return
|
||||
|
||||
# Determine the profile_name based on the current source folder
|
||||
source_name = self.app_instance.left_canvas_data.get('folder')
|
||||
if not source_name:
|
||||
# Fallback or handle case where no source is selected, perhaps default to "system" or log an error
|
||||
# For now, let's assume "system" if no specific folder is selected for keyfile status
|
||||
profile_name = "system"
|
||||
else:
|
||||
profile_name = "system" if source_name == "Computer" else source_name
|
||||
self.keyfile_dest_path_label.config(text=destination, foreground="#FFFFFF") # Adapt color to theme
|
||||
|
||||
source_name = self.app_instance.left_canvas_data.get('folder') or "system"
|
||||
profile_name = "system" if source_name == "Computer" else source_name
|
||||
|
||||
key_file_path = self.app_instance.backup_manager.encryption_manager.get_key_file_path(
|
||||
self.app_instance.destination_path, profile_name)
|
||||
destination, profile_name)
|
||||
|
||||
if os.path.exists(key_file_path):
|
||||
self.key_file_status_var.set(f"Key file exists: {key_file_path}")
|
||||
self.key_file_status_var.set(Msg.STR["keyfile_exists"].format(key_file_path=key_file_path))
|
||||
else:
|
||||
self.key_file_status_var.set(
|
||||
"Key file has not been created for this destination.")
|
||||
self.key_file_status_var.set(Msg.STR["keyfile_not_found_for_dest"])
|
||||
|
||||
def _switch_view(self, index):
|
||||
self.current_view_index = index
|
||||
@@ -310,7 +323,7 @@ class AdvancedSettingsFrame(ttk.Frame):
|
||||
self.backup_defaults_frame.pack_forget()
|
||||
|
||||
# Show/hide the main action buttons based on the view
|
||||
if index == 1: # Manual Excludes view
|
||||
if index in [1, 2]: # Manual Excludes and Keyfile Settings views
|
||||
self.bottom_button_frame.pack_forget()
|
||||
else:
|
||||
self.bottom_button_frame.pack(pady=10)
|
||||
|
@@ -6,7 +6,6 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
from core.pbp_app_config import AppConfig, Msg
|
||||
from core.backup_manager import BackupManager
|
||||
from pyimage_ui.advanced_settings_frame import AdvancedSettingsFrame
|
||||
from shared_libs.custom_file_dialog import CustomFileDialog
|
||||
from shared_libs.message import MessageDialog, PasswordDialog
|
||||
@@ -47,19 +46,12 @@ class SettingsFrame(ttk.Frame):
|
||||
self.button_frame, text=Msg.STR["add_to_exclude_list"], command=self._add_to_exclude_list, style="Gray.Toolbutton")
|
||||
add_to_exclude_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
ttk.Separator(self.button_frame, orient=tk.VERTICAL).pack(
|
||||
side=tk.LEFT, ipady=15, padx=5)
|
||||
|
||||
reset_button = ttk.Button(
|
||||
self.button_frame, text=Msg.STR["default_settings"], command=self.actions.reset_to_default_settings, style="Gray.Toolbutton")
|
||||
reset_button.pack(side=tk.LEFT)
|
||||
|
||||
ttk.Separator(self.button_frame, orient=tk.VERTICAL).pack(
|
||||
side=tk.LEFT, ipady=15, padx=5)
|
||||
|
||||
# Right-aligned buttons
|
||||
hard_reset_button = ttk.Button(
|
||||
self.button_frame, text=Msg.STR["hard_reset"], command=self._toggle_hard_reset_view, style="Gray.Toolbutton")
|
||||
self.button_frame, text=Msg.STR["reset"], command=self._toggle_hard_reset_view, style="Gray.Toolbutton")
|
||||
hard_reset_button.pack(side=tk.LEFT, padx=5)
|
||||
|
||||
ttk.Separator(self.button_frame, orient=tk.VERTICAL).pack(
|
||||
@@ -119,30 +111,93 @@ class SettingsFrame(ttk.Frame):
|
||||
self.hidden_tree.bind("<Button-1>", self._toggle_include_status_hidden)
|
||||
self.hidden_tree_frame.pack_forget() # Initially hidden
|
||||
|
||||
# --- Default Reset Frame (initially hidden) ---
|
||||
self.default_reset_frame = ttk.LabelFrame(
|
||||
self, text=Msg.STR["default_config_settings"], padding=10)
|
||||
|
||||
default_reset_label = ttk.Label(
|
||||
self.default_reset_frame, text=Msg.STR["default_reset_info"], wraplength=400, justify=tk.CENTER)
|
||||
default_reset_label.pack(pady=10, expand=True)
|
||||
|
||||
# Frame to center the button
|
||||
default_reset_button_frame = ttk.Frame(self.default_reset_frame)
|
||||
default_reset_button_frame.pack(pady=5)
|
||||
|
||||
reset_button = ttk.Button(
|
||||
default_reset_button_frame, text=Msg.STR["default_settings"], command=self._reset_to_default_settings)
|
||||
reset_button.pack() # Centered by default in its own frame
|
||||
|
||||
# --- Hard Reset Frame (initially hidden) ---
|
||||
self.hard_reset_frame = ttk.LabelFrame(
|
||||
self, text=Msg.STR["full_delete_config_settings"], padding=10)
|
||||
|
||||
hard_reset_label = ttk.Label(
|
||||
self.hard_reset_frame, text=Msg.STR["hard_reset_warning"], wraplength=400, justify=tk.LEFT)
|
||||
hard_reset_label.pack(pady=10)
|
||||
self.hard_reset_frame, text=Msg.STR["hard_reset_warning"], wraplength=400, justify=tk.CENTER)
|
||||
hard_reset_label.pack(pady=10, expand=True)
|
||||
|
||||
hard_reset_button_frame = ttk.Frame(self.hard_reset_frame)
|
||||
hard_reset_button_frame.pack(pady=10)
|
||||
hard_reset_button_frame.pack(pady=5)
|
||||
|
||||
self.delete_now_button = ttk.Button(
|
||||
hard_reset_button_frame, text=Msg.STR["delete_now"], command=self._perform_hard_reset)
|
||||
self.delete_now_button.pack(side=tk.LEFT, padx=5)
|
||||
self.delete_now_button.pack() # Centered by default
|
||||
|
||||
self.cancel_hard_reset_button = ttk.Button(
|
||||
hard_reset_button_frame, text=Msg.STR["cancel"], command=self._toggle_hard_reset_view)
|
||||
self.cancel_hard_reset_button.pack(side=tk.LEFT, padx=5)
|
||||
# --- Bottom Cancel Button for Reset View (initially hidden) ---
|
||||
self.reset_view_cancel_frame = ttk.Frame(self)
|
||||
self.reset_view_cancel_button = ttk.Button(
|
||||
self.reset_view_cancel_frame, text=Msg.STR["cancel"], command=self._toggle_hard_reset_view)
|
||||
self.reset_view_cancel_button.pack(pady=10)
|
||||
|
||||
self.hidden_files_visible = False
|
||||
self.hard_reset_visible = False
|
||||
# To hold the instance of AdvancedSettingsFrame
|
||||
self.advanced_settings_frame_instance = None
|
||||
|
||||
def _reset_to_default_settings(self):
|
||||
app_instance = self.master.master.master
|
||||
header = app_instance.header_frame
|
||||
try:
|
||||
self.config_manager.set_setting("backup_destination_path", None)
|
||||
self.config_manager.set_setting("restore_source_path", None)
|
||||
self.config_manager.set_setting("restore_destination_path", None)
|
||||
|
||||
self.config_manager.remove_setting("backup_animation_type")
|
||||
self.config_manager.remove_setting("calculation_animation_type")
|
||||
self.config_manager.remove_setting("force_full_backup")
|
||||
self.config_manager.remove_setting("force_incremental_backup")
|
||||
self.config_manager.remove_setting("force_compression")
|
||||
self.config_manager.remove_setting("force_encryption")
|
||||
|
||||
app_instance.update_backup_options_from_config()
|
||||
|
||||
AppConfig.generate_and_write_final_exclude_list()
|
||||
app_logger.log("Settings have been reset to default values.")
|
||||
|
||||
self.load_and_display_excludes()
|
||||
if self.hidden_files_visible:
|
||||
self._load_hidden_files()
|
||||
|
||||
app_instance.destination_path = None
|
||||
app_instance.start_cancel_button.config(state="disabled")
|
||||
|
||||
app_instance.backup_left_canvas_data.clear()
|
||||
app_instance.backup_right_canvas_data.clear()
|
||||
app_instance.restore_left_canvas_data.clear()
|
||||
app_instance.restore_right_canvas_data.clear()
|
||||
|
||||
current_source = app_instance.left_canvas_data.get('folder')
|
||||
if current_source:
|
||||
self.actions.on_sidebar_button_click(current_source)
|
||||
|
||||
app_instance.backup_content_frame.system_backups_frame._load_backup_content()
|
||||
app_instance.backup_content_frame.user_backups_frame._load_backup_content()
|
||||
|
||||
header.show_temporary_message(Msg.STR["default_reset_success"])
|
||||
|
||||
except Exception as e:
|
||||
app_logger.log(f"Error resetting settings: {e}")
|
||||
header.show_temporary_message(Msg.STR["default_reset_failed"])
|
||||
|
||||
def _perform_hard_reset(self):
|
||||
try:
|
||||
# First, always attempt to unmount all encrypted drives
|
||||
@@ -153,7 +208,7 @@ class SettingsFrame(ttk.Frame):
|
||||
app_logger.log(
|
||||
"WARNING: Not all encrypted drives could be unmounted. Preventing application closure.")
|
||||
MessageDialog(
|
||||
message_type="error", title=Msg.STR["unmount_failed_title"], text=Msg.STR["unmount_failed_message"]).show()
|
||||
message_type="error", title=Msg.STR["unmount_failed_title"], text=Msg.STR["unmount_failed_message"])
|
||||
return # Prevent application from closing
|
||||
|
||||
# Try to delete the config directory without elevated rights
|
||||
@@ -179,10 +234,16 @@ class SettingsFrame(ttk.Frame):
|
||||
self.trees_container.pack_forget()
|
||||
self.button_frame.pack_forget()
|
||||
self.bottom_button_frame.pack_forget()
|
||||
self.default_reset_frame.pack(
|
||||
fill=tk.X, expand=True, padx=10, pady=5)
|
||||
self.hard_reset_frame.pack(
|
||||
fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||||
fill=tk.X, expand=True, padx=10, pady=5)
|
||||
self.reset_view_cancel_frame.pack(fill=tk.X, side=tk.BOTTOM)
|
||||
|
||||
else:
|
||||
self.default_reset_frame.pack_forget()
|
||||
self.hard_reset_frame.pack_forget()
|
||||
self.reset_view_cancel_frame.pack_forget()
|
||||
self.button_frame.pack(fill=tk.X, padx=10)
|
||||
self.trees_container.pack(
|
||||
fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||||
|
Reference in New Issue
Block a user