Compare commits
5 Commits
3a295ce70a
...
313f3b9654
Author | SHA1 | Date | |
---|---|---|---|
313f3b9654 | |||
fd06c29a18 | |||
6d55a476fd | |||
1b4fcc8a1c | |||
bd947bd80e |
Binary file not shown.
@@ -204,10 +204,13 @@ class Msg:
|
||||
"back": _("Back"),
|
||||
"active": _("Active"),
|
||||
"source": _("Source"),
|
||||
"select_source": _("Select Source"),
|
||||
"sources": _("Sources"),
|
||||
"destination": _("Destination"),
|
||||
"system_backup_info": _("System Backup"),
|
||||
"system_restore_info": _("System Restore"),
|
||||
"system_restore": _("System Restore"),
|
||||
"select_source_first": _("Please select a source first"),
|
||||
"user_backup_info": _("User Backup"),
|
||||
"user_restore_info": _("User Restore"),
|
||||
"select_destination_first": _("Please select a destination first"),
|
||||
|
45
main_app.py
45
main_app.py
@@ -249,14 +249,9 @@ class MainApplication(tk.Tk):
|
||||
target_label_frame, text="0.00 GB / 0.00 GB")
|
||||
self.target_size_label.pack(side=tk.RIGHT)
|
||||
|
||||
self.restore_size_frame = ttk.Frame(self.content_frame)
|
||||
self.restore_size_frame.grid(row=4, column=0, sticky="ew", padx=10, pady=5, rowspan=2)
|
||||
self.restore_size_frame.grid_columnconfigure(0, weight=1)
|
||||
self.restore_size_frame.grid_remove()
|
||||
|
||||
self.restore_size_frame_before = ttk.LabelFrame(
|
||||
self.restore_size_frame, text="Before Restoration", padding=10)
|
||||
self.restore_size_frame_before.grid(row=0, column=0, sticky="ew", padx=10, pady=5)
|
||||
self.content_frame, text="Before Restoration", padding=10)
|
||||
self.restore_size_frame_before.grid(row=4, column=0, sticky="ew", padx=10, pady=5)
|
||||
self.restore_size_frame_before.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.restore_size_canvas_before = tk.Canvas(
|
||||
@@ -270,8 +265,8 @@ class MainApplication(tk.Tk):
|
||||
self.restore_size_label_before.pack(side=tk.RIGHT)
|
||||
|
||||
self.restore_size_frame_after = ttk.LabelFrame(
|
||||
self.restore_size_frame, text="After Restoration", padding=10)
|
||||
self.restore_size_frame_after.grid(row=1, column=0, sticky="ew", padx=10, pady=5)
|
||||
self.content_frame, text="After Restoration", padding=10)
|
||||
self.restore_size_frame_after.grid(row=5, column=0, sticky="ew", padx=10, pady=5)
|
||||
self.restore_size_frame_after.grid_columnconfigure(0, weight=1)
|
||||
|
||||
self.restore_size_canvas_after = tk.Canvas(
|
||||
@@ -289,6 +284,9 @@ class MainApplication(tk.Tk):
|
||||
restore_label_frame_after, text="")
|
||||
self.restore_size_label_diff.pack(side=tk.RIGHT)
|
||||
|
||||
self.restore_size_frame_before.grid_remove()
|
||||
self.restore_size_frame_after.grid_remove()
|
||||
|
||||
self._load_state_and_initialize()
|
||||
self.update_backup_options_from_config() # Add this call
|
||||
self.protocol("WM_DELETE_WINDOW", self.on_closing)
|
||||
@@ -298,6 +296,23 @@ class MainApplication(tk.Tk):
|
||||
last_mode = self.config_manager.get_setting("last_mode", "backup")
|
||||
|
||||
# Pre-load data from config before initializing the UI
|
||||
backup_source_path = self.config_manager.get_setting("backup_source_path")
|
||||
if backup_source_path and os.path.isdir(backup_source_path):
|
||||
folder_name = next((name for name, path_obj in AppConfig.FOLDER_PATHS.items() if str(path_obj) == backup_source_path), None)
|
||||
|
||||
if folder_name:
|
||||
icon_name = self.buttons_map[folder_name]['icon']
|
||||
else:
|
||||
# Handle custom folder path
|
||||
folder_name = os.path.basename(backup_source_path.rstrip('/'))
|
||||
icon_name = 'folder_extralarge' # A generic folder icon
|
||||
|
||||
self.backup_left_canvas_data.update({
|
||||
'icon': icon_name,
|
||||
'folder': folder_name,
|
||||
'path_display': backup_source_path,
|
||||
})
|
||||
|
||||
backup_dest_path = self.config_manager.get_setting(
|
||||
"backup_destination_path")
|
||||
if backup_dest_path and os.path.isdir(backup_dest_path):
|
||||
@@ -339,7 +354,7 @@ class MainApplication(tk.Tk):
|
||||
self.navigation.initialize_ui_for_mode(last_mode)
|
||||
|
||||
# Trigger calculations if needed
|
||||
if last_mode == 'backup' and backup_dest_path:
|
||||
if last_mode == 'backup':
|
||||
self.after(100, self.actions.on_sidebar_button_click,
|
||||
self.backup_left_canvas_data.get('folder', 'Computer'))
|
||||
elif last_mode == 'restore':
|
||||
@@ -351,10 +366,6 @@ class MainApplication(tk.Tk):
|
||||
'folder', 'Computer')
|
||||
self.after(100, self.actions.on_sidebar_button_click,
|
||||
restore_dest_folder)
|
||||
else:
|
||||
# Default action if no specific state to restore
|
||||
self.after(100, self.actions.on_sidebar_button_click, "Computer")
|
||||
|
||||
self.data_processing.process_queue()
|
||||
|
||||
def _setup_log_window(self):
|
||||
@@ -445,6 +456,12 @@ class MainApplication(tk.Tk):
|
||||
self.config_manager.set_setting("last_mode", self.mode)
|
||||
|
||||
# Save paths from the data dictionaries
|
||||
if self.backup_left_canvas_data.get('path_display'):
|
||||
self.config_manager.set_setting(
|
||||
"backup_source_path", self.backup_left_canvas_data['path_display'])
|
||||
else:
|
||||
self.config_manager.set_setting("backup_source_path", None)
|
||||
|
||||
if self.backup_right_canvas_data.get('path_display'):
|
||||
self.config_manager.set_setting(
|
||||
"backup_destination_path", self.backup_right_canvas_data['path_display'])
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -20,7 +20,7 @@ class Actions:
|
||||
def _check_for_first_backup(self):
|
||||
# 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
|
||||
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.
|
||||
@@ -48,7 +48,8 @@ class Actions:
|
||||
def on_sidebar_button_click(self, button_text):
|
||||
self.app.drawing.reset_projection_canvases()
|
||||
if not self.app.canvas_frame.winfo_viewable():
|
||||
self.app.navigation.toggle_mode(self.app.mode, trigger_calculation=False)
|
||||
self.app.navigation.toggle_mode(
|
||||
self.app.mode, trigger_calculation=False)
|
||||
|
||||
self.app.log_window.clear_log()
|
||||
folder_path = AppConfig.FOLDER_PATHS.get(button_text)
|
||||
@@ -73,16 +74,17 @@ class Actions:
|
||||
if button_text == "Computer":
|
||||
if self.app.mode == 'backup':
|
||||
extra_info = Msg.STR["system_backup_info"]
|
||||
else: # restore
|
||||
else: # restore
|
||||
extra_info = Msg.STR["system_restore_info"]
|
||||
else: # User folder
|
||||
else: # User folder
|
||||
if self.app.mode == 'backup':
|
||||
extra_info = Msg.STR["user_backup_info"]
|
||||
else: # restore
|
||||
else: # restore
|
||||
extra_info = Msg.STR["user_restore_info"]
|
||||
|
||||
# Unified logic for starting a calculation on the left canvas
|
||||
self._start_left_canvas_calculation(button_text, str(folder_path), icon_name, extra_info)
|
||||
self._start_left_canvas_calculation(
|
||||
button_text, str(folder_path), icon_name, extra_info)
|
||||
|
||||
def _start_left_canvas_calculation(self, button_text, folder_path, icon_name, extra_info):
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
@@ -98,6 +100,18 @@ class Actions:
|
||||
self.app.drawing.redraw_left_canvas()
|
||||
return
|
||||
|
||||
if self.app.mode == 'restore' and not self.app.right_canvas_data.get('path_display'):
|
||||
self.app.left_canvas_data.update({
|
||||
'icon': icon_name,
|
||||
'folder': button_text,
|
||||
'path_display': folder_path,
|
||||
'size': Msg.STR["select_source_first"],
|
||||
'calculating': False,
|
||||
'extra_info': extra_info
|
||||
})
|
||||
self.app.drawing.redraw_left_canvas()
|
||||
return
|
||||
|
||||
if self.app.calculation_thread and self.app.calculation_thread.is_alive():
|
||||
self.app.calculation_stop_event.set()
|
||||
|
||||
@@ -126,8 +140,9 @@ class Actions:
|
||||
|
||||
if self.app.mode == 'backup':
|
||||
self._check_for_first_backup()
|
||||
else: # restore mode
|
||||
self.app.config_manager.set_setting("restore_destination_path", folder_path)
|
||||
else: # restore mode
|
||||
self.app.config_manager.set_setting(
|
||||
"restore_destination_path", folder_path)
|
||||
|
||||
def on_right_canvas_click(self, event):
|
||||
self.app.drawing.reset_projection_canvases()
|
||||
@@ -171,11 +186,12 @@ class Actions:
|
||||
size_str = f"{used / (1024**3):.2f} GB / {total / (1024**3):.2f} GB"
|
||||
|
||||
self.app.right_canvas_data.update({
|
||||
'folder': os.path.basename(path.rstrip('/')),
|
||||
'folder': os.path.basename(path.rstrip('/')),
|
||||
'path_display': path,
|
||||
'size': size_str
|
||||
})
|
||||
self.app.config_manager.set_setting("backup_destination_path", path)
|
||||
self.app.config_manager.set_setting(
|
||||
"backup_destination_path", path)
|
||||
self.app.drawing.redraw_right_canvas()
|
||||
self.app.drawing.update_target_projection()
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
@@ -187,11 +203,12 @@ class Actions:
|
||||
|
||||
elif self.app.mode == "restore":
|
||||
self.app.right_canvas_data.update({
|
||||
'folder': os.path.basename(path.rstrip('/')),
|
||||
'folder': os.path.basename(path.rstrip('/')),
|
||||
'path_display': path,
|
||||
'size': ''
|
||||
})
|
||||
self.app.config_manager.set_setting("restore_source_path", path)
|
||||
self.app.config_manager.set_setting(
|
||||
"restore_source_path", path)
|
||||
self.app.drawing.calculate_restore_folder_size()
|
||||
self.app.start_pause_button.config(state="normal")
|
||||
|
||||
@@ -221,22 +238,22 @@ class Actions:
|
||||
# Update the main UI to reflect the cleared settings
|
||||
self.app.update_backup_options_from_config()
|
||||
|
||||
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()
|
||||
|
||||
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.navigation.initialize_ui_for_mode(self.app.mode)
|
||||
self.app.start_pause_button.config(state="disabled")
|
||||
|
||||
# Clear the canvases and reset the UI to its initial state for the current mode
|
||||
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()
|
||||
|
||||
with message_box_animation(self.app.animated_icon):
|
||||
MessageDialog(master=self.app, message_type="info",
|
||||
title=Msg.STR["settings_reset_title"], text=Msg.STR["settings_reset_text"])
|
||||
@@ -249,10 +266,12 @@ class Actions:
|
||||
self.app.start_pause_button["text"] = "Pause"
|
||||
|
||||
self.app.animated_icon.destroy()
|
||||
backup_animation_type = self.app.config_manager.get_setting("backup_animation_type", "counter_arc")
|
||||
backup_animation_type = self.app.config_manager.get_setting(
|
||||
"backup_animation_type", "counter_arc")
|
||||
self.app.animated_icon = AnimatedIcon(
|
||||
self.app.action_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type=backup_animation_type)
|
||||
self.app.animated_icon.pack(side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
self.app.animated_icon.pack(
|
||||
side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
|
||||
self.app.animated_icon.start()
|
||||
if self.app.mode == "backup":
|
||||
@@ -268,7 +287,8 @@ class Actions:
|
||||
self.app.animated_icon.destroy()
|
||||
self.app.animated_icon = AnimatedIcon(
|
||||
self.app.action_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type="blink")
|
||||
self.app.animated_icon.pack(side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
self.app.animated_icon.pack(
|
||||
side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
|
||||
self.app.animated_icon.start()
|
||||
self.app.backup_manager.pause_backup()
|
||||
@@ -277,11 +297,13 @@ class Actions:
|
||||
self.app.start_pause_button["text"] = "Pause"
|
||||
|
||||
self.app.animated_icon.destroy()
|
||||
backup_animation_type = self.app.config_manager.get_setting("backup_animation_type", "counter_arc")
|
||||
backup_animation_type = self.app.config_manager.get_setting(
|
||||
"backup_animation_type", "counter_arc")
|
||||
self.app.animated_icon = AnimatedIcon(
|
||||
self.app.action_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type=backup_animation_type)
|
||||
self.app.animated_icon.pack(side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
|
||||
self.app.animated_icon.pack(
|
||||
side=tk.LEFT, padx=5, before=self.app.task_progress)
|
||||
|
||||
self.app.animated_icon.start()
|
||||
self.app.backup_manager.resume_backup()
|
||||
|
||||
@@ -306,7 +328,7 @@ class Actions:
|
||||
MessageDialog(master=self.app, message_type="error",
|
||||
title=Msg.STR["error"], text=Msg.STR["system_backup_in_home_error"])
|
||||
return
|
||||
|
||||
|
||||
exclude_file_paths = []
|
||||
if AppConfig.GENERATED_EXCLUDE_LIST_PATH.exists():
|
||||
exclude_file_paths.append(AppConfig.GENERATED_EXCLUDE_LIST_PATH)
|
||||
@@ -330,4 +352,4 @@ class Actions:
|
||||
source, dest, False, is_dry_run=is_dry_run, exclude_files=None, on_progress=self.update_task_progress, on_completion=self.on_backup_completion, on_error=self.on_backup_error)
|
||||
|
||||
def update_task_progress(self, percentage):
|
||||
self.app.task_progress["value"] = percentage
|
||||
self.app.task_progress["value"] = percentage
|
||||
|
@@ -8,6 +8,7 @@ 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):
|
||||
super().__init__(master, **kwargs)
|
||||
@@ -17,46 +18,60 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
self.app_instance = app_instance
|
||||
|
||||
# --- Warning Label ---
|
||||
warning_label = ttk.Label(self, text=Msg.STR["advanced_settings_warning"], wraplength=780, justify="center")
|
||||
warning_label = ttk.Label(
|
||||
self, text=Msg.STR["advanced_settings_warning"], wraplength=780, justify="center")
|
||||
warning_label.pack(pady=10, fill=tk.X, padx=10)
|
||||
|
||||
# --- Treeview for system folder exclusion ---
|
||||
self.tree_frame = ttk.LabelFrame(self, text=Msg.STR["exclude_system_folders"], padding=10)
|
||||
self.tree_frame = ttk.LabelFrame(
|
||||
self, text=Msg.STR["exclude_system_folders"], padding=10)
|
||||
self.tree_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||
|
||||
columns = ("included", "name", "path")
|
||||
self.tree = ttk.Treeview(self.tree_frame, columns=columns, show="headings")
|
||||
self.tree = ttk.Treeview(
|
||||
self.tree_frame, columns=columns, show="headings")
|
||||
self.tree.heading("included", text=Msg.STR["in_backup"])
|
||||
self.tree.heading("name", text=Msg.STR["name"])
|
||||
self.tree.heading("path", text=Msg.STR["path"])
|
||||
self.tree.column("path", anchor="center")
|
||||
self.tree.column("name", anchor="center")
|
||||
self.tree.column("included", width=100, anchor="center")
|
||||
self.tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
self.tree.tag_configure("backup_dest_exclude", foreground="gray")
|
||||
|
||||
self.tree.bind("<Button-1>", self._toggle_include_status)
|
||||
|
||||
# --- Animation Settings ---
|
||||
animation_frame = ttk.LabelFrame(self, text=Msg.STR["animation_settings_title"], padding=10)
|
||||
animation_frame = ttk.LabelFrame(
|
||||
self, text=Msg.STR["animation_settings_title"], padding=10)
|
||||
animation_frame.pack(fill=tk.X, padx=10, pady=5)
|
||||
|
||||
animation_types = ["counter_arc", "double_arc", "line", "blink"]
|
||||
|
||||
ttk.Label(animation_frame, text=Msg.STR["backup_animation_label"]).grid(row=0, column=0, sticky="w", pady=2)
|
||||
ttk.Label(animation_frame, text=Msg.STR["backup_animation_label"]).grid(
|
||||
row=0, column=0, sticky="w", pady=2)
|
||||
self.backup_anim_var = tk.StringVar()
|
||||
self.backup_anim_combo = ttk.Combobox(animation_frame, textvariable=self.backup_anim_var, values=animation_types, state="readonly")
|
||||
self.backup_anim_combo = ttk.Combobox(
|
||||
animation_frame, textvariable=self.backup_anim_var, values=animation_types, state="readonly")
|
||||
self.backup_anim_combo.grid(row=0, column=1, sticky="ew", padx=5)
|
||||
|
||||
ttk.Label(animation_frame, text=Msg.STR["calc_animation_label"]).grid(row=1, column=0, sticky="w", pady=2)
|
||||
ttk.Label(animation_frame, text=Msg.STR["calc_animation_label"]).grid(
|
||||
row=1, column=0, sticky="w", pady=2)
|
||||
self.calc_anim_var = tk.StringVar()
|
||||
self.calc_anim_combo = ttk.Combobox(animation_frame, textvariable=self.calc_anim_var, values=animation_types, state="readonly")
|
||||
self.calc_anim_combo = ttk.Combobox(
|
||||
animation_frame, textvariable=self.calc_anim_var, values=animation_types, state="readonly")
|
||||
self.calc_anim_combo.grid(row=1, column=1, sticky="ew", padx=5)
|
||||
|
||||
reset_button = ttk.Button(animation_frame, text=Msg.STR["default_settings"], command=self._reset_animation_settings)
|
||||
reset_button = ttk.Button(
|
||||
animation_frame, text=Msg.STR["default_settings"], command=self._reset_animation_settings)
|
||||
reset_button.grid(row=0, column=2, rowspan=2, padx=10)
|
||||
|
||||
animation_frame.columnconfigure(1, weight=1)
|
||||
|
||||
# --- Backup Default Settings ---
|
||||
defaults_frame = ttk.LabelFrame(self, text="Backup Defaults", padding=10)
|
||||
defaults_frame = ttk.LabelFrame(
|
||||
self, text="Backup Defaults", padding=10)
|
||||
defaults_frame.pack(fill=tk.X, padx=10, pady=5)
|
||||
|
||||
self.force_full_var = tk.BooleanVar()
|
||||
@@ -64,22 +79,30 @@ 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: 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)
|
||||
|
||||
ttk.Separator(defaults_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, pady=5)
|
||||
|
||||
encryption_note = ttk.Label(defaults_frame, text=Msg.STR["encryption_note_system_backup"], wraplength=750, justify="left")
|
||||
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)
|
||||
|
||||
ttk.Separator(defaults_frame, orient=tk.HORIZONTAL).pack(
|
||||
fill=tk.X, pady=5)
|
||||
|
||||
encryption_note = ttk.Label(
|
||||
defaults_frame, text=Msg.STR["encryption_note_system_backup"], wraplength=750, justify="left")
|
||||
encryption_note.pack(anchor=tk.W, pady=5)
|
||||
|
||||
# --- Action Buttons ---
|
||||
button_frame = ttk.Frame(self)
|
||||
button_frame.pack(pady=10)
|
||||
|
||||
ttk.Button(button_frame, text=Msg.STR["apply"], command=self._apply_changes).pack(side=tk.LEFT, padx=5)
|
||||
ttk.Button(button_frame, text=Msg.STR["cancel"], command=self.destroy).pack(side=tk.LEFT, padx=5)
|
||||
ttk.Button(button_frame, text=Msg.STR["apply"], command=self._apply_changes).pack(
|
||||
side=tk.LEFT, padx=5)
|
||||
ttk.Button(button_frame, text=Msg.STR["cancel"], command=self.destroy).pack(
|
||||
side=tk.LEFT, padx=5)
|
||||
|
||||
self._load_system_folders()
|
||||
self._load_animation_settings()
|
||||
@@ -100,14 +123,20 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
self.app_instance.update_backup_options_from_config()
|
||||
|
||||
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))
|
||||
self.force_compression_var.set(self.config_manager.get_setting("force_compression", False))
|
||||
self.force_encryption_var.set(self.config_manager.get_setting("force_encryption", False))
|
||||
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))
|
||||
self.force_compression_var.set(
|
||||
self.config_manager.get_setting("force_compression", False))
|
||||
self.force_encryption_var.set(
|
||||
self.config_manager.get_setting("force_encryption", False))
|
||||
|
||||
def _load_animation_settings(self):
|
||||
backup_anim = self.config_manager.get_setting("backup_animation_type", "counter_arc")
|
||||
calc_anim = self.config_manager.get_setting("calculation_animation_type", "double_arc")
|
||||
backup_anim = self.config_manager.get_setting(
|
||||
"backup_animation_type", "counter_arc")
|
||||
calc_anim = self.config_manager.get_setting(
|
||||
"calculation_animation_type", "double_arc")
|
||||
self.backup_anim_var.set(backup_anim)
|
||||
self.calc_anim_var.set(calc_anim)
|
||||
|
||||
@@ -132,18 +161,26 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
continue
|
||||
is_user_excluded = f"{item_path_str}/*" in user_patterns
|
||||
included_text = Msg.STR["no"] if is_user_excluded else Msg.STR["yes"]
|
||||
items_to_display[item_path_str] = (included_text, item.name, item_path_str)
|
||||
items_to_display[item_path_str] = (
|
||||
included_text, item.name, item_path_str)
|
||||
|
||||
if self.app_instance and self.app_instance.destination_path:
|
||||
backup_root_path = Path(f"/{self.app_instance.destination_path.strip('/').split('/')[0]}")
|
||||
backup_root_path = Path(
|
||||
f"/{self.app_instance.destination_path.strip('/').split('/')[0]}")
|
||||
backup_root_path_str = str(backup_root_path.absolute())
|
||||
items_to_display[backup_root_path_str] = (Msg.STR["no"], backup_root_path.name, backup_root_path_str)
|
||||
items_to_display[backup_root_path_str] = (
|
||||
Msg.STR["no"], backup_root_path.name, backup_root_path_str)
|
||||
|
||||
for item_path_str in sorted(items_to_display.keys()):
|
||||
tags = ()
|
||||
item_values = items_to_display[item_path_str]
|
||||
tag = "yes" if item_values[0] == Msg.STR["yes"] else "no"
|
||||
|
||||
# Special tag for the backup destination, which is always excluded and read-only
|
||||
if self.app_instance and self.app_instance.destination_path and item_path_str == str(Path(f"/{self.app_instance.destination_path.strip('/').split('/')[0]}").absolute()):
|
||||
tags = ("backup_dest_exclude",)
|
||||
self.tree.insert("", "end", values=items_to_display[item_path_str], tags=tags)
|
||||
tags = ("backup_dest_exclude", tag)
|
||||
else:
|
||||
tags = (tag,)
|
||||
self.tree.insert("", "end", values=item_values, tags=tags)
|
||||
|
||||
def _toggle_include_status(self, event):
|
||||
item_id = self.tree.identify_row(event.y)
|
||||
@@ -153,15 +190,25 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
return
|
||||
current_values = self.tree.item(item_id, 'values')
|
||||
new_status = Msg.STR["yes"] if current_values[0] == Msg.STR["no"] else Msg.STR["no"]
|
||||
self.tree.item(item_id, values=(new_status, current_values[1], current_values[2]))
|
||||
|
||||
new_tag = "yes" if new_status == Msg.STR["yes"] else "no"
|
||||
|
||||
self.tree.item(item_id, values=(
|
||||
new_status, current_values[1], current_values[2]), tags=(new_tag,))
|
||||
|
||||
def _apply_changes(self):
|
||||
self.config_manager.set_setting("backup_animation_type", self.backup_anim_var.get())
|
||||
self.config_manager.set_setting("calculation_animation_type", self.calc_anim_var.get())
|
||||
self.config_manager.set_setting("force_full_backup", self.force_full_var.get())
|
||||
self.config_manager.set_setting("force_incremental_backup", self.force_incremental_var.get())
|
||||
self.config_manager.set_setting("force_compression", self.force_compression_var.get())
|
||||
self.config_manager.set_setting("force_encryption", self.force_encryption_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"backup_animation_type", self.backup_anim_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"calculation_animation_type", self.calc_anim_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"force_full_backup", self.force_full_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"force_incremental_backup", self.force_incremental_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"force_compression", self.force_compression_var.get())
|
||||
self.config_manager.set_setting(
|
||||
"force_encryption", self.force_encryption_var.get())
|
||||
|
||||
if self.app_instance:
|
||||
self.app_instance.update_backup_options_from_config()
|
||||
@@ -171,17 +218,18 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
# Create a new one
|
||||
bg_color = self.app_instance.style.lookup('TFrame', 'background')
|
||||
backup_animation_type = self.backup_anim_var.get()
|
||||
|
||||
|
||||
initial_animation_type = "blink"
|
||||
if backup_animation_type == "line":
|
||||
initial_animation_type = "line"
|
||||
|
||||
self.app_instance.animated_icon = AnimatedIcon(
|
||||
self.app_instance.action_frame, width=20, height=20, use_pillow=True, bg=bg_color, animation_type=initial_animation_type)
|
||||
|
||||
|
||||
# Pack it in the correct order
|
||||
self.app_instance.animated_icon.pack(side=tk.LEFT, padx=5, before=self.app_instance.task_progress)
|
||||
|
||||
self.app_instance.animated_icon.pack(
|
||||
side=tk.LEFT, padx=5, before=self.app_instance.task_progress)
|
||||
|
||||
# Set the correct state
|
||||
self.app_instance.animated_icon.stop("DISABLE")
|
||||
self.app_instance.animated_icon.animation_type = backup_animation_type
|
||||
@@ -204,7 +252,8 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
existing_patterns = []
|
||||
if AppConfig.USER_EXCLUDE_LIST_PATH.exists():
|
||||
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'r') as f:
|
||||
existing_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
existing_patterns = [
|
||||
line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
|
||||
preserved_patterns = []
|
||||
for pattern in existing_patterns:
|
||||
@@ -222,23 +271,26 @@ class AdvancedSettingsFrame(tk.Toplevel):
|
||||
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'w') as f:
|
||||
for path in final_excludes:
|
||||
f.write(f"{path}\n")
|
||||
|
||||
|
||||
self.destroy()
|
||||
|
||||
if self.app_instance:
|
||||
current_source = self.app_instance.left_canvas_data.get('folder')
|
||||
if current_source:
|
||||
self.app_instance.actions.on_sidebar_button_click(current_source)
|
||||
self.app_instance.actions.on_sidebar_button_click(
|
||||
current_source)
|
||||
|
||||
def _load_exclude_patterns(self):
|
||||
generated_patterns = []
|
||||
if AppConfig.GENERATED_EXCLUDE_LIST_PATH.exists():
|
||||
with open(AppConfig.GENERATED_EXCLUDE_LIST_PATH, 'r') as f:
|
||||
generated_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
generated_patterns = [
|
||||
line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
|
||||
user_patterns = []
|
||||
if AppConfig.USER_EXCLUDE_LIST_PATH.exists():
|
||||
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'r') as f:
|
||||
user_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
|
||||
user_patterns = [
|
||||
line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
|
||||
return generated_patterns, user_patterns
|
||||
|
@@ -6,6 +6,7 @@ import re
|
||||
|
||||
from app_config import Msg
|
||||
|
||||
|
||||
class BackupContentFrame(ttk.Frame):
|
||||
def __init__(self, master, backup_manager, **kwargs):
|
||||
super().__init__(master, **kwargs)
|
||||
@@ -21,11 +22,14 @@ class BackupContentFrame(ttk.Frame):
|
||||
columns = ("name", "date", "size")
|
||||
self.content_tree = ttk.Treeview(
|
||||
self.content_frame, columns=columns, show="headings")
|
||||
self.content_tree.heading("name", text=Msg.STR["name"])
|
||||
self.content_tree.heading("date", text=Msg.STR["date"])
|
||||
self.content_tree.heading("size", text=Msg.STR["size"])
|
||||
self.content_tree.heading(
|
||||
"name", text=Msg.STR["name"])
|
||||
self.content_tree.heading(
|
||||
"date", text=Msg.STR["date"])
|
||||
self.content_tree.heading(
|
||||
"size", text=Msg.STR["size"])
|
||||
for col in columns:
|
||||
self.content_tree.column(col, width=150)
|
||||
self.content_tree.column(col, width=150, anchor="center")
|
||||
self.content_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
list_button_frame = ttk.Frame(self.content_frame)
|
||||
@@ -59,8 +63,8 @@ class BackupContentFrame(ttk.Frame):
|
||||
match = re.match(r"(\d{4}-\d{2}-\d{2})", backup_name)
|
||||
if match:
|
||||
backup_date = match.group(1)
|
||||
|
||||
backup_size = ""
|
||||
|
||||
backup_size = ""
|
||||
|
||||
self.content_tree.insert("", "end", values=(
|
||||
backup_name, backup_date, backup_size
|
||||
|
@@ -392,3 +392,12 @@ class Drawing:
|
||||
|
||||
# Also reset the main info label
|
||||
self.app.info_label.config(text="")
|
||||
|
||||
def reset_all_canvases(self):
|
||||
self.reset_projection_canvases()
|
||||
self.app.left_canvas.delete("all")
|
||||
self.app.right_canvas.delete("all")
|
||||
self.app.left_canvas_data.clear()
|
||||
self.app.right_canvas_data.clear()
|
||||
self.redraw_left_canvas()
|
||||
self.redraw_right_canvas()
|
||||
|
@@ -14,9 +14,9 @@ class Navigation:
|
||||
self.app.calculation_stop_event.set()
|
||||
if self.app.right_calculation_thread and self.app.right_calculation_thread.is_alive():
|
||||
self.app.right_calculation_stop_event.set()
|
||||
|
||||
|
||||
# Stop all calculation animations and update UI
|
||||
self.app.drawing._stop_calculating_animation() # Stops both left and right
|
||||
self.app.drawing._stop_calculating_animation() # Stops both left and right
|
||||
if self.app.left_canvas_data:
|
||||
self.app.left_canvas_data['calculating'] = False
|
||||
if self.app.right_canvas_data:
|
||||
@@ -35,7 +35,8 @@ class Navigation:
|
||||
active_index = 0
|
||||
|
||||
# Restore backup destination disk metrics
|
||||
backup_dest_path = self.app.backup_right_canvas_data.get('path_display')
|
||||
backup_dest_path = self.app.backup_right_canvas_data.get(
|
||||
'path_display')
|
||||
if backup_dest_path and os.path.isdir(backup_dest_path):
|
||||
try:
|
||||
total, used, free = shutil.disk_usage(backup_dest_path)
|
||||
@@ -54,7 +55,8 @@ class Navigation:
|
||||
active_index = 1
|
||||
|
||||
# Restore restore destination disk metrics
|
||||
restore_dest_path = self.app.restore_left_canvas_data.get('path_display')
|
||||
restore_dest_path = self.app.restore_left_canvas_data.get(
|
||||
'path_display')
|
||||
if restore_dest_path and os.path.isdir(restore_dest_path):
|
||||
try:
|
||||
total, used, free = shutil.disk_usage(restore_dest_path)
|
||||
@@ -77,10 +79,10 @@ class Navigation:
|
||||
'path_display': '',
|
||||
'size': ''
|
||||
})
|
||||
else: # In restore mode, left is destination
|
||||
else: # In restore mode, left is destination
|
||||
self.app.left_canvas_data.update({
|
||||
'icon': 'computer_extralarge', # Default icon
|
||||
'folder': Msg.STR["select_destination"],
|
||||
'icon': 'computer_extralarge',
|
||||
'folder': 'Computer',
|
||||
'path_display': '',
|
||||
'size': ''
|
||||
})
|
||||
@@ -89,7 +91,7 @@ class Navigation:
|
||||
# Right canvas is always the destination/HDD view conceptually
|
||||
self.app.right_canvas_data.update({
|
||||
'icon': 'hdd_extralarge',
|
||||
'folder': Msg.STR["select_destination"] if mode == 'backup' else Msg.STR["source"],
|
||||
'folder': Msg.STR["select_destination"] if mode == 'backup' else Msg.STR["select_source"],
|
||||
'path_display': '',
|
||||
'size': ''
|
||||
})
|
||||
@@ -98,28 +100,34 @@ class Navigation:
|
||||
if mode == "backup":
|
||||
self.app.source_size_frame.grid()
|
||||
self.app.target_size_frame.grid()
|
||||
self.app.restore_size_frame.grid_remove()
|
||||
self.app.mode_button_icon = self.app.image_manager.get_icon("forward_extralarge")
|
||||
self.app.restore_size_frame_before.grid_remove()
|
||||
self.app.restore_size_frame_after.grid_remove()
|
||||
self.app.mode_button_icon = self.app.image_manager.get_icon(
|
||||
"forward_extralarge")
|
||||
self.app.info_label.config(text=Msg.STR["backup_mode_info"])
|
||||
self.app.full_backup_cb.config(state="normal")
|
||||
self.app.incremental_cb.config(state="normal")
|
||||
self.app.compressed_cb.config(state="normal")
|
||||
self.app.encrypted_cb.config(state="normal")
|
||||
self.app.bypass_security_cb.config(state='disabled') # This one is mode-dependent
|
||||
self.app.bypass_security_cb.config(
|
||||
state='disabled') # This one is mode-dependent
|
||||
# Let the central config function handle the state of these checkboxes
|
||||
self.app.update_backup_options_from_config()
|
||||
else: # restore
|
||||
self.app.source_size_frame.grid_remove()
|
||||
self.app.target_size_frame.grid_remove()
|
||||
self.app.restore_size_frame.grid()
|
||||
self.app.mode_button_icon = self.app.image_manager.get_icon("back_extralarge")
|
||||
self.app.restore_size_frame_before.grid()
|
||||
self.app.restore_size_frame_after.grid()
|
||||
self.app.mode_button_icon = self.app.image_manager.get_icon(
|
||||
"back_extralarge")
|
||||
self.app.info_label.config(text=Msg.STR["restore_mode_info"])
|
||||
self.app.full_backup_cb.config(state='disabled')
|
||||
self.app.incremental_cb.config(state='disabled')
|
||||
self.app.compressed_cb.config(state='disabled')
|
||||
self.app.encrypted_cb.config(state='disabled')
|
||||
self.app.bypass_security_cb.config(state='normal') # This one is mode-dependent
|
||||
|
||||
self.app.bypass_security_cb.config(
|
||||
state='normal') # This one is mode-dependent
|
||||
|
||||
self.app.mode_button.config(image=self.app.mode_button_icon)
|
||||
self.app.drawing.update_nav_buttons(active_index)
|
||||
self.app.drawing.redraw_left_canvas()
|
||||
@@ -157,8 +165,9 @@ class Navigation:
|
||||
if trigger_calculation:
|
||||
# Always trigger the calculation for the left canvas, which is controlled by the sidebar
|
||||
current_folder_on_left = self.app.left_canvas_data.get('folder')
|
||||
if current_folder_on_left:
|
||||
self.app.actions.on_sidebar_button_click(current_folder_on_left)
|
||||
if current_folder_on_left and current_folder_on_left in self.app.buttons_map:
|
||||
self.app.actions.on_sidebar_button_click(
|
||||
current_folder_on_left)
|
||||
|
||||
# Additionally, in restore mode, trigger calculation for the right canvas if a source is set
|
||||
if self.app.mode == 'restore':
|
||||
@@ -187,7 +196,8 @@ class Navigation:
|
||||
self.app.backup_content_frame.hide()
|
||||
self.app.source_size_frame.grid_remove()
|
||||
self.app.target_size_frame.grid_remove()
|
||||
self.app.restore_size_frame.grid_remove()
|
||||
self.app.restore_size_frame_before.grid_remove()
|
||||
self.app.restore_size_frame_after.grid_remove()
|
||||
self.app.log_frame.grid()
|
||||
self.app.top_bar.grid()
|
||||
self._update_task_bar_visibility("log")
|
||||
@@ -203,7 +213,8 @@ class Navigation:
|
||||
self.app.backup_content_frame.hide()
|
||||
self.app.source_size_frame.grid_remove()
|
||||
self.app.target_size_frame.grid_remove()
|
||||
self.app.restore_size_frame.grid_remove()
|
||||
self.app.restore_size_frame_before.grid_remove()
|
||||
self.app.restore_size_frame_after.grid_remove()
|
||||
self.app.scheduler_frame.show()
|
||||
self.app.top_bar.grid()
|
||||
self._update_task_bar_visibility("scheduler")
|
||||
@@ -219,7 +230,8 @@ class Navigation:
|
||||
self.app.scheduler_frame.hide()
|
||||
self.app.source_size_frame.grid_remove()
|
||||
self.app.target_size_frame.grid_remove()
|
||||
self.app.restore_size_frame.grid_remove()
|
||||
self.app.restore_size_frame_before.grid_remove()
|
||||
self.app.restore_size_frame_after.grid_remove()
|
||||
self.app.settings_frame.show()
|
||||
self.app.top_bar.grid()
|
||||
self._update_task_bar_visibility("settings")
|
||||
@@ -241,7 +253,8 @@ class Navigation:
|
||||
self.app.settings_frame.hide()
|
||||
self.app.source_size_frame.grid_remove()
|
||||
self.app.target_size_frame.grid_remove()
|
||||
self.app.restore_size_frame.grid_remove()
|
||||
self.app.restore_size_frame_before.grid_remove()
|
||||
self.app.restore_size_frame_after.grid_remove()
|
||||
self.app.backup_content_frame.show(self.app.destination_path)
|
||||
self.app.top_bar.grid()
|
||||
self._update_task_bar_visibility("scheduler")
|
||||
|
@@ -26,7 +26,7 @@ class SchedulerFrame(ttk.Frame):
|
||||
self.jobs_tree.heading("destination", text=Msg.STR["destination"])
|
||||
self.jobs_tree.heading("sources", text=Msg.STR["sources"])
|
||||
for col in columns:
|
||||
self.jobs_tree.column(col, width=100)
|
||||
self.jobs_tree.column(col, width=100, anchor="center")
|
||||
self.jobs_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
self._load_scheduled_jobs()
|
||||
|
||||
@@ -149,7 +149,7 @@ class SchedulerFrame(ttk.Frame):
|
||||
if job_type == "user":
|
||||
command += f" --sources "
|
||||
for s in job_sources:
|
||||
command += f'\"{s}\" ' # This line has an issue with escaping
|
||||
command += f'\"{s}\" ' # This line has an issue with escaping
|
||||
|
||||
comment = f"{self.backup_manager.app_tag}; type:{job_type}; freq:{job_frequency}; dest:{dest}"
|
||||
if job_type == "user":
|
||||
@@ -174,7 +174,7 @@ class SchedulerFrame(ttk.Frame):
|
||||
for job in jobs:
|
||||
self.jobs_tree.insert("", "end", values=(
|
||||
job["active"], job["type"], job["frequency"], job["destination"], ", ".join(
|
||||
job["sources"])
|
||||
job["sources"])
|
||||
), iid=job["id"])
|
||||
|
||||
def _remove_selected_job(self):
|
||||
|
@@ -33,6 +33,10 @@ class SettingsFrame(ttk.Frame):
|
||||
self.tree.heading("included", text=Msg.STR["in_backup"])
|
||||
self.tree.heading("name", text=Msg.STR["name"])
|
||||
self.tree.heading("path", text=Msg.STR["path"])
|
||||
|
||||
self.tree.tag_configure("yes", background="#89b4fe")
|
||||
self.tree.tag_configure("no", background="#4c92ed")
|
||||
|
||||
self.tree.column("included", width=100, anchor="center")
|
||||
self.tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
@@ -46,8 +50,13 @@ class SettingsFrame(ttk.Frame):
|
||||
self.hidden_tree.heading("included", text=Msg.STR["in_backup"])
|
||||
self.hidden_tree.heading("name", text=Msg.STR["name"])
|
||||
self.hidden_tree.heading("path", text=Msg.STR["path"])
|
||||
|
||||
self.hidden_tree.column("included", width=100, anchor="center")
|
||||
self.hidden_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||||
|
||||
self.hidden_tree.tag_configure("yes", background="#89b4fe")
|
||||
self.hidden_tree.tag_configure("no", background="#4c92ed")
|
||||
|
||||
self.hidden_tree.bind("<Button-1>", self._toggle_include_status_hidden)
|
||||
self.hidden_tree_frame.pack_forget() # Initially hidden
|
||||
|
||||
@@ -126,7 +135,8 @@ class SettingsFrame(ttk.Frame):
|
||||
items_to_display.sort(key=lambda x: x[0], reverse=True)
|
||||
|
||||
for item in items_to_display:
|
||||
self.tree.insert("", "end", values=item)
|
||||
tag = "yes" if item[0] == Msg.STR["yes"] else "no"
|
||||
self.tree.insert("", "end", values=item, tags=(tag,))
|
||||
|
||||
def _toggle_include_status(self, event):
|
||||
item_id = self.tree.identify_row(event.y)
|
||||
@@ -137,8 +147,10 @@ class SettingsFrame(ttk.Frame):
|
||||
current_status = current_values[0]
|
||||
new_status = Msg.STR["yes"] if current_status == Msg.STR["no"] else Msg.STR["no"]
|
||||
|
||||
new_tag = "yes" if new_status == Msg.STR["yes"] else "no"
|
||||
|
||||
self.tree.item(item_id, values=(
|
||||
new_status, current_values[1], current_values[2]))
|
||||
new_status, current_values[1], current_values[2]), tags=(new_tag,))
|
||||
|
||||
def _apply_changes(self):
|
||||
# Get all paths displayed in the treeviews
|
||||
@@ -175,7 +187,8 @@ class SettingsFrame(ttk.Frame):
|
||||
existing_patterns = []
|
||||
if AppConfig.USER_EXCLUDE_LIST_PATH.exists():
|
||||
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'r') as f:
|
||||
existing_patterns = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
existing_patterns = [
|
||||
line.strip() for line in f if line.strip() and not line.startswith('#')]
|
||||
|
||||
# Preserve patterns that are not managed by this view
|
||||
preserved_patterns = []
|
||||
@@ -196,18 +209,16 @@ class SettingsFrame(ttk.Frame):
|
||||
with open(AppConfig.USER_EXCLUDE_LIST_PATH, 'w') as f:
|
||||
for path in final_excludes:
|
||||
f.write(f"{path}\n")
|
||||
|
||||
self.hide()
|
||||
|
||||
# Trigger recalculation
|
||||
current_source = self.master.master.master.left_canvas_data.get('folder')
|
||||
if current_source:
|
||||
self.master.master.master.actions.on_sidebar_button_click(current_source)
|
||||
# Reload the excludes to show the changes
|
||||
self.load_and_display_excludes()
|
||||
if self.hidden_files_visible:
|
||||
self._load_hidden_files()
|
||||
|
||||
def _open_advanced_settings(self):
|
||||
advanced_settings_window = AdvancedSettingsFrame(
|
||||
self.master,
|
||||
config_manager=self.master.master.master.config_manager,
|
||||
self.master,
|
||||
config_manager=self.master.master.master.config_manager,
|
||||
app_instance=self.master.master.master
|
||||
)
|
||||
advanced_settings_window.grab_set()
|
||||
@@ -246,7 +257,8 @@ class SettingsFrame(ttk.Frame):
|
||||
items_to_display.sort(key=lambda x: x[1])
|
||||
|
||||
for item in items_to_display:
|
||||
self.hidden_tree.insert("", "end", values=item)
|
||||
tag = "yes" if item[0] == Msg.STR["yes"] else "no"
|
||||
self.hidden_tree.insert("", "end", values=item, tags=(tag,))
|
||||
|
||||
def _toggle_include_status_hidden(self, event):
|
||||
item_id = self.hidden_tree.identify_row(event.y)
|
||||
@@ -257,5 +269,7 @@ class SettingsFrame(ttk.Frame):
|
||||
current_status = current_values[0]
|
||||
new_status = Msg.STR["yes"] if current_status == Msg.STR["no"] else Msg.STR["no"]
|
||||
|
||||
new_tag = "yes" if new_status == Msg.STR["yes"] else "no"
|
||||
|
||||
self.hidden_tree.item(item_id, values=(
|
||||
new_status, current_values[1], current_values[2]))
|
||||
new_status, current_values[1], current_values[2]), tags=(new_tag,))
|
||||
|
Reference in New Issue
Block a user