diff --git a/__pycache__/cfd_app_config.cpython-312.pyc b/__pycache__/cfd_app_config.cpython-312.pyc index b3ed709..5d59b46 100644 Binary files a/__pycache__/cfd_app_config.cpython-312.pyc and b/__pycache__/cfd_app_config.cpython-312.pyc differ diff --git a/__pycache__/cfd_ui_setup.cpython-312.pyc b/__pycache__/cfd_ui_setup.cpython-312.pyc index 0a26d25..c1acd7c 100644 Binary files a/__pycache__/cfd_ui_setup.cpython-312.pyc and b/__pycache__/cfd_ui_setup.cpython-312.pyc differ diff --git a/__pycache__/custom_file_dialog.cpython-312.pyc b/__pycache__/custom_file_dialog.cpython-312.pyc index c4cee9b..059feb4 100644 Binary files a/__pycache__/custom_file_dialog.cpython-312.pyc and b/__pycache__/custom_file_dialog.cpython-312.pyc differ diff --git a/cfd_app_config.py b/cfd_app_config.py index ecadeda..481c236 100755 --- a/cfd_app_config.py +++ b/cfd_app_config.py @@ -60,7 +60,7 @@ class AppConfig: # UI configuration UI_CONFIG: Dict[str, Any] = { "window_title": "File Dialog", - "window_size": (1100, 850), + "window_size": (1050, 850), "font_family": "Ubuntu", "font_size": 11, "resizable_window": (True, True), diff --git a/cfd_ui_setup.py b/cfd_ui_setup.py index aeff3cd..20f0e7f 100644 --- a/cfd_ui_setup.py +++ b/cfd_ui_setup.py @@ -369,32 +369,50 @@ class WidgetManager: left_bottom_buttons, text="", anchor="w", style="AccentBottom.TLabel") if self.dialog.dialog_mode == "save": - self.filename_entry = ttk.Entry(left_bottom_buttons, width=50) - self.filename_entry.grid( - row=0, column=1, padx=(5, 5), pady=5, sticky="ew") left_bottom_buttons.grid_columnconfigure(1, weight=1) - ttk.Button(left_bottom_buttons, text="Speichern", - command=self.dialog.on_save).grid(row=0, column=0, padx=(10, 5), pady=10) - ttk.Button(left_bottom_buttons, text="Abbrechen", - command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5)) - self.status_bar.grid(row=2, column=0, columnspan=2, - sticky="ew", padx=10, pady=5) + # Widgets for save mode + self.filename_entry = ttk.Entry(left_bottom_buttons, width=60) + self.filename_entry.grid(row=0, column=1, padx=( + 0, 5), pady=(10, 10), sticky="ew") + + save_button = ttk.Button( + left_bottom_buttons, text="Speichern", command=self.dialog.on_save) + save_button.grid(row=0, column=0, padx=(10, 5), pady=10) + + cancel_button = ttk.Button( + left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel) + cancel_button.grid(row=1, column=0, padx=(10, 5), pady=(0, 10)) + + self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[ + ft[0] for ft in self.dialog.filetypes], state="readonly") + self.filter_combobox.grid( + row=1, column=1, sticky="w", padx=(0, 10), pady=(0, 10)) + self.filter_combobox.bind( + "<>", self.dialog.on_filter_change) + self.filter_combobox.set(self.dialog.filetypes[0][0]) + + self.status_bar.grid( + row=0, column=1, sticky="w", padx=0, pady=(0, 5)) + else: + # Open mode layout + left_bottom_buttons.grid_columnconfigure(1, weight=1) - # Status bar (top-left in the bottom area) - self.status_bar.grid(row=0, column=1, columnspan=2, - sticky="e", padx=10, pady=5) - ttk.Button(left_bottom_buttons, text="Öffnen", command=self.dialog.on_open).grid( - row=0, column=0, padx=(10, 5), pady=10) - ttk.Button(left_bottom_buttons, text="Abbrechen", - command=self.dialog.on_cancel).grid(row=1, column=0, padx=(10, 5)) + open_button = ttk.Button( + left_bottom_buttons, text="Öffnen", command=self.dialog.on_open) + open_button.grid(row=0, column=0, padx=(10, 5), pady=10) - # Filter combobox (bottom-right) - self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[ - ft[0] for ft in self.dialog.filetypes], state="readonly") - self.filter_combobox.grid( - row=1, column=1, sticky="w", padx=(5, 10)) - self.filter_combobox.bind( - "<>", self.dialog.on_filter_change) - self.filter_combobox.set(self.dialog.filetypes[0][0]) + cancel_button = ttk.Button( + left_bottom_buttons, text="Abbrechen", command=self.dialog.on_cancel) + cancel_button.grid(row=1, column=0, padx=(10, 5), pady=(0, 10)) + + self.filter_combobox = ttk.Combobox(left_bottom_buttons, values=[ + ft[0] for ft in self.dialog.filetypes], state="readonly") + self.filter_combobox.grid( + row=1, column=1, sticky="w", padx=(0, 10), pady=(0, 10)) + self.filter_combobox.bind( + "<>", self.dialog.on_filter_change) + self.filter_combobox.set(self.dialog.filetypes[0][0]) + + self.status_bar.grid(row=0, column=1, sticky="w", padx=0, pady=5) diff --git a/custom_file_dialog.py b/custom_file_dialog.py index f185e31..9afae75 100644 --- a/custom_file_dialog.py +++ b/custom_file_dialog.py @@ -151,6 +151,7 @@ class CustomFileDialog(tk.Toplevel): self.original_path_text = self.widget_manager.path_entry.get() self.widget_manager.path_entry.delete(0, tk.END) self.widget_manager.path_entry.insert(0, "Suchbegriff eingeben...") + self.widget_manager.path_entry.focus_set() # Set focus to path entry self.widget_manager.path_entry.bind( "", self.execute_search) self.widget_manager.path_entry.bind( @@ -371,6 +372,30 @@ class CustomFileDialog(tk.Toplevel): except (FileNotFoundError, PermissionError): continue + # Bind selection event + def on_search_select(event): + selection = search_tree.selection() + if selection: + item = search_tree.item(selection[0]) + filename = item['text'].strip() + directory = item['values'][0] + full_path = os.path.join(directory, filename) + + # Update status bar + try: + stat = os.stat(full_path) + size_str = self._format_size(stat.st_size) + self.widget_manager.status_bar.config(text=f"'{filename}' Größe: {size_str}") + except (FileNotFoundError, PermissionError): + self.widget_manager.status_bar.config(text=f"'{filename}' nicht zugänglich") + + # If in save mode, update filename entry + if self.dialog_mode == "save": + self.widget_manager.filename_entry.delete(0, tk.END) + self.widget_manager.filename_entry.insert(0, filename) + + search_tree.bind("<>", on_search_select) + # Bind double-click to select file def on_search_double_click(event): selection = search_tree.selection() @@ -392,7 +417,7 @@ class CustomFileDialog(tk.Toplevel): self.unbind_all("") self.unbind_all("") - def populate_files(self, item_to_rename=None): + def populate_files(self, item_to_rename=None, item_to_select=None): # Unbind previous global mouse wheel events self._unbind_mouse_wheel_events() @@ -403,9 +428,9 @@ class CustomFileDialog(tk.Toplevel): self.selected_file = None self.update_status_bar() if self.view_mode.get() == "list": - self.populate_list_view(item_to_rename) + self.populate_list_view(item_to_rename, item_to_select) else: - self.populate_icon_view(item_to_rename) + self.populate_icon_view(item_to_rename, item_to_select) def _get_sorted_items(self): try: @@ -425,7 +450,22 @@ class CustomFileDialog(tk.Toplevel): except FileNotFoundError: return ([], "Verzeichnis nicht gefunden.", None) - def populate_icon_view(self, item_to_rename=None): + def _get_folder_content_count(self, folder_path): + try: + if not os.path.isdir(folder_path) or not os.access(folder_path, os.R_OK): + return None + + items = os.listdir(folder_path) + + # Filter based on hidden files setting + if not self.show_hidden_files.get(): + items = [item for item in items if not item.startswith('.')] + + return len(items) + except (PermissionError, FileNotFoundError): + return None + + def populate_icon_view(self, item_to_rename=None, item_to_select=None): canvas = tk.Canvas(self.widget_manager.file_list_frame, highlightthickness=0, bg=self.style_manager.icon_bg_color) v_scrollbar = ttk.Scrollbar( @@ -488,7 +528,14 @@ class CustomFileDialog(tk.Toplevel): 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(item_frame, name) + + tooltip_text = name + if is_dir: + 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("", lambda e, @@ -501,11 +548,15 @@ class CustomFileDialog(tk.Toplevel): widget.bind("", 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 - def populate_list_view(self, item_to_rename=None): + def populate_list_view(self, item_to_rename=None, item_to_select=None): tree_frame = ttk.Frame(self.widget_manager.file_list_frame) tree_frame.pack(fill='both', expand=True) tree_frame.grid_rowconfigure(0, weight=1) @@ -571,7 +622,12 @@ class CustomFileDialog(tk.Toplevel): 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.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 except (FileNotFoundError, PermissionError): continue @@ -589,9 +645,10 @@ class CustomFileDialog(tk.Toplevel): self.selected_item_frame = item_frame self.selected_file = path self.update_status_bar() + self.bind("", lambda e, p=path, f=item_frame: self.on_rename_request(e, p, f)) if self.dialog_mode == "save" and not os.path.isdir(path): - self.widget_manager.path_entry.delete(0, tk.END) - self.widget_manager.path_entry.insert(0, path) + self.widget_manager.filename_entry.delete(0, tk.END) + self.widget_manager.filename_entry.insert(0, os.path.basename(path)) def on_list_select(self, event): if not self.tree.selection(): @@ -601,8 +658,8 @@ class CustomFileDialog(tk.Toplevel): self.selected_file = os.path.join(self.current_dir, item_text) self.update_status_bar() if self.dialog_mode == "save" and not os.path.isdir(self.selected_file): - self.widget_manager.path_entry.delete(0, tk.END) - self.widget_manager.path_entry.insert(0, self.selected_file) + self.widget_manager.filename_entry.delete(0, tk.END) + self.widget_manager.filename_entry.insert(0, item_text) def on_rename_request(self, event, item_path=None, item_frame=None): if self.view_mode.get() == "list": @@ -686,6 +743,7 @@ class CustomFileDialog(tk.Toplevel): self.populate_files() self.update_nav_buttons() self.update_status_bar() + self.update_action_buttons_state() def go_forward(self): if self.history_pos < len(self.history) - 1: @@ -694,6 +752,7 @@ class CustomFileDialog(tk.Toplevel): self.populate_files() self.update_nav_buttons() self.update_status_bar() + self.update_action_buttons_state() def update_nav_buttons(self): self.widget_manager.back_button.config( @@ -784,7 +843,7 @@ class CustomFileDialog(tk.Toplevel): entry = ttk.Entry(item_frame) entry.insert(0, os.path.basename(item_path)) entry.select_range(0, tk.END) - entry.pack(fill="both", expand=True, padx=5, pady=5) + entry.pack(fill="x", expand=True, padx=5, pady=5) entry.focus_set() def finish_rename(event): @@ -794,14 +853,17 @@ class CustomFileDialog(tk.Toplevel): if os.path.exists(new_path): self.widget_manager.status_bar.config( text=f"'{new_name}' existiert bereits.") - self.populate_files() + self.populate_files(item_to_select=os.path.basename(item_path)) return try: os.rename(item_path, new_path) + self.populate_files(item_to_select=new_name) except Exception as e: self.widget_manager.status_bar.config( text=f"Fehler beim Umbenennen: {e}") - self.populate_files() + self.populate_files() + else: + self.populate_files(item_to_select=os.path.basename(item_path)) def cancel_rename(event): self.populate_files() @@ -813,7 +875,9 @@ class CustomFileDialog(tk.Toplevel): def _start_rename_list_view(self, item_id): x, y, width, height = self.tree.bbox(item_id, column="#0") entry = ttk.Entry(self.tree) - entry.place(x=x, y=y, width=width, height=height) + # Set a fixed width for the entry widget to prevent it from expanding too much + entry_width = self.tree.column("#0", "width") + entry.place(x=x, y=y, width=entry_width, height=height) item_text = self.tree.item(item_id, "text").strip() entry.insert(0, item_text) @@ -829,14 +893,18 @@ class CustomFileDialog(tk.Toplevel): if os.path.exists(new_path): self.widget_manager.status_bar.config( text=f"'{new_name}' existiert bereits.") + self.populate_files(item_to_select=item_text) else: try: os.rename(old_path, new_path) + self.populate_files(item_to_select=new_name) except Exception as e: self.widget_manager.status_bar.config( text=f"Fehler beim Umbenennen: {e}") + self.populate_files() + else: + self.populate_files(item_to_select=item_text) entry.destroy() - self.populate_files() def cancel_rename(event): entry.destroy() diff --git a/mainwindow.py b/mainwindow.py index 4d2f12b..c7d103a 100755 --- a/mainwindow.py +++ b/mainwindow.py @@ -30,23 +30,23 @@ class GlotzMol(tk.Tk): def open_custom_dialog(self): - CustomFileDialog(self, - initial_dir=os.path.expanduser("~"), - filetypes=[("All Files", "*.*") - ], dialog_mode="save") + dialog = CustomFileDialog(self, + initial_dir=os.path.expanduser("~"), + filetypes=[("All Files", "*.*") + ]) # This is the crucial part: wait for the dialog to be closed - # self.wait_window(dialog) + self.wait_window(dialog) # Now, get the result - # selected_path = dialog.get_selected_file() + selected_path = dialog.get_selected_file() - # if selected_path: - # self.iso_path_entry.delete(0, tk.END) - # self.iso_path_entry.insert(0, selected_path) - # print(f"Die ausgewählte Datei ist: {selected_path}") - # else: - # print("Keine Datei ausgewählt.") + if selected_path: + self.iso_path_entry.delete(0, tk.END) + self.iso_path_entry.insert(0, selected_path) + print(f"Die ausgewählte Datei ist: {selected_path}") + else: + print("Keine Datei ausgewählt.") if __name__ == "__main__":