xfstestsdb/xfstestsdb/gtk/sidebar.py

132 lines
5.0 KiB
Python

# Copyright 2023 (c) Anna Schumaker.
"""Our sidebar for selecting a specific xfstests run to view."""
import datetime
import typing
from gi.repository import GObject
from gi.repository import Gio
from gi.repository import Gtk
from .. import sqlite
from . import row
from . import tree
class RunidView(Gtk.ScrolledWindow):
"""Our RunidView class."""
runid = GObject.Property(type=int)
model = GObject.Property(type=Gio.ListModel)
def __init__(self, model: tree.DateDeviceList) -> None:
"""Initialize a RunidView instance."""
super().__init__(model=model, vexpand=True)
self._selection = Gtk.SingleSelection(model=model.treemodel)
self._view = Gtk.ListView(model=self._selection,
factory=row.SidebarFactory(),
single_click_activate=True)
self._view.connect("activate", self.__activate)
self.connect("notify::model", self.__notify_model)
self._view.add_css_class("navigation-sidebar")
self._view.add_css_class("background")
self.set_child(self._view)
def __activate(self, view: Gtk.ListView, position: int) -> None:
treeitem = self._selection[position]
item = treeitem.get_item()
if isinstance(item, tree.XfstestsRun):
self.runid = item.runid
elif treeitem.props.expanded:
treeitem.props.expanded = False
else:
treeitem.props.expanded = True
self.runid = item.get_earliest_run().runid
def __notify_model(self, sidebar: typing.Self,
param: GObject.ParamSpec) -> None:
model = None if self.model is None else self.model.treemodel
self._selection.props.model = model
class CalendarView(Gtk.Box):
"""Our calendar view for seleting an xfstests run by date."""
runid = GObject.Property(type=int)
sql = GObject.Property(type=GObject.TYPE_PYOBJECT)
def __init__(self, sql: sqlite.Connection) -> None:
"""Initialize a CalendarView instance."""
super().__init__(sql=sql, spacing=6,
orientation=Gtk.Orientation.VERTICAL)
today = datetime.date.today()
self._calendar = Gtk.Calendar()
self._view = RunidView(model=tree.DateDeviceList(sql, today))
self._view.bind_property("runid", self, "runid")
self._calendar.connect("day-selected", self.__day_selected)
self._calendar.connect("next-month", self.__date_changed)
self._calendar.connect("next-year", self.__date_changed)
self._calendar.connect("prev-month", self.__date_changed)
self._calendar.connect("prev-year", self.__date_changed)
self.__mark_days(today)
self.append(self._calendar)
self.append(self._view)
def __day_selected(self, calendar: Gtk.Calendar) -> None:
self.__select_day(datetime.date(*calendar.get_date().get_ymd()))
def __date_changed(self, calendar: Gtk.Calendar) -> None:
date = datetime.date(*calendar.get_date().get_ymd())
self.__mark_days(date)
self.__select_day(date)
def __select_day(self, date: datetime.date) -> None:
self._view.model = tree.DateDeviceList(self.sql, date)
def __mark_days(self, date: datetime.date) -> None:
min = datetime.datetime.combine(date.replace(day=1), datetime.time())
max = (min + datetime.timedelta(days=40)).replace(day=1)
self._calendar.clear_marks()
for stamp in self.sql("""SELECT DISTINCT timestamp FROM tagged_runs
WHERE timestamp >= ? AND timestamp < ?""",
min, max).fetchall():
ts = datetime.datetime.fromisoformat(stamp['timestamp'])
self._calendar.mark_day(ts.day)
class Sidebar(Gtk.Box):
"""Our sidebar for seleting an xfstests run."""
runid = GObject.Property(type=int)
sql = GObject.Property(type=GObject.TYPE_PYOBJECT)
def __init__(self, sql: sqlite.Connection) -> None:
"""Initialize a CalendarView instance."""
animation = Gtk.StackTransitionType.OVER_LEFT_RIGHT
super().__init__(sql=sql, orientation=Gtk.Orientation.VERTICAL)
self._stack = Gtk.Stack(transition_type=animation)
self._switcher = Gtk.StackSwitcher(stack=self._stack,
margin_top=6, margin_bottom=6,
margin_start=80, margin_end=80)
self._calendar = CalendarView(sql)
self._tags = RunidView(model=tree.TagList(sql))
self._calendar.bind_property("runid", self, "runid")
self._tags.bind_property("runid", self, "runid")
self.__add_page(self._calendar, "Calendar", "month-symbolic")
self.__add_page(self._tags, "Tags", "tag-symbolic")
self._switcher.add_css_class("large-icons")
self.append(self._switcher)
self.append(Gtk.Separator())
self.append(self._stack)
def __add_page(self, page: Gtk.Widget, title: str, icon: str) -> None:
pg = self._stack.add_titled(page, title.lower(), title)
pg.set_icon_name(icon)