commit 46
This commit is contained in:
BIN
__pycache__/cfd_app_config.cpython-312.pyc
Normal file
BIN
__pycache__/cfd_app_config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/cfd_ui_setup.cpython-312.pyc
Normal file
BIN
__pycache__/cfd_ui_setup.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/custom_file_dialog.cpython-312.pyc
Normal file
BIN
__pycache__/custom_file_dialog.cpython-312.pyc
Normal file
Binary file not shown.
@@ -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():
|
||||
|
Reference in New Issue
Block a user