[gtk/wip/otte/bitset: 213/217] selectionmodel: Replace query_range() with get_selection()



commit 2f22912cfd052cd38f7d953816c2187d002bf10a
Author: Benjamin Otte <otte redhat com>
Date:   Sun Jun 14 05:30:06 2020 +0200

    selectionmodel: Replace query_range() with get_selection()

 docs/reference/gtk/gtk4-sections.txt |   3 +-
 gtk/gtkmultiselection.c              |  18 -----
 gtk/gtknoselection.c                 |  23 ------
 gtk/gtkpropertyselection.c           |  38 +--------
 gtk/gtkselectionmodel.c              | 148 ++++++++++++++++++++---------------
 gtk/gtkselectionmodel.h              |  38 +++++----
 gtk/gtksingleselection.c             |  62 ++++-----------
 testsuite/gtk/singleselection.c      |  46 +++++------
 8 files changed, 150 insertions(+), 226 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 59df2f46e8..19bf9d5302 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -344,6 +344,8 @@ gtk_list_box_row_get_type
 <TITLE>GtkSelectionModel</TITLE>
 GtkSelectionModel
 gtk_selection_model_is_selected
+gtk_selection_model_get_selection
+gtk_selection_model_get_selection_in_range
 gtk_selection_model_select_item
 gtk_selection_model_unselect_item
 gtk_selection_model_select_range
@@ -353,7 +355,6 @@ gtk_selection_model_unselect_all
 GtkSelectionCallback
 gtk_selection_model_select_callback
 gtk_selection_model_unselect_callback
-gtk_selection_model_query_range
 <SUBSECTION>
 gtk_selection_model_selection_changed
 <SUBSECTION Standard>
diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c
index 051d45ae33..40fc3402a9 100644
--- a/gtk/gtkmultiselection.c
+++ b/gtk/gtkmultiselection.c
@@ -246,21 +246,6 @@ gtk_multi_selection_unselect_callback (GtkSelectionModel    *model,
   return gtk_multi_selection_add_or_remove (model, FALSE, FALSE, callback, data);
 }
 
-#if 0
-static void
-gtk_multi_selection_query_range (GtkSelectionModel *model,
-                                 guint              position,
-                                 guint             *start_range,
-                                 guint             *n_items,
-                                 gboolean          *selected)
-{
-  GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
-  guint upper_bound = g_list_model_get_n_items (self->model);
-
-  gtk_set_find_range (self->selected, position, upper_bound, start_range, n_items, selected);
-}
-#endif
-
 static void
 gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface)
 {
@@ -273,9 +258,6 @@ gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface)
   iface->unselect_all = gtk_multi_selection_unselect_all;
   iface->select_callback = gtk_multi_selection_select_callback;
   iface->unselect_callback = gtk_multi_selection_unselect_callback;
-#if 0
-  iface->query_range = gtk_multi_selection_query_range;
-#endif
 }
 
 G_DEFINE_TYPE_EXTENDED (GtkMultiSelection, gtk_multi_selection, G_TYPE_OBJECT, 0,
diff --git a/gtk/gtknoselection.c b/gtk/gtknoselection.c
index c3706f2e1c..192d3e75b1 100644
--- a/gtk/gtknoselection.c
+++ b/gtk/gtknoselection.c
@@ -89,32 +89,9 @@ gtk_no_selection_list_model_init (GListModelInterface *iface)
   iface->get_item = gtk_no_selection_get_item;
 }
 
