From 11941c3bd3719571424efbfdfb5ca82d26784442 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Fri, 3 Nov 2023 17:08:33 -0400 Subject: [PATCH] gtk: Add a TagList listmodel This includes a treemodel property that is intended to be set on a listview to show our tag tree. Signed-off-by: Anna Schumaker --- tests/gtk/test_tree.py | 61 ++++++++++++++++++++++++++++++++++++++++++ xfstestsdb/gtk/tree.py | 42 +++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/tests/gtk/test_tree.py b/tests/gtk/test_tree.py index 09a4536..b5d630b 100644 --- a/tests/gtk/test_tree.py +++ b/tests/gtk/test_tree.py @@ -267,3 +267,64 @@ class TestTagDeviceList(unittest.TestCase): then = now - datetime.timedelta(seconds=42) self.tag.add_run(2, "/dev/vda2", then) self.assertEqual(self.tag.get_earliest_run().runid, 2) + + +class TestTagList(unittest.TestCase): + """Test case for our TagList ListModel.""" + + def setUp(self): + """Set up common variables.""" + self.xfstestsdb = xfstestsdb.Command() + with unittest.mock.patch("sys.stdout"): + self.xfstestsdb.run(["new", "/dev/vda2"]) + self.xfstestsdb.run(["new", "/dev/vda1"]) + self.xfstestsdb.run(["new", "/dev/vda1"]) + self.xfstestsdb.run(["new", "/dev/vda3"]) + + self.xfstestsdb.run(["tag", "1", "mytag2"]) + self.xfstestsdb.run(["tag", "2", "mytag2"]) + self.xfstestsdb.run(["tag", "4", "mytag1"]) + + self.taglist = xfstestsdb.gtk.tree.TagList(self.xfstestsdb.sql) + + def test_init(self): + """Test that the TagList was set up properly.""" + self.assertIsInstance(self.taglist, GObject.GObject) + self.assertIsInstance(self.taglist, Gio.ListModel) + + def test_get_item_type(self): + """Test the get_item_type() function.""" + self.assertEqual(self.taglist.get_item_type(), + xfstestsdb.gtk.tree.TagDeviceList.__gtype__) + + def test_get_n_items(self): + """Test the get_n_items() function.""" + self.assertEqual(self.taglist.get_n_items(), 2) + self.assertEqual(self.taglist.n_items, 2) + + def test_get_item(self): + """Test the get_item() function.""" + self.assertIsInstance(self.taglist.get_item(0), + xfstestsdb.gtk.tree.TagDeviceList) + self.assertIsInstance(self.taglist[0][0][0].timestamp, + datetime.datetime) + self.assertEqual(self.taglist.get_item(0).name, "mytag1") + self.assertEqual(self.taglist.get_item(1).name, "mytag2") + + def test_treemodel(self): + """Test the treemodel property.""" + self.assertIsInstance(self.taglist.treemodel, Gtk.TreeListModel) + self.assertFalse(self.taglist.treemodel.props.passthrough) + self.assertFalse(self.taglist.treemodel.props.autoexpand) + + tree = self.taglist.treemodel + self.assertEqual(tree[0].get_item().name, "mytag1") + tree[0].set_expanded(True) + self.assertEqual(tree[1].get_item().name, "/dev/vda3") + tree[1].set_expanded(True) + self.assertEqual(tree[2].get_item().runid, 4) + + self.assertEqual(tree[3].get_item().name, "mytag2") + tree[3].set_expanded(True) + self.assertEqual(tree[4].get_item().name, "/dev/vda1") + self.assertEqual(tree[5].get_item().name, "/dev/vda2") diff --git a/xfstestsdb/gtk/tree.py b/xfstestsdb/gtk/tree.py index 6c537f9..5494a57 100644 --- a/xfstestsdb/gtk/tree.py +++ b/xfstestsdb/gtk/tree.py @@ -180,3 +180,45 @@ class TagDeviceList(GObject.GObject, Gio.ListModel): """Get the earliest run added to the tag.""" runs = [d.get_earliest_run() for d in self.__devices] return min(runs, default=None) + + +class TagList(GObject.GObject, Gio.ListModel): + """A list containing all tagged xfstests runs.""" + + n_items = GObject.Property(type=int) + treemodel = GObject.Property(type=Gtk.TreeListModel) + + def __init__(self, sql: sqlite.Connection) -> None: + """Initialize our TagList.""" + super().__init__() + + tags = {} + for row in sql("""SELECT DISTINCT runid, device, timestamp, tag + FROM tagged_runs WHERE tag IS NOT NULL""").fetchall(): + if (tag := tags.get(row['tag'])) is None: + tags[row['tag']] = tag = TagDeviceList(row['tag']) + ts = datetime.datetime.fromisoformat(row['timestamp']) + tag.add_run(row['runid'], row['device'], ts) + + self.__items = sorted(tags.values()) + self.n_items = len(self.__items) + self.treemodel = Gtk.TreeListModel.new(root=self, passthrough=False, + autoexpand=False, + create_func=self.__create_func) + + def __create_func(self, item: GObject.GObject) -> Gio.ListModel: + if isinstance(item, TagDeviceList | DeviceRunsList): + return item + return None + + def do_get_item_type(self) -> GObject.GType: + """Get the type of objects in the list.""" + return TagDeviceList.__gtype__ + + def do_get_n_items(self) -> int: + """Get the number of items in the list.""" + return self.n_items + + def do_get_item(self, n: int) -> TagDeviceList: + """Get a specific item in the list.""" + return self.__items[n]