From f84301e1dcc9ca1cc808d54c23ced8b659612241 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Thu, 12 Sep 2024 23:57:31 +0200 Subject: [PATCH] browser.py: Refactor sorters code. --- browser.py | 134 ++++++++++++++++++++++++++++------------------------- 1 file changed, 71 insertions(+), 63 deletions(-) diff --git a/browser.py b/browser.py index 7849f6b..1f25d2d 100755 --- a/browser.py +++ b/browser.py @@ -33,13 +33,30 @@ CSS = """ """ -class SortLabelItem(GObject.GObject): - """Sort order list representation of sorter label.""" +class Sorter(GObject.GObject): + """Sort order box representation of sorting attribute.""" + list_item: Gtk.Box def __init__(self, name): super().__init__() self.name = name + def set_label(self, gallery_store, gallery_store_filtered): + """Set .list_item's label to .name and n of different values for it.""" + diversities = [0, 0] + for i, store in enumerate([gallery_store_filtered, gallery_store]): + values = set() + for j in range(store.get_n_items()): + item = store.get_item(j) + if isinstance(item, ImgItem): + val = None + if hasattr(item, self.name): + val = getattr(item, self.name) + values.add(val) + diversities[i] = len(values) + label = f'{self.name} ({diversities[0]}/{diversities[1]}) ' + self.list_item.get_first_child().set_text(label) + class FileItem(GObject.GObject): """Gallery representation of filesystem entry, base to DirItem, ImgItem.""" @@ -109,7 +126,6 @@ class MainWindow(Gtk.Window): filter_inputs = dict button_activate_sort: Gtk.Button counter: Gtk.Label - sort_attribute_diversities: dict def __init__(self, app, **kwargs): super().__init__(**kwargs) @@ -166,52 +182,39 @@ class MainWindow(Gtk.Window): return metadata_box def init_sorter_and_filterer(): - self.sort_order = [p.lower() for p in GEN_PARAMS] - self.sort_order += ['bookmarked'] - new_sort_order = [] - do_reverse = '-' in self.app.suggested_sort_order - for pattern in self.app.suggested_sort_order: - for name in [n for n in self.sort_order - if n.startswith(pattern)]: - self.sort_order.remove(name) - new_sort_order += [name] - self.sort_order = new_sort_order + self.sort_order - if do_reverse: - self.sort_order.reverse() - self.sort_store = Gio.ListStore(item_type=SortLabelItem) + self.sort_store = Gio.ListStore(item_type=Sorter) self.sort_selection = Gtk.SingleSelection.new(self.sort_store) self.sort_selection.connect( 'selection-changed', - lambda a, b, c: self.sort_selection.props.selected_item.box - .props.child.get_parent().grab_focus()) + lambda a, b, c: self.sort_selection.props.selected_item. + list_item.get_parent().grab_focus()) factory = Gtk.SignalListItemFactory() - def setup_sort_order_item(_, item): + def setup_sort_order_item(_, list_item): box = Gtk.Box(orientation=OR_H) box.append(Gtk.Label(hexpand=True)) box.append(Gtk.Entry.new()) box.get_last_child().props.placeholder_text = 'filter?' - item.set_child(box) + list_item.set_child(box) - def bind_sort_order_item(_, item): + def bind_sort_order_item(_, list_item): def on_filter_enter(entry): entry.remove_css_class('temp') text = entry.get_buffer().get_text() if '' != text.rstrip(): - self.filter_inputs[item.props.item.name] = text - elif item.props.item.name in self.filter_inputs: - del self.filter_inputs[item.props.item.name] + self.filter_inputs[sorter.name] = text + elif sorter.name in self.filter_inputs: + del self.filter_inputs[sorter.name] self.update_gallery() - item.props.item.box = item - sorter_name = item.props.item.name - diversity = self.sort_attribute_diversities.get(sorter_name, 0) - label = f'{sorter_name} ({diversity}) ' - item.props.item.filterer = item.props.child.get_last_child() - item.props.child.get_first_child().set_text(label) - filter_entry = item.props.child.get_last_child() - filter_text = self.filter_inputs.get(item.props.item.name, '') + sorter = list_item.props.item + sorter.list_item = list_item.props.child + sorter.set_label(self.gallery_store, + self.gallery_store_filtered) + sorter.filterer = sorter.list_item.get_last_child() + filter_entry = sorter.list_item.get_last_child() + filter_text = self.filter_inputs.get(sorter.name, '') filter_buffer = filter_entry.get_buffer() filter_buffer.set_text(filter_text, -1) filter_entry.connect('activate', on_filter_enter) @@ -234,7 +237,6 @@ class MainWindow(Gtk.Window): 'clicked', lambda _: self.activate_sort_order()) sort_box.append(self.button_activate_sort) self.filter_inputs = {} - self.sort_attribute_diversities = {} return sort_box def init_gallery_content(): @@ -325,7 +327,7 @@ class MainWindow(Gtk.Window): json_dump(list(bookmarks), f) self.update_file_selection() self.update_gallery_view() - self.update_sort_order_box(self.sort_order) + self.update_sort_order_box() def update_gallery(self, suggested_selection=None): """Build gallery based on .per_row and .gallery_selection.""" @@ -344,7 +346,7 @@ class MainWindow(Gtk.Window): return +1 # apply self.sort_order within DirItems and FileItems (separately) ret = 0 - for key in self.sort_order: + for key in [sorter.name for sorter in self.app.sort_order]: a_cmp = None b_cmp = None if hasattr(a, key): @@ -395,7 +397,7 @@ class MainWindow(Gtk.Window): to_select.activate() else: self.counter.set_text(' (nothing) ') - self.update_sort_order_box(self.sort_order) + self.update_sort_order_box() self.update_gallery_view() def update_gallery_view(self, refocus=False): @@ -493,33 +495,21 @@ class MainWindow(Gtk.Window): total = self.gallery_selection.get_n_items() self.counter.set_text(f' {idx} of {total} ') - def update_sort_order_box(self, sort_order_source, cur_selection=0): - """Rebuild .sort_store from .sort_order, update diversity counts.""" - values = {} - for k in sort_order_source: - values[k] = set() - for i in range(self.gallery_store_filtered.get_n_items()): - item = self.gallery.get_child_at_index(i).props.child.item - if isinstance(item, ImgItem): - for attr_name in values: - val = None - if hasattr(item, attr_name): - val = getattr(item, attr_name) - values[attr_name].add(val) - for attr_name in values: - self.sort_attribute_diversities[attr_name] = len(values[attr_name]) + def update_sort_order_box(self, alt_order=None, cur_selection=0): + """Rebuild .sort_store from .sort_order or alt_order.""" + sort_order = alt_order if alt_order else self.app.sort_order self.sort_store.remove_all() - for s in sort_order_source: - self.sort_store.append(SortLabelItem(s)) + for sorter in sort_order: + self.sort_store.append(sorter) self.sort_selection.props.selected = cur_selection def activate_sort_order(self): - """Write sort order box order into self.sort_order, mark finalized.""" - self.sort_order = [] + """Write sort order box order into .app.sort_order, mark finalized.""" + self.app.sort_order = [] for i in range(self.sort_store.get_n_items()): - sort_item = self.sort_store.get_item(i) - sort_item.box.props.child.remove_css_class('temp') - self.sort_order += [sort_item.name] + sorter = self.sort_store.get_item(i) + sorter.list_item.remove_css_class('temp') + self.app.sort_order += [sorter] self.button_activate_sort.props.sensitive = False old_selection = self.gallery_selection.props.selected_item self.update_gallery(old_selection) @@ -680,7 +670,7 @@ class MainWindow(Gtk.Window): """Move selected item in sort order view, ensure temporary state.""" tmp_sort_order = [] for i in range(self.sort_store.get_n_items()): - tmp_sort_order += [self.sort_store.get_item(i).name] + tmp_sort_order += [self.sort_store.get_item(i)] cur_idx = self.sort_selection.props.selected selected = tmp_sort_order[cur_idx] if direction == -1 and cur_idx > 0: @@ -699,12 +689,12 @@ class MainWindow(Gtk.Window): self.sort_selection.props.selected = cur_idx + direction for i in range(self.sort_store.get_n_items()): sort_item = self.sort_store.get_item(i) - sort_item.box.props.child.add_css_class('temp') + sort_item.list_item.add_css_class('temp') self.button_activate_sort.props.sensitive = True def move_selection_in_sort_order(self, direction): """Move sort order selection by direction (-1 or +1).""" - min_idx, max_idx = 0, len(self.sort_order) - 1 + min_idx, max_idx = 0, len(self.app.sort_order) - 1 cur_idx = self.sort_selection.props.selected if (1 == direction and cur_idx < max_idx)\ or (-1 == direction and cur_idx > min_idx): @@ -765,11 +755,29 @@ class MainWindow(Gtk.Window): class Application(Gtk.Application): """Image browser application class.""" img_dir_absolute: str - suggested_sort_order: list[str] + sort_order: list[Sorter] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + def _build_sort_order(self, suggestion_fused): + suggestion = suggestion_fused.split(',') + names = [p.lower() for p in GEN_PARAMS] + ['bookmarked'] + sort_order = [] + for name in names: + sort_order += [Sorter(name)] + new_sort_order = [] + do_reverse = '-' in suggestion + for pattern in suggestion: + for sorter in [sorter for sorter in sort_order + if sorter.name.startswith(pattern)]: + sort_order.remove(sorter) + new_sort_order += [sorter] + sort_order = new_sort_order + sort_order + if do_reverse: + sort_order.reverse() + return sort_order + def do_activate(self, *args, **kwargs): """Parse arguments, start window, and keep it open.""" parser = ArgumentParser() @@ -777,7 +785,7 @@ class Application(Gtk.Application): parser.add_argument('-s', '--sort-order', default=SORT_DEFAULT) opts = parser.parse_args() self.img_dir_absolute = abspath(opts.directory) - self.suggested_sort_order = opts.sort_order.split(',') + self.sort_order = self._build_sort_order(opts.sort_order) win = MainWindow(self) win.present() self.hold() -- 2.30.2