Files
shared_libs/cfd_settings_dialog.py
Désiré Werner Menrath b8d46fb547 Refactor: Decompose CustomFileDialog class
The `CustomFileDialog` class had become too large and complex, making it difficult to maintain.

This change refactors the monolithic class into several specialized manager classes, each responsible for a specific area of concern:

- `SettingsDialog`: Moved to its own file, `cfd_settings_dialog.py`.
- `FileOperationsManager`: Handles file/folder creation, deletion, and renaming.
- `SearchManager`: Encapsulates all search-related logic.
- `NavigationManager`: Manages directory navigation and history.
- `ViewManager`: Controls the rendering of file and folder views.

The main `CustomFileDialog` class has been streamlined and now acts as an orchestrator for these managers. This improves readability, separation of concerns, and the overall maintainability of the code.
2025-08-09 11:51:58 +02:00

174 lines
8.4 KiB
Python

import tkinter as tk
from tkinter import ttk
from cfd_app_config import CfdConfigManager
from cfd_animated_icon import PIL_AVAILABLE
try:
import send2trash
SEND2TRASH_AVAILABLE = True
except ImportError:
SEND2TRASH_AVAILABLE = False
class SettingsDialog(tk.Toplevel):
def __init__(self, parent, dialog_mode="save"):
super().__init__(parent)
self.transient(parent)
self.grab_set()
self.title("Einstellungen")
self.settings = CfdConfigManager.load()
self.dialog_mode = dialog_mode
# Variables
self.search_icon_pos = tk.StringVar(
value=self.settings.get("search_icon_pos", "right"))
self.button_box_pos = tk.StringVar(
value=self.settings.get("button_box_pos", "left"))
self.window_size_preset = tk.StringVar(
value=self.settings.get("window_size_preset", "1050x850"))
self.default_view_mode = tk.StringVar(
value=self.settings.get("default_view_mode", "icons"))
self.search_hidden_files = tk.BooleanVar(
value=self.settings.get("search_hidden_files", False))
self.recursive_search = tk.BooleanVar(
value=self.settings.get("recursive_search", True))
self.use_trash = tk.BooleanVar(
value=self.settings.get("use_trash", False))
self.confirm_delete = tk.BooleanVar(
value=self.settings.get("confirm_delete", False))
self.use_pillow_animation = tk.BooleanVar(
value=self.settings.get("use_pillow_animation", False))
self.animation_type = tk.StringVar(
value=self.settings.get("animation_type", "double_arc"))
# --- UI Elements ---
main_frame = ttk.Frame(self, padding=10)
main_frame.pack(fill="both", expand=True)
# Button Box Position
button_box_frame = ttk.LabelFrame(
main_frame, text="Position der Dialog-Buttons", padding=10)
button_box_frame.pack(fill="x", pady=5)
ttk.Radiobutton(button_box_frame, text="Links",
variable=self.button_box_pos, value="left").pack(side="left", padx=5)
ttk.Radiobutton(button_box_frame, text="Rechts",
variable=self.button_box_pos, value="right").pack(side="left", padx=5)
# Window Size
size_frame = ttk.LabelFrame(
main_frame, text="Fenstergröße", padding=10)
size_frame.pack(fill="x", pady=5)
sizes = ["1050x850", "850x650", "650x450"]
size_combo = ttk.Combobox(
size_frame, textvariable=self.window_size_preset, values=sizes, state="readonly")
size_combo.pack(fill="x")
# Default View Mode
view_mode_frame = ttk.LabelFrame(
main_frame, text="Standardansicht", padding=10)
view_mode_frame.pack(fill="x", pady=5)
ttk.Radiobutton(view_mode_frame, text="Kacheln",
variable=self.default_view_mode, value="icons").pack(side="left", padx=5)
ttk.Radiobutton(view_mode_frame, text="Liste",
variable=self.default_view_mode, value="list").pack(side="left", padx=5)
# Search Hidden Files
search_hidden_frame = ttk.LabelFrame(
main_frame, text="Sucheinstellungen", padding=10)
search_hidden_frame.pack(fill="x", pady=5)
ttk.Checkbutton(search_hidden_frame, text="Versteckte Dateien und Ordner durchsuchen",
variable=self.search_hidden_files).pack(anchor="w")
ttk.Checkbutton(search_hidden_frame, text="Rekursiv suchen",
variable=self.recursive_search).pack(anchor="w")
# Deletion Settings
delete_frame = ttk.LabelFrame(
main_frame, text="Löscheinstellungen", padding=10)
delete_frame.pack(fill="x", pady=5)
self.use_trash_checkbutton = ttk.Checkbutton(delete_frame, text="Dateien in den Papierkorb verschieben (empfohlen)",
variable=self.use_trash)
self.use_trash_checkbutton.pack(anchor="w")
if not SEND2TRASH_AVAILABLE:
self.use_trash_checkbutton.config(state=tk.DISABLED)
ttk.Label(delete_frame, text="(send2trash-Bibliothek nicht gefunden)",
font=("TkDefaultFont", 9, "italic")).pack(anchor="w", padx=(20, 0))
self.confirm_delete_checkbutton = ttk.Checkbutton(delete_frame, text="Löschen/Verschieben ohne Bestätigung",
variable=self.confirm_delete)
self.confirm_delete_checkbutton.pack(anchor="w")
# Pillow Animation
pillow_frame = ttk.LabelFrame(
main_frame, text="Animationseinstellungen", padding=10)
pillow_frame.pack(fill="x", pady=5)
self.use_pillow_animation_checkbutton = ttk.Checkbutton(pillow_frame, text="Hochauflösende Animation verwenden (Pillow)",
variable=self.use_pillow_animation)
self.use_pillow_animation_checkbutton.pack(anchor="w")
if not PIL_AVAILABLE:
self.use_pillow_animation_checkbutton.config(state=tk.DISABLED)
ttk.Label(pillow_frame, text="(Pillow-Bibliothek nicht gefunden)",
font=("TkDefaultFont", 9, "italic")).pack(anchor="w", padx=(20, 0))
# Animation Type
anim_type_frame = ttk.LabelFrame(
main_frame, text="Animationstyp", padding=10)
anim_type_frame.pack(fill="x", pady=5)
ttk.Radiobutton(anim_type_frame, text="Gegenläufige Bogen", variable=self.animation_type,
value="counter_arc").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text="Doppelbogen", variable=self.animation_type,
value="double_arc").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text="Linie", variable=self.animation_type,
value="line").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text="Blinken", variable=self.animation_type,
value="blink").pack(side="left", padx=5)
# Disable deletion options in "open" mode
if not self.dialog_mode == "save":
self.use_trash_checkbutton.config(state=tk.DISABLED)
self.confirm_delete_checkbutton.config(state=tk.DISABLED)
info_label = ttk.Label(delete_frame, text="(Löschoptionen sind nur im Speichern-Modus verfügbar)",
font=("TkDefaultFont", 9, "italic"))
info_label.pack(anchor="w", padx=(20, 0))
# --- Action Buttons ---
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill="x", pady=(10, 0))
ttk.Button(button_frame, text="Auf Standard zurücksetzen",
command=self.reset_to_defaults).pack(side="left", padx=5)
ttk.Button(button_frame, text="Speichern",
command=self.save_settings).pack(side="right", padx=5)
ttk.Button(button_frame, text="Abbrechen",
command=self.destroy).pack(side="right")
def save_settings(self):
new_settings = {
"button_box_pos": self.button_box_pos.get(),
"window_size_preset": self.window_size_preset.get(),
"default_view_mode": self.default_view_mode.get(),
"search_hidden_files": self.search_hidden_files.get(),
"recursive_search": self.recursive_search.get(),
"use_trash": self.use_trash.get(),
"confirm_delete": self.confirm_delete.get(),
"use_pillow_animation": self.use_pillow_animation.get(),
"animation_type": self.animation_type.get()
}
CfdConfigManager.save(new_settings)
self.master.reload_config_and_rebuild_ui()
self.destroy()
def reset_to_defaults(self):
defaults = CfdConfigManager._default_settings
self.button_box_pos.set(defaults["button_box_pos"])
self.window_size_preset.set(defaults["window_size_preset"])
self.default_view_mode.set(defaults["default_view_mode"])
self.search_hidden_files.set(defaults["search_hidden_files"])
self.recursive_search.set(defaults["recursive_search"])
self.use_trash.set(defaults["use_trash"])
self.confirm_delete.set(defaults["confirm_delete"])
self.use_pillow_animation.set(defaults.get("use_pillow_animation", True) and PIL_AVAILABLE)
self.animation_type.set(defaults.get("animation_type", "counter_arc"))