From: Christian Heller Date: Fri, 23 Aug 2024 22:38:16 +0000 (+0200) Subject: To browser, add file selection panel. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/cards?a=commitdiff_plain;h=9e37a09c126fe73945597e659b7e08a5444673f9;p=stable_plom To browser, add file selection panel. --- diff --git a/browser.py b/browser.py index c2ab5b8..d6925f6 100755 --- a/browser.py +++ b/browser.py @@ -1,90 +1,118 @@ #!/usr/bin/env python3 -from os import scandir -from os.path import splitext from exiftool import ExifToolHelper # type: ignore import gi # type: ignore gi.require_version('Gtk', '4.0') +gi.require_version('Gio', '2.0') # pylint: disable=wrong-import-position -from gi.repository import Gtk # type: ignore # noqa: E402 +from gi.repository import Gtk, Gio, GObject # type: ignore # noqa: E402 from stable.gen_params import GenParams # noqa: E402 +class FileItem(GObject.GObject): + + def __init__(self, name, last_mod): + super().__init__() + self.name = name + self.last_mod = last_mod + self._metadata = None + + @property + def metadata(self): + if not self._metadata: + with ExifToolHelper() as et: + for d in et.get_tags([self.name], ['Comment']): + for k, v in d.items(): + if k.endswith('Comment'): + self._metadata = '' + gen_params = GenParams.from_str(v) + for k, v_ in gen_params.as_dict.items(): + self._metadata += f'\n{k}: {v_}' + if not self._metadata: + self._metadata = 'no SD comment' + return self._metadata + + class Window(Gtk.ApplicationWindow): def __init__(self, **kwargs): super().__init__(**kwargs) box_buttons = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - btn_close = Gtk.Button(label='close') - btn_close.connect('clicked', lambda _: self.close()) - box_buttons.append(btn_close) - btn = Gtk.Button(label='oldest') - btn.connect('clicked', self.oldest) - box_buttons.append(btn) - btn = Gtk.Button(label='older') - btn.connect('clicked', self.older) - box_buttons.append(btn) - btn = Gtk.Button(label='newer') - btn.connect('clicked', self.newer) - box_buttons.append(btn) - btn = Gtk.Button(label='newest') - btn.connect('clicked', self.newest) - box_buttons.append(btn) + for args in (('oldest', lambda _: self.move_selection(None, 0)), + ('older', lambda _: self.move_selection(-1, None)), + ('newer', lambda _: self.move_selection(1, None)), + ('newest', lambda _: self.move_selection(None, -1))): + btn = Gtk.Button(label=args[0]) + btn.connect('clicked', args[1]) + box_buttons.append(btn) self.metadata = Gtk.Label() self.label_nothing_to_show = Gtk.Label(label='nothing to show') - self.box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) - self.box_outer.append(box_buttons) - self.box_outer.append(self.metadata) - self.box_outer.append(self.label_nothing_to_show) - self.props.child = self.box_outer - - self.entries = [] - self.current_index = -1 - self.newest(None) - - def _reload(self, set_max=False): - self.entries = [e for e in scandir('.') - if e.is_file() - and splitext(e)[1] in {'.png', '.jpg', '.jpeg'}] - self.entries.sort(key=lambda e: e.stat().st_mtime) - if set_max or self.current_index + 1 > len(self.entries): - self.current_index = len(self.entries) - 1 - self.box_outer.remove(self.box_outer.get_last_child()) - if self.current_index >= 0: - path = self.entries[self.current_index].path - metadata = 'no SD comment' - with ExifToolHelper() as et: - for d in et.get_tags([path], ['Comment']): - for k, v in d.items(): - if k.endswith('Comment'): - metadata = '' - gen_params = GenParams.from_str(v) - for k, v_ in gen_params.as_dict.items(): - metadata += f'\n{k}: {v_}' - self.metadata.props.label = f'{path}: {metadata}' - pic = Gtk.Picture.new_for_filename(path) - self.box_outer.append(pic) + self.viewer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) + self.viewer.append(box_buttons) + self.viewer.append(self.metadata) + self.viewer.append(self.label_nothing_to_show) + + self.dir = Gio.File.new_for_path('.') + self.list_store = Gio.ListStore(item_type=FileItem) + self.selection = Gtk.SingleSelection.new(self.list_store) + factory = Gtk.SignalListItemFactory() + self.selector = Gtk.ListView(model=self.selection, factory=factory) + + box_outer = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) + box_outer.append(self.selector) + box_outer.append(self.viewer) + self.props.child = box_outer + + self.max_index = 0 + self.item = None + self.selection.connect('selection-changed', self.update_selected) + factory.connect('setup', + lambda _, i: i.set_child(Gtk.Label())) + factory.connect('bind', + lambda _, i: i.props.child.set_text(i.props.item.name)) + query_attrs = 'standard::name,standard::content-type,time::*' + enumerator = self.dir.enumerate_children( + query_attrs, Gio.FileQueryInfoFlags.NONE, None) + to_sort = [] + for info in [info for info in enumerator + if info.get_content_type().startswith('image/')]: + item = FileItem(info.get_name(), + info.get_modification_date_time().format_iso8601()) + to_sort += [item] + to_sort.sort(key=lambda i: i.last_mod) + for file_item in to_sort: + self.list_store.append(file_item) + self.max_index = len(self.list_store) - 1 + self.update_selected() + + def update_selected(self, *_args): + self.item = self.selection.props.selected_item + self.reload() + self.selector.scroll_to(self.selection.props.selected, + Gtk.ListScrollFlags.NONE, None) + + def reload(self): + self.viewer.remove(self.viewer.get_last_child()) + if self.item: + metadata = f'{self.item.name}: {self.item.metadata}' + self.metadata.props.label = metadata + pic = Gtk.Picture.new_for_filename(self.item.name) + self.viewer.append(pic) else: self.metadata.props.label = None - self.box_outer.append(self.label_nothing_to_show) - - def oldest(self, _widget): - self.current_index = 0 - self._reload() - - def older(self, _widget): - if self.current_index > 0: - self.current_index -= 1 - self._reload() - - def newer(self, _widget): - self.current_index += 1 - self._reload() - - def newest(self, _widget): - self._reload(set_max=True) + self.viewer.append(self.label_nothing_to_show) + + def move_selection(self, increment, absolute_position): + cur_index = self.selection.props.selected + if 0 == absolute_position: + self.selection.props.selected = 0 + elif -1 == absolute_position: + self.selection.props.selected = self.max_index + elif (1 == increment and cur_index < self.max_index)\ + or (-1 == increment and cur_index > 0): + self.selection.props.selected = cur_index + increment def on_activate(app_):