diff options
author | Jean Felder <jfelder@src.gnome.org> | 2020-04-04 13:09:37 +0200 |
---|---|---|
committer | Jean Felder <jfelder@src.gnome.org> | 2020-12-05 00:47:12 +0100 |
commit | 02313bef1cf07a1c5f85378360d45ef019955c43 (patch) | |
tree | c77b1d3a13575cda765586d6b84e1e4c09156c22 | |
parent | 7df001655da6bd31c023c010a66e272f468a762a (diff) | |
download | pygobject-wip/jfelder/gtk4-sort-list-model.tar.gz |
gtk: Add override for Gtk.CustomSorter.set_sort_funcwip/jfelder/gtk4-sort-list-model
This function use CompareDataFunc which works with pointers and
doesn't know anything about GObjects.
The same logic as in Gio.List.sort and Gio.List.insert_sorted is
used.
An associated unit_test is also added.
-rw-r--r-- | gi/overrides/Gio.py | 17 | ||||
-rw-r--r-- | gi/overrides/Gtk.py | 21 | ||||
-rw-r--r-- | gi/overrides/__init__.py | 12 | ||||
-rw-r--r-- | tests/test_overrides_gtk.py | 95 |
4 files changed, 128 insertions, 17 deletions
diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py index 5cc12a6c..c807fe0b 100644 --- a/gi/overrides/Gio.py +++ b/gi/overrides/Gio.py @@ -21,9 +21,8 @@ import warnings from .._ossighelper import wakeup_on_signal, register_sigint_fallback -from ..overrides import override, deprecated_init +from ..overrides import override, deprecated_init, wrap_list_store_sort_func from ..module import get_introspection_module -from gi._gi import pygobject_new_full from gi import PyGIWarning from gi.repository import GLib @@ -461,16 +460,6 @@ ListModel = override(ListModel) __all__.append('ListModel') -def _wrap_list_store_sort_func(func): - - def wrap(a, b, *user_data): - a = pygobject_new_full(a, False) - b = pygobject_new_full(b, False) - return func(a, b, *user_data) - - return wrap - - if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) < (2, 57, 1): # The "additions" functionality in splice() was broken in older glib # https://bugzilla.gnome.org/show_bug.cgi?id=795307 @@ -487,11 +476,11 @@ else: class ListStore(Gio.ListStore): def sort(self, compare_func, *user_data): - compare_func = _wrap_list_store_sort_func(compare_func) + compare_func = wrap_list_store_sort_func(compare_func) return super(ListStore, self).sort(compare_func, *user_data) def insert_sorted(self, item, compare_func, *user_data): - compare_func = _wrap_list_store_sort_func(compare_func) + compare_func = wrap_list_store_sort_func(compare_func) return super(ListStore, self).insert_sorted( item, compare_func, *user_data) diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py index 721e5317..b1bebf77 100644 --- a/gi/overrides/Gtk.py +++ b/gi/overrides/Gtk.py @@ -26,7 +26,8 @@ from collections import abc from gi.repository import GObject from .._ossighelper import wakeup_on_signal, register_sigint_fallback from .._gtktemplate import Template -from ..overrides import override, strip_boolean_result, deprecated_init +from ..overrides import (override, strip_boolean_result, deprecated_init, + wrap_list_store_sort_func) from ..module import get_introspection_module from gi import PyGIDeprecationWarning @@ -1647,6 +1648,24 @@ class TreeModelFilter(Gtk.TreeModelFilter): TreeModelFilter = override(TreeModelFilter) __all__.append('TreeModelFilter') +if GTK4: + class CustomSorter(Gtk.CustomSorter): + + @classmethod + def new(cls, sort_func=None, user_data=None): + self = Gtk.CustomSorter.new(None, None) + if sort_func: + self.set_sort_func(sort_func, user_data) + + return self + + def set_sort_func(self, sort_func, user_data=None): + compare_func = wrap_list_store_sort_func(sort_func) + return super(CustomSorter, self).set_sort_func(compare_func, user_data) + + CustomSorter = override(CustomSorter) + __all__.append("CustomSorter") + if GTK3: class Menu(Gtk.Menu): def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time): diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py index 1572d251..37dfbbe5 100644 --- a/gi/overrides/__init__.py +++ b/gi/overrides/__init__.py @@ -6,7 +6,7 @@ import sys from pkgutil import get_loader from gi import PyGIDeprecationWarning -from gi._gi import CallableInfo +from gi._gi import CallableInfo, pygobject_new_full from gi._constants import \ TYPE_NONE, \ TYPE_INVALID @@ -341,3 +341,13 @@ def strip_boolean_result(method, exc_type=None, exc_str=None, fail_ret=None): raise exc_type(exc_str or 'call failed') return fail_ret return wrapped + + +def wrap_list_store_sort_func(func): + + def wrap(a, b, *user_data): + a = pygobject_new_full(a, False) + b = pygobject_new_full(b, False) + return func(a, b, *user_data) + + return wrap diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py index 6337d7c4..bde0b5fa 100644 --- a/tests/test_overrides_gtk.py +++ b/tests/test_overrides_gtk.py @@ -14,7 +14,7 @@ from .helper import ignore_gi_deprecation_warnings, capture_glib_warnings import gi.overrides import gi.types -from gi.repository import GLib, GObject +from gi.repository import Gio, GLib, GObject try: from gi.repository import Gtk, GdkPixbuf, Gdk @@ -1267,6 +1267,99 @@ class TestTreeModelRow(unittest.TestCase): assert row.previous.previous is None +@unittest.skipUnless(Gtk, "Gtk not available") +class TestCustomSorter(): + class Person(GObject.GObject): + + name = GObject.Property(type=str, default="") + + def __init__(self, name): + super().__init__() + self.props.name = name + + user_data = "user_data" + + def names_sort(self, name_a, name_b, user_data): + assert user_data is None + if name_a.props.name < name_b.props.name: + return Gtk.Ordering.SMALLER + elif name_a.props.name > name_b.props.name: + return Gtk.Ordering.LARGER + else: + return Gtk.Ordering.EQUAL + + def names_invert_sort(self, name_a, name_b, user_data): + assert user_data == self.user_data + if name_a.props.name < name_b.props.name: + return Gtk.Ordering.LARGER + elif name_a.props.name > name_b.props.name: + return Gtk.Ordering.SMALLER + else: + return Gtk.Ordering.EQUAL + + @unittest.skipIf(Gtk_version != "4.0", "gtk4 only") + def test_custom_sorter_init(self): + custom_sorter_empty = Gtk.CustomSorter() + assert isinstance(custom_sorter_empty, Gtk.CustomSorter) + + custom_sorter_empty.set_sort_func(self.names_sort) + assert isinstance(custom_sorter_empty, Gtk.CustomSorter) + + custom_sorter_empty.set_sort_func( + self.names_invert_sort, self.user_data) + assert isinstance(custom_sorter_empty, Gtk.CustomSorter) + + custom_sorter_empty_sort = Gtk.CustomSorter.new(None) + assert isinstance(custom_sorter_empty_sort, Gtk.CustomSorter) + + custom_sorter_with_sort = Gtk.CustomSorter.new(self.names_sort, None) + assert isinstance(custom_sorter_with_sort, Gtk.CustomSorter) + + custom_sorter_with_sort_ud = Gtk.CustomSorter.new( + self.names_invert_sort, self.user_data) + assert isinstance(custom_sorter_with_sort_ud, Gtk.CustomSorter) + + @unittest.skipIf(Gtk_version != "4.0", "gtk4 only") + def test_custom_sorter_with_model(self): + model = Gio.ListStore.new(self.Person) + sort_model = Gtk.SortListModel.new(model) + assert sort_model.props.sorter is None + + empty_sorter = Gtk.CustomSorter() + empty_sorter.set_sort_func(self.names_sort, None) + sort_model.set_sorter(empty_sorter) + assert sort_model.props.sorter is empty_sorter + + john = self.Person("john") + bob = self.Person("bob") + model.append(john) + model.append(bob) + assert sort_model[0] == bob + assert sort_model[1] == john + + alice = self.Person("alice") + model.append(alice) + assert sort_model[0] == alice + assert sort_model[2] == john + + new_model = Gio.ListStore.new(self.Person) + new_sort_model = Gtk.SortListModel.new(new_model) + assert new_sort_model.props.sorter is None + + invert_sorter = Gtk.CustomSorter.new( + self.names_invert_sort, self.user_data) + new_sort_model.set_sorter(invert_sorter) + assert new_sort_model.props.sorter is invert_sorter + + beatles = ["john", "paul", "george", "ringo"] + for member in beatles: + new_model.append(self.Person(member)) + + expected_result = ["ringo", "paul", "john", "george"] + for result, member in zip(new_sort_model, expected_result): + assert result.props.name == member + + @ignore_gi_deprecation_warnings @unittest.skipUnless(Gtk, 'Gtk not available') class TestTreeModel(unittest.TestCase): |