Use ListModel for faster directory traversal

This commit is contained in:
Jan Hamal Dvořák 2025-03-09 13:25:14 +01:00
parent c54f183b0a
commit 2fb5265463
2 changed files with 55 additions and 16 deletions

View file

@ -7,20 +7,20 @@ from typing import Any, cast
import gi import gi
from .file_model import FileItem, FileType from .file_model import FileItem, FileListModel, FileType
gi.require_version("Gdk", "4.0") gi.require_version("Gdk", "4.0")
gi.require_version("Gtk", "4.0") gi.require_version("Gtk", "4.0")
gi.require_version("Gst", "1.0") gi.require_version("Gst", "1.0")
gi.require_version("Pango", "1.0") gi.require_version("Pango", "1.0")
from gi.repository import Gdk, Gio, Gst, Gtk, Pango # NOQA: E402 from gi.repository import Gdk, Gst, Gtk, Pango # NOQA: E402
class MainWindow(Gtk.ApplicationWindow): class MainWindow(Gtk.ApplicationWindow):
file_info_label: Gtk.Label file_info_label: Gtk.Label
stack: Gtk.Stack stack: Gtk.Stack
list_view: Gtk.ListView list_view: Gtk.ListView
list_store: Gio.ListStore list_model: FileListModel
selection_model: Gtk.SingleSelection selection_model: Gtk.SingleSelection
video_widget: Gtk.Picture video_widget: Gtk.Picture
pipeline: Gst.Pipeline pipeline: Gst.Pipeline
@ -137,10 +137,10 @@ class MainWindow(Gtk.ApplicationWindow):
main_box.append(grid) main_box.append(grid)
# Create list store and view # Create list model and view
self.list_store = Gio.ListStore(item_type=FileItem) self.list_model = FileListModel()
self.list_view = Gtk.ListView() self.list_view = Gtk.ListView()
self.selection_model = Gtk.SingleSelection.new(self.list_store) self.selection_model = Gtk.SingleSelection.new(self.list_model)
self.selection_model.connect("selection-changed", self._on_selection_changed) self.selection_model.connect("selection-changed", self._on_selection_changed)
self.list_view.set_model(self.selection_model) self.list_view.set_model(self.selection_model)
self.list_view.set_vexpand(True) self.list_view.set_vexpand(True)
@ -285,8 +285,8 @@ class MainWindow(Gtk.ApplicationWindow):
self._populate_file_list() self._populate_file_list()
# Find and select the directory we came from # Find and select the directory we came from
for i in range(self.list_store.get_n_items()): for i in range(self.list_model.get_n_items()):
item = self.list_store.get_item(i) item = self.list_model.get_item(i)
if not item: if not item:
continue continue
@ -392,7 +392,7 @@ class MainWindow(Gtk.ApplicationWindow):
file_item.save_attribute("position", duration) file_item.save_attribute("position", duration)
# Force the list to update the changed item # Force the list to update the changed item
self.list_store.items_changed(self.selection_model.get_selected(), 1, 1) self.list_model.items_changed(self.selection_model.get_selected(), 1, 1)
def _on_menu_key_pressed( def _on_menu_key_pressed(
self, self,
@ -551,11 +551,7 @@ class MainWindow(Gtk.ApplicationWindow):
# Sort directories first, then files, both alphabetically # Sort directories first, then files, both alphabetically
items.sort(key=lambda x: (x.file_type != FileType.DIRECTORY, x.name.lower())) items.sort(key=lambda x: (x.file_type != FileType.DIRECTORY, x.name.lower()))
while self.list_store.get_n_items(): self.list_model.set_items(items)
self.list_store.remove(0)
for item in items:
self.list_store.append(item)
if items: if items:
self.file_info_label.set_text(items[0].name) self.file_info_label.set_text(items[0].name)

View file

@ -3,12 +3,12 @@ from __future__ import annotations
import os import os
from enum import Enum, auto from enum import Enum, auto
from pathlib import Path from pathlib import Path
from typing import overload from typing import Optional, overload
import gi import gi
gi.require_version("GObject", "2.0") gi.require_version("GObject", "2.0")
from gi.repository import GObject # NOQA: E402 from gi.repository import Gio, GObject # NOQA: E402
class FileType(Enum): class FileType(Enum):
@ -54,3 +54,46 @@ class FileItem(GObject.Object):
pass pass
self.notify("attrs-changed") self.notify("attrs-changed")
class FileListModel(GObject.Object, Gio.ListModel):
"""A ListModel implementation for FileItems"""
__gtype_name__ = "FileListModel"
items: list[FileItem]
def __init__(self):
super().__init__()
self.items = []
def do_get_item_type(self) -> GObject.GType:
return GObject.type_from_name("FileItem")
def do_get_n_items(self) -> int:
return len(self.items)
def do_get_item(self, position: int) -> Optional[FileItem]:
if 0 <= position < len(self.items):
return self.items[position]
return None
def remove_all(self) -> None:
removed = len(self.items)
self.items = []
self.items_changed(0, removed, 0)
def set_items(self, items: list[FileItem]):
removed = len(self.items)
self.items = list(items)
self.items_changed(0, removed, len(self.items))
def append(self, item: FileItem) -> None:
pos = len(self.items)
self.items.append(item)
self.items_changed(pos, 0, 1)
def remove(self, position: int) -> None:
if 0 <= position < len(self.items):
self.items.pop(position)
self.items_changed(position, 1, 0)