commit 57
This commit is contained in:
@@ -38,6 +38,8 @@ class SettingsDialog(tk.Toplevel):
|
||||
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(
|
||||
@@ -89,6 +91,8 @@ class SettingsDialog(tk.Toplevel):
|
||||
search_hidden_frame.pack(fill="x", pady=5)
|
||||
ttk.Checkbutton(search_hidden_frame, text="Versteckte Dateien und Ordner durchsuchen",
|
||||
variable=self.search_hidden_files).pack(anchor="w")
|
||||
ttk.Checkbutton(search_hidden_frame, text="Rekursiv suchen",
|
||||
variable=self.recursive_search).pack(anchor="w")
|
||||
|
||||
# Deletion Settings
|
||||
delete_frame = ttk.LabelFrame(
|
||||
@@ -134,6 +138,7 @@ class SettingsDialog(tk.Toplevel):
|
||||
"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()
|
||||
}
|
||||
@@ -148,6 +153,7 @@ class SettingsDialog(tk.Toplevel):
|
||||
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"])
|
||||
|
||||
@@ -194,6 +200,7 @@ class CustomFileDialog(tk.Toplevel):
|
||||
self.items_to_load_per_batch = 250
|
||||
self.item_path_map = {}
|
||||
self.responsive_buttons_hidden = None # State for responsive buttons
|
||||
self.search_job = None
|
||||
|
||||
self.icon_manager = IconManager()
|
||||
self.style_manager = StyleManager(self)
|
||||
@@ -217,31 +224,63 @@ class CustomFileDialog(tk.Toplevel):
|
||||
# Bind the intelligent return handler
|
||||
self.widget_manager.path_entry.bind(
|
||||
"<Return>", self.handle_path_entry_return)
|
||||
|
||||
|
||||
|
||||
self.bind("<Key>", self.show_search_bar)
|
||||
|
||||
# Bind the delete key only in "save" mode
|
||||
if self.dialog_mode == "save":
|
||||
self.bind("<Delete>", self.delete_selected_item)
|
||||
|
||||
def handle_path_entry_return(self, event):
|
||||
"""Intelligently handles the Enter key in the path entry.
|
||||
|
||||
|
||||
If the text is a valid directory, it navigates there.
|
||||
Otherwise, if in search mode, it executes a search.
|
||||
def show_search_bar(self, event=None):
|
||||
# Ignore key presses if they are coming from an entry widget or have no character
|
||||
if isinstance(event.widget, (ttk.Entry, tk.Entry)) or not event.char.strip():
|
||||
return
|
||||
|
||||
self.search_mode = True
|
||||
if self.dialog_mode == "open":
|
||||
self.widget_manager.status_bar.pack_forget()
|
||||
self.widget_manager.search_entry.pack(side="top", fill="x", in_=self.widget_manager.center_container)
|
||||
self.widget_manager.search_entry.focus_set()
|
||||
self.widget_manager.search_entry.insert(0, event.char)
|
||||
self.widget_manager.search_entry.bind("<Return>", self.execute_search)
|
||||
self.widget_manager.search_entry.bind("<Escape>", self.hide_search_bar)
|
||||
else: # save mode
|
||||
self.widget_manager.filename_entry.focus_set()
|
||||
self.widget_manager.filename_entry.insert(tk.END, event.char)
|
||||
self.widget_manager.filename_entry.bind("<Return>", self.execute_search)
|
||||
self.widget_manager.filename_entry.bind("<Escape>", self.hide_search_bar)
|
||||
|
||||
def hide_search_bar(self, event=None):
|
||||
self.search_mode = False
|
||||
if self.dialog_mode == "open":
|
||||
self.widget_manager.search_entry.pack_forget()
|
||||
self.widget_manager.status_bar.pack(side="top", fill="x", in_=self.widget_manager.center_container)
|
||||
self.widget_manager.search_entry.delete(0, tk.END)
|
||||
else: # save mode
|
||||
self.widget_manager.filename_entry.delete(0, tk.END)
|
||||
self.widget_manager.search_status_label.config(text="")
|
||||
self.populate_files()
|
||||
|
||||
def toggle_search_mode(self, event=None):
|
||||
if self.search_mode:
|
||||
self.hide_search_bar(event)
|
||||
else:
|
||||
self.show_search_bar(event)
|
||||
|
||||
def handle_path_entry_return(self, event):
|
||||
"""Handles the Enter key in the path entry to navigate.
|
||||
Search is handled by on_path_entry_key_release.
|
||||
"""
|
||||
path_text = self.widget_manager.path_entry.get().strip()
|
||||
|
||||
# Try to interpret as a path first
|
||||
# Expand user-home and resolve relative paths
|
||||
potential_path = os.path.realpath(os.path.expanduser(path_text))
|
||||
|
||||
if os.path.isdir(potential_path):
|
||||
# If search was active, turn it off before navigating
|
||||
if self.search_mode:
|
||||
self.toggle_search_mode()
|
||||
self.navigate_to(potential_path)
|
||||
elif self.search_mode:
|
||||
# If not a valid path and in search mode, execute search
|
||||
self.execute_search(event)
|
||||
# If not a directory, do nothing on Enter. Search is triggered on key release.
|
||||
|
||||
def load_settings(self):
|
||||
self.settings = CfdConfigManager.load()
|
||||
@@ -435,36 +474,7 @@ class CustomFileDialog(tk.Toplevel):
|
||||
widget_y - buffer <= y <= widget_y + widget_height + buffer):
|
||||
self.widget_manager.devices_scrollbar.grid_remove()
|
||||
|
||||
def toggle_search_mode(self):
|
||||
"""Toggle between search mode and normal mode"""
|
||||
if not self.search_mode:
|
||||
# Enter search mode
|
||||
self.search_mode = True
|
||||
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...")
|
||||
# Use after() to ensure the focus is set after the UI has updated
|
||||
self.after(10, lambda: self.widget_manager.path_entry.focus_set())
|
||||
self.after(
|
||||
20, lambda: self.widget_manager.path_entry.select_range(0, tk.END))
|
||||
|
||||
self.widget_manager.path_entry.bind(
|
||||
"<FocusIn>", self.clear_search_placeholder)
|
||||
|
||||
# Show search options
|
||||
self.widget_manager.recursive_button.pack(side="left", padx=5)
|
||||
else:
|
||||
# Exit search mode
|
||||
self.search_mode = False
|
||||
self.widget_manager.path_entry.delete(0, tk.END)
|
||||
self.widget_manager.path_entry.insert(0, self.original_path_text)
|
||||
self.widget_manager.path_entry.unbind("<FocusIn>")
|
||||
|
||||
# Hide search options
|
||||
self.widget_manager.recursive_button.pack_forget()
|
||||
|
||||
# Return to normal file view
|
||||
self.populate_files()
|
||||
|
||||
|
||||
def toggle_recursive_search(self):
|
||||
"""Toggle recursive search on/off and update button style"""
|
||||
@@ -502,17 +512,21 @@ class CustomFileDialog(tk.Toplevel):
|
||||
self._update_view_mode_buttons()
|
||||
self.populate_files()
|
||||
|
||||
def clear_search_placeholder(self, event):
|
||||
"""Clear placeholder text when focus enters search field"""
|
||||
if self.widget_manager.path_entry.get() == "Suchbegriff eingeben...":
|
||||
self.widget_manager.path_entry.delete(0, tk.END)
|
||||
|
||||
|
||||
def execute_search(self, event):
|
||||
"""Execute search when Enter is pressed in search mode"""
|
||||
search_term = self.widget_manager.path_entry.get().strip()
|
||||
if not search_term or search_term == "Suchbegriff eingeben...":
|
||||
def execute_search(self, event=None):
|
||||
if self.dialog_mode == "open":
|
||||
search_term = self.widget_manager.search_entry.get().strip()
|
||||
else:
|
||||
search_term = self.widget_manager.filename_entry.get().strip()
|
||||
|
||||
if not search_term:
|
||||
self.hide_search_bar()
|
||||
return
|
||||
|
||||
self.widget_manager.search_status_label.config(text=f"Suche nach '{search_term}'...")
|
||||
self.update_idletasks()
|
||||
|
||||
# Clear previous search results
|
||||
self.search_results.clear()
|
||||
|
||||
@@ -550,12 +564,12 @@ class CustomFileDialog(tk.Toplevel):
|
||||
os.chdir(search_dir)
|
||||
|
||||
# Build find command based on recursive setting (use . for current directory)
|
||||
if self.widget_manager.recursive_search.get():
|
||||
# Find both files and directories
|
||||
find_cmd = ['find', '.', '-iname', f'*{search_term}*']
|
||||
if self.settings.get("recursive_search", True):
|
||||
# Find both files and directories, following symlinks
|
||||
find_cmd = ['find', '-L', '.', '-iname', f'*{search_term}*']
|
||||
else:
|
||||
# Find both files and directories, but only in the current level
|
||||
find_cmd = ['find', '.', '-maxdepth', '1',
|
||||
# Find both files and directories, but only in the current level, following symlinks
|
||||
find_cmd = ['find', '-L', '.', '-maxdepth', '1',
|
||||
'-iname', f'*{search_term}*']
|
||||
|
||||
result = subprocess.run(
|
||||
@@ -604,7 +618,11 @@ class CustomFileDialog(tk.Toplevel):
|
||||
# Show search results in TreeView
|
||||
if self.search_results:
|
||||
self.show_search_results_treeview()
|
||||
folder_count = sum(1 for p in self.search_results if os.path.isdir(p))
|
||||
file_count = len(self.search_results) - folder_count
|
||||
self.widget_manager.search_status_label.config(text=f"{folder_count} Ordner und {file_count} Dateien gefunden.")
|
||||
else:
|
||||
self.widget_manager.search_status_label.config(text=f"Keine Ergebnisse für '{search_term}'.")
|
||||
MessageDialog(
|
||||
message_type="info",
|
||||
text=f"Keine Dateien mit '{search_term}' gefunden.",
|
||||
@@ -718,11 +736,10 @@ class CustomFileDialog(tk.Toplevel):
|
||||
item = search_tree.item(selection[0])
|
||||
filename = item['text'].strip()
|
||||
directory = item['values'][0]
|
||||
full_path = os.path.join(directory, filename)
|
||||
|
||||
# Select the file and close dialog
|
||||
self.selected_file = full_path
|
||||
self.destroy()
|
||||
|
||||
# Exit search mode and navigate to the file's location
|
||||
self.hide_search_bar()
|
||||
self.navigate_to(directory, file_to_select=filename)
|
||||
|
||||
search_tree.bind("<Double-1>", on_search_double_click)
|
||||
|
||||
@@ -751,7 +768,7 @@ class CustomFileDialog(tk.Toplevel):
|
||||
directory = item['values'][0]
|
||||
|
||||
# Exit search mode and navigate to the directory
|
||||
self.toggle_search_mode() # To restore normal view
|
||||
self.hide_search_bar()
|
||||
self.navigate_to(directory)
|
||||
|
||||
# Select the file in the list
|
||||
@@ -1171,7 +1188,7 @@ class CustomFileDialog(tk.Toplevel):
|
||||
break
|
||||
self.populate_files()
|
||||
|
||||
def navigate_to(self, path):
|
||||
def navigate_to(self, path, file_to_select=None):
|
||||
try:
|
||||
real_path = os.path.realpath(
|
||||
os.path.abspath(os.path.expanduser(path)))
|
||||
@@ -1189,7 +1206,7 @@ class CustomFileDialog(tk.Toplevel):
|
||||
if not self.history or self.history[-1] != self.current_dir:
|
||||
self.history.append(self.current_dir)
|
||||
self.history_pos = len(self.history) - 1
|
||||
self.populate_files()
|
||||
self.populate_files(item_to_select=file_to_select)
|
||||
self.update_nav_buttons()
|
||||
self.update_status_bar()
|
||||
self.update_action_buttons_state()
|
||||
|
||||
Reference in New Issue
Block a user