Files
Py-Backup/pyimage_ui/user_backup_content_frame.py
Désiré Werner Menrath f69e77cdd2 feat: Implement backup deletion and improve exclusion list
This commit introduces two main improvements:

1.  **Backup Deletion:** The user can now delete system and user backups from the "Backup Content" view.
2.  **Improved Exclusion List:** The `.cache` directory is now excluded from backups by default, which should prevent "file has vanished" warnings from rsync.
2025-08-31 19:54:14 +02:00

143 lines
5.7 KiB
Python

import tkinter as tk
from tkinter import ttk
import os
from pbp_app_config import Msg
from pyimage_ui.comment_editor_dialog import CommentEditorDialog
class UserBackupContentFrame(ttk.Frame):
def __init__(self, master, backup_manager, **kwargs):
super().__init__(master, **kwargs)
self.backup_manager = backup_manager
self.backup_path = None
# --- Backup Content List View ---
self.content_frame = ttk.LabelFrame(
self, text=Msg.STR["backup_content"], padding=10)
self.content_frame.pack(fill=tk.BOTH, expand=True)
columns = ("date", "size", "comment", "folder_name")
self.content_tree = ttk.Treeview(
self.content_frame, columns=columns, show="headings")
self.content_tree.heading(
"date", text=Msg.STR["date"])
self.content_tree.heading(
"size", text=Msg.STR["size"])
self.content_tree.heading(
"comment", text=Msg.STR["comment"])
self.content_tree.heading(
"folder_name", text=Msg.STR["folder"])
self.content_tree.column("date", width=120, anchor="w")
self.content_tree.column("size", width=100, anchor="e")
self.content_tree.column("comment", width=200, anchor="w")
self.content_tree.column("folder_name", width=250, anchor="w")
self.content_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
self.content_tree.bind("<<TreeviewSelect>>", self._on_item_select)
list_button_frame = ttk.Frame(self.content_frame)
list_button_frame.pack(pady=10)
self.restore_button = ttk.Button(list_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(list_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(list_button_frame, text="Kommentar bearbeiten",
command=self._edit_comment, state="disabled")
self.edit_comment_button.pack(side=tk.LEFT, padx=5)
def show(self, backup_path):
if backup_path and self.backup_path != backup_path:
self.backup_path = backup_path
self._load_backup_content()
def hide(self):
self.grid_remove()
def _load_backup_content(self):
for i in self.content_tree.get_children():
self.content_tree.delete(i)
if not self.backup_path or not os.path.isdir(self.backup_path):
return
user_backups = self.backup_manager.list_user_backups(self.backup_path)
for backup_info in user_backups:
self.content_tree.insert("", "end", values=(
backup_info.get("date", "N/A"),
backup_info.get("size", "N/A"),
backup_info.get("comment", ""),
backup_info.get("folder_name", "N/A")
))
self._on_item_select(None)
def _on_item_select(self, event):
selected_item = self.content_tree.focus()
is_selected = True if selected_item else False
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 _edit_comment(self):
selected_item = self.content_tree.focus()
if not selected_item:
return
item_values = self.content_tree.item(selected_item)["values"]
folder_name = item_values[3] # Assuming folder_name is the 4th value
# Construct the path to the info file
info_file_path = os.path.join(self.backup_path, f"{folder_name}.txt")
if not os.path.exists(info_file_path):
self.backup_manager.update_comment(info_file_path, "")
CommentEditorDialog(self, info_file_path, self.backup_manager)
self._load_backup_content() # Refresh list to show new comment
def _restore_selected(self):
# Placeholder for restore logic
selected_item = self.content_tree.focus()
if not selected_item:
return
backup_name = self.content_tree.item(selected_item)["values"][0]
print(f"Restoring {backup_name}...")
def _delete_selected(self):
selected_item = self.content_tree.focus()
if not selected_item:
return
item_values = self.content_tree.item(selected_item)["values"]
folder_name = item_values[3] # Assuming folder_name is the 4th value
# Construct the full path to the backup folder
folder_to_delete = os.path.join(self.backup_path, folder_name)
info_file_to_delete = os.path.join(self.backup_path, f"{folder_name}.txt")
# Ask for confirmation
from shared_libs.message import MessageDialog
dialog = MessageDialog(master=self, message_type="warning",
title=Msg.STR["confirm_delete_title"],
text=Msg.STR["confirm_delete_text"].format(folder_name=folder_name),
buttons=["ok_cancel"])
if dialog.get_result() != "ok":
return
try:
import shutil
if os.path.isdir(folder_to_delete):
shutil.rmtree(folder_to_delete)
if os.path.exists(info_file_to_delete):
os.remove(info_file_to_delete)
except Exception as e:
MessageDialog(master=self, message_type="error",
title=Msg.STR["error"], text=str(e))
self._load_backup_content()