forked from AuroraMiddleware/gtk
filterlistmodel: Rewrite with bitset data structure
Bitsets are more powerful, less memory intensive and faster than the old GtkRbTree version.
This commit is contained in:
parent
b54f6710a7
commit
d4b868d9bc
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "gtkfilterlistmodel.h"
|
#include "gtkfilterlistmodel.h"
|
||||||
|
|
||||||
#include "gtkrbtreeprivate.h"
|
#include "gtkbitset.h"
|
||||||
#include "gtkintl.h"
|
#include "gtkintl.h"
|
||||||
#include "gtkprivate.h"
|
#include "gtkprivate.h"
|
||||||
|
|
||||||
@ -44,20 +44,6 @@ enum {
|
|||||||
NUM_PROPERTIES
|
NUM_PROPERTIES
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _FilterNode FilterNode;
|
|
||||||
typedef struct _FilterAugment FilterAugment;
|
|
||||||
|
|
||||||
struct _FilterNode
|
|
||||||
{
|
|
||||||
guint visible : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _FilterAugment
|
|
||||||
{
|
|
||||||
guint n_items;
|
|
||||||
guint n_visible;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _GtkFilterListModel
|
struct _GtkFilterListModel
|
||||||
{
|
{
|
||||||
GObject parent_instance;
|
GObject parent_instance;
|
||||||
@ -66,7 +52,7 @@ struct _GtkFilterListModel
|
|||||||
GtkFilter *filter;
|
GtkFilter *filter;
|
||||||
GtkFilterMatch strictness;
|
GtkFilterMatch strictness;
|
||||||
|
|
||||||
GtkRbTree *items; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
GtkBitset *matches; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GtkFilterListModelClass
|
struct _GtkFilterListModelClass
|
||||||
@ -76,119 +62,6 @@ struct _GtkFilterListModelClass
|
|||||||
|
|
||||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_filter_list_model_augment (GtkRbTree *filter,
|
|
||||||
gpointer _aug,
|
|
||||||
gpointer _node,
|
|
||||||
gpointer left,
|
|
||||||
gpointer right)
|
|
||||||
{
|
|
||||||
FilterNode *node = _node;
|
|
||||||
FilterAugment *aug = _aug;
|
|
||||||
|
|
||||||
aug->n_items = 1;
|
|
||||||
aug->n_visible = node->visible ? 1 : 0;
|
|
||||||
|
|
||||||
if (left)
|
|
||||||
{
|
|
||||||
FilterAugment *left_aug = gtk_rb_tree_get_augment (filter, left);
|
|
||||||
aug->n_items += left_aug->n_items;
|
|
||||||
aug->n_visible += left_aug->n_visible;
|
|
||||||
}
|
|
||||||
if (right)
|
|
||||||
{
|
|
||||||
FilterAugment *right_aug = gtk_rb_tree_get_augment (filter, right);
|
|
||||||
aug->n_items += right_aug->n_items;
|
|
||||||
aug->n_visible += right_aug->n_visible;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilterNode *
|
|
||||||
gtk_filter_list_model_get_nth_filtered (GtkRbTree *tree,
|
|
||||||
guint position,
|
|
||||||
guint *out_unfiltered)
|
|
||||||
{
|
|
||||||
FilterNode *node, *tmp;
|
|
||||||
guint unfiltered;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_get_root (tree);
|
|
||||||
unfiltered = 0;
|
|
||||||
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
tmp = gtk_rb_tree_node_get_left (node);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
|
||||||
if (position < aug->n_visible)
|
|
||||||
{
|
|
||||||
node = tmp;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
position -= aug->n_visible;
|
|
||||||
unfiltered += aug->n_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->visible)
|
|
||||||
{
|
|
||||||
if (position == 0)
|
|
||||||
break;
|
|
||||||
position--;
|
|
||||||
}
|
|
||||||
|
|
||||||
unfiltered++;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_node_get_right (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_unfiltered)
|
|
||||||
*out_unfiltered = unfiltered;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilterNode *
|
|
||||||
gtk_filter_list_model_get_nth (GtkRbTree *tree,
|
|
||||||
guint position,
|
|
||||||
guint *out_filtered)
|
|
||||||
{
|
|
||||||
FilterNode *node, *tmp;
|
|
||||||
guint filtered;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_get_root (tree);
|
|
||||||
filtered = 0;
|
|
||||||
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
tmp = gtk_rb_tree_node_get_left (node);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
|
||||||
if (position < aug->n_items)
|
|
||||||
{
|
|
||||||
node = tmp;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
position -= aug->n_items;
|
|
||||||
filtered += aug->n_visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
position--;
|
|
||||||
if (node->visible)
|
|
||||||
filtered++;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_node_get_right (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_filtered)
|
|
||||||
*out_filtered = filtered;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GType
|
static GType
|
||||||
gtk_filter_list_model_get_item_type (GListModel *list)
|
gtk_filter_list_model_get_item_type (GListModel *list)
|
||||||
{
|
{
|
||||||
@ -199,8 +72,6 @@ static guint
|
|||||||
gtk_filter_list_model_get_n_items (GListModel *list)
|
gtk_filter_list_model_get_n_items (GListModel *list)
|
||||||
{
|
{
|
||||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||||
FilterAugment *aug;
|
|
||||||
FilterNode *node;
|
|
||||||
|
|
||||||
switch (self->strictness)
|
switch (self->strictness)
|
||||||
{
|
{
|
||||||
@ -211,18 +82,12 @@ gtk_filter_list_model_get_n_items (GListModel *list)
|
|||||||
return g_list_model_get_n_items (self->model);
|
return g_list_model_get_n_items (self->model);
|
||||||
|
|
||||||
case GTK_FILTER_MATCH_SOME:
|
case GTK_FILTER_MATCH_SOME:
|
||||||
break;
|
return gtk_bitset_get_size (self->matches);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = gtk_rb_tree_get_root (self->items);
|
|
||||||
if (node == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
aug = gtk_rb_tree_get_augment (self->items, node);
|
|
||||||
return aug->n_visible;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gpointer
|
static gpointer
|
||||||
@ -242,7 +107,9 @@ gtk_filter_list_model_get_item (GListModel *list,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GTK_FILTER_MATCH_SOME:
|
case GTK_FILTER_MATCH_SOME:
|
||||||
gtk_filter_list_model_get_nth_filtered (self->items, position, &unfiltered);
|
unfiltered = gtk_bitset_get_nth (self->matches, position);
|
||||||
|
if (unfiltered == 0 && position >= gtk_bitset_get_size (self->matches))
|
||||||
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -264,8 +131,8 @@ G_DEFINE_TYPE_WITH_CODE (GtkFilterListModel, gtk_filter_list_model, G_TYPE_OBJEC
|
|||||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init))
|
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init))
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
gtk_filter_list_model_run_filter_on_item (GtkFilterListModel *self,
|
||||||
guint position)
|
guint position)
|
||||||
{
|
{
|
||||||
gpointer item;
|
gpointer item;
|
||||||
gboolean visible;
|
gboolean visible;
|
||||||
@ -280,23 +147,62 @@ gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
|||||||
return visible;
|
return visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_filter_list_model_run_filter (GtkFilterListModel *self)
|
||||||
|
{
|
||||||
|
guint i, n_items;
|
||||||
|
GtkBitset *other;
|
||||||
|
|
||||||
|
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||||
|
|
||||||
|
if (self->matches == NULL || self->model == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
n_items = g_list_model_get_n_items (self->model);
|
||||||
|
other = self->matches;
|
||||||
|
self->matches = gtk_bitset_new_empty ();
|
||||||
|
|
||||||
|
for (i = 0; i < n_items; i++)
|
||||||
|
{
|
||||||
|
if (gtk_filter_list_model_run_filter_on_item (self, i))
|
||||||
|
gtk_bitset_add (self->matches, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_bitset_difference (other, self->matches);
|
||||||
|
if (!gtk_bitset_is_empty (other))
|
||||||
|
{
|
||||||
|
guint min, max, changes, additions, existing;
|
||||||
|
|
||||||
|
min = gtk_bitset_get_minimum (other);
|
||||||
|
max = gtk_bitset_get_maximum (other);
|
||||||
|
existing = gtk_bitset_get_size_in_range (self->matches, min, max);
|
||||||
|
changes = gtk_bitset_get_size (other);
|
||||||
|
gtk_bitset_intersect (other, self->matches);
|
||||||
|
additions = gtk_bitset_get_size (other);
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||||
|
min > 0 ? gtk_bitset_get_size_in_range (self->matches, 0, min - 1) : 0,
|
||||||
|
existing - additions + (changes - additions),
|
||||||
|
existing);
|
||||||
|
}
|
||||||
|
gtk_bitset_unref (other);
|
||||||
|
}
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
gtk_filter_list_model_add_items (GtkFilterListModel *self,
|
gtk_filter_list_model_add_items (GtkFilterListModel *self,
|
||||||
FilterNode *after,
|
|
||||||
guint position,
|
guint position,
|
||||||
guint n_items)
|
guint n_items)
|
||||||
{
|
{
|
||||||
FilterNode *node;
|
|
||||||
guint i, n_visible;
|
guint i, n_visible;
|
||||||
|
|
||||||
n_visible = 0;
|
n_visible = 0;
|
||||||
|
|
||||||
for (i = 0; i < n_items; i++)
|
for (i = 0; i < n_items; i++)
|
||||||
{
|
{
|
||||||
node = gtk_rb_tree_insert_before (self->items, after);
|
if (gtk_filter_list_model_run_filter_on_item (self, position + i))
|
||||||
node->visible = gtk_filter_list_model_run_filter (self, position + i);
|
{
|
||||||
if (node->visible)
|
gtk_bitset_add (self->matches, position + i);
|
||||||
n_visible++;
|
n_visible++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return n_visible;
|
return n_visible;
|
||||||
@ -309,8 +215,7 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
|||||||
guint added,
|
guint added,
|
||||||
GtkFilterListModel *self)
|
GtkFilterListModel *self)
|
||||||
{
|
{
|
||||||
FilterNode *node;
|
guint filter_position, filter_removed, filter_added;
|
||||||
guint i, filter_position, filter_removed, filter_added;
|
|
||||||
|
|
||||||
switch (self->strictness)
|
switch (self->strictness)
|
||||||
{
|
{
|
||||||
@ -328,19 +233,15 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
|||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
node = gtk_filter_list_model_get_nth (self->items, position, &filter_position);
|
if (removed > 0)
|
||||||
|
filter_removed = gtk_bitset_get_size_in_range (self->matches, position, position + removed - 1);
|
||||||
|
else
|
||||||
|
filter_removed = 0;
|
||||||
|
|
||||||
filter_removed = 0;
|
gtk_bitset_slice (self->matches, position, removed, added);
|
||||||
for (i = 0; i < removed; i++)
|
|
||||||
{
|
|
||||||
FilterNode *next = gtk_rb_tree_node_get_next (node);
|
|
||||||
if (node->visible)
|
|
||||||
filter_removed++;
|
|
||||||
gtk_rb_tree_remove (self->items, node);
|
|
||||||
node = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_added = gtk_filter_list_model_add_items (self, node, position, added);
|
filter_position = gtk_bitset_get_size_in_range (self->matches, 0, position);
|
||||||
|
filter_added = gtk_filter_list_model_add_items (self, position, added);
|
||||||
|
|
||||||
if (filter_removed > 0 || filter_added > 0)
|
if (filter_removed > 0 || filter_added > 0)
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added);
|
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added);
|
||||||
@ -402,107 +303,13 @@ gtk_filter_list_model_clear_model (GtkFilterListModel *self)
|
|||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self);
|
g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self);
|
||||||
g_clear_object (&self->model);
|
g_clear_object (&self->model);
|
||||||
if (self->items)
|
if (self->matches)
|
||||||
gtk_rb_tree_remove_all (self->items);
|
gtk_bitset_remove_all (self->matches);
|
||||||
}
|
|
||||||
|
|
||||||
/*<private>
|
|
||||||
* gtk_filter_list_model_find_filtered:
|
|
||||||
* @self: a #GtkFilterListModel
|
|
||||||
* @start: (out) (caller-allocates): number of unfiltered items
|
|
||||||
* at start of list
|
|
||||||
* @end: (out) (caller-allocates): number of unfiltered items
|
|
||||||
* at end of list
|
|
||||||
* @n_items: (out) (caller-allocates): number of unfiltered items in
|
|
||||||
* list
|
|
||||||
*
|
|
||||||
* Checks if elements in self->items are filtered out and returns
|
|
||||||
* the range that they occupy.
|
|
||||||
* This function is intended to be used for GListModel::items-changed
|
|
||||||
* emissions, so it is called in an intermediate state for @self.
|
|
||||||
*
|
|
||||||
* Returns: %TRUE if elements are filtered out, %FALSE if none are
|
|
||||||
**/
|
|
||||||
static gboolean
|
|
||||||
gtk_filter_list_model_find_filtered (GtkFilterListModel *self,
|
|
||||||
guint *start,
|
|
||||||
guint *end,
|
|
||||||
guint *n_items)
|
|
||||||
{
|
|
||||||
FilterNode *root, *node, *tmp;
|
|
||||||
FilterAugment *aug;
|
|
||||||
|
|
||||||
if (self->items == NULL || self->model == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
root = gtk_rb_tree_get_root (self->items);
|
|
||||||
if (root == NULL)
|
|
||||||
return FALSE; /* empty parent model */
|
|
||||||
|
|
||||||
aug = gtk_rb_tree_get_augment (self->items, root);
|
|
||||||
if (aug->n_items == aug->n_visible)
|
|
||||||
return FALSE; /* all items visible */
|
|
||||||
|
|
||||||
/* find first filtered */
|
|
||||||
*start = 0;
|
|
||||||
*end = 0;
|
|
||||||
*n_items = aug->n_visible;
|
|
||||||
|
|
||||||
node = root;
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
tmp = gtk_rb_tree_node_get_left (node);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
|
||||||
if (aug->n_visible < aug->n_items)
|
|
||||||
{
|
|
||||||
node = tmp;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*start += aug->n_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!node->visible)
|
|
||||||
break;
|
|
||||||
|
|
||||||
(*start)++;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_node_get_right (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find last filtered by doing everything the opposite way */
|
|
||||||
node = root;
|
|
||||||
while (node)
|
|
||||||
{
|
|
||||||
tmp = gtk_rb_tree_node_get_right (node);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
|
||||||
if (aug->n_visible < aug->n_items)
|
|
||||||
{
|
|
||||||
node = tmp;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*end += aug->n_items;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!node->visible)
|
|
||||||
break;
|
|
||||||
|
|
||||||
(*end)++;
|
|
||||||
|
|
||||||
node = gtk_rb_tree_node_get_left (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_filter_list_model_refilter (GtkFilterListModel *self);
|
gtk_filter_list_model_refilter (GtkFilterListModel *self,
|
||||||
|
GtkFilterChange change)
|
||||||
static void
|
|
||||||
gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
|
||||||
{
|
{
|
||||||
GtkFilterMatch new_strictness;
|
GtkFilterMatch new_strictness;
|
||||||
|
|
||||||
@ -520,7 +327,7 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
|||||||
case GTK_FILTER_MATCH_NONE:
|
case GTK_FILTER_MATCH_NONE:
|
||||||
{
|
{
|
||||||
guint n_before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
guint n_before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||||
self->strictness = new_strictness;
|
self->strictness = new_strictness;
|
||||||
if (n_before > 0)
|
if (n_before > 0)
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_before, 0);
|
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_before, 0);
|
||||||
@ -541,16 +348,34 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
|||||||
case GTK_FILTER_MATCH_SOME:
|
case GTK_FILTER_MATCH_SOME:
|
||||||
{
|
{
|
||||||
guint start, end, n_before, n_after;
|
guint start, end, n_before, n_after;
|
||||||
|
|
||||||
self->strictness = new_strictness;
|
self->strictness = new_strictness;
|
||||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_before))
|
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||||
|
start = gtk_bitset_get_minimum (self->matches);
|
||||||
|
end = gtk_bitset_get_maximum (self->matches);
|
||||||
|
|
||||||
|
n_before = gtk_bitset_get_size (self->matches);
|
||||||
|
if (n_before == n_after)
|
||||||
{
|
{
|
||||||
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
GtkBitset *inverse = gtk_bitset_new_empty ();
|
||||||
|
|
||||||
|
gtk_bitset_add_range (inverse, 0, n_after);
|
||||||
|
gtk_bitset_subtract (inverse, self->matches);
|
||||||
|
/* otherwise all items would be visible */
|
||||||
|
g_assert (!gtk_bitset_is_empty (inverse));
|
||||||
|
|
||||||
|
/* find first filtered */
|
||||||
|
start = gtk_bitset_get_minimum (inverse);
|
||||||
|
end = n_after - gtk_bitset_get_maximum (inverse) - 1;
|
||||||
|
|
||||||
|
gtk_bitset_unref (inverse);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -562,40 +387,15 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case GTK_FILTER_MATCH_SOME:
|
case GTK_FILTER_MATCH_SOME:
|
||||||
switch (self->strictness)
|
if (self->matches == NULL)
|
||||||
{
|
{
|
||||||
case GTK_FILTER_MATCH_NONE:
|
self->matches = gtk_bitset_new_empty ();
|
||||||
{
|
if (self->strictness == GTK_FILTER_MATCH_ALL)
|
||||||
guint n_after;
|
gtk_bitset_add_range (self->matches, 0, g_list_model_get_n_items (self->model));
|
||||||
self->strictness = new_strictness;
|
|
||||||
self->items = gtk_rb_tree_new (FilterNode,
|
|
||||||
FilterAugment,
|
|
||||||
gtk_filter_list_model_augment,
|
|
||||||
NULL, NULL);
|
|
||||||
n_after = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (self->model));
|
|
||||||
if (n_after > 0)
|
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, 0, n_after);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GTK_FILTER_MATCH_ALL:
|
|
||||||
{
|
|
||||||
guint start, end, n_before, n_after;
|
|
||||||
self->strictness = new_strictness;
|
|
||||||
self->items = gtk_rb_tree_new (FilterNode,
|
|
||||||
FilterAugment,
|
|
||||||
gtk_filter_list_model_augment,
|
|
||||||
NULL, NULL);
|
|
||||||
n_before = g_list_model_get_n_items (self->model);
|
|
||||||
gtk_filter_list_model_add_items (self, NULL, 0, n_before);
|
|
||||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_after))
|
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case GTK_FILTER_MATCH_SOME:
|
|
||||||
gtk_filter_list_model_refilter (self);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->strictness = new_strictness;
|
||||||
|
gtk_filter_list_model_run_filter (self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +404,7 @@ gtk_filter_list_model_filter_changed_cb (GtkFilter *filter,
|
|||||||
GtkFilterChange change,
|
GtkFilterChange change,
|
||||||
GtkFilterListModel *self)
|
GtkFilterListModel *self)
|
||||||
{
|
{
|
||||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
gtk_filter_list_model_refilter (self, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -624,7 +424,7 @@ gtk_filter_list_model_dispose (GObject *object)
|
|||||||
|
|
||||||
gtk_filter_list_model_clear_model (self);
|
gtk_filter_list_model_clear_model (self);
|
||||||
gtk_filter_list_model_clear_filter (self);
|
gtk_filter_list_model_clear_filter (self);
|
||||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object);
|
G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
@ -725,7 +525,7 @@ gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTER]);
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTER]);
|
||||||
@ -784,11 +584,11 @@ gtk_filter_list_model_set_model (GtkFilterListModel *self,
|
|||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||||
added = 0;
|
added = 0;
|
||||||
}
|
}
|
||||||
else if (self->items)
|
else if (self->matches)
|
||||||
added = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model));
|
added = gtk_filter_list_model_add_items (self, 0, g_list_model_get_n_items (model));
|
||||||
else
|
else
|
||||||
added = g_list_model_get_n_items (model);
|
added = g_list_model_get_n_items (model);
|
||||||
}
|
}
|
||||||
@ -820,54 +620,3 @@ gtk_filter_list_model_get_model (GtkFilterListModel *self)
|
|||||||
return self->model;
|
return self->model;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_filter_list_model_refilter (GtkFilterListModel *self)
|
|
||||||
{
|
|
||||||
FilterNode *node;
|
|
||||||
guint i, first_change, last_change;
|
|
||||||
guint n_is_visible, n_was_visible;
|
|
||||||
gboolean visible;
|
|
||||||
|
|
||||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
|
||||||
|
|
||||||
if (self->items == NULL || self->model == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
first_change = G_MAXUINT;
|
|
||||||
last_change = 0;
|
|
||||||
n_is_visible = 0;
|
|
||||||
n_was_visible = 0;
|
|
||||||
for (i = 0, node = gtk_rb_tree_get_first (self->items);
|
|
||||||
node != NULL;
|
|
||||||
i++, node = gtk_rb_tree_node_get_next (node))
|
|
||||||
{
|
|
||||||
visible = gtk_filter_list_model_run_filter (self, i);
|
|
||||||
if (visible == node->visible)
|
|
||||||
{
|
|
||||||
if (visible)
|
|
||||||
{
|
|
||||||
n_is_visible++;
|
|
||||||
n_was_visible++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
node->visible = visible;
|
|
||||||
gtk_rb_tree_node_mark_dirty (node);
|
|
||||||
first_change = MIN (n_is_visible, first_change);
|
|
||||||
if (visible)
|
|
||||||
n_is_visible++;
|
|
||||||
else
|
|
||||||
n_was_visible++;
|
|
||||||
last_change = MAX (n_is_visible, last_change);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first_change <= last_change)
|
|
||||||
{
|
|
||||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
|
||||||
first_change,
|
|
||||||
last_change - first_change + n_was_visible - n_is_visible,
|
|
||||||
last_change - first_change);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user