local_file_picker.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import platform
  2. from pathlib import Path
  3. from typing import Optional
  4. from nicegui import events, ui
  5. class local_file_picker(ui.dialog):
  6. def __init__(self, directory: str, *,
  7. upper_limit: Optional[str] = ..., multiple: bool = False, show_hidden_files: bool = False) -> None:
  8. """Local File Picker
  9. This is a simple file picker that allows you to select a file from the local filesystem where NiceGUI is running.
  10. :param directory: The directory to start in.
  11. :param upper_limit: The directory to stop at (None: no limit, default: same as the starting directory).
  12. :param multiple: Whether to allow multiple files to be selected.
  13. :param show_hidden_files: Whether to show hidden files.
  14. """
  15. super().__init__()
  16. self.path = Path(directory).expanduser()
  17. if upper_limit is None:
  18. self.upper_limit = None
  19. else:
  20. self.upper_limit = Path(directory if upper_limit == ... else upper_limit).expanduser()
  21. self.show_hidden_files = show_hidden_files
  22. with self, ui.card():
  23. self.add_drives_toggle()
  24. self.grid = ui.aggrid({
  25. 'columnDefs': [{'field': 'name', 'headerName': 'File'}],
  26. 'rowSelection': 'multiple' if multiple else 'single',
  27. }, html_columns=[0]).classes('w-96').on('cellDoubleClicked', self.handle_double_click)
  28. with ui.row().classes('w-full justify-end'):
  29. ui.button('Cancel', on_click=self.close).props('outline')
  30. ui.button('Ok', on_click=self._handle_ok)
  31. self.update_grid()
  32. def add_drives_toggle(self):
  33. if platform.system() == 'Windows':
  34. import win32api
  35. drives = win32api.GetLogicalDriveStrings().split('\000')[:-1]
  36. self.drives_toggle = ui.toggle(drives, value=drives[0], on_change=self.update_drive)
  37. def update_drive(self):
  38. self.path = Path(self.drives_toggle.value).expanduser()
  39. self.update_grid()
  40. def update_grid(self) -> None:
  41. paths = list(self.path.glob('*'))
  42. if not self.show_hidden_files:
  43. paths = [p for p in paths if not p.name.startswith('.')]
  44. paths.sort(key=lambda p: p.name.lower())
  45. paths.sort(key=lambda p: not p.is_dir())
  46. self.grid.options['rowData'] = [
  47. {
  48. 'name': f'📁 <strong>{p.name}</strong>' if p.is_dir() else p.name,
  49. 'path': str(p),
  50. }
  51. for p in paths
  52. ]
  53. if (self.upper_limit is None and self.path != self.path.parent) or \
  54. (self.upper_limit is not None and self.path != self.upper_limit):
  55. self.grid.options['rowData'].insert(0, {
  56. 'name': '📁 <strong>..</strong>',
  57. 'path': str(self.path.parent),
  58. })
  59. self.grid.update()
  60. def handle_double_click(self, e: events.GenericEventArguments) -> None:
  61. self.path = Path(e.args['data']['path'])
  62. if self.path.is_dir():
  63. self.update_grid()
  64. else:
  65. self.submit([str(self.path)])
  66. async def _handle_ok(self):
  67. rows = await self.grid.get_selected_rows()
  68. self.submit([r['path'] for r in rows])