- Fixes a bug where the backup list would not display "orphan" incremental backups in the encrypted view. - Fixes a bug where system backups were incorrectly shown in the user backup list. - Prevents the app from asking for system permissions to lock an encrypted container on exit if it is not currently mounted. - Fixes pathing inconsistencies for the encryption manager to ensure mapper names are created consistently. - Adds debug logging to the backup list functions to help diagnose future issues.
173 lines
7.6 KiB
Python
173 lines
7.6 KiB
Python
import tkinter as tk
|
|
from tkinter import ttk
|
|
import os
|
|
|
|
from pbp_app_config import Msg
|
|
from pyimage_ui.system_backup_content_frame import SystemBackupContentFrame
|
|
from pyimage_ui.user_backup_content_frame import UserBackupContentFrame
|
|
from shared_libs.logger import app_logger
|
|
from shared_libs.message import MessageDialog
|
|
|
|
class BackupContentFrame(ttk.Frame):
|
|
def __init__(self, master, backup_manager, actions, app, **kwargs):
|
|
super().__init__(master, **kwargs)
|
|
app_logger.log("BackupContentFrame: __init__ called")
|
|
self.backup_manager = backup_manager
|
|
self.actions = actions
|
|
self.app = app
|
|
|
|
self.base_backup_path = None
|
|
self.current_view_index = 0
|
|
self.viewing_encrypted = False
|
|
|
|
self.grid_rowconfigure(1, weight=1)
|
|
self.grid_columnconfigure(0, weight=1)
|
|
|
|
header_frame = ttk.Frame(self)
|
|
header_frame.grid(row=0, column=0, sticky=tk.NSEW)
|
|
|
|
top_nav_frame = ttk.Frame(header_frame)
|
|
top_nav_frame.pack(side=tk.LEFT)
|
|
|
|
self.nav_buttons_defs = [
|
|
(Msg.STR["system_backup_info"], lambda: self._switch_view(0)),
|
|
(Msg.STR["user_backup_info"], lambda: self._switch_view(1)),
|
|
]
|
|
|
|
self.nav_buttons = []
|
|
self.nav_progress_bars = []
|
|
|
|
for i, (text, command) in enumerate(self.nav_buttons_defs):
|
|
button_frame = ttk.Frame(top_nav_frame)
|
|
button_frame.pack(side=tk.LEFT, padx=5)
|
|
button = ttk.Button(button_frame, text=text,
|
|
command=command, style="TButton.Borderless.Round")
|
|
button.pack(side=tk.TOP)
|
|
self.nav_buttons.append(button)
|
|
progress_bar = ttk.Progressbar(
|
|
button_frame, orient="horizontal", length=50, mode="determinate", style="Small.Horizontal.TProgressbar")
|
|
progress_bar.pack_forget()
|
|
self.nav_progress_bars.append(progress_bar)
|
|
|
|
if i < len(self.nav_buttons_defs) - 1:
|
|
ttk.Separator(top_nav_frame, orient=tk.VERTICAL).pack(
|
|
side=tk.LEFT, fill=tk.Y, padx=2)
|
|
|
|
content_container = ttk.Frame(self)
|
|
content_container.grid(row=1, column=0, sticky="nsew")
|
|
content_container.grid_rowconfigure(0, weight=1)
|
|
content_container.grid_columnconfigure(0, weight=1)
|
|
|
|
self.system_backups_frame = SystemBackupContentFrame(content_container, backup_manager, actions, parent_view=self)
|
|
self.user_backups_frame = UserBackupContentFrame(content_container, backup_manager, actions, parent_view=self)
|
|
self.system_backups_frame.grid(row=0, column=0, sticky=tk.NSEW)
|
|
self.user_backups_frame.grid(row=0, column=0, sticky=tk.NSEW)
|
|
|
|
action_button_frame = ttk.Frame(self, padding=10)
|
|
action_button_frame.grid(row=2, column=0, sticky="ew")
|
|
|
|
self.toggle_encrypted_button = ttk.Button(action_button_frame, text=Msg.STR["show_encrypted_backups"], command=self._toggle_encrypted_view)
|
|
self.toggle_encrypted_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self.restore_button = ttk.Button(action_button_frame, text=Msg.STR["restore"], command=self._restore_selected, state="disabled")
|
|
self.restore_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self.delete_button = ttk.Button(action_button_frame, text=Msg.STR["delete"], command=self._delete_selected, state="disabled")
|
|
self.delete_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self.edit_comment_button = ttk.Button(action_button_frame, text=Msg.STR["comment"], command=self._edit_comment, state="disabled")
|
|
self.edit_comment_button.pack(side=tk.LEFT, padx=5)
|
|
|
|
self._switch_view(0)
|
|
|
|
def update_button_state(self, is_selected):
|
|
self.restore_button.config(state="normal" if is_selected else "disabled")
|
|
self.delete_button.config(state="normal" if is_selected else "disabled")
|
|
self.edit_comment_button.config(state="normal" if is_selected else "disabled")
|
|
|
|
def _get_active_subframe(self):
|
|
return self.system_backups_frame if self.current_view_index == 0 else self.user_backups_frame
|
|
|
|
def _restore_selected(self):
|
|
self._get_active_subframe()._restore_selected()
|
|
|
|
def _delete_selected(self):
|
|
self._get_active_subframe()._delete_selected()
|
|
|
|
def _edit_comment(self):
|
|
self._get_active_subframe()._edit_comment()
|
|
|
|
def _toggle_encrypted_view(self):
|
|
if not self.app.destination_path:
|
|
MessageDialog(master=self.app, message_type="info", title=Msg.STR["info_menu"], text=Msg.STR["err_no_dest_folder"])
|
|
return
|
|
|
|
if not self.viewing_encrypted:
|
|
username = os.path.basename(self.app.destination_path.rstrip('/'))
|
|
password = self.app.backup_manager.encryption_manager.get_password(username, confirm=False)
|
|
if not password:
|
|
return
|
|
|
|
mount_point = self.app.backup_manager.encryption_manager.unlock_container(self.app.destination_path, password)
|
|
if mount_point:
|
|
self.viewing_encrypted = True
|
|
self.toggle_encrypted_button.config(text=Msg.STR["show_normal_backups"])
|
|
self.show(mount_point)
|
|
self.app.header_frame.refresh_status()
|
|
else:
|
|
MessageDialog(master=self.app, message_type="error", title=Msg.STR["error"], text=Msg.STR["err_unlock_failed"])
|
|
else:
|
|
self.app.backup_manager.encryption_manager.lock_container(self.app.destination_path)
|
|
self.viewing_encrypted = False
|
|
self.toggle_encrypted_button.config(text=Msg.STR["show_encrypted_backups"])
|
|
self.show(self.app.destination_path)
|
|
self.app.header_frame.refresh_status()
|
|
|
|
def _switch_view(self, index):
|
|
self.current_view_index = index
|
|
config_key = "last_encrypted_backup_content_view" if self.viewing_encrypted else "last_backup_content_view"
|
|
self.app.config_manager.set_setting(config_key, index)
|
|
self.update_nav_buttons(index)
|
|
|
|
if index == 0:
|
|
self.system_backups_frame.grid()
|
|
self.user_backups_frame.grid_remove()
|
|
else:
|
|
self.user_backups_frame.grid()
|
|
self.system_backups_frame.grid_remove()
|
|
self.update_button_state(False)
|
|
|
|
def update_nav_buttons(self, active_index):
|
|
for i, button in enumerate(self.nav_buttons):
|
|
if i == active_index:
|
|
button.configure(style="Toolbutton")
|
|
self.nav_progress_bars[i].pack(side=tk.BOTTOM, fill=tk.X)
|
|
self.nav_progress_bars[i]['value'] = 100
|
|
else:
|
|
button.configure(style="Gray.Toolbutton")
|
|
self.nav_progress_bars[i].pack_forget()
|
|
|
|
def show(self, backup_path):
|
|
app_logger.log(f"BackupContentFrame: show called with path {backup_path}")
|
|
self.grid(row=2, column=0, sticky="nsew")
|
|
|
|
self.base_backup_path = backup_path
|
|
|
|
if self.viewing_encrypted:
|
|
actual_backup_path = backup_path
|
|
else:
|
|
actual_backup_path = os.path.join(backup_path, "pybackup")
|
|
|
|
if not os.path.isdir(actual_backup_path):
|
|
app_logger.log(f"Backup path {actual_backup_path} does not exist or is not a directory.")
|
|
# Clear views if path is invalid
|
|
self.system_backups_frame.show(None)
|
|
self.user_backups_frame.show(None)
|
|
return
|
|
|
|
self.system_backups_frame.show(actual_backup_path)
|
|
self.user_backups_frame.show(actual_backup_path)
|
|
|
|
config_key = "last_encrypted_backup_content_view" if self.viewing_encrypted else "last_backup_content_view"
|
|
last_view = self.app.config_manager.get_setting(config_key, 0)
|
|
self._switch_view(last_view) |