Files
shared_libs/custom_file_dialog/cfd_settings_dialog.py

233 lines
12 KiB
Python

import tkinter as tk
from tkinter import ttk
from typing import TYPE_CHECKING
from .cfd_app_config import CfdConfigManager, LocaleStrings
from shared_libs.animated_icon import PIL_AVAILABLE
from .cfd_sftp_manager import PARAMIKO_AVAILABLE
if TYPE_CHECKING:
from custom_file_dialog import CustomFileDialog
try:
import send2trash
SEND2TRASH_AVAILABLE = True
except ImportError:
SEND2TRASH_AVAILABLE = False
class SettingsDialog(tk.Toplevel):
"""A dialog window for configuring the application settings."""
def __init__(self, parent: 'CustomFileDialog', dialog_mode: str = "save") -> None:
"""
Initializes the SettingsDialog.
Args:
parent: The parent widget.
dialog_mode (str, optional): The mode of the main dialog ("open" or "save"),
which affects available settings. Defaults to "save".
"""
super().__init__(parent)
self.transient(parent)
self.grab_set()
self.title(LocaleStrings.SET["title"])
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"))
self.keep_bookmarks_on_reset = tk.BooleanVar(
value=self.settings.get("keep_bookmarks_on_reset", True))
# --- 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=LocaleStrings.SET["button_box_pos_label"], padding=10)
button_box_frame.pack(fill="x", pady=5)
ttk.Radiobutton(button_box_frame, text=LocaleStrings.SET["left_radio"],
variable=self.button_box_pos, value="left").pack(side="left", padx=5)
ttk.Radiobutton(button_box_frame, text=LocaleStrings.SET["right_radio"],
variable=self.button_box_pos, value="right").pack(side="left", padx=5)
# Window Size
size_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["window_size_label"], 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=LocaleStrings.SET["default_view_mode_label"], padding=10)
view_mode_frame.pack(fill="x", pady=5)
ttk.Radiobutton(view_mode_frame, text=LocaleStrings.SET["icons_radio"],
variable=self.default_view_mode, value="icons").pack(side="left", padx=5)
ttk.Radiobutton(view_mode_frame, text=LocaleStrings.SET["list_radio"],
variable=self.default_view_mode, value="list").pack(side="left", padx=5)
# Search Hidden Files
search_hidden_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["search_settings"], padding=10)
search_hidden_frame.pack(fill="x", pady=5)
ttk.Checkbutton(search_hidden_frame, text=LocaleStrings.SET["search_hidden_check"],
variable=self.search_hidden_files).pack(anchor="w")
ttk.Checkbutton(search_hidden_frame, text=LocaleStrings.SET["recursive_search_check"],
variable=self.recursive_search).pack(anchor="w")
# Deletion Settings
delete_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["deletion_settings"], padding=10)
delete_frame.pack(fill="x", pady=5)
self.use_trash_checkbutton = ttk.Checkbutton(delete_frame, text=f"{LocaleStrings.SET['use_trash_check']} ({LocaleStrings.SET['recommended']})",
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=f"({LocaleStrings.SET['send2trash_not_found']})",
font=("TkDefaultFont", 9, "italic")).pack(anchor="w", padx=(20, 0))
self.confirm_delete_checkbutton = ttk.Checkbutton(delete_frame, text=LocaleStrings.SET["confirm_delete_check"],
variable=self.confirm_delete)
self.confirm_delete_checkbutton.pack(anchor="w")
# Pillow Animation
pillow_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["animation_settings"], padding=10)
pillow_frame.pack(fill="x", pady=5)
self.use_pillow_animation_checkbutton = ttk.Checkbutton(pillow_frame, text=f"{LocaleStrings.SET['use_pillow_check']} ({LocaleStrings.SET['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=f"({LocaleStrings.SET['pillow_not_found']})",
font=("TkDefaultFont", 9, "italic")).pack(anchor="w", padx=(20, 0))
# Animation Type
anim_type_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["animation_type"], padding=10)
anim_type_frame.pack(fill="x", pady=5)
ttk.Radiobutton(anim_type_frame, text=LocaleStrings.SET["counter_arc"], variable=self.animation_type,
value="counter_arc").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text=LocaleStrings.SET["double_arc"], variable=self.animation_type,
value="double_arc").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text=LocaleStrings.SET["line"], variable=self.animation_type,
value="line").pack(side="left", padx=5)
ttk.Radiobutton(anim_type_frame, text=LocaleStrings.SET["blink"], variable=self.animation_type,
value="blink").pack(side="left", padx=5)
# SFTP Settings
sftp_frame = ttk.LabelFrame(
main_frame, text=LocaleStrings.SET["sftp_settings"], padding=10)
sftp_frame.pack(fill="x", pady=5)
if not PARAMIKO_AVAILABLE:
ttk.Label(sftp_frame, text=LocaleStrings.SET["paramiko_not_found"],
font=("TkDefaultFont", 9, "italic")).pack(anchor="w")
ttk.Label(sftp_frame, text=LocaleStrings.SET["sftp_disabled"],
font=("TkDefaultFont", 9, "italic")).pack(anchor="w")
else:
ttk.Label(sftp_frame, text=LocaleStrings.SET["paramiko_found"],
font=("TkDefaultFont", 9)).pack(anchor="w")
# Keyring status
try:
import keyring
keyring_available = True
except ImportError:
keyring_available = False
if keyring_available:
ttk.Label(sftp_frame, text="Keyring library found. Passwords will be stored securely.",
font=("TkDefaultFont", 9)).pack(anchor="w", pady=(5,0))
else:
ttk.Label(sftp_frame, text="Keyring library not found. Passwords cannot be saved.",
font=("TkDefaultFont", 9, "italic")).pack(anchor="w", pady=(5,0))
self.keep_bookmarks_checkbutton = ttk.Checkbutton(sftp_frame, text=LocaleStrings.SET["keep_sftp_bookmarks"],
variable=self.keep_bookmarks_on_reset)
self.keep_bookmarks_checkbutton.pack(anchor="w", pady=(5,0))
# 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=f"({LocaleStrings.SET['deletion_options_info']})",
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=LocaleStrings.SET["reset_to_default"],
command=self.reset_to_defaults).pack(side="left", padx=5)
ttk.Button(button_frame, text=LocaleStrings.SET["save_button"],
command=self.save_settings).pack(side="right", padx=5)
ttk.Button(button_frame, text=LocaleStrings.SET["cancel_button"],
command=self.destroy).pack(side="right")
def save_settings(self) -> None:
"""
Saves the current settings to the configuration file and closes the dialog.
Triggers a UI rebuild in the parent dialog to apply the changes.
"""
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(),
"keep_bookmarks_on_reset": self.keep_bookmarks_on_reset.get()
}
CfdConfigManager.save(new_settings)
self.master.reload_config_and_rebuild_ui()
self.destroy()
def reset_to_defaults(self) -> None:
"""Resets all settings in the dialog to their default values."""
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"))
self.keep_bookmarks_on_reset.set(defaults.get("keep_bookmarks_on_reset", True))