-static gboolean
-gtk_no_selection_is_selected (GtkSelectionModel *model,
-                              guint              position)
-{
-  return FALSE;
-}
-
-static void
-gtk_no_selection_query_range (GtkSelectionModel *model,
-                              guint              position,
-                              guint             *start_range,
-                              guint             *n_range,
-                              gboolean          *selected)
-{
-  GtkNoSelection *self = GTK_NO_SELECTION (model);
-
-  *start_range = 0;
-  *n_range = g_list_model_get_n_items (self->model);
-  *selected = FALSE;
-}
-
 static void
 gtk_no_selection_selection_model_init (GtkSelectionModelInterface *iface)
 {
-  iface->is_selected = gtk_no_selection_is_selected; 
-  iface->query_range = gtk_no_selection_query_range;
 }
 
 G_DEFINE_TYPE_EXTENDED (GtkNoSelection, gtk_no_selection, G_TYPE_OBJECT, 0,
diff --git a/gtk/gtkpropertyselection.c b/gtk/gtkpropertyselection.c
index 25fb94846d..2fa311091e 100644
--- a/gtk/gtkpropertyselection.c
+++ b/gtk/gtkpropertyselection.c
@@ -21,6 +21,7 @@
 
 #include "gtkpropertyselection.h"
 
+#include "gtkbitset.h"
 #include "gtkintl.h"
 #include "gtkselectionmodel.h"
 
@@ -275,42 +276,6 @@ gtk_property_selection_unselect_callback (GtkSelectionModel    *model,
   return gtk_property_selection_add_or_remove (model, FALSE, FALSE, callback, data);
 }
 
-static void
-gtk_property_selection_query_range (GtkSelectionModel *model,
-                                    guint              position,
-                                    guint             *start_range,
-                                    guint             *n_items,
-                                    gboolean          *selected)
-{
-  GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model);
-  guint n;
-  gboolean sel;
-  guint start, end;
-
-  n = g_list_model_get_n_items (G_LIST_MODEL (self));
-  sel = is_selected (self, position);
-
-  start = position;
-  while (start > 0)
-    {
-      if (is_selected (self, start - 1) != sel)
-        break;
-      start--;
-    }
-
-  end = position;
-  while (end + 1 < n)
-    {
-      if (is_selected (self, end + 1) != sel)
-        break;
-      end++;
-    }
-
-  *start_range = start;
-  *n_items = end - start + 1;
-  *selected = sel;
-}
-
 static void
 gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface)
 {
@@ -323,7 +288,6 @@ gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface)
   iface->unselect_all = gtk_property_selection_unselect_all;
   iface->select_callback = gtk_property_selection_select_callback;
   iface->unselect_callback = gtk_property_selection_unselect_callback;
-  iface->query_range = gtk_property_selection_query_range;
 }
 
 G_DEFINE_TYPE_EXTENDED (GtkPropertySelection, gtk_property_selection, G_TYPE_OBJECT, 0,
diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c
index 1bd62e810d..24db61f739 100644
--- a/gtk/gtkselectionmodel.c
+++ b/gtk/gtkselectionmodel.c
@@ -21,6 +21,7 @@
 
 #include "gtkselectionmodel.h"
 
+#include "gtkbitset.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 
@@ -79,7 +80,33 @@ static gboolean
 gtk_selection_model_default_is_selected (GtkSelectionModel *model,
                                          guint              position)
 {
-  return FALSE;
+  GtkBitset *bitset;
+  gboolean selected;
+
+  bitset = gtk_selection_model_get_selection_in_range (model, position, 1);
+  selected = gtk_bitset_contains (bitset, position);
+  gtk_bitset_unref (bitset);
+
+  return selected;
+}
+
+static GtkBitset *
+gtk_selection_model_default_get_selection_in_range (GtkSelectionModel *model,
+                                                    guint              position,
+                                                    guint              n_items)
+{
+  GtkBitset *bitset;
+  guint i;
+
+  bitset = gtk_bitset_new_empty ();
+
+  for (i = position; i < position + n_items; i++)
+    {
+      if (gtk_selection_model_is_selected (model, i))
+        gtk_bitset_add (bitset, i);
+    }
+
+  return bitset;
 }
 
 static gboolean
@@ -142,31 +169,11 @@ gtk_selection_model_default_unselect_all (GtkSelectionModel *model)
   return gtk_selection_model_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
 }
 
