commit two

This commit is contained in:
2025-07-26 11:44:23 +02:00
parent ff970973e2
commit 06774c0653
17 changed files with 388 additions and 199 deletions

5
GEMINI.md Normal file
View File

@@ -0,0 +1,5 @@
# Gemini Project Configuration
## Language
Please respond in German.

BIN
audio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -1,7 +1,56 @@
import os
import shutil
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
import os from datetime import datetime
from functools import partial
class Tooltip:
def __init__(self, widget, text, wraplength=250):
self.widget = widget
self.text = text
self.wraplength = wraplength
self.tooltip_window = None
self.id = None
self.widget.bind("<Enter>", self.enter)
self.widget.bind("<Leave>", self.leave)
self.widget.bind("<ButtonPress>", self.leave)
def enter(self, event=None): self.schedule()
def leave(self, event=None): self.unschedule(); self.hide_tooltip()
def schedule(self): self.unschedule(
); self.id = self.widget.after(500, self.show_tooltip)
def unschedule(self):
id = self.id
self.id = None
if id:
self.widget.after_cancel(id)
def show_tooltip(self, event=None):
x, y, _, _ = self.widget.bbox("insert")
x += self.widget.winfo_rootx() + 25
y += self.widget.winfo_rooty() + 20
self.tooltip_window = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(True)
tw.wm_geometry(f"+{x}+{y}")
style = ttk.Style()
try:
bg = style.lookup("Tooltip", "background", default="#FFFFE0")
fg = style.lookup("Tooltip", "foreground", default="black")
except tk.TclError:
bg = "#FFFFE0"
fg = "black"
label = ttk.Label(tw, text=self.text, justify=tk.LEFT, background=bg, foreground=fg,
relief=tk.SOLID, borderwidth=1, wraplength=self.wraplength, padding=(4, 2, 4, 2))
label.pack(ipadx=1)
def hide_tooltip(self):
tw = self.tooltip_window
self.tooltip_window = None
if tw:
tw.destroy()
class CustomFileDialog(tk.Toplevel): class CustomFileDialog(tk.Toplevel):
@@ -9,249 +58,384 @@ class CustomFileDialog(tk.Toplevel):
super().__init__(parent) super().__init__(parent)
self.parent = parent self.parent = parent
self.title("Datei auswählen") self.title("Datei auswählen")
self.geometry("800x600") # Standardgröße, kann angepasst werden self.geometry("900x650")
# Macht das Dialogfenster modal zum Hauptfenster self.minsize(650, 400)
self.transient(parent) self.transient(parent)
self.grab_set() # Fängt alle Ereignisse ab, bis der Dialog geschlossen wird self.grab_set()
self.selected_file = None self.selected_file = None
self.current_dir = os.path.abspath( self.current_dir = os.path.abspath(
initial_dir) if initial_dir else os.getcwd() initial_dir) if initial_dir else os.path.expanduser("~")
self.filetypes = filetypes if filetypes else [("All files", "*.*")] self.filetypes = filetypes if filetypes else [("Alle Dateien", "*.*")]
self.current_filter_pattern = "*.*" # Standardfilter
# Icons (Platzhalter, müssten geladen werden)
# Sie müssen hier Ihre eigenen Icons laden oder generieren
# Beispiel: self.folder_icon = tk.PhotoImage(file="path/to/your/folder_icon.png")
# Für den Anfang verwenden wir leere PhotoImages
self.folder_icon = tk.PhotoImage(
file="./water-folder.png")
self.file_icon = tk.PhotoImage(
file="./text-x-generic.png")
self.iso_icon = tk.PhotoImage(
file="./media-optical.png")
self._create_widgets()
# Filter-Combobox initialisieren
filter_descriptions = [desc for desc, pattern in self.filetypes]
self.filter_combobox["values"] = filter_descriptions
# Ersten Filter als Standard setzen
self.filter_combobox.set(filter_descriptions[0])
# Den initialen Filter explizit setzen, da <<ComboboxSelected>> nicht immer ausgelöst wird
self.current_filter_pattern = self.filetypes[0][1] self.current_filter_pattern = self.filetypes[0][1]
self.history = [self.current_dir]
self.history_pos = 0
self.view_mode = tk.StringVar(value="icons")
self.resize_job = None
self.last_width = 0
self._populate_files() self.load_icons()
self.create_styles()
self.create_widgets()
self.update_status_bar()
self.after(50, self.populate_files)
# Behandelt das Schließen des Fensters def load_icons(self):
self.protocol("WM_DELETE_WINDOW", self._on_closing) try:
self.wait_window(self) # Wartet, bis das Fenster geschlossen wird self.folder_icon_large = tk.PhotoImage(
file="./folder-water.png").zoom(1)
self.file_icon_large = tk.PhotoImage(
file="./document.png").zoom(1)
self.iso_icon_large = tk.PhotoImage(
file="./media-optical.png").zoom(1)
self.folder_icon_small = tk.PhotoImage(file="./folder-water.png")
self.file_icon_small = tk.PhotoImage(file="./document.png")
self.iso_icon_small = tk.PhotoImage(file="./media-optical.png")
except tk.TclError:
self.folder_icon_large = tk.PhotoImage(width=48, height=48)
self.file_icon_large = tk.PhotoImage(width=48, height=48)
self.iso_icon_large = tk.PhotoImage(width=48, height=48)
self.folder_icon_small = tk.PhotoImage(width=16, height=16)
self.file_icon_small = tk.PhotoImage(width=16, height=16)
self.iso_icon_small = tk.PhotoImage(width=16, height=16)
def _create_widgets(self): def create_styles(self):
# Hauptframe style = ttk.Style(self)
self.selection_color = "#0078D7"
style.map('Item.TFrame', background=[
('selected', self.selection_color)])
style.configure("Treeview.Heading", relief="raised",
borderwidth=1, font=('TkDefaultFont', 10, 'bold'))
style.configure("Treeview", rowheight=24)
style.layout("Treeview.Row",
[('Treeview.row', {'children': [('Treeview.padding', {'children': [('Treeview.indicator', {'side': 'left', 'sticky': 'ns'}), ('Treeview.image', {'side': 'left', 'sticky': 'ns'}), ('Treeview.text', {'side': 'left', 'sticky': 'ns'})], 'sticky': 'nsew'})], 'sticky': 'nsew'})])
def create_widgets(self):
main_frame = ttk.Frame(self, padding="10") main_frame = ttk.Frame(self, padding="10")
main_frame.pack(fill="both", expand=True) main_frame.pack(fill="both", expand=True)
# Canvas-Bereich soll sich ausdehnen paned_window = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
main_frame.grid_rowconfigure(1, weight=1) paned_window.pack(fill="both", expand=True)
main_frame.grid_columnconfigure(0, weight=1)
# Pfad-Navigation sidebar_frame = ttk.Frame(paned_window, padding=5)
path_frame = ttk.Frame(main_frame) paned_window.add(sidebar_frame, weight=0)
path_frame.grid(row=0, column=0, sticky="ew", pady=(0, 5)) sidebar_frame.grid_rowconfigure(1, weight=1)
path_frame.grid_columnconfigure(1, weight=1)
ttk.Button(path_frame, text="Up", command=self._go_up_dir).grid( # --- Navigation buttons in Sidebar ---
row=0, column=0, padx=(0, 5)) sidebar_nav_frame = ttk.Frame(sidebar_frame)
self.path_entry = ttk.Entry(path_frame, state="readonly") sidebar_nav_frame.grid(row=0, column=0, sticky="ew", pady=(0, 10))
self.path_entry.grid(row=0, column=1, sticky="ew") self.back_button = ttk.Button(
sidebar_nav_frame, text="", command=self.go_back, state=tk.DISABLED, width=3)
self.back_button.pack(side="left", fill="x", expand=True)
self.home_button = ttk.Button(sidebar_nav_frame, text="🏠", command=lambda: self.navigate_to(
os.path.expanduser("~")), width=3)
self.home_button.pack(side="left", fill="x", expand=True, padx=2)
self.forward_button = ttk.Button(
sidebar_nav_frame, text="", command=self.go_forward, state=tk.DISABLED, width=3)
self.forward_button.pack(side="left", fill="x", expand=True)
ttk.Label(path_frame, text="Dateityp:").grid( sidebar_buttons_frame = ttk.Frame(sidebar_frame)
row=0, column=2, padx=(10, 5)) sidebar_buttons_frame.grid(row=1, column=0, sticky="nsew")
self.filter_combobox = ttk.Combobox(path_frame, state="readonly") sidebar_buttons_config = [
self.filter_combobox.grid(row=0, column=3, sticky="ew") {'name': 'Downloads', 'unicode': '📥', 'path': os.path.join(
os.path.expanduser("~"), "Downloads")},
{'name': 'Dokumente', 'unicode': '📄', 'path': os.path.join(
os.path.expanduser("~"), "Documents")},
{'name': 'Bilder', 'unicode': '🖼️', 'path': os.path.join(
os.path.expanduser("~"), "Pictures")},
{'name': 'Musik', 'unicode': '🎵', 'path': os.path.join(
os.path.expanduser("~"), "Music")},
{'name': 'Videos', 'unicode': '🎬', 'path': os.path.join(
os.path.expanduser("~"), "Videos")},
]
for config in sidebar_buttons_config:
btn = ttk.Button(sidebar_buttons_frame, text=f" {config['unicode']} {config['name']}",
command=lambda p=config['path']: self.navigate_to(p), style="Sidebar.TButton")
btn.pack(fill="x", pady=1)
ttk.Style().configure("Sidebar.TButton", anchor="w", padding=5)
content_frame = ttk.Frame(paned_window, padding=(5, 0, 0, 0))
paned_window.add(content_frame, weight=1)
content_frame.grid_rowconfigure(1, weight=1)
content_frame.grid_columnconfigure(0, weight=1)
top_bar = ttk.Frame(content_frame)
top_bar.grid(row=0, column=0, sticky="ew", pady=(5, 5))
top_bar.grid_columnconfigure(0, weight=1)
self.path_entry = ttk.Entry(top_bar)
self.path_entry.grid(row=0, column=0, sticky="ew")
view_switch = ttk.Frame(top_bar, padding=(5, 0))
view_switch.grid(row=0, column=1)
ttk.Radiobutton(view_switch, text="Kacheln", variable=self.view_mode,
value="icons", command=self.populate_files).pack(side="left")
ttk.Radiobutton(view_switch, text="Liste", variable=self.view_mode,
value="list", command=self.populate_files).pack(side="left")
self.filter_combobox = ttk.Combobox(
top_bar, values=[ft[0] for ft in self.filetypes], state="readonly", width=15)
self.filter_combobox.grid(row=0, column=2, padx=5)
self.filter_combobox.bind( self.filter_combobox.bind(
"<<ComboboxSelected>>", self._on_filter_select) "<<ComboboxSelected>>", self.on_filter_change)
# Optional: Pfad im System-Explorer öffnen self.filter_combobox.set(self.filetypes[0][0])
# Canvas für Dateianzeige (Kachelansicht)
self.canvas_frame = ttk.Frame(main_frame)
self.canvas_frame.grid(row=1, column=0, sticky="nsew")
self.canvas_frame.grid_rowconfigure(0, weight=1)
self.canvas_frame.grid_columnconfigure(0, weight=1)
self.canvas = tk.Canvas( self.file_list_frame = ttk.Frame(content_frame)
self.canvas_frame, bg="white", highlightthickness=0) self.file_list_frame.grid(row=1, column=0, sticky="nsew")
self.canvas.grid(row=0, column=0, sticky="nsew") self.bind("<Configure>", self.on_window_resize)
self.v_scrollbar = ttk.Scrollbar( bottom_frame = ttk.Frame(content_frame)
self.canvas_frame, orient="vertical", command=self.canvas.yview) bottom_frame.grid(row=2, column=0, sticky="ew", pady=(5, 0))
self.v_scrollbar.grid(row=0, column=1, sticky="ns") bottom_frame.grid_columnconfigure(0, weight=1)
self.canvas.configure(yscrollcommand=self.v_scrollbar.set) self.status_bar = ttk.Label(bottom_frame, text="", anchor="w")
self.status_bar.grid(row=0, column=0, sticky="ew")
action_buttons_frame = ttk.Frame(bottom_frame)
action_buttons_frame.grid(row=0, column=1)
ttk.Button(action_buttons_frame, text="Öffnen",
command=self.on_open).pack(side="right")
ttk.Button(action_buttons_frame, text="Abbrechen",
command=self.on_cancel).pack(side="right", padx=5)
self.h_scrollbar = ttk.Scrollbar( def on_window_resize(self, event):
self.canvas_frame, orient="horizontal", command=self.canvas.xview) new_width = self.file_list_frame.winfo_width()
self.h_scrollbar.grid(row=1, column=0, sticky="ew") if self.view_mode.get() == "icons" and abs(new_width - self.last_width) > 50:
self.canvas.configure(xscrollcommand=self.h_scrollbar.set) if self.resize_job:
self.after_cancel(self.resize_job)
self.resize_job = self.after(200, self.populate_files)
self.last_width = new_width
# Frame zum Halten der Kacheln def populate_files(self):
self.inner_frame = ttk.Frame(self.canvas) for widget in self.file_list_frame.winfo_children():
self.canvas.create_window((0, 0), window=self.inner_frame, anchor="nw")
self.inner_frame.bind("<Configure>", lambda e: self.canvas.configure(
scrollregion=self.canvas.bbox("all")))
# Für Klicks auf leeren Bereich
self.canvas.bind("<Button-1>", self._on_canvas_click)
# Buttons
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=2, column=0, sticky="ew", pady=(5, 0))
button_frame.grid_columnconfigure(0, weight=1) # Leerraum links
ttk.Button(button_frame, text="Öffnen", command=self._on_open).grid(
row=0, column=1, padx=(0, 5))
ttk.Button(button_frame, text="Abbrechen",
command=self._on_cancel).grid(row=0, column=2)
def _populate_files(self):
# Lösche alle vorhandenen Kacheln
for widget in self.inner_frame.winfo_children():
widget.destroy() widget.destroy()
self.path_entry.config(state="normal")
self.path_entry.delete(0, tk.END) self.path_entry.delete(0, tk.END)
self.path_entry.insert(0, self.current_dir) self.path_entry.insert(0, self.current_dir)
self.path_entry.config(state="readonly") self.selected_file = None
self.update_status_bar()
if self.view_mode.get() == "list":
self.populate_list_view()
else:
self.populate_icon_view()
def populate_icon_view(self):
canvas = tk.Canvas(self.file_list_frame, highlightthickness=0)
v_scrollbar = ttk.Scrollbar(
self.file_list_frame, orient="vertical", command=canvas.yview)
style = ttk.Style(self)
bg_color = style.lookup("TFrame", "background")
canvas.configure(bg=bg_color)
canvas.pack(side="left", fill="both", expand=True)
v_scrollbar.pack(side="right", fill="y")
container_frame = ttk.Frame(canvas, style="TFrame")
self.container_frame = container_frame
canvas.create_window((0, 0), window=container_frame, anchor="nw")
container_frame.bind("<Configure>", lambda e: canvas.configure(
scrollregion=canvas.bbox("all")))
files_and_dirs = []
try: try:
for item in os.listdir(self.current_dir): items = os.listdir(self.current_dir)
full_path = os.path.join(self.current_dir, item)
if os.path.isdir(full_path):
files_and_dirs.append((item, "dir"))
elif os.path.isfile(full_path):
# Dateien nur hinzufügen, wenn sie dem aktuellen Filter entsprechen
if self._matches_filetype(item):
files_and_dirs.append((item, "file"))
except PermissionError: except PermissionError:
# Fehlerbehandlung für nicht zugängliche Verzeichnisse ttk.Label(container_frame, text="Zugriff verweigert.").pack(pady=20)
ttk.Label(self.inner_frame,
text="Zugriff verweigert.").pack(pady=20)
return
except Exception as e:
ttk.Label(self.inner_frame, text=f"Fehler: {e}").pack(pady=20)
return return
# Sortieren: Ordner zuerst, dann Dateien, alphabetisch item_width = 120
files_and_dirs.sort(key=lambda x: (x[1] == "file", x[0].lower())) item_height = 100
frame_width = self.file_list_frame.winfo_width()
col_count = max(1, frame_width // item_width)
row, col = 0, 0
for name in sorted(items, key=str.lower):
path = os.path.join(self.current_dir, name)
is_dir = os.path.isdir(path)
if not is_dir and not self._matches_filetype(name):
continue
# Kachel-Layout (Beispiel: 4 Spalten)
col_count = 4
for i, (name, item_type) in enumerate(files_and_dirs):
row = i // col_count
col = i % col_count
icon = self.folder_icon if item_type == "dir" else (
self.iso_icon if name.lower().endswith(".iso") else self.file_icon)
# Kachel-Frame
item_frame = ttk.Frame( item_frame = ttk.Frame(
self.inner_frame, relief="solid", borderwidth=1, padding=5) container_frame, width=item_width, height=item_height, style="Item.TFrame")
item_frame.grid(row=row, column=col, padx=5, pady=5, sticky="nsew") item_frame.grid(row=row, column=col, padx=5, pady=5)
# Text soll sich ausdehnen item_frame.grid_propagate(False)
item_frame.grid_rowconfigure(1, weight=1)
item_frame.grid_columnconfigure(
0, weight=1) # Icon/Text zentrieren
# Daten an den Frame anhängen icon = self.folder_icon_large if is_dir else (
item_frame.file_path = full_path self.iso_icon_large if name.lower().endswith(".iso") else self.file_icon_large)
item_frame.item_type = item_type
# Icon
icon_label = ttk.Label(item_frame, image=icon) icon_label = ttk.Label(item_frame, image=icon)
icon_label.grid(row=0, column=0, pady=(0, 5)) icon_label.pack(pady=(10, 5))
# Daten an das Icon-Label anhängen name_label = ttk.Label(
icon_label.file_path = full_path item_frame, text=self.shorten_text(name, 15), anchor="center")
icon_label.item_type = item_type name_label.pack(fill="x", expand=True)
# Dateiname Tooltip(item_frame, name)
# wraplength für Zeilenumbruch for widget in [item_frame, icon_label, name_label]:
name_label = ttk.Label(item_frame, text=name, widget.bind("<Double-Button-1>", lambda e,
wraplength=100, anchor="n") p=path: self.on_item_double_click(p))
name_label.grid(row=1, column=0, sticky="ew") widget.bind("<Button-1>", lambda e,
# Daten an das Name-Label anhängen p=path: self.on_item_select(p, item_frame))
name_label.file_path = full_path
name_label.item_type = item_type
# Bindungen für Klicks (mit functools.partial) col += 1
item_frame.bind( if col >= col_count:
"<Button-1>", partial(self._on_item_click, full_path, item_type)) col = 0
icon_label.bind( row += 1
"<Button-1>", partial(self._on_item_click, full_path, item_type))
name_label.bind(
"<Button-1>", partial(self._on_item_click, full_path, item_type))
item_frame.bind( def populate_list_view(self):
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type)) tree_frame = ttk.Frame(self.file_list_frame)
icon_label.bind( tree_frame.pack(fill='both', expand=True)
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type)) columns = ("name", "size", "type", "modified")
name_label.bind( self.tree = ttk.Treeview(tree_frame, columns=columns, show="headings")
"<Double-Button-1>", partial(self._on_item_double_click, full_path, item_type)) self.tree.heading("name", text="Name", anchor="w")
self.tree.column("name", anchor="w", width=300, stretch=True)
self.tree.heading("size", text="Größe", anchor="e")
self.tree.column("size", anchor="e", width=120, stretch=False)
self.tree.heading("type", text="Typ", anchor="w")
self.tree.column("type", anchor="w", width=120, stretch=False)
self.tree.heading("modified", text="Geändert am", anchor="w")
self.tree.column("modified", anchor="w", width=160, stretch=False)
v_scrollbar = ttk.Scrollbar(
tree_frame, orient="vertical", command=self.tree.yview)
h_scrollbar = ttk.Scrollbar(
tree_frame, orient="horizontal", command=self.tree.xview)
self.tree.configure(yscrollcommand=v_scrollbar.set,
xscrollcommand=h_scrollbar.set)
self.tree.pack(side="left", fill="both", expand=True)
v_scrollbar.pack(side="right", fill="y")
h_scrollbar.pack(side="bottom", fill="x")
self.tree.bind("<Double-1>", self.on_list_double_click)
self.tree.bind("<<TreeviewSelect>>", self.on_list_select)
def _go_up_dir(self): try:
parent_dir = os.path.dirname(self.current_dir) items = os.listdir(self.current_dir)
if parent_dir != self.current_dir: # Verhindert, dass man über das Root-Verzeichnis hinausgeht except PermissionError:
self.current_dir = parent_dir return
self._populate_files()
def _on_item_click(self, path, item_type, event): for name in sorted(items, key=str.lower):
print(f"DEBUG: _on_item_click - Path: {path}, Type: {item_type}") path = os.path.join(self.current_dir, name)
# Hier können Sie eine visuelle Auswahl hervorheben is_dir = os.path.isdir(path)
self.selected_file = path # Temporär speichern if not is_dir and not self._matches_filetype(name):
continue
try:
stat = os.stat(path)
modified_time = datetime.fromtimestamp(
stat.st_mtime).strftime('%d.%m.%Y %H:%M')
if is_dir:
icon = self.folder_icon_small
file_type = "Ordner"
size = ""
else:
icon = self.iso_icon_small if name.lower().endswith(
".iso") else self.file_icon_small
file_type = "Datei"
size = self._format_size(stat.st_size)
self.tree.insert("", "end", text=name, image=icon, values=(
name, size, file_type, modified_time))
except (FileNotFoundError, PermissionError):
continue
def _on_item_double_click(self, path, item_type, event): def on_item_select(self, path, item_frame):
print( for child in self.container_frame.winfo_children():
f"DEBUG: _on_item_double_click - Path: {path}, Type: {item_type}") child.state(['!selected'])
if item_type == "dir": item_frame.state(['selected'])
self.current_dir = path self.selected_file = path
self._populate_files() self.update_status_bar()
def on_list_select(self, event):
if not self.tree.selection():
return
item_text = self.tree.item(self.tree.selection()[0])['text']
self.selected_file = os.path.join(self.current_dir, item_text)
self.update_status_bar()
def on_item_double_click(self, path):
if os.path.isdir(path):
self.navigate_to(path)
else: else:
self.selected_file = path self.selected_file = path
self.destroy() # Dialog schließen und ausgewählte Datei zurückgeben
def _on_open(self):
if self.selected_file and os.path.isfile(self.selected_file):
self.destroy() self.destroy()
def on_list_double_click(self, event):
if not self.tree.selection():
return
item_text = self.tree.item(self.tree.selection()[0])['text']
path = os.path.join(self.current_dir, item_text)
if os.path.isdir(path):
self.navigate_to(path)
else: else:
# Optional: Fehlermeldung, wenn keine Datei ausgewählt oder Ordner doppelt geklickt wurde self.selected_file = path
print("Bitte eine Datei auswählen oder einen Ordner doppelt klicken.") self.destroy()
def _on_cancel(self): def on_filter_change(self, event):
self.selected_file = None # Nichts ausgewählt
self.destroy()
def _on_closing(self):
self.selected_file = None # Nichts ausgewählt, wenn Fenster geschlossen wird
self.destroy()
def _matches_filetype(self, filename):
# Wenn der aktuelle Filter "*.*" ist, passen alle Dateien
if self.current_filter_pattern == "*.*":
return True
# Ansonsten prüfen, ob die Datei zum aktuellen spezifischen Filter passt
ext = self.current_filter_pattern[2:].lower()
return filename.lower().endswith("." + ext)
def _on_filter_select(self, event):
selected_desc = self.filter_combobox.get() selected_desc = self.filter_combobox.get()
for desc, pattern in self.filetypes: for desc, pattern in self.filetypes:
if desc == selected_desc: if desc == selected_desc:
self.current_filter_pattern = pattern self.current_filter_pattern = pattern
break break
self._populate_files() # Dateiliste neu laden mit neuem Filter self.populate_files()
def _on_canvas_click(self, event): def navigate_to(self, path):
# Wenn auf den leeren Bereich des Canvas geklickt wird, Auswahl aufheben home_dir = os.path.expanduser("~")
abs_path = os.path.abspath(path)
if os.path.isdir(abs_path) and abs_path.startswith(home_dir):
self.current_dir = abs_path
if self.history_pos < len(self.history) - 1:
self.history = self.history[:self.history_pos + 1]
if self.history[-1] != self.current_dir:
self.history.append(self.current_dir)
self.history_pos += 1
self.populate_files()
self.update_nav_buttons()
else:
print(
f"Info: Navigation außerhalb von {home_dir} ist nicht erlaubt.")
def go_back(self):
if self.history_pos > 0:
self.history_pos -= 1
self.current_dir = self.history[self.history_pos]
self.populate_files()
self.update_nav_buttons()
def go_forward(self):
if self.history_pos < len(self.history) - 1:
self.history_pos += 1
self.current_dir = self.history[self.history_pos]
self.populate_files()
self.update_nav_buttons()
def update_nav_buttons(self):
self.back_button.config(
state=tk.NORMAL if self.history_pos > 0 else tk.DISABLED)
self.forward_button.config(state=tk.NORMAL if self.history_pos < len(
self.history) - 1 else tk.DISABLED)
def update_status_bar(self):
try:
_, _, free = shutil.disk_usage(self.current_dir)
free_str = self._format_size(free)
status_text = f"Freier Speicher: {free_str}"
if self.selected_file and os.path.exists(self.selected_file) and not os.path.isdir(self.selected_file):
size = os.path.getsize(self.selected_file)
size_str = self._format_size(size)
status_text += f" | Dateigröße: {size_str}"
self.status_bar.config(text=status_text)
except FileNotFoundError:
self.status_bar.config(text="Verzeichnis nicht gefunden")
def on_open(self):
if self.selected_file and os.path.isfile(self.selected_file):
self.destroy()
def on_cancel(self):
self.selected_file = None self.selected_file = None
# Optional: Visuelle Hervorhebung entfernen self.destroy()
def get_selected_file(self): def get_selected_file(self): return self.selected_file
return self.selected_file
def _matches_filetype(self, filename):
if self.current_filter_pattern == "*.*":
return True
return filename.lower().endswith(self.current_filter_pattern.lower().replace("*", ""))
def _format_size(self, size_bytes):
if size_bytes is None:
return ""
if size_bytes < 1024:
return f"{size_bytes} B"
if size_bytes < 1024**2:
return f"{size_bytes/1024:.1f} KB"
if size_bytes < 1024**3:
return f"{size_bytes/1024**2:.1f} MB"
return f"{size_bytes/1024**3:.1f} GB"
def shorten_text(self, text, max_len):
return text[:max_len-3] + "..." if len(text) > max_len else text

View File

Before

Width:  |  Height:  |  Size: 612 B

After

Width:  |  Height:  |  Size: 612 B

BIN
file-python.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water-documents.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water-download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water-music.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water-pictures.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water-video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
folder-water.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
pdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
picture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
tar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB