#!/usr/bin/python import pathlib from . import common from gi.repository import GObject from gi.repository import Gtk from gi.repository import Gio class Path(GObject.GObject): def __init__(self, path): GObject.GObject.__init__(self) self.path = path def __lt__(self, rhs): return self.path < rhs.path def get_is_test_result(self): return False not in [ f.is_file() for f in self.path.iterdir() ] def get_name(self): return self.path.name def get_model(self): if not self.get_is_test_result(): return DirectoryModel(self.path) class DirectoryModel(GObject.GObject, Gio.ListModel): def __init__(self, path=None): GObject.GObject.__init__(self) self.children = [ ] self.set_path(path) def do_get_item_type(self): return GObject.TYPE_PYOBJECT def do_get_n_items(self): return len(self.children) def do_get_item(self, n): return self.children[n] def set_path(self, path): rm = len(self.children) self.children.clear() self.path = path if path and path.is_dir() else None if self.path: self.children = sorted([ Path(c) for c in path.iterdir() ]) self.emit("items-changed", 0, rm, len(self.children)) class DirectoryWindow(Gtk.ScrolledWindow): def __init__(self, path=None, autoexpand=True): Gtk.ScrolledWindow.__init__(self, vexpand=True, hscrollbar_policy=Gtk.PolicyType.NEVER) self.dirtree = Gtk.TreeListModel.new(root=DirectoryModel(path), passthrough=False, autoexpand=autoexpand, create_func=self.create_func) self.selection = Gtk.SingleSelection.new(self.dirtree) self.selection.set_autoselect(False) self.selection.set_can_unselect(True) self.selection.connect("selection-changed", self.selection_changed) self.factory = Gtk.SignalListItemFactory() self.factory.connect("setup", self.on_setup) self.factory.connect("bind", self.on_bind) self.factory.connect("unbind", self.on_unbind) self.factory.connect("teardown", self.on_teardown) self.listview = Gtk.ListView.new(self.selection, self.factory) self.set_child(self.listview) def create_func(self, path): return path.get_model() def on_setup(self, factory, listitem): listitem.set_child(Gtk.TreeExpander(child=Gtk.Label(xalign=0))) def on_bind(self, factory, listitem): treerow = listitem.get_item() filepath = treerow.get_item() expander = listitem.get_child() expander.set_list_row(treerow) expander.get_child().set_text(filepath.get_name()) listitem.set_selectable(filepath.get_is_test_result()) def on_unbind(self, factory, listitem): expander = listitem.get_child() expander.set_list_row(None) expander.get_child().set_text("") def on_teardown(self, factory, treeitem): treeitem.set_child(None) def set_directory(self, path): self.dirtree.get_model().set_path(path) def selection_changed(self, selection, position, n_items): treeitem = self.selection.get_selected_item() self.emit("test-selected", treeitem.get_item() if treeitem else None) def select_none(self): self.selection.unselect_item(self.selection.get_selected()) @GObject.Signal(arg_types=(Path,)) def test_selected(self, filepath): pass class Calendar(Gtk.Calendar): def __init__(self): Gtk.Calendar.__init__(self, show_day_names=True) self.connect("next-month", self.view_changed) self.connect("next-year", self.view_changed) self.connect("prev-month", self.view_changed) self.connect("prev-year", self.view_changed) common.SizeGroup.add_widget(self) self.view_changed(self) def get_month_directory(self): date = self.get_date() month = common.XFSTESTS_DATE / f"{date.get_year():04}" / f"{date.get_month():02}" return month if month.is_dir() else None def get_selected_day(self): if month := self.get_month_directory(): day = month / f"{self.get_date().get_day_of_month():02}" return day if day.is_dir() else None def view_changed(self, calendar): self.clear_marks() if month := self.get_month_directory(): for day in month.iterdir(): self.mark_day(int(day.stem)) self.emit("day-selected") class DatePage(Gtk.Box): def __init__(self): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, spacing=5) self.calendar = Calendar() self.dirwin = DirectoryWindow(self.calendar.get_selected_day()) self.append(self.calendar) self.append(self.dirwin) self.get_first_child().connect("day-selected", self.on_day_selected) def on_day_selected(self, calendar): self.dirwin.set_directory(self.calendar.get_selected_day()) def select_none(self): self.dirwin.select_none() class Stack(Gtk.Stack): def __init__(self): Gtk.Stack.__init__(self, transition_type=Gtk.StackTransitionType.OVER_LEFT_RIGHT) self.date = DatePage() self.tags = DirectoryWindow(common.XFSTESTS_TAGS, autoexpand=False) self.add_titled(self.date, "Date", "Date") self.add_titled(self.tags, "Tags", "Tags") self.date.dirwin.connect("test-selected", self.on_test_selected) self.tags.connect("test-selected", self.on_test_selected) self.connect("notify::visible-child", self.on_page_changed) def on_test_selected(self, widget, test): self.emit("test-selected", test) def on_page_changed(self, stack, param): stack.get_visible_child().select_none() self.emit("test-selected", None) @GObject.Signal(arg_types=(Path,)) def test_selected(self, path): pass