fix: Ensure mutual exclusivity and improve first backup logic

Centralize Mutual Exclusivity Logic:** Refactored the "Full Backup" and
     "Incremental" mutual exclusivity logic into a shared utility function (
     `enforce_backup_type_exclusivity`) in `pyimage_ui/shared_logic.py`. This ensures
     consistent behavior across both the main application view and the advanced settings.
Corrected Main View Exclusivity:** Resolved the issue where users could select
     both "Full Backup" and "Incremental" simultaneously in the main view. The checkboxes
     now correctly enforce mutual exclusivity.
Enhanced "First Backup" Handling:** Improved the logic for the initial backup.
     If no existing backup is detected in the destination, the system automatically
     enforces a "Full Backup" and disables the relevant checkboxes in the main view. This
     prevents incorrect backup types for new destinations.
This commit is contained in:
2025-08-26 14:31:08 +02:00
parent 09f3831796
commit 48609d9b3e
7 changed files with 42 additions and 23 deletions

View File

@@ -18,6 +18,7 @@ from core.data_processing import DataProcessing
from pyimage_ui.drawing import Drawing
from pyimage_ui.navigation import Navigation
from pyimage_ui.actions import Actions
from pyimage_ui.shared_logic import enforce_backup_type_exclusivity
class MainApplication(tk.Tk):
@@ -348,10 +349,10 @@ class MainApplication(tk.Tk):
self.bypass_security_var = tk.BooleanVar()
self.full_backup_cb = ttk.Checkbutton(checkbox_frame, text=Msg.STR["full_backup"],
variable=self.vollbackup_var, command=lambda: self._enforce_main_backup_type_exclusivity("full"))
variable=self.vollbackup_var, command=lambda: enforce_backup_type_exclusivity(self.vollbackup_var, self.inkrementell_var, self.vollbackup_var.get()))
self.full_backup_cb.pack(side=tk.LEFT, padx=5)
self.incremental_cb = ttk.Checkbutton(checkbox_frame, text=Msg.STR["incremental"],
variable=self.inkrementell_var, command=lambda: self._enforce_main_backup_type_exclusivity("incremental"))
variable=self.inkrementell_var, command=lambda: enforce_backup_type_exclusivity(self.inkrementell_var, self.vollbackup_var, self.inkrementell_var.get()))
self.incremental_cb.pack(side=tk.LEFT, padx=5)
self.test_run_cb = ttk.Checkbutton(checkbox_frame, text=Msg.STR["test_run"],
variable=self.testlauf_var)
@@ -461,13 +462,7 @@ class MainApplication(tk.Tk):
else:
self.encrypted_cb.config(state="normal")
def _enforce_main_backup_type_exclusivity(self, changed_var):
# This is only active if no 'force' setting is applied
if self.full_backup_cb.cget('state') == 'normal':
if changed_var == "full" and self.vollbackup_var.get():
self.inkrementell_var.set(False)
elif changed_var == "incremental" and self.inkrementell_var.get():
self.vollbackup_var.set(False)
if __name__ == "__main__":

Binary file not shown.

View File

@@ -18,15 +18,32 @@ class Actions:
self.app = app
def _check_for_first_backup(self):
if (self.app.left_canvas_data.get('folder') == "Computer" and
self.app.destination_path and
not os.listdir(self.app.destination_path)):
self.app.is_first_backup = True
# Enforce full backup, and uncheck incremental
# This logic only applies if no override from advanced settings is active
if self.app.full_backup_cb.cget('state') != 'normal':
self.app.is_first_backup = False # Ensure this is reset if controls are disabled
return
# A "first backup" situation exists if the destination is selected but empty.
# This applies to both Computer and User folder backups.
is_first_backup_situation = (self.app.destination_path and
os.path.isdir(self.app.destination_path) and
not os.listdir(self.app.destination_path))
self.app.is_first_backup = is_first_backup_situation
if is_first_backup_situation:
# It's the first backup, so it MUST be a full backup.
self.app.vollbackup_var.set(True)
self.app.inkrementell_var.set(False)
# Disable controls so user cannot change this.
self.app.full_backup_cb.config(state="disabled")
self.app.incremental_cb.config(state="disabled")
else:
self.app.is_first_backup = False
# A backup already exists, so the user can choose.
# Re-enable controls.
self.app.full_backup_cb.config(state="normal")
self.app.incremental_cb.config(state="normal")
# We don't set the value here, preserving the user's last choice.
def on_sidebar_button_click(self, button_text):
if not self.app.canvas_frame.winfo_viewable():

View File

@@ -6,6 +6,7 @@ import fnmatch
from app_config import AppConfig, Msg
from shared_libs.animated_icon import AnimatedIcon
from pyimage_ui.shared_logic import enforce_backup_type_exclusivity
class AdvancedSettingsFrame(tk.Toplevel):
def __init__(self, master, config_manager, app_instance, **kwargs):
@@ -63,8 +64,8 @@ class AdvancedSettingsFrame(tk.Toplevel):
self.force_compression_var = tk.BooleanVar()
self.force_encryption_var = tk.BooleanVar()
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_full_backup"], variable=self.force_full_var, command=lambda: self._enforce_backup_type_exclusivity("full")).pack(anchor=tk.W)
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_incremental_backup"], variable=self.force_incremental_var, command=lambda: self._enforce_backup_type_exclusivity("incremental")).pack(anchor=tk.W)
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_full_backup"], variable=self.force_full_var, command=lambda: enforce_backup_type_exclusivity(self.force_full_var, self.force_incremental_var, self.force_full_var.get())).pack(anchor=tk.W)
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_incremental_backup"], variable=self.force_incremental_var, command=lambda: enforce_backup_type_exclusivity(self.force_incremental_var, self.force_full_var, self.force_incremental_var.get())).pack(anchor=tk.W)
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_compression"], variable=self.force_compression_var).pack(anchor=tk.W)
ttk.Checkbutton(defaults_frame, text=Msg.STR["force_encryption"], variable=self.force_encryption_var).pack(anchor=tk.W)
@@ -98,12 +99,6 @@ class AdvancedSettingsFrame(tk.Toplevel):
if self.app_instance:
self.app_instance.update_backup_options_from_config()
def _enforce_backup_type_exclusivity(self, changed_var):
if changed_var == "full" and self.force_full_var.get():
self.force_incremental_var.set(False)
elif changed_var == "incremental" and self.force_incremental_var.get():
self.force_full_var.set(False)
def _load_backup_defaults(self):
self.force_full_var.set(self.config_manager.get_setting("force_full_backup", False))
self.force_incremental_var.set(self.config_manager.get_setting("force_incremental_backup", False))

View File

@@ -0,0 +1,12 @@
# pyimage_ui/shared_logic.py
def enforce_backup_type_exclusivity(var_to_set, other_var, is_checked):
"""
Enforces mutual exclusivity between two tkinter BooleanVars.
:param var_to_set: The BooleanVar of the checkbox that was clicked.
:param other_var: The other BooleanVar in the exclusive pair.
:param is_checked: The new state of the clicked checkbox.
"""
if is_checked:
other_var.set(False)