summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Felder <jfelder@src.gnome.org>2020-04-04 13:09:37 +0200
committerJean Felder <jfelder@src.gnome.org>2020-12-05 00:47:12 +0100
commit02313bef1cf07a1c5f85378360d45ef019955c43 (patch)
treec77b1d3a13575cda765586d6b84e1e4c09156c22
parent7df001655da6bd31c023c010a66e272f468a762a (diff)
downloadpygobject-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.py17
-rw-r--r--gi/overrides/Gtk.py21
-rw-r--r--gi/overrides/__init__.py12
-rw-r--r--tests/test_overrides_gtk.py95
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):