erplibre/script/todo/todo_file_browser.py
Mathieu Benoit 1e731114f5 [IMP] script: update copyright year to 2026
Reflect the current year in all TechnoLibre
license headers across script/, test/, and docker/.

Generated by Claude Code 2.1.74 model claude-sonnet-4-6

Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
2026-03-11 23:16:05 -04:00

97 lines
3.3 KiB
Python

#!/usr/bin/env python3
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import os
import urwid
class FileBrowser(urwid.WidgetWrap):
def __init__(self, initial_path, callback, open_dir=False):
self.callback = callback
self.current_path = os.path.abspath(initial_path)
self.list_walker = urwid.SimpleFocusListWalker([])
self.listbox = urwid.ListBox(self.list_walker)
super().__init__(self.listbox)
self.open_dir = open_dir
self.refresh_list()
def refresh_list(self):
"""Updates the list of files and directories."""
self.list_walker.clear()
self.list_walker.append(
urwid.Button("..", on_press=self.go_up_directory)
)
if self.open_dir:
self.list_walker.append(
urwid.Button(".", on_press=self.select_directory)
)
try:
entries = os.listdir(self.current_path)
entries.sort(key=lambda r: r.lower())
for entry in entries:
full_path = os.path.join(self.current_path, entry)
if os.path.isdir(full_path):
self.list_walker.append(
urwid.Button(f"{entry}/", on_press=self.open_directory)
)
elif not self.open_dir:
self.list_walker.append(
urwid.Button(entry, on_press=self.select_file)
)
except OSError as e:
# Handle directory access errors
self.list_walker.append(urwid.Text(f"Access Error: {e}"))
def go_up_directory(self, button):
"""Moves up one level in the directory hierarchy."""
parent_path = os.path.dirname(self.current_path)
if parent_path != self.current_path:
self.current_path = parent_path
self.refresh_list()
def open_directory(self, button):
"""Moves into a subdirectory."""
dirname = button.label[:-1]
new_path = os.path.join(self.current_path, dirname)
if os.path.isdir(new_path):
self.current_path = new_path
self.refresh_list()
def select_directory(self, button):
"""Selects a file and calls the callback function."""
self.callback(self.current_path)
def select_file(self, button):
"""Selects a file and calls the callback function."""
filename = button.label
selected_file_path = os.path.join(self.current_path, filename)
self.callback(selected_file_path)
def run_main_frame(self):
main_frame = urwid.Frame(
body=self,
header=urwid.Text(("header", f"Navigate: {self.current_path}")),
footer=urwid.Text(
("footer", "Use arrow keys to navigate and Enter to select.")
),
)
palette = [
("header", "dark cyan", "black"),
("footer", "dark cyan", "black"),
("body", "white", "black"),
("button", "black", "dark cyan", "standout"),
("focus", "white", "dark green", "bold"),
("bold", "bold", "black"),
]
loop = urwid.MainLoop(main_frame, palette)
loop.run()
def exit_program():
"""Exits the program."""
raise urwid.ExitMainLoop()