-static void
-gtk_selection_model_default_query_range (GtkSelectionModel *model,
-                                         guint              position,
-                                         guint             *start_range,
-                                         guint             *n_items,
-                                         gboolean          *selected)
-{
-  *start_range = position;
-
-  if (position >= g_list_model_get_n_items (G_LIST_MODEL (model)))
-    {
-      *n_items = 0;
-      *selected = FALSE;
-    }
-  else
-    {
-      *n_items = 1;
-      *selected = gtk_selection_model_is_selected (model, position);
-    }
-}
-
 static void
 gtk_selection_model_default_init (GtkSelectionModelInterface *iface)
 {
   iface->is_selected = gtk_selection_model_default_is_selected;
+  iface->get_selection_in_range = gtk_selection_model_default_get_selection_in_range;
   iface->select_item = gtk_selection_model_default_select_item;
   iface->unselect_item = gtk_selection_model_default_unselect_item;
   iface->select_range = gtk_selection_model_default_select_range;
@@ -175,7 +182,6 @@ gtk_selection_model_default_init (GtkSelectionModelInterface *iface)
   iface->unselect_all = gtk_selection_model_default_unselect_all;
   iface->select_callback = gtk_selection_model_default_select_callback;
   iface->unselect_callback = gtk_selection_model_default_unselect_callback;
-  iface->query_range = gtk_selection_model_default_query_range;
 
   /**
    * GtkSelectionModel::selection-changed
@@ -225,6 +231,62 @@ gtk_selection_model_is_selected (GtkSelectionModel *model,
   return iface->is_selected (model, position);
 }
 
+/**
+ * gtk_selection_model_get_selection:
+ * @model: a #GtkSelectionModel
+ *
+ * Gets the set containing all currently selected items in the model.
+ *
+ * This function may be slow, so if you are only interested in single item,
+ * consider using gtk_selection_model_is_selected() or if you are only
+ * interested in a few consider gtk_selection_model_get_selection_in_range().
+ *
+ * Returns: (transfer full): a #GtkBitset containing all the values currently
+ *     selected in @model. If no items are selected, the bitset is empty.
+ *     The bitset must not be modified.
+ **/
+GtkBitset *
+gtk_selection_model_get_selection (GtkSelectionModel *model)
+{
+  g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ());
+
+  return gtk_selection_model_get_selection_in_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL 
(model)));
+}
+
+/**
+ * gtk_selection_model_get_selection_in_range:
+ * @model: a #GtkSelectionModel
+ * @position: start of the queired range
+ * @n_items: number of items in the queried range
+ *
+ * Gets a set containing a set where the values in the range [position,
+ * position + n_items) match the selected state of the items in that range.
+ * All values outside that range are undefined.
+ *
+ * This function is an optimization for gtk_selection_model_get_selection() when
+ * you are only interested in part of the model's selected state. A common use
+ * case is in response to the :selection-changed signal.
+ *
+ * Returns: A #GtkBitset that matches the selection state for the given state
+ *     with all other values being undefined.
+ *     The bitset must not be modified.
+ **/
+GtkBitset *
+gtk_selection_model_get_selection_in_range (GtkSelectionModel *model,
+                                            guint              position,
+                                            guint              n_items)
+{
+  GtkSelectionModelInterface *iface;
+
+  g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ());
+
+  if (n_items == 0)
+    return gtk_bitset_new_empty ();
+
+  iface = GTK_SELECTION_MODEL_GET_IFACE (model);
+  return iface->get_selection_in_range (model, position, n_items);
+}
+
 /**
  * gtk_selection_model_select_item:
  * @model: a #GtkSelectionModel
@@ -383,46 +445,6 @@ gtk_selection_model_unselect_callback (GtkSelectionModel    *model,
   return GTK_SELECTION_MODEL_GET_IFACE (model)->unselect_callback (model, callback, data);
 }
 
-/**
- * gtk_selection_model_query_range:
- * @model: a #GtkSelectionModel
- * @position: the position inside the range
- * @start_range: (out): returns the position of the first element of the range
- * @n_items: (out): returns the size of the range
- * @selected: (out): returns whether items in @range are selected
- *
- * This function allows to query the selection status of multiple elements at once.
- * It is passed a position and returns a range of elements of uniform selection status.
- *
- * If @position is greater than the number of items in @model, @n_items is set to 0.
- * Otherwise the returned range is guaranteed to include the passed-in position, so
- * @n_items will be >= 1.
- *
- * Positions directly adjacent to the returned range may have the same selection
- * status as the returned range.
- *
- * This is an optimization function to make iterating over a model faster when few
- * items are selected. However, it is valid behavior for implementations to use a
- * naive implementation that only ever returns a single element.
- */
-void
-gtk_selection_model_query_range (GtkSelectionModel *model,
-                                 guint              position,
-                                 guint             *start_range,
-                                 guint             *n_items,
-                                 gboolean          *selected)
-{
-  GtkSelectionModelInterface *iface;
-
-  g_return_if_fail (GTK_IS_SELECTION_MODEL (model));
-  g_return_if_fail (start_range != NULL);
-  g_return_if_fail (n_items != NULL);
-  g_return_if_fail (selected != NULL);
-
-  iface = GTK_SELECTION_MODEL_GET_IFACE (model);
-  return iface->query_range (model, position, start_range, n_items, selected);
-}
-
 /**
  * gtk_selection_model_selection_changed:
  * @model: a #GtkSelectionModel
diff --git a/gtk/gtkselectionmodel.h b/gtk/gtkselectionmodel.h
index 55a012e3d6..e48ce20fee 100644
--- a/gtk/gtkselectionmodel.h
+++ b/gtk/gtkselectionmodel.h
@@ -24,7 +24,7 @@
 #error "Only <gtk/gtk.h> can be included directly."
 #endif
 
-#include <gdk/gdk.h>
+#include <gtk/gtktypes.h>
 
 G_BEGIN_DECLS
 
@@ -66,6 +66,9 @@ typedef void     (* GtkSelectionCallback) (guint     position,
 /**
  * GtkSelectionModelInterface:
  * @is_selected: Return if the item at the given position is selected.
+ * @get_selection_in_range: Return a bitset with all currently selected
+ *     items in the given range. By default, this function will call
+ *     #GtkSelectionModel::is_selected() on all items in the given range.
  * @select_item: Select the item in the given position. If the operation
  *     is known to fail, return %FALSE.
  * @unselect_item: Unselect the item in the given position. If the
@@ -81,10 +84,13 @@ typedef void     (* GtkSelectionCallback) (guint     position,
  *     unsupported or known to fail for all items, return %FALSE.
  *
  * The list of virtual functions for the #GtkSelectionModel interface.
- * All getter functions are mandatory to implement, but the model does
- * not need to implement any functions to support selecting or unselecting
- * items. Of course, if the model does not do that, it means that users
- * cannot select or unselect items in a list widgets using the model.
+ * No function must be implemented, but unless #GtkSelectionModel::is_selected()
+ * is implemented, it will not be possible to select items in the set.
+ * 
+ * The model does not need to implement any functions to support either
+ * selecting or unselecting items. Of course, if the model does not do that,
+ * it means that users cannot select or unselect items in a list widget
+ * using the model.
  */
 struct _GtkSelectionModelInterface
 {
@@ -94,6 +100,9 @@ struct _GtkSelectionModelInterface
   /*< public >*/
   gboolean              (* is_selected)                         (GtkSelectionModel      *model,
                                                                  guint                   position);
+  GtkBitset *           (* get_selection_in_range)              (GtkSelectionModel      *model,
+                                                                 guint                   position,
+                                                                 guint                   n_items);
 
   gboolean              (* select_item)                         (GtkSelectionModel      *model,
                                                                  guint                   position,
@@ -116,16 +125,18 @@ struct _GtkSelectionModelInterface
   gboolean              (* unselect_callback)                   (GtkSelectionModel      *model,
                                                                  GtkSelectionCallback    callback,
                                                                  gpointer                data);
-  void                  (* query_range)                         (GtkSelectionModel      *model,
-                                                                 guint                   position,
-                                                                 guint                  *start_range,
-                                                                 guint                  *n_items,
-                                                                 gboolean               *selected);
 };
 
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_selection_model_is_selected         (GtkSelectionModel      *model,
                                                                  guint                   position);
+GDK_AVAILABLE_IN_ALL
+GtkBitset *             gtk_selection_model_get_selection       (GtkSelectionModel      *model);
+GDK_AVAILABLE_IN_ALL
+GtkBitset *             gtk_selection_model_get_selection_in_range
+                                                                (GtkSelectionModel      *model,
+                                                                 guint                   position,
+                                                                 guint                   n_items);
 
 GDK_AVAILABLE_IN_ALL
 gboolean                gtk_selection_model_select_item         (GtkSelectionModel      *model,
@@ -158,13 +169,6 @@ gboolean                gtk_selection_model_unselect_callback   (GtkSelectionMod
                                                                  GtkSelectionCallback    callback,
                                                                  gpointer                data);
 
-GDK_AVAILABLE_IN_ALL
-void                    gtk_selection_model_query_range         (GtkSelectionModel      *model,
-                                                                 guint                   position,
-                                                                 guint                  *start_range,
-                                                                 guint                  *n_items,
-                                                                 gboolean               *selected);
-
 /* for implementations only */
 GDK_AVAILABLE_IN_ALL
 void                    gtk_selection_model_selection_changed   (GtkSelectionModel      *model,
diff --git a/gtk/gtksingleselection.c b/gtk/gtksingleselection.c
index 5d0172c7b1..bd35aed782 100644
--- a/gtk/gtksingleselection.c
+++ b/gtk/gtksingleselection.c
@@ -21,6 +21,7 @@
 
 #include "gtksingleselection.h"
 
+#include "gtkbitset.h"
 #include "gtkintl.h"
 #include "gtkselectionmodel.h"
 
@@ -110,6 +111,21 @@ gtk_single_selection_is_selected (GtkSelectionModel *model,
   return self->selected == position;
 }
 
+static GtkBitset *
+gtk_single_selection_get_selection_in_range (GtkSelectionModel *model,
+                                             guint              position,
+                                             guint              n_items)
+{
+  GtkSingleSelection *self = GTK_SINGLE_SELECTION (model);
+  GtkBitset *result;
+
+  result = gtk_bitset_new_empty ();
+  if (self->selected != GTK_INVALID_LIST_POSITION)
+    gtk_bitset_add (result, self->selected);
+
+  return result;
+}
+
 static gboolean
 gtk_single_selection_select_item (GtkSelectionModel *model,
                                   guint              position,
@@ -138,57 +154,13 @@ gtk_single_selection_unselect_item (GtkSelectionModel *model,
   return TRUE;
 }
 
-static void
-gtk_single_selection_query_range (GtkSelectionModel *model,
-                                  guint              position,
-                                  guint             *start_range,
-                                  guint             *n_range,
-                                  gboolean          *selected)
-{
-  GtkSingleSelection *self = GTK_SINGLE_SELECTION (model);
-  guint n_items;
-
-  n_items = g_list_model_get_n_items (self->model);
-
-  if (position >= n_items)
-    {
-      *start_range = position;
-      *n_range = 0;
-      *selected = FALSE;
-    }
-  else if (self->selected == GTK_INVALID_LIST_POSITION)
-    {
-      *start_range = 0;
-      *n_range = n_items;
-      *selected = FALSE;
-    }
-  else if (position < self->selected)
-    {
-      *start_range = 0;
-      *n_range = self->selected;
-      *selected = FALSE;
-    }
-  else if (position > self->selected)
-    {
-      *start_range = self->selected + 1;
-      *n_range = n_items - *start_range;
-      *selected = FALSE;
-    }
-  else
-    {
-      *start_range = self->selected;
-      *n_range = 1;
-      *selected = TRUE;
-    }
-}
-
 static void
 gtk_single_selection_selection_model_init (GtkSelectionModelInterface *iface)
 {
   iface->is_selected = gtk_single_selection_is_selected; 
+  iface->get_selection_in_range = gtk_single_selection_get_selection_in_range; 
   iface->select_item = gtk_single_selection_select_item; 
   iface->unselect_item = gtk_single_selection_unselect_item; 
-  iface->query_range = gtk_single_selection_query_range;
 }
 
 G_DEFINE_TYPE_EXTENDED (GtkSingleSelection, gtk_single_selection, G_TYPE_OBJECT, 0,
diff --git a/testsuite/gtk/singleselection.c b/testsuite/gtk/singleselection.c
index 24de458e1c..81b96e90d0 100644
--- a/testsuite/gtk/singleselection.c
+++ b/testsuite/gtk/singleselection.c
@@ -593,28 +593,30 @@ test_persistence (void)
 }
 
 static void
-check_query_range (GtkSelectionModel *selection)
+check_get_selection (GtkSelectionModel *selection)
 {
-  guint i, j;
-  guint position, n_items;
-  gboolean selected;
+  GtkBitset *set;
+  guint i, n_items;
 
-  /* check that range always contains position, and has uniform selection */
-  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (selection)); i++)
+  set = gtk_selection_model_get_selection (selection);
+  
+  n_items = g_list_model_get_n_items (G_LIST_MODEL (selection));
+  if (n_items == 0)
     {
-      gtk_selection_model_query_range (selection, i, &position, &n_items, &selected);
-      g_assert_cmpint (position, <=, i);
-      g_assert_cmpint (i, <, position + n_items);
-      for (j = position; j < position + n_items; j++)
-        g_assert_true (selected == gtk_selection_model_is_selected (selection, j));
+      g_assert_true (gtk_bitset_is_empty (set));
     }
-  
-  /* check that out-of-range returns the correct invalid values */
-  i = MIN (i, g_random_int ());
-  gtk_selection_model_query_range (selection, i, &position, &n_items, &selected);
-  g_assert_cmpint (position, ==, i);
-  g_assert_cmpint (n_items, ==, 0);
-  g_assert_true (!selected);
+  else
+    {
+      for (i = 0; i < n_items; i++)
+        {
+          g_assert_cmpint (gtk_bitset_contains (set, i), ==, gtk_selection_model_is_selected (selection, i));
+        }
+      
+      /* check that out-of-range has no bits set */
+      g_assert_cmpint (gtk_bitset_get_maximum (set), <, g_list_model_get_n_items (G_LIST_MODEL (selection)));
+    }
+
+  gtk_bitset_unref (set);
 }
 
 static void
@@ -625,16 +627,16 @@ test_query_range (void)
   
   store = new_store (1, 5, 1);
   selection = new_model (store, TRUE, TRUE);
-  check_query_range (selection);
+  check_get_selection (selection);
 
   gtk_selection_model_unselect_item (selection, 0);
-  check_query_range (selection);
+  check_get_selection (selection);
 
   gtk_selection_model_select_item (selection, 2,  TRUE);
-  check_query_range (selection);
+  check_get_selection (selection);
 
   gtk_selection_model_select_item (selection, 4, TRUE);
-  check_query_range (selection);
+  check_get_selection (selection);
 
   ignore_selection_changes (selection);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]