selectionmodel: Replace query_range() with get_selection()

This commit is contained in:
Benjamin Otte 2020-06-14 05:30:06 +02:00
parent 277a91dbf8
commit 8395698090
8 changed files with 159 additions and 217 deletions

View File

@ -389,6 +389,8 @@ gtk_bitset_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
@ -398,7 +400,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>

View File

@ -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,

View File

@ -21,6 +21,7 @@
#include "gtknoselection.h"
#include "gtkbitset.h"
#include "gtkintl.h"
#include "gtkselectionmodel.h"
@ -96,25 +97,19 @@ gtk_no_selection_is_selected (GtkSelectionModel *model,
return FALSE;
}
static void
gtk_no_selection_query_range (GtkSelectionModel *model,
guint position,
guint *start_range,
guint *n_range,
gboolean *selected)
static GtkBitset *
gtk_no_selection_get_selection_in_range (GtkSelectionModel *model,
guint pos,
guint n_items)
{
GtkNoSelection *self = GTK_NO_SELECTION (model);
*start_range = 0;
*n_range = g_list_model_get_n_items (self->model);
*selected = FALSE;
return gtk_bitset_new_empty ();
}
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;
iface->is_selected = gtk_no_selection_is_selected;
iface->get_selection_in_range = gtk_no_selection_get_selection_in_range;
}
G_DEFINE_TYPE_EXTENDED (GtkNoSelection, gtk_no_selection, G_TYPE_OBJECT, 0,

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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++)
{
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));
}
set = gtk_selection_model_get_selection (selection);
/* 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);
n_items = g_list_model_get_n_items (G_LIST_MODEL (selection));
if (n_items == 0)
{
g_assert_true (gtk_bitset_is_empty (set));
}
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);