commit 73
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -251,7 +251,9 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
self.widget_manager.path_entry.bind(
|
self.widget_manager.path_entry.bind(
|
||||||
"<Return>", self.handle_path_entry_return)
|
"<Return>", self.handle_path_entry_return)
|
||||||
|
|
||||||
|
# Bind focus events to show the static animation
|
||||||
|
self.widget_manager.path_entry.bind("<FocusIn>", self.show_search_ready)
|
||||||
|
self.widget_manager.filename_entry.bind("<FocusIn>", self.show_search_ready)
|
||||||
|
|
||||||
self.bind("<Key>", self.show_search_bar)
|
self.bind("<Key>", self.show_search_bar)
|
||||||
|
|
||||||
@@ -259,7 +261,10 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
if self.dialog_mode == "save":
|
if self.dialog_mode == "save":
|
||||||
self.bind("<Delete>", self.delete_selected_item)
|
self.bind("<Delete>", self.delete_selected_item)
|
||||||
|
|
||||||
|
def show_search_ready(self, event=None):
|
||||||
|
"""Shows the static 'full circle' to indicate search is ready."""
|
||||||
|
if not self.search_mode:
|
||||||
|
self.widget_manager.search_animation.show_full_circle()
|
||||||
|
|
||||||
def activate_search(self, event=None):
|
def activate_search(self, event=None):
|
||||||
"""Activates the search entry or cancels an ongoing search."""
|
"""Activates the search entry or cancels an ongoing search."""
|
||||||
@@ -271,13 +276,14 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
os.killpg(os.getpgid(self.search_process.pid), 9) # Send SIGKILL to process group
|
os.killpg(os.getpgid(self.search_process.pid), 9) # Send SIGKILL to process group
|
||||||
except (ProcessLookupError, AttributeError):
|
except (ProcessLookupError, AttributeError):
|
||||||
pass # Process might have already finished or not started
|
pass # Process might have already finished or not started
|
||||||
self.widget_manager.search_animation.stop()
|
self.widget_manager.search_animation.stop() # Stop animation, show static frame
|
||||||
self.widget_manager.search_status_label.config(text="Suche abgebrochen.")
|
self.widget_manager.search_status_label.config(text="Suche abgebrochen.")
|
||||||
self.hide_search_bar() # Reset UI after cancellation
|
# Don't hide the search bar, just stop the process
|
||||||
else:
|
else:
|
||||||
# If not animating, activate search entry
|
# If not animating, activate search entry
|
||||||
self.widget_manager.filename_entry.focus_set()
|
self.widget_manager.filename_entry.focus_set()
|
||||||
self.search_mode = True # Ensure search mode is active
|
self.search_mode = True # Ensure search mode is active
|
||||||
|
self.widget_manager.search_animation.show_full_circle()
|
||||||
self.widget_manager.filename_entry.bind("<Return>", self.execute_search)
|
self.widget_manager.filename_entry.bind("<Return>", self.execute_search)
|
||||||
self.widget_manager.filename_entry.bind("<Escape>", self.hide_search_bar)
|
self.widget_manager.filename_entry.bind("<Escape>", self.hide_search_bar)
|
||||||
|
|
||||||
@@ -290,7 +296,7 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
self.widget_manager.filename_entry.insert(0, event.char)
|
self.widget_manager.filename_entry.insert(0, event.char)
|
||||||
self.widget_manager.filename_entry.bind("<Return>", self.execute_search)
|
self.widget_manager.filename_entry.bind("<Return>", self.execute_search)
|
||||||
self.widget_manager.filename_entry.bind("<Escape>", self.hide_search_bar)
|
self.widget_manager.filename_entry.bind("<Escape>", self.hide_search_bar)
|
||||||
# Removed: self.widget_manager.search_animation.start()
|
self.widget_manager.search_animation.show_full_circle()
|
||||||
|
|
||||||
def hide_search_bar(self, event=None):
|
def hide_search_bar(self, event=None):
|
||||||
self.search_mode = False
|
self.search_mode = False
|
||||||
@@ -301,7 +307,7 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
if self.dialog_mode == "save":
|
if self.dialog_mode == "save":
|
||||||
self.widget_manager.filename_entry.bind("<Return>", lambda e: self.on_save())
|
self.widget_manager.filename_entry.bind("<Return>", lambda e: self.on_save())
|
||||||
self.populate_files()
|
self.populate_files()
|
||||||
self.widget_manager.search_animation.stop()
|
self.widget_manager.search_animation.hide()
|
||||||
|
|
||||||
def execute_search(self, event=None):
|
def execute_search(self, event=None):
|
||||||
if self.search_thread and self.search_thread.is_alive():
|
if self.search_thread and self.search_thread.is_alive():
|
||||||
@@ -326,44 +332,59 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
all_files = []
|
all_files = []
|
||||||
|
is_recursive = self.settings.get("recursive_search", True)
|
||||||
for search_dir in search_dirs:
|
for search_dir in search_dirs:
|
||||||
if not (self.search_thread and self.search_thread.is_alive()): break
|
if not (self.search_thread and self.search_thread.is_alive()):
|
||||||
if not os.path.exists(search_dir): continue
|
break
|
||||||
original_cwd = os.getcwd()
|
if not os.path.exists(search_dir):
|
||||||
try:
|
continue
|
||||||
os.chdir(search_dir)
|
|
||||||
cmd = ['find', '-L', '.', '-iname', f'*{search_term}*']
|
|
||||||
if not self.settings.get("recursive_search", True):
|
|
||||||
cmd.insert(3, '-maxdepth')
|
|
||||||
cmd.insert(4, '1')
|
|
||||||
self.search_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, preexec_fn=os.setsid)
|
|
||||||
stdout, _ = self.search_process.communicate()
|
|
||||||
if self.search_process.returncode == 0:
|
|
||||||
all_files.extend([os.path.join(search_dir, f[2:]) for f in stdout.strip().split('\n') if f and f.startswith('./') and os.path.exists(os.path.join(search_dir, f[2:]))])
|
|
||||||
finally:
|
|
||||||
os.chdir(original_cwd)
|
|
||||||
|
|
||||||
if not (self.search_thread and self.search_thread.is_alive()): raise subprocess.SubprocessError("Search cancelled by user")
|
cmd = ['find', '-L', search_dir, '-iname', f'*{search_term}*']
|
||||||
|
if not is_recursive:
|
||||||
|
cmd.insert(3, '-maxdepth')
|
||||||
|
cmd.insert(4, '1')
|
||||||
|
|
||||||
|
self.search_process = subprocess.Popen(
|
||||||
|
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
|
text=True, preexec_fn=os.setsid
|
||||||
|
)
|
||||||
|
stdout, _ = self.search_process.communicate()
|
||||||
|
if self.search_process.returncode == 0:
|
||||||
|
all_files.extend([line for line in stdout.strip().split('\n') if line and os.path.exists(line)])
|
||||||
|
|
||||||
|
if is_recursive:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not (self.search_thread and self.search_thread.is_alive()):
|
||||||
|
raise subprocess.SubprocessError("Search cancelled by user")
|
||||||
|
|
||||||
seen = set()
|
seen = set()
|
||||||
unique_files = [x for x in all_files if not (x in seen or seen.add(x))]
|
unique_files = [x for x in all_files if not (x in seen or seen.add(x))]
|
||||||
search_hidden = self.settings.get("search_hidden_files", False)
|
search_hidden = self.settings.get("search_hidden_files", False)
|
||||||
self.search_results = [p for p in unique_files if (search_hidden or not any(part.startswith('.') for part in p.split(os.sep))) and (self._matches_filetype(os.path.basename(p)) or os.path.isdir(p))]
|
self.search_results = [
|
||||||
|
p for p in unique_files
|
||||||
|
if (search_hidden or not any(part.startswith('.') for part in p.split(os.sep))) and
|
||||||
|
(self._matches_filetype(os.path.basename(p)) or os.path.isdir(p))
|
||||||
|
]
|
||||||
|
|
||||||
def update_ui():
|
def update_ui():
|
||||||
if self.search_results:
|
if self.search_results:
|
||||||
self.show_search_results_treeview()
|
self.show_search_results_treeview()
|
||||||
folder_count = sum(1 for p in self.search_results if os.path.isdir(p))
|
folder_count = sum(1 for p in self.search_results if os.path.isdir(p))
|
||||||
file_count = len(self.search_results) - folder_count
|
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.")
|
self.widget_manager.search_status_label.config(
|
||||||
|
text=f"{folder_count} Ordner und {file_count} Dateien gefunden.")
|
||||||
else:
|
else:
|
||||||
self.widget_manager.search_status_label.config(text=f"Keine Ergebnisse für '{search_term}'.")
|
self.widget_manager.search_status_label.config(
|
||||||
|
text=f"Keine Ergebnisse für '{search_term}'.")
|
||||||
self.after(0, update_ui)
|
self.after(0, update_ui)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if isinstance(e, subprocess.SubprocessError):
|
if isinstance(e, subprocess.SubprocessError):
|
||||||
self.after(0, lambda: self.widget_manager.search_status_label.config(text="Suche abgebrochen."))
|
self.after(0, lambda: self.widget_manager.search_status_label.config(text="Suche abgebrochen."))
|
||||||
else:
|
else:
|
||||||
self.after(0, lambda: MessageDialog(message_type="error", text=f"Fehler bei der Suche: {e}", title="Suchfehler", master=self).show())
|
self.after(0, lambda: MessageDialog(
|
||||||
|
message_type="error", text=f"Fehler bei der Suche: {e}", title="Suchfehler", master=self).show())
|
||||||
finally:
|
finally:
|
||||||
self.after(0, self.widget_manager.search_animation.stop)
|
self.after(0, self.widget_manager.search_animation.stop)
|
||||||
self.search_process = None
|
self.search_process = None
|
||||||
@@ -371,7 +392,7 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
def handle_path_entry_return(self, event):
|
def handle_path_entry_return(self, event):
|
||||||
"""Handles the Enter key in the path entry to navigate.
|
"""Handles the Enter key in the path entry to navigate.
|
||||||
Search is handled by on_path_entry_key_release.
|
Search is handled by on_path_entry_key_release.
|
||||||
"""
|
"""
|
||||||
path_text = self.widget_manager.path_entry.get().strip()
|
path_text = self.widget_manager.path_entry.get().strip()
|
||||||
potential_path = os.path.realpath(os.path.expanduser(path_text))
|
potential_path = os.path.realpath(os.path.expanduser(path_text))
|
||||||
|
|
||||||
@@ -1195,6 +1216,9 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
if not self.history or self.history[-1] != self.current_dir:
|
if not self.history or self.history[-1] != self.current_dir:
|
||||||
self.history.append(self.current_dir)
|
self.history.append(self.current_dir)
|
||||||
self.history_pos = len(self.history) - 1
|
self.history_pos = len(self.history) - 1
|
||||||
|
|
||||||
|
self.widget_manager.search_animation.hide() # Hide animation on navigation
|
||||||
|
|
||||||
self.populate_files(item_to_select=file_to_select)
|
self.populate_files(item_to_select=file_to_select)
|
||||||
self.update_nav_buttons()
|
self.update_nav_buttons()
|
||||||
self.update_status_bar()
|
self.update_status_bar()
|
||||||
@@ -1579,4 +1603,4 @@ class CustomFileDialog(tk.Toplevel):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting mounted devices: {e}")
|
print(f"Error getting mounted devices: {e}")
|
||||||
return devices
|
return devices
|
||||||
|
|||||||
Reference in New Issue
Block a user