commit 46

This commit is contained in:
2025-08-03 02:35:48 +02:00
parent e211072cc2
commit 94c32ddd9e
4 changed files with 101 additions and 56 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -56,6 +56,8 @@ class CustomFileDialog(tk.Toplevel):
self.search_results = [] # Store search results
self.search_mode = False # Track if in search mode
self.original_path_text = "" # Store original path text
self.items_to_load_per_batch = 250
self.item_path_map = {}
self.icon_manager = IconManager()
self.style_manager = StyleManager(self)
@@ -508,7 +510,42 @@ class CustomFileDialog(tk.Toplevel):
except (PermissionError, FileNotFoundError):
return None
def _get_item_path_from_widget(self, widget):
# Traverse up the widget hierarchy to find the item_frame
while widget and not hasattr(widget, 'item_path'):
widget = widget.master
return getattr(widget, 'item_path', None)
def _handle_icon_click(self, event):
item_path = self._get_item_path_from_widget(event.widget)
if item_path:
item_frame = event.widget
while not hasattr(item_frame, 'item_path'):
item_frame = item_frame.master
self.on_item_select(item_path, item_frame)
def _handle_icon_double_click(self, event):
item_path = self._get_item_path_from_widget(event.widget)
if item_path:
self.on_item_double_click(item_path)
def _handle_icon_context_menu(self, event):
item_path = self._get_item_path_from_widget(event.widget)
if item_path:
self._show_context_menu(event, item_path)
def _handle_icon_rename_request(self, event):
item_path = self._get_item_path_from_widget(event.widget)
if item_path:
item_frame = event.widget
while not hasattr(item_frame, 'item_path'):
item_frame = item_frame.master
self.on_rename_request(event, item_path, item_frame)
def populate_icon_view(self, item_to_rename=None, item_to_select=None):
self.all_items, error, warning = self._get_sorted_items()
self.currently_loaded_count = 0
canvas = tk.Canvas(self.widget_manager.file_list_frame,
highlightthickness=0, bg=self.style_manager.icon_bg_color)
v_scrollbar = ttk.Scrollbar(
@@ -521,33 +558,42 @@ class CustomFileDialog(tk.Toplevel):
scrollregion=canvas.bbox("all")))
def _on_mouse_wheel(event):
# Determine the scroll direction and magnitude
if event.num == 4: # Scroll up on Linux
delta = -1
elif event.num == 5: # Scroll down on Linux
delta = 1
else: # MouseWheel event for Windows/macOS
delta = -1 * int(event.delta / 120)
if event.num == 4: delta = -1
elif event.num == 5: delta = 1
else: delta = -1 * int(event.delta / 120)
canvas.yview_scroll(delta, "units")
# Check if scrolled to the bottom and if there are more items to load
if self.currently_loaded_count < len(self.all_items) and canvas.yview()[1] > 0.9:
self._load_more_items_icon_view(container_frame)
# Bind mouse wheel events to the canvas and the container frame
for widget in [canvas, container_frame]:
widget.bind("<MouseWheel>", _on_mouse_wheel)
widget.bind("<Button-4>", _on_mouse_wheel)
widget.bind("<Button-5>", _on_mouse_wheel)
items, error, warning = self._get_sorted_items()
if warning:
self.widget_manager.status_bar.config(text=warning)
if error:
ttk.Label(container_frame, text=error).pack(pady=20)
return
self._load_more_items_icon_view(container_frame, item_to_rename, item_to_select)
def _load_more_items_icon_view(self, container, item_to_rename=None, item_to_select=None):
start_index = self.currently_loaded_count
end_index = min(len(self.all_items), start_index + self.items_to_load_per_batch)
if start_index >= end_index: return # All items loaded
item_width, item_height = 125, 100
frame_width = self.widget_manager.file_list_frame.winfo_width()
col_count = max(1, frame_width // item_width - 1)
row, col = 0, 0
for name in items:
row = start_index // col_count
col = start_index % col_count
for i in range(start_index, end_index):
name = self.all_items[i]
if not self.show_hidden_files.get() and name.startswith('.'):
continue
path = os.path.join(self.current_dir, name)
@@ -556,65 +602,54 @@ class CustomFileDialog(tk.Toplevel):
continue
item_frame = ttk.Frame(
container_frame, width=item_width, height=item_height, style="Item.TFrame")
container, width=item_width, height=item_height, style="Item.TFrame")
item_frame.grid(row=row, column=col, padx=5, ipadx=25, pady=5)
item_frame.grid_propagate(False)
if name == item_to_rename:
self.start_rename(item_frame, path)
else:
icon = self.icon_manager.get_icon('folder_large') if is_dir else self.get_file_icon(
name, 'large')
icon_label = ttk.Label(
item_frame, image=icon, style="Icon.TLabel")
icon = self.icon_manager.get_icon('folder_large') if is_dir else self.get_file_icon(name, 'large')
icon_label = ttk.Label(item_frame, image=icon, style="Icon.TLabel")
icon_label.pack(pady=(10, 5))
name_label = ttk.Label(item_frame, text=self.shorten_text(
name, 14), anchor="center", style="Item.TLabel")
name_label = ttk.Label(item_frame, text=self.shorten_text(name, 14), anchor="center", style="Item.TLabel")
name_label.pack(fill="x", expand=True)
tooltip_text = name
if is_dir:
if is_dir and len(self.all_items) < 500:
content_count = self._get_folder_content_count(path)
if content_count is not None:
tooltip_text += f"\n({content_count} Einträge)"
Tooltip(item_frame, tooltip_text)
# Bind events to all individual widgets so scrolling works everywhere
for widget in [item_frame, icon_label, name_label]:
widget.bind("<Double-Button-1>", lambda e,
p=path: self.on_item_double_click(p))
widget.bind("<Button-1>", lambda e, p=path,
f=item_frame: self.on_item_select(p, f))
widget.bind("<Double-Button-1>", lambda e, p=path: self.on_item_double_click(p))
widget.bind("<Button-1>", lambda e, p=path, f=item_frame: self.on_item_select(p, f))
widget.bind("<ButtonRelease-3>", lambda e, p=path: self._show_context_menu(e, p))
widget.bind("<MouseWheel>", _on_mouse_wheel)
widget.bind("<Button-4>", _on_mouse_wheel)
widget.bind("<Button-5>", _on_mouse_wheel)
widget.bind("<F2>", lambda e, p=path,
f=item_frame: self.on_rename_request(e, p, f))
widget.bind("<F2>", lambda e, p=path, f=item_frame: self.on_rename_request(e, p, f))
if name == item_to_select:
self.on_item_select(path, item_frame)
canvas.yview_moveto(row / max(1, (len(items) // col_count)))
col = (col + 1) % col_count
if col == 0:
row += 1
if col == 0: row += 1
self.currently_loaded_count = end_index
def populate_list_view(self, item_to_rename=None, item_to_select=None):
self.all_items, error, warning = self._get_sorted_items()
self.currently_loaded_count = 0
tree_frame = ttk.Frame(self.widget_manager.file_list_frame)
tree_frame.pack(fill='both', expand=True)
tree_frame.grid_rowconfigure(0, weight=1)
tree_frame.grid_columnconfigure(0, weight=1)
columns = ("size", "type", "modified")
self.tree = ttk.Treeview(
tree_frame, columns=columns, show="tree headings")
self.tree = ttk.Treeview(tree_frame, columns=columns, show="tree headings")
# Tree Column (#0)
self.tree.heading("#0", text="Name", anchor="w")
self.tree.column("#0", anchor="w", width=250, stretch=True)
# Other Columns
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")
@@ -622,30 +657,43 @@ class CustomFileDialog(tk.Toplevel):
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)
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.grid(row=0, column=0, sticky='nsew')
v_scrollbar.grid(row=0, column=1, sticky='ns')
h_scrollbar.grid(row=1, column=0, sticky='ew')
def _on_scroll(*args):
# Check if scrolled to the bottom and if there are more items to load
if self.currently_loaded_count < len(self.all_items) and self.tree.yview()[1] > 0.9:
self._load_more_items_list_view(item_to_rename, item_to_select)
v_scrollbar.set(*args)
self.tree.configure(yscrollcommand=_on_scroll)
self.tree.bind("<Double-1>", self.on_list_double_click)
self.tree.bind("<<TreeviewSelect>>", self.on_list_select)
self.tree.bind("<F2>", self.on_rename_request)
self.tree.bind("<ButtonRelease-3>", self.on_list_context_menu)
items, error, warning = self._get_sorted_items()
if warning:
self.widget_manager.status_bar.config(text=warning)
if error:
self.tree.insert("", "end", text=error, values=())
return
for name in items:
self._load_more_items_list_view(item_to_rename, item_to_select)
def _load_more_items_list_view(self, item_to_rename=None, item_to_select=None):
start_index = self.currently_loaded_count
end_index = min(len(self.all_items), start_index + self.items_to_load_per_batch)
if start_index >= end_index:
return # All items loaded
for i in range(start_index, end_index):
name = self.all_items[i]
if not self.show_hidden_files.get() and name.startswith('.'):
continue
path = os.path.join(self.current_dir, name)
@@ -654,28 +702,25 @@ class CustomFileDialog(tk.Toplevel):
continue
try:
stat = os.stat(path)
modified_time = datetime.fromtimestamp(
stat.st_mtime).strftime('%d.%m.%Y %H:%M')
modified_time = datetime.fromtimestamp(stat.st_mtime).strftime('%d.%m.%Y %H:%M')
if is_dir:
icon, file_type, size = self.icon_manager.get_icon(
'folder_small'), "Ordner", ""
icon, file_type, size = self.icon_manager.get_icon('folder_small'), "Ordner", ""
else:
icon, file_type, size = self.get_file_icon(
name, 'small'), "Datei", self._format_size(stat.st_size)
item_id = self.tree.insert("", "end", text=f" {name}", image=icon, values=(
size, file_type, modified_time))
icon, file_type, size = self.get_file_icon(name, 'small'), "Datei", self._format_size(stat.st_size)
item_id = self.tree.insert("", "end", text=f" {name}", image=icon, values=(size, file_type, modified_time))
if name == item_to_rename:
self.tree.selection_set(item_id)
self.tree.focus(item_id)
self.tree.see(item_id) # Scroll to the item
self.tree.see(item_id)
self.start_rename(item_id, path)
elif name == item_to_select:
self.tree.selection_set(item_id)
self.tree.focus(item_id)
self.tree.see(item_id) # Scroll to the item
self.tree.see(item_id)
except (FileNotFoundError, PermissionError):
continue
self.currently_loaded_count = end_index
def on_item_select(self, path, item_frame):
if hasattr(self, 'selected_item_frame') and self.selected_item_frame.winfo_exists():