mirror of
https://gitlab.gnome.org/GNOME/calls.git
synced 2024-12-04 20:07:36 +00:00
gtklistmodels: remove gtklistmodels polyfills
Part-of: <https://gitlab.gnome.org/GNOME/calls/-/merge_requests/714>
This commit is contained in:
parent
d7504da0d2
commit
bc90d6e64f
29 changed files with 7 additions and 5013 deletions
13
debian/copyright
vendored
13
debian/copyright
vendored
|
@ -31,19 +31,6 @@ Comment:
|
|||
From gnome-control-center,
|
||||
see https://bugzilla.gnome.org/show_bug.cgi?id=792243
|
||||
|
||||
Files:
|
||||
src/gtklistmodels/*
|
||||
Copyright:
|
||||
2018-2019 Benjamin Otte
|
||||
2019 Matthias Clasen
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files:
|
||||
src/gtklistmodels/gtkprivate.h
|
||||
Copyright:
|
||||
1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
License: LGPL-2+
|
||||
|
||||
Files:
|
||||
data/org.gnome.Calls.metainfo.xml
|
||||
Copyright:
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
#include "calls-plugin-manager.h"
|
||||
#include "calls-util.h"
|
||||
|
||||
#include "gtkcustomfilter.h"
|
||||
#include "gtkfilterlistmodel.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
|
||||
|
@ -397,7 +394,7 @@ calls_account_overview_init (CallsAccountOverview *self)
|
|||
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->account_provider_filter = gtk_custom_filter_new (match_account_provider, NULL, NULL);
|
||||
self->account_provider_filter = GTK_FILTER (gtk_custom_filter_new (match_account_provider, NULL, NULL));
|
||||
self->providers =
|
||||
G_LIST_MODEL (gtk_filter_list_model_new (all_providers,
|
||||
self->account_provider_filter));
|
||||
|
@ -410,7 +407,7 @@ calls_account_overview_init (CallsAccountOverview *self)
|
|||
0, 0, g_list_model_get_n_items (self->providers),
|
||||
self);
|
||||
|
||||
self->account_filter = gtk_custom_filter_new (match_account, NULL, NULL);
|
||||
self->account_filter = GTK_FILTER (gtk_custom_filter_new (match_account, NULL, NULL));
|
||||
self->accounts =
|
||||
G_LIST_MODEL (gtk_filter_list_model_new (all_origins,
|
||||
self->account_filter));
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "calls-history-box.h"
|
||||
#include "calls-call-record.h"
|
||||
#include "calls-call-record-row.h"
|
||||
#include "gtklistmodels/gtkmodels.h"
|
||||
#include "calls-util.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
|
|
@ -40,10 +40,6 @@
|
|||
|
||||
#include "enum-types.h"
|
||||
|
||||
#include "gtkcustomfilter.h"
|
||||
#include "gtkfilterlistmodel.h"
|
||||
#include "gtkflattenlistmodel.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <libpeas/peas.h>
|
||||
|
||||
|
@ -454,9 +450,6 @@ calls_manager_finalize (GObject *object)
|
|||
g_clear_object (&self->origins);
|
||||
g_clear_object (&self->contacts_provider);
|
||||
|
||||
g_clear_pointer (&self->origins_by_protocol, g_hash_table_unref);
|
||||
g_clear_pointer (&self->dial_actions_by_protocol, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (calls_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -599,7 +592,7 @@ calls_manager_init (CallsManager *self)
|
|||
self->state_flags = CALLS_MANAGER_FLAGS_UNKNOWN;
|
||||
|
||||
self->origins = g_list_store_new (G_TYPE_LIST_MODEL); /* list of lists */
|
||||
self->origins_flat = gtk_flatten_list_model_new (CALLS_TYPE_ORIGIN, G_LIST_MODEL (self->origins));
|
||||
self->origins_flat = gtk_flatten_list_model_new (G_LIST_MODEL (self->origins));
|
||||
|
||||
providers = calls_plugin_manager_get_providers (plugin_manager);
|
||||
g_signal_connect_object (providers,
|
||||
|
@ -616,8 +609,8 @@ calls_manager_init (CallsManager *self)
|
|||
g_object_unref);
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (protocols); i++) {
|
||||
g_autoptr (GtkFilter) filter =
|
||||
gtk_custom_filter_new (match_origin_supports_protocol, (gpointer) protocols[i], NULL);
|
||||
GtkFilter* filter =
|
||||
GTK_FILTER (gtk_custom_filter_new (match_origin_supports_protocol, (gpointer) protocols[i], NULL));
|
||||
GtkFilterListModel *f_list =
|
||||
gtk_filter_list_model_new (G_LIST_MODEL (self->origins_flat), filter);
|
||||
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkcustomfilter.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcustomfilter
|
||||
* @Title: GtkCustomFilter
|
||||
* @Short_description: Filtering with callbacks
|
||||
*
|
||||
* #GtkCustomFilter is a #GtkFilter that uses a callback to determine whether
|
||||
* to include an item or not.
|
||||
*/
|
||||
struct _GtkCustomFilter
|
||||
{
|
||||
GtkFilter parent_instance;
|
||||
|
||||
GtkCustomFilterFunc match_func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_destroy;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkCustomFilter, gtk_custom_filter, GTK_TYPE_FILTER)
|
||||
|
||||
static gboolean
|
||||
gtk_custom_filter_match (GtkFilter *filter,
|
||||
gpointer item)
|
||||
{
|
||||
GtkCustomFilter *self = GTK_CUSTOM_FILTER (filter);
|
||||
|
||||
if (!self->match_func)
|
||||
return TRUE;
|
||||
|
||||
return self->match_func (item, self->user_data);
|
||||
}
|
||||
|
||||
static GtkFilterMatch
|
||||
gtk_custom_filter_get_strictness (GtkFilter *filter)
|
||||
{
|
||||
GtkCustomFilter *self = GTK_CUSTOM_FILTER (filter);
|
||||
|
||||
if (!self->match_func)
|
||||
return GTK_FILTER_MATCH_ALL;
|
||||
|
||||
return GTK_FILTER_MATCH_SOME;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_filter_dispose (GObject *object)
|
||||
{
|
||||
GtkCustomFilter *self = GTK_CUSTOM_FILTER (object);
|
||||
|
||||
if (self->user_destroy)
|
||||
self->user_destroy (self->user_data);
|
||||
|
||||
G_OBJECT_CLASS (gtk_custom_filter_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_filter_class_init (GtkCustomFilterClass *class)
|
||||
{
|
||||
GtkFilterClass *filter_class = GTK_FILTER_CLASS (class);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
filter_class->match = gtk_custom_filter_match;
|
||||
filter_class->get_strictness = gtk_custom_filter_get_strictness;
|
||||
|
||||
object_class->dispose = gtk_custom_filter_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_filter_init (GtkCustomFilter *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_custom_filter_new:
|
||||
* @match_func: (nullable): function to filter items
|
||||
* @user_data: (nullable): user data to pass to @match_func
|
||||
* @user_destroy: destory notify
|
||||
*
|
||||
* Creates a new filter using the given @match_func to filter
|
||||
* items.
|
||||
*
|
||||
* If the filter func changes its filtering behavior,
|
||||
* gtk_filter_changed() needs to be called.
|
||||
*
|
||||
* Returns: a new #GtkFilter
|
||||
**/
|
||||
GtkFilter *
|
||||
gtk_custom_filter_new (GtkCustomFilterFunc match_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
GtkCustomFilter *result;
|
||||
|
||||
result = g_object_new (GTK_TYPE_CUSTOM_FILTER, NULL);
|
||||
|
||||
gtk_custom_filter_set_filter_func (result, match_func, user_data, user_destroy);
|
||||
|
||||
return GTK_FILTER (result);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_custom_filter_set_filter_func:
|
||||
* @self: a #GtkCustomFilter
|
||||
* @match_func: (nullable): function to filter items
|
||||
* @user_data: (nullable): user data to pass to @match_func
|
||||
* @user_destroy: destory notify
|
||||
*
|
||||
* Sets (or unsets) the function used for filtering items.
|
||||
*
|
||||
* If the filter func changes its filtering behavior,
|
||||
* gtk_filter_changed() needs to be called.
|
||||
*
|
||||
* If a previous function was set, its @user_destroy will be
|
||||
* called now.
|
||||
**/
|
||||
void
|
||||
gtk_custom_filter_set_filter_func (GtkCustomFilter *self,
|
||||
GtkCustomFilterFunc match_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CUSTOM_FILTER (self));
|
||||
g_return_if_fail (match_func || (user_data == NULL && !user_destroy));
|
||||
|
||||
if (self->user_destroy)
|
||||
self->user_destroy (self->user_data);
|
||||
|
||||
self->match_func = match_func;
|
||||
self->user_data = user_data;
|
||||
self->user_destroy = user_destroy;
|
||||
|
||||
gtk_filter_changed (GTK_FILTER (self), GTK_FILTER_CHANGE_DIFFERENT);
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CUSTOM_FILTER_H__
|
||||
#define __GTK_CUSTOM_FILTER_H__
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include "gtkfilter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GtkCustomFilterFunc:
|
||||
* @item: (type GObject): The item to be matched
|
||||
* @user_data: user data
|
||||
*
|
||||
* User function that is called to determine if the @item should be matched.
|
||||
* If the filter matches the item, this function must return %TRUE. If the
|
||||
* item should be filtered out, %FALSE must be returned.
|
||||
*
|
||||
* Returns: %TRUE to keep the item around
|
||||
*/
|
||||
typedef gboolean (* GtkCustomFilterFunc) (gpointer item, gpointer user_data);
|
||||
|
||||
#define GTK_TYPE_CUSTOM_FILTER (gtk_custom_filter_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkCustomFilter, gtk_custom_filter, GTK, CUSTOM_FILTER, GtkFilter)
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilter * gtk_custom_filter_new (GtkCustomFilterFunc match_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_custom_filter_set_filter_func (GtkCustomFilter *self,
|
||||
GtkCustomFilterFunc match_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CUSTOM_FILTER_H__ */
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkcustomsorter.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcustomsorter
|
||||
* @Title: GtkCustomSorter
|
||||
* @Short_description: Sorting with a callback
|
||||
*
|
||||
* GtkCustomSorter is a #GtkSorter implementation that sorts
|
||||
* via a traditional #GCompareDataFunc callback.
|
||||
*/
|
||||
struct _GtkCustomSorter
|
||||
{
|
||||
GtkSorter parent_instance;
|
||||
|
||||
GCompareDataFunc sort_func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_destroy;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkCustomSorter, gtk_custom_sorter, GTK_TYPE_SORTER)
|
||||
|
||||
static inline GtkOrdering
|
||||
gtk_ordering_from_cmpfunc (int cmpfunc_result)
|
||||
{
|
||||
return (GtkOrdering) ((cmpfunc_result > 0) - (cmpfunc_result < 0));
|
||||
}
|
||||
|
||||
static GtkOrdering
|
||||
gtk_custom_sorter_compare (GtkSorter *sorter,
|
||||
gpointer item1,
|
||||
gpointer item2)
|
||||
{
|
||||
GtkCustomSorter *self = GTK_CUSTOM_SORTER (sorter);
|
||||
|
||||
if (!self->sort_func)
|
||||
return GTK_ORDERING_EQUAL;
|
||||
|
||||
return gtk_ordering_from_cmpfunc (self->sort_func (item1, item2, self->user_data));
|
||||
}
|
||||
|
||||
static GtkSorterOrder
|
||||
gtk_custom_sorter_get_order (GtkSorter *sorter)
|
||||
{
|
||||
GtkCustomSorter *self = GTK_CUSTOM_SORTER (sorter);
|
||||
|
||||
if (!self->sort_func)
|
||||
return GTK_SORTER_ORDER_NONE;
|
||||
|
||||
return GTK_SORTER_ORDER_PARTIAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_sorter_dispose (GObject *object)
|
||||
{
|
||||
GtkCustomSorter *self = GTK_CUSTOM_SORTER (object);
|
||||
|
||||
if (self->user_destroy)
|
||||
self->user_destroy (self->user_data);
|
||||
|
||||
self->sort_func = NULL;
|
||||
self->user_destroy = NULL;
|
||||
self->user_data = NULL;
|
||||
|
||||
G_OBJECT_CLASS (gtk_custom_sorter_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_sorter_class_init (GtkCustomSorterClass *class)
|
||||
{
|
||||
GtkSorterClass *sorter_class = GTK_SORTER_CLASS (class);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
sorter_class->compare = gtk_custom_sorter_compare;
|
||||
sorter_class->get_order = gtk_custom_sorter_get_order;
|
||||
|
||||
object_class->dispose = gtk_custom_sorter_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_custom_sorter_init (GtkCustomSorter *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_custom_sorter_new:
|
||||
* @sort_func: the #GCompareDataFunc to use for sorting
|
||||
* @user_data: (nullable): user data to pass to @sort_func
|
||||
* @user_destroy: (nullable): destroy notify for @user_data
|
||||
*
|
||||
* Creates a new #GtkSorter that works by calling
|
||||
* @sort_func to compare items.
|
||||
*
|
||||
* Returns: a new #GTkSorter
|
||||
*/
|
||||
GtkSorter *
|
||||
gtk_custom_sorter_new (GCompareDataFunc sort_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
GtkCustomSorter *sorter;
|
||||
|
||||
sorter = g_object_new (GTK_TYPE_CUSTOM_SORTER, NULL);
|
||||
|
||||
gtk_custom_sorter_set_sort_func (sorter, sort_func, user_data, user_destroy);
|
||||
|
||||
return GTK_SORTER (sorter);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_custom_sorter_set_sort_func:
|
||||
* @self: a #GtkCustomSorter
|
||||
* @sort_func: (nullable): function to sort items
|
||||
* @user_data: (nullable): user data to pass to @match_func
|
||||
* @user_destroy: destory notify
|
||||
*
|
||||
* Sets (or unsets) the function used for sorting items.
|
||||
*
|
||||
* If the sort func changes its sorting behavior,
|
||||
* gtk_sorter_changed() needs to be called.
|
||||
*
|
||||
* If a previous function was set, its @user_destroy will be
|
||||
* called now.
|
||||
**/
|
||||
void
|
||||
gtk_custom_sorter_set_sort_func (GtkCustomSorter *self,
|
||||
GCompareDataFunc sort_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CUSTOM_SORTER (self));
|
||||
g_return_if_fail (sort_func || (user_data == NULL && !user_destroy));
|
||||
|
||||
if (self->user_destroy)
|
||||
self->user_destroy (self->user_data);
|
||||
|
||||
self->sort_func = sort_func;
|
||||
self->user_data = user_data;
|
||||
self->user_destroy = user_destroy;
|
||||
|
||||
gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CUSTOM_SORTER_H__
|
||||
#define __GTK_CUSTOM_SORTER_H__
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
/* #include <gtk/gtkexpression.h> */
|
||||
#include "gtksorter.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_CUSTOM_SORTER (gtk_custom_sorter_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkCustomSorter, gtk_custom_sorter, GTK, CUSTOM_SORTER, GtkSorter)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_custom_sorter_new (GCompareDataFunc sort_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_custom_sorter_set_sort_func (GtkCustomSorter *self,
|
||||
GCompareDataFunc sort_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CUSTOM_SORTER_H__ */
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkfilter.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkfilter
|
||||
* @Title: GtkFilter
|
||||
* @Short_description: Filtering items
|
||||
* @See_also: #GtkFilerListModel
|
||||
*
|
||||
* #GtkFilter is the way to describe filters to be used in #GtkFilterListModel.
|
||||
*
|
||||
* The model will use a filter to determine if it should filter items or not
|
||||
* by calling gtk_filter_match() for each item and only keeping the ones
|
||||
* visible that the function returns %TRUE for.
|
||||
*
|
||||
* Filters may change what items they match through their lifetime. In that
|
||||
* case, they can call gtk_filter_changed() which will emit the #GtkFilter:changed
|
||||
* signal to notify that previous filter results are no longer valid and that
|
||||
* items should be checked via gtk_filter_match() again.
|
||||
*
|
||||
* GTK provides various premade filter implementations for common filtering
|
||||
* operations. These filters often include properties that can be linked to
|
||||
* various widgets to easily allow searches.
|
||||
*
|
||||
* However, in particular for large lists or complex search methods, it is
|
||||
* also possible to subclass #GtkFilter and provide one's own filter.
|
||||
*/
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkFilter, gtk_filter, G_TYPE_OBJECT)
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static gboolean
|
||||
gtk_filter_default_match (GtkFilter *self,
|
||||
gpointer item)
|
||||
{
|
||||
g_critical ("Filter of type '%s' does not implement GtkFilter::match", G_OBJECT_TYPE_NAME (self));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkFilterMatch
|
||||
gtk_filter_default_get_strictness (GtkFilter *self)
|
||||
{
|
||||
return GTK_FILTER_MATCH_SOME;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_class_init (GtkFilterClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
class->match = gtk_filter_default_match;
|
||||
class->get_strictness = gtk_filter_default_get_strictness;
|
||||
|
||||
/**
|
||||
* GtkFilter:changed:
|
||||
* @self: The #GtkFilter
|
||||
* @change: how the filter changed
|
||||
*
|
||||
* This signal is emitted whenever the filter changed. Users of the filter
|
||||
* should then check items again via gtk_filter_match().
|
||||
*
|
||||
* #GtkFilterListModel handles this signal automatically.
|
||||
*
|
||||
* Depending on the @change parameter, not all items need to be changed, but
|
||||
* only some. Refer to the #GtkFilterChange documentation for details.
|
||||
*/
|
||||
signals[CHANGED] =
|
||||
g_signal_new (I_("changed"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__ENUM,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_FILTER_CHANGE);
|
||||
g_signal_set_va_marshaller (signals[CHANGED],
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
g_cclosure_marshal_VOID__ENUMv);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_init (GtkFilter *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_match:
|
||||
* @self: a #GtkFilter
|
||||
* @item: (type GObject) (transfer none): The item to check
|
||||
*
|
||||
* Checks if the given @item is matched by the filter or not.
|
||||
*
|
||||
* Returns: %TRUE if the filter matches the item and a filter model should
|
||||
* keep it, %FALSE if not.
|
||||
*/
|
||||
gboolean
|
||||
gtk_filter_match (GtkFilter *self,
|
||||
gpointer item)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER (self), FALSE);
|
||||
g_return_val_if_fail (item != NULL, FALSE);
|
||||
|
||||
return GTK_FILTER_GET_CLASS (self)->match (self, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_get_strictness:
|
||||
* @self: a #GtkFilter
|
||||
*
|
||||
* Gets the known strictness of @filters. If the strictness is not known,
|
||||
* %GTK_FILTER_MATCH_SOME is returned.
|
||||
*
|
||||
* This value may change after emission of the GtkFilter:changed signal.
|
||||
*
|
||||
* This function is meant purely for optimization purposes, filters can
|
||||
* choose to omit implementing it, but #GtkFilterListModel uses it.
|
||||
*
|
||||
* Returns: the strictness of @self
|
||||
**/
|
||||
GtkFilterMatch
|
||||
gtk_filter_get_strictness (GtkFilter *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER (self), GTK_FILTER_MATCH_SOME);
|
||||
|
||||
return GTK_FILTER_GET_CLASS (self)->get_strictness (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_changed:
|
||||
* @self: a #GtkFilter
|
||||
* @change: How the filter changed
|
||||
*
|
||||
* Emits the #GtkFilter:changed signal to notify all users of the filter that
|
||||
* the filter changed. Users of the filter should then check items again via
|
||||
* gtk_filter_match().
|
||||
*
|
||||
* Depending on the @change parameter, not all items need to be changed, but
|
||||
* only some. Refer to the #GtkFilterChange documentation for details.
|
||||
*
|
||||
* This function is intended for implementors of #GtkFilter subclasses and
|
||||
* should not be called from other functions.
|
||||
*/
|
||||
void
|
||||
gtk_filter_changed (GtkFilter *self,
|
||||
GtkFilterChange change)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_FILTER (self));
|
||||
|
||||
g_signal_emit (self, signals[CHANGED], 0, change);
|
||||
}
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_FILTER_H__
|
||||
#define __GTK_FILTER_H__
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GtkFilterMatch:
|
||||
* @GTK_FILTER_MATCH_SOME: The filter matches some items,
|
||||
* gtk_filter_match() may return %TRUE or %FALSE
|
||||
* @GTK_FILTER_MATCH_NONE: The filter does not match any item,
|
||||
* gtk_filter_match() will always return %FALSE.
|
||||
* @GTK_FILTER_MATCH_ALL: The filter matches all items,
|
||||
* gtk_filter_match() will alays return %TRUE.
|
||||
*
|
||||
* Describes the known strictness of a filter.
|
||||
*
|
||||
* Note that for filters where the strictness is not known,
|
||||
* %@GTK_FILTER_MATCH_SOME is always an acceptable value,
|
||||
* even if a filter does match all or no items.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_FILTER_MATCH_SOME = 0,
|
||||
GTK_FILTER_MATCH_NONE,
|
||||
GTK_FILTER_MATCH_ALL
|
||||
} GtkFilterMatch;
|
||||
|
||||
/**
|
||||
* GtkFilterChange:
|
||||
* @GTK_FILTER_CHANGE_DIFFERENT: The filter change cannot be
|
||||
* described with any of the other enumeration values.
|
||||
* @GTK_FILTER_CHANGE_LESS_STRICT: The filter is less strict than
|
||||
* it was before: All items that it used to return %TRUE for
|
||||
* still return %TRUE, others now may, too.
|
||||
* @GTK_FILTER_CHANGE_MORE_STRICT: The filter is more strict than
|
||||
* it was before: All items that it used to return %FALSE for
|
||||
* still return %FALSE, others now may, too.
|
||||
*
|
||||
* Describes changes in a filter in more detail and allows objects
|
||||
* using the filter to optimize refiltering items.
|
||||
*
|
||||
* If you are writing an implementation and are not sure which
|
||||
* value to pass, @GTK_FILTER_CHANGE_DIFFERENT is always a correct
|
||||
* choice.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_FILTER_CHANGE_DIFFERENT = 0,
|
||||
GTK_FILTER_CHANGE_LESS_STRICT,
|
||||
GTK_FILTER_CHANGE_MORE_STRICT,
|
||||
} GtkFilterChange;
|
||||
|
||||
#define GTK_TYPE_FILTER (gtk_filter_get_type ())
|
||||
|
||||
/**
|
||||
* GtkFilter:
|
||||
*
|
||||
* The object describing a filter.
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_DERIVABLE_TYPE (GtkFilter, gtk_filter, GTK, FILTER, GObject)
|
||||
|
||||
struct _GtkFilterClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* match) (GtkFilter *self,
|
||||
gpointer item);
|
||||
|
||||
/* optional */
|
||||
GtkFilterMatch (* get_strictness) (GtkFilter *self);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_filter_match (GtkFilter *self,
|
||||
gpointer item);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterMatch gtk_filter_get_strictness (GtkFilter *self);
|
||||
|
||||
/* for filter implementations */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_changed (GtkFilter *self,
|
||||
GtkFilterChange change);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_FILTER_H__ */
|
|
@ -1,916 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkfilterlistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkfilterlistmodel
|
||||
* @title: GtkFilterListModel
|
||||
* @short_description: A list model that filters its items
|
||||
* @see_also: #GListModel, #GtkFilter
|
||||
*
|
||||
* #GtkFilterListModel is a list model that filters a given other
|
||||
* listmodel.
|
||||
* It hides some elements from the other model according to
|
||||
* criteria given by a #GtkFilter.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_FILTER,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
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
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkFilter *filter;
|
||||
GtkFilterMatch strictness;
|
||||
|
||||
GtkRbTree *items; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||
};
|
||||
|
||||
struct _GtkFilterListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
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
|
||||
gtk_filter_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
FilterAugment *aug;
|
||||
FilterNode *node;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
return 0;
|
||||
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
return g_list_model_get_n_items (self->model);
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
gtk_filter_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
guint unfiltered;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
return NULL;
|
||||
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
unfiltered = position;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
gtk_filter_list_model_get_nth_filtered (self->items, position, &unfiltered);
|
||||
break;
|
||||
}
|
||||
|
||||
return g_list_model_get_item (self->model, unfiltered);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_filter_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_filter_list_model_get_n_items;
|
||||
iface->get_item = gtk_filter_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkFilterListModel, gtk_filter_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init))
|
||||
|
||||
static gboolean
|
||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean visible;
|
||||
|
||||
/* all other cases should have beeen optimized away */
|
||||
g_assert (self->strictness == GTK_FILTER_MATCH_SOME);
|
||||
|
||||
item = g_list_model_get_item (self->model, position);
|
||||
visible = gtk_filter_match (self->filter, item);
|
||||
g_object_unref (item);
|
||||
|
||||
return visible;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_add_items (GtkFilterListModel *self,
|
||||
FilterNode *after,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, n_visible;
|
||||
|
||||
n_visible = 0;
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->visible = gtk_filter_list_model_run_filter (self, position + i);
|
||||
if (node->visible)
|
||||
n_visible++;
|
||||
}
|
||||
|
||||
return n_visible;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, filter_position, filter_removed, filter_added;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
return;
|
||||
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
break;
|
||||
}
|
||||
|
||||
node = gtk_filter_list_model_get_nth (self->items, position, &filter_position);
|
||||
|
||||
filter_removed = 0;
|
||||
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);
|
||||
|
||||
if (filter_removed > 0 || filter_added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILTER:
|
||||
gtk_filter_list_model_set_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_filter_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_FILTER:
|
||||
g_value_set_object (value, self->filter);
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_clear_model (GtkFilterListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
if (self->items)
|
||||
gtk_rb_tree_remove_all (self->items);
|
||||
}
|
||||
|
||||
/*<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
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self);
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
{
|
||||
GtkFilterMatch new_strictness;
|
||||
|
||||
if (self->model == NULL)
|
||||
new_strictness = GTK_FILTER_MATCH_NONE;
|
||||
else if (self->filter == NULL)
|
||||
new_strictness = GTK_FILTER_MATCH_ALL;
|
||||
else
|
||||
new_strictness = gtk_filter_get_strictness (self->filter);
|
||||
|
||||
/* don't set self->strictness yet so get_n_items() and friends return old values */
|
||||
|
||||
switch (new_strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
guint n_before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
self->strictness = new_strictness;
|
||||
if (n_before > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_before, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
self->strictness = new_strictness;
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, 0, g_list_model_get_n_items (self->model));
|
||||
break;
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
self->strictness = new_strictness;
|
||||
break;
|
||||
default:
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
{
|
||||
guint start, end, n_before, n_after;
|
||||
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));
|
||||
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
|
||||
{
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
guint n_after;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_filter_changed_cb (GtkFilter *filter,
|
||||
GtkFilterChange change,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_clear_filter (GtkFilterListModel *self)
|
||||
{
|
||||
if (self->filter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->filter, gtk_filter_list_model_filter_changed_cb, self);
|
||||
g_clear_object (&self->filter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (object);
|
||||
|
||||
gtk_filter_list_model_clear_model (self);
|
||||
gtk_filter_list_model_clear_filter (self);
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_filter_list_model_set_property;
|
||||
gobject_class->get_property = gtk_filter_list_model_get_property;
|
||||
gobject_class->dispose = gtk_filter_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:filter:
|
||||
*
|
||||
* The filter for this model
|
||||
*/
|
||||
properties[PROP_FILTER] =
|
||||
g_param_spec_object ("filter",
|
||||
P_("Filter"),
|
||||
P_("The filter set for this model"),
|
||||
GTK_TYPE_FILTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:model:
|
||||
*
|
||||
* The model being filtered
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("The model being filtered"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_init (GtkFilterListModel *self)
|
||||
{
|
||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new:
|
||||
* @model: the model to sort
|
||||
* @filter: (allow-none): filter or %NULL to not filter items
|
||||
*
|
||||
* Creates a new #GtkFilterListModel that will filter @model using the given
|
||||
* @filter.
|
||||
*
|
||||
* Returns: a new #GtkFilterListModel
|
||||
**/
|
||||
GtkFilterListModel *
|
||||
gtk_filter_list_model_new (GListModel *model,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
GtkFilterListModel *result;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new_for_type:
|
||||
* @item_type: the type of the items that will be returned
|
||||
*
|
||||
* Creates a new empty filter list model set up to return items of type @item_type.
|
||||
* It is up to the application to set a proper filter and model to ensure
|
||||
* the item type is matched.
|
||||
*
|
||||
* Returns: a new #GtkFilterListModel
|
||||
**/
|
||||
GtkFilterListModel *
|
||||
gtk_filter_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_set_filter:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @filter: (allow-none) (transfer none): filter to use or %NULL to not filter items
|
||||
*
|
||||
* Sets the filter used to filter items.
|
||||
**/
|
||||
void
|
||||
gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
g_return_if_fail (filter == NULL || GTK_IS_FILTER (filter));
|
||||
|
||||
if (self->filter == filter)
|
||||
return;
|
||||
|
||||
gtk_filter_list_model_clear_filter (self);
|
||||
|
||||
if (filter)
|
||||
{
|
||||
self->filter = g_object_ref (filter);
|
||||
g_signal_connect (filter, "changed", G_CALLBACK (gtk_filter_list_model_filter_changed_cb), self);
|
||||
gtk_filter_list_model_filter_changed_cb (filter, GTK_FILTER_CHANGE_DIFFERENT, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_filter:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Gets the #GtkFilter currently set on @self.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The filter currently in use
|
||||
* or %NULL if the list isn't filtered
|
||||
**/
|
||||
GtkFilter *
|
||||
gtk_filter_list_model_get_filter (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE);
|
||||
|
||||
return self->filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_set_model:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @model: (allow-none): The model to be filtered
|
||||
*
|
||||
* Sets the model to be filtered.
|
||||
*
|
||||
* Note that GTK makes no effort to ensure that @model conforms to
|
||||
* the item type of @self. It assumes that the caller knows what they
|
||||
* are doing and have set up an appropriate filter to ensure that item
|
||||
* types match.
|
||||
**/
|
||||
void
|
||||
gtk_filter_list_model_set_model (GtkFilterListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added;
|
||||
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
/* Note: We don't check for matching item type here, we just assume the
|
||||
* filter func takes care of filtering wrong items. */
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_filter_list_model_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_filter_list_model_items_changed_cb), self);
|
||||
if (removed == 0)
|
||||
{
|
||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
added = 0;
|
||||
}
|
||||
else if (self->items)
|
||||
added = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model));
|
||||
else
|
||||
added = g_list_model_get_n_items (model);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||
added = 0;
|
||||
}
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_model:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Gets the model currently filtered or %NULL if none.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model that gets filtered
|
||||
**/
|
||||
GListModel *
|
||||
gtk_filter_list_model_get_model (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), NULL);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_FILTER_LIST_MODEL_H__
|
||||
#define __GTK_FILTER_LIST_MODEL_H__
|
||||
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "gtkfilter.h"
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_FILTER_LIST_MODEL (gtk_filter_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkFilterListModel, gtk_filter_list_model, GTK, FILTER_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new (GListModel *model,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilter * gtk_filter_list_model_get_filter (GtkFilterListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_model (GtkFilterListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_filter_list_model_get_model (GtkFilterListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_FILTER_LIST_MODEL_H__ */
|
|
@ -1,541 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkflattenlistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkflattenlistmodel
|
||||
* @title: GtkFlattenListModel
|
||||
* @short_description: A list model that flattens a list of lists
|
||||
* @see_also: #GListModel
|
||||
*
|
||||
* #GtkFlattenListModel is a list model that takes a list model containing
|
||||
* list models and flattens it into a single model.
|
||||
*
|
||||
* Another term for this is concatenation: #GtkFlattenListModel takes a
|
||||
* list of lists and concatenates them into a single list.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
typedef struct _FlattenNode FlattenNode;
|
||||
typedef struct _FlattenAugment FlattenAugment;
|
||||
|
||||
struct _FlattenNode
|
||||
{
|
||||
GListModel *model;
|
||||
GtkFlattenListModel *list;
|
||||
};
|
||||
|
||||
struct _FlattenAugment
|
||||
{
|
||||
guint n_items;
|
||||
guint n_models;
|
||||
};
|
||||
|
||||
struct _GtkFlattenListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkRbTree *items; /* NULL if model == NULL */
|
||||
};
|
||||
|
||||
struct _GtkFlattenListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static FlattenNode *
|
||||
gtk_flatten_list_model_get_nth (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *model_position)
|
||||
{
|
||||
FlattenNode *node, *tmp;
|
||||
guint model_n_items;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FlattenAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_items;
|
||||
}
|
||||
|
||||
model_n_items = g_list_model_get_n_items (node->model);
|
||||
if (position < model_n_items)
|
||||
break;
|
||||
position -= model_n_items;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (model_position)
|
||||
*model_position = node ? position : 0;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static FlattenNode *
|
||||
gtk_flatten_list_model_get_nth_model (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *items_before)
|
||||
{
|
||||
FlattenNode *node, *tmp;
|
||||
guint before;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
before = 0;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FlattenAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_models)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_models;
|
||||
before += aug->n_items;
|
||||
}
|
||||
|
||||
if (position == 0)
|
||||
break;
|
||||
position--;
|
||||
before += g_list_model_get_n_items (node->model);
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (items_before)
|
||||
*items_before = before;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_flatten_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_flatten_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list);
|
||||
FlattenAugment *aug;
|
||||
FlattenNode *node;
|
||||
|
||||
if (!self->items)
|
||||
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_items;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_flatten_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list);
|
||||
FlattenNode *node;
|
||||
guint model_pos;
|
||||
|
||||
if (!self->items)
|
||||
return NULL;
|
||||
|
||||
node = gtk_flatten_list_model_get_nth (self->items, position, &model_pos);
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (node->model, model_pos);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_flatten_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_flatten_list_model_get_n_items;
|
||||
iface->get_item = gtk_flatten_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkFlattenListModel, gtk_flatten_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_flatten_list_model_model_init))
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
gpointer _node)
|
||||
{
|
||||
FlattenNode *node = _node, *parent, *left;
|
||||
GtkFlattenListModel *self = node->list;
|
||||
guint real_position;
|
||||
|
||||
gtk_rb_tree_node_mark_dirty (node);
|
||||
real_position = position;
|
||||
|
||||
left = gtk_rb_tree_node_get_left (node);
|
||||
if (left)
|
||||
{
|
||||
FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left);
|
||||
real_position += aug->n_items;
|
||||
}
|
||||
|
||||
for (;
|
||||
(parent = gtk_rb_tree_node_get_parent (node)) != NULL;
|
||||
node = parent)
|
||||
{
|
||||
left = gtk_rb_tree_node_get_left (parent);
|
||||
if (left != node)
|
||||
{
|
||||
if (left)
|
||||
{
|
||||
FlattenAugment *aug = gtk_rb_tree_get_augment (self->items, left);
|
||||
real_position += aug->n_items;
|
||||
}
|
||||
real_position += g_list_model_get_n_items (parent->model);
|
||||
}
|
||||
}
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), real_position, removed, added);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_clear_node (gpointer _node)
|
||||
{
|
||||
FlattenNode *node= _node;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (node->model, gtk_flatten_list_model_items_changed_cb, node);
|
||||
g_object_unref (node->model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_augment (GtkRbTree *flatten,
|
||||
gpointer _aug,
|
||||
gpointer _node,
|
||||
gpointer left,
|
||||
gpointer right)
|
||||
{
|
||||
FlattenNode *node = _node;
|
||||
FlattenAugment *aug = _aug;
|
||||
|
||||
aug->n_items = g_list_model_get_n_items (node->model);
|
||||
aug->n_models = 1;
|
||||
|
||||
if (left)
|
||||
{
|
||||
FlattenAugment *left_aug = gtk_rb_tree_get_augment (flatten, left);
|
||||
aug->n_items += left_aug->n_items;
|
||||
aug->n_models += left_aug->n_models;
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
FlattenAugment *right_aug = gtk_rb_tree_get_augment (flatten, right);
|
||||
aug->n_items += right_aug->n_items;
|
||||
aug->n_models += right_aug->n_models;
|
||||
}
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_flatten_list_model_add_items (GtkFlattenListModel *self,
|
||||
FlattenNode *after,
|
||||
guint position,
|
||||
guint n)
|
||||
{
|
||||
FlattenNode *node;
|
||||
guint added, i;
|
||||
|
||||
added = 0;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->model = g_list_model_get_item (self->model, position + i);
|
||||
g_warn_if_fail (g_type_is_a (g_list_model_get_item_type (node->model), self->item_type));
|
||||
g_signal_connect (node->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_flatten_list_model_items_changed_cb),
|
||||
node);
|
||||
node->list = self;
|
||||
added +=g_list_model_get_n_items (node->model);
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_flatten_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkFlattenListModel *self)
|
||||
{
|
||||
FlattenNode *node;
|
||||
guint i, real_position, real_removed, real_added;
|
||||
|
||||
node = gtk_flatten_list_model_get_nth_model (self->items, position, &real_position);
|
||||
|
||||
real_removed = 0;
|
||||
for (i = 0; i < removed; i++)
|
||||
{
|
||||
FlattenNode *next = gtk_rb_tree_node_get_next (node);
|
||||
real_removed += g_list_model_get_n_items (node->model);
|
||||
gtk_rb_tree_remove (self->items, node);
|
||||
node = next;
|
||||
}
|
||||
|
||||
real_added = gtk_flatten_list_model_add_items (self, node, position, added);
|
||||
|
||||
if (real_removed > 0 || real_added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), real_position, real_removed, real_added);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_clear_model (GtkFlattenListModel *self)
|
||||
{
|
||||
if (self->model)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_flatten_list_model_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object);
|
||||
|
||||
gtk_flatten_list_clear_model (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_flatten_list_model_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_class_init (GtkFlattenListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_flatten_list_model_set_property;
|
||||
gobject_class->get_property = gtk_flatten_list_model_get_property;
|
||||
gobject_class->dispose = gtk_flatten_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:item-type:
|
||||
*
|
||||
* The #GTpe for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:model:
|
||||
*
|
||||
* The model being flattened
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("The model being flattened"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flatten_list_model_init (GtkFlattenListModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_flatten_list_model_new:
|
||||
* @item_type: The type of items in the to-be-flattened models
|
||||
* @model: (nullable) (transfer none): the item to be flattened
|
||||
*
|
||||
* Creates a new #GtkFlattenListModel that flattens @list. The
|
||||
* models returned by @model must conform to the given @item_type,
|
||||
* either by having an identical type or a subtype.
|
||||
*
|
||||
* Returns: a new #GtkFlattenListModel
|
||||
**/
|
||||
GtkFlattenListModel *
|
||||
gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model)
|
||||
{
|
||||
GtkFlattenListModel *result;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FLATTEN_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
"model", model,
|
||||
NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_flatten_list_model_set_model:
|
||||
* @self: a #GtkFlattenListModel
|
||||
* @model: (nullable) (transfer none): the new model or %NULL
|
||||
*
|
||||
* Sets a new model to be flattened. The model must contain items of
|
||||
* #GtkListModel that conform to the item type of @self.
|
||||
**/
|
||||
void
|
||||
gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added = 0;
|
||||
|
||||
g_return_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
if (model)
|
||||
{
|
||||
g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), G_TYPE_LIST_MODEL));
|
||||
}
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_flatten_list_clear_model (self);
|
||||
|
||||
self->model = model;
|
||||
|
||||
if (model)
|
||||
{
|
||||
g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_flatten_list_model_model_items_changed_cb), self);
|
||||
self->items = gtk_rb_tree_new (FlattenNode,
|
||||
FlattenAugment,
|
||||
gtk_flatten_list_model_augment,
|
||||
gtk_flatten_list_model_clear_node,
|
||||
NULL);
|
||||
|
||||
added = gtk_flatten_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model));
|
||||
}
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_flatten_list_model_get_model:
|
||||
* @self: a #GtkFlattenListModel
|
||||
*
|
||||
* Gets the model set via gtk_flatten_list_model_set_model().
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model flattened by @self
|
||||
**/
|
||||
GListModel *
|
||||
gtk_flatten_list_model_get_model (GtkFlattenListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_FLATTEN_LIST_MODEL_H__
|
||||
#define __GTK_FLATTEN_LIST_MODEL_H__
|
||||
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_FLATTEN_LIST_MODEL (gtk_flatten_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkFlattenListModel, gtk_flatten_list_model, GTK, FLATTEN_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFlattenListModel * gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_flatten_list_model_get_model (GtkFlattenListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_FLATTEN_LIST_MODEL_H__ */
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef __GTKINTL_H__
|
||||
#define __GTKINTL_H__
|
||||
|
||||
#ifndef GETTEXT_PACKAGE
|
||||
# define GETTEXT_PACKAGE
|
||||
#endif
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#ifndef G_GNUC_FALLTHROUGH
|
||||
#define G_GNUC_FALLTHROUGH __attribute__((fallthrough))
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#define P_(String) g_dgettext(GETTEXT_PACKAGE "-properties",String)
|
||||
#else
|
||||
#define P_(String) (String)
|
||||
#endif
|
||||
|
||||
/* not really I18N-related, but also a string marker macro */
|
||||
#define I_(string) g_intern_static_string (string)
|
||||
|
||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||
#include "gtksorter.h"
|
||||
#include "gtkcustomsorter.h"
|
||||
#include "gtkfilter.h"
|
||||
#include "gtkcustomfilter.h"
|
||||
#include "gtksortlistmodel.h"
|
||||
#include "gtkfilterlistmodel.h"
|
||||
#include "gtkflattenlistmodel.h"
|
||||
#include "gtkslicelistmodel.h"
|
|
@ -1,38 +0,0 @@
|
|||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
||||
* file for a list of people on the GTK+ Team. See the ChangeLog
|
||||
* files for a list of changes. These files are distributed with
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_PRIVATE_H__
|
||||
#define __GTK_PRIVATE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||||
#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||||
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PRIVATE_H__ */
|
|
@ -1,800 +0,0 @@
|
|||
/* gtkrbtree.c
|
||||
* Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
|
||||
/* #include "gtkdebug.h" */
|
||||
|
||||
/* Define the following to print adds and removals to stdout.
|
||||
* The format of the printout will be suitable for addition as a new test to
|
||||
* testsuite/gtk/rbtree-crash.c
|
||||
* by just grepping the printouts from the relevant rbtree.
|
||||
*
|
||||
* This is meant to be a trivial way to add rbtree tests to the testsuite.
|
||||
*/
|
||||
#undef DUMP_MODIFICATION
|
||||
|
||||
typedef struct _GtkRbNode GtkRbNode;
|
||||
|
||||
struct _GtkRbTree
|
||||
{
|
||||
guint ref_count;
|
||||
|
||||
gsize element_size;
|
||||
gsize augment_size;
|
||||
GtkRbTreeAugmentFunc augment_func;
|
||||
GDestroyNotify clear_func;
|
||||
GDestroyNotify clear_augment_func;
|
||||
|
||||
GtkRbNode *root;
|
||||
};
|
||||
|
||||
struct _GtkRbNode
|
||||
{
|
||||
guint red :1;
|
||||
guint dirty :1;
|
||||
|
||||
GtkRbNode *left;
|
||||
GtkRbNode *right;
|
||||
/* The difference between tree and parent here is that we OR the tree with 1 and because
|
||||
* pointers are always multiples of 4, we can know if we've stored a parent or the tree here */
|
||||
union {
|
||||
gpointer parent_or_tree;
|
||||
GtkRbNode *parent;
|
||||
GtkRbTree *tree;
|
||||
};
|
||||
};
|
||||
|
||||
#define NODE_FROM_POINTER(ptr) ((GtkRbNode *) ((ptr) ? (((guchar *) (ptr)) - sizeof (GtkRbNode)) : NULL))
|
||||
#define NODE_TO_POINTER(node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkRbNode)) : NULL))
|
||||
#define NODE_TO_AUG_POINTER(tree, node) ((gpointer) ((node) ? (((guchar *) (node)) + sizeof (GtkRbNode) + (tree)->element_size) : NULL))
|
||||
|
||||
static inline gboolean
|
||||
is_root (GtkRbNode *node)
|
||||
{
|
||||
return GPOINTER_TO_SIZE (node->parent_or_tree) & 1 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static inline GtkRbNode *
|
||||
parent (GtkRbNode *node)
|
||||
{
|
||||
if (is_root (node))
|
||||
return NULL;
|
||||
else
|
||||
return node->parent;
|
||||
}
|
||||
|
||||
static GtkRbTree *
|
||||
tree (GtkRbNode *node)
|
||||
{
|
||||
while (!is_root (node))
|
||||
node = parent (node);
|
||||
|
||||
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (node->tree) & ~1);
|
||||
}
|
||||
|
||||
static void
|
||||
set_parent (GtkRbTree *tree,
|
||||
GtkRbNode *node,
|
||||
GtkRbNode *new_parent)
|
||||
{
|
||||
|
||||
if (new_parent != NULL)
|
||||
{
|
||||
node->parent = new_parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->tree = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (tree) | 1);
|
||||
tree->root = node;
|
||||
}
|
||||
}
|
||||
|
||||
static inline gsize
|
||||
gtk_rb_node_get_size (GtkRbTree *tree)
|
||||
{
|
||||
return sizeof (GtkRbNode) + tree->element_size + tree->augment_size;
|
||||
}
|
||||
|
||||
static GtkRbNode *
|
||||
gtk_rb_node_new (GtkRbTree *tree)
|
||||
{
|
||||
GtkRbNode *result;
|
||||
|
||||
result = g_slice_alloc0 (gtk_rb_node_get_size (tree));
|
||||
|
||||
result->red = TRUE;
|
||||
result->dirty = TRUE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_node_free (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
if (tree->clear_func)
|
||||
tree->clear_func (NODE_TO_POINTER (node));
|
||||
if (tree->clear_augment_func)
|
||||
tree->clear_augment_func (NODE_TO_AUG_POINTER (tree, node));
|
||||
|
||||
g_slice_free1 (gtk_rb_node_get_size (tree), node);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_node_free_deep (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *right = node->right;
|
||||
|
||||
if (node->left)
|
||||
gtk_rb_node_free_deep (tree, node->left);
|
||||
|
||||
gtk_rb_node_free (tree, node);
|
||||
|
||||
if (right)
|
||||
gtk_rb_node_free_deep (tree, right);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_node_mark_dirty (GtkRbNode *node,
|
||||
gboolean mark_parent)
|
||||
{
|
||||
if (node->dirty)
|
||||
return;
|
||||
|
||||
node->dirty = TRUE;
|
||||
|
||||
if (mark_parent && parent (node))
|
||||
gtk_rb_node_mark_dirty (parent (node), TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_node_clean (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
if (!node->dirty)
|
||||
return;
|
||||
|
||||
node->dirty = FALSE;
|
||||
if (tree->augment_func)
|
||||
tree->augment_func (tree,
|
||||
NODE_TO_AUG_POINTER (tree, node),
|
||||
NODE_TO_POINTER (node),
|
||||
NODE_TO_POINTER (node->left),
|
||||
NODE_TO_POINTER (node->right));
|
||||
}
|
||||
|
||||
static GtkRbNode *
|
||||
gtk_rb_node_get_first (GtkRbNode *node)
|
||||
{
|
||||
while (node->left)
|
||||
node = node->left;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GtkRbNode *
|
||||
gtk_rb_node_get_last (GtkRbNode *node)
|
||||
{
|
||||
while (node->right)
|
||||
node = node->right;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GtkRbNode *
|
||||
gtk_rb_node_get_previous (GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *p;
|
||||
|
||||
if (node->left)
|
||||
return gtk_rb_node_get_last (node->left);
|
||||
|
||||
for (p = parent (node); p != NULL; p = parent (node))
|
||||
{
|
||||
if (p->right == node)
|
||||
return p;
|
||||
|
||||
node = p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GtkRbNode *
|
||||
gtk_rb_node_get_next (GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *p;
|
||||
|
||||
if (node->right)
|
||||
return gtk_rb_node_get_first (node->right);
|
||||
|
||||
for (p = parent (node); p != NULL; p = parent (node))
|
||||
{
|
||||
if (p->left == node)
|
||||
return p;
|
||||
|
||||
node = p;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DUMP_MODIFICATION
|
||||
static guint
|
||||
position (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *n;
|
||||
guint i;
|
||||
|
||||
i = 0;
|
||||
for (n = gtk_rb_node_get_first (tree->root);
|
||||
n != node;
|
||||
n = gtk_rb_node_get_next (n))
|
||||
i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gtk_rb_node_rotate_left (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *right, *p;
|
||||
|
||||
right = node->right;
|
||||
p = parent (node);
|
||||
|
||||
node->right = right->left;
|
||||
if (right->left)
|
||||
set_parent (tree, right->left, node);
|
||||
|
||||
set_parent (tree, right, p);
|
||||
if (p)
|
||||
{
|
||||
if (node == p->left)
|
||||
p->left = right;
|
||||
else
|
||||
p->right = right;
|
||||
}
|
||||
|
||||
right->left = node;
|
||||
set_parent (tree, node, right);
|
||||
|
||||
gtk_rb_node_mark_dirty (node, FALSE);
|
||||
gtk_rb_node_mark_dirty (right, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_node_rotate_right (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *left, *p;
|
||||
|
||||
left = node->left;
|
||||
p = parent (node);
|
||||
|
||||
node->left = left->right;
|
||||
if (left->right)
|
||||
set_parent (tree, left->right, node);
|
||||
|
||||
set_parent (tree, left, p);
|
||||
if (p)
|
||||
{
|
||||
if (node == p->right)
|
||||
p->right = left;
|
||||
else
|
||||
p->left = left;
|
||||
}
|
||||
|
||||
/* link node and left */
|
||||
left->right = node;
|
||||
set_parent (tree, node, left);
|
||||
|
||||
gtk_rb_node_mark_dirty (node, FALSE);
|
||||
gtk_rb_node_mark_dirty (left, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_red (GtkRbNode *node_or_null)
|
||||
{
|
||||
if (node_or_null == NULL)
|
||||
return FALSE;
|
||||
else
|
||||
return node_or_null->red;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
is_black (GtkRbNode *node_or_null)
|
||||
{
|
||||
return !is_red (node_or_null);
|
||||
}
|
||||
|
||||
static void
|
||||
set_black (GtkRbNode *node_or_null)
|
||||
{
|
||||
if (node_or_null == NULL)
|
||||
return;
|
||||
|
||||
node_or_null->red = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_red (GtkRbNode *node_or_null)
|
||||
{
|
||||
if (node_or_null == NULL)
|
||||
return;
|
||||
|
||||
node_or_null->red = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_tree_insert_fixup (GtkRbTree *tree,
|
||||
GtkRbNode *node)
|
||||
{
|
||||
GtkRbNode *p;
|
||||
|
||||
/* check Red-Black properties */
|
||||
for (p = parent (node);
|
||||
p && is_red (p);
|
||||
p = parent (node))
|
||||
{
|
||||
GtkRbNode *pp = parent (p);
|
||||
|
||||
/* we have a violation */
|
||||
g_assert (pp);
|
||||
|
||||
if (p == pp->left)
|
||||
{
|
||||
GtkRbNode *uncle = pp->right;
|
||||
|
||||
if (is_red (uncle))
|
||||
{
|
||||
/* uncle is red */
|
||||
set_black (p);
|
||||
set_black (uncle);
|
||||
set_red (pp);
|
||||
node = pp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* uncle is black */
|
||||
if (node == p->right)
|
||||
{
|
||||
/* make node a left child */
|
||||
node = p;
|
||||
gtk_rb_node_rotate_left (tree, node);
|
||||
p = parent (node);
|
||||
pp = parent (p);
|
||||
}
|
||||
/* recolor and rotate */
|
||||
set_black (p);
|
||||
set_red (pp);
|
||||
gtk_rb_node_rotate_right (tree, pp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* mirror image of above code */
|
||||
GtkRbNode *uncle = pp->left;
|
||||
|
||||
if (is_red (uncle))
|
||||
{
|
||||
/* uncle is red */
|
||||
set_black (p);
|
||||
set_black (uncle);
|
||||
set_red (pp);
|
||||
node = pp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* uncle is black */
|
||||
if (node == p->left)
|
||||
{
|
||||
node = p;
|
||||
gtk_rb_node_rotate_right (tree, node);
|
||||
p = parent (node);
|
||||
pp = parent (p);
|
||||
}
|
||||
set_black (p);
|
||||
set_red (pp);
|
||||
gtk_rb_node_rotate_left (tree, pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_black (tree->root);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_rb_tree_remove_node_fixup (GtkRbTree *tree,
|
||||
GtkRbNode *node,
|
||||
GtkRbNode *p)
|
||||
{
|
||||
while (node != tree->root && is_black (node))
|
||||
{
|
||||
if (node == p->left)
|
||||
{
|
||||
GtkRbNode *w = p->right;
|
||||
|
||||
if (is_red (w))
|
||||
{
|
||||
set_black (w);
|
||||
set_red (p);
|
||||
gtk_rb_node_rotate_left (tree, p);
|
||||
w = p->right;
|
||||
}
|
||||
if (is_black (w->left) && is_black (w->right))
|
||||
{
|
||||
set_red (w);
|
||||
node = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_black (w->right))
|
||||
{
|
||||
set_black (w->left);
|
||||
set_red (w);
|
||||
gtk_rb_node_rotate_right (tree, w);
|
||||
w = p->right;
|
||||
}
|
||||
w->red = p->red;
|
||||
set_black (p);
|
||||
set_black (w->right);
|
||||
gtk_rb_node_rotate_left (tree, p);
|
||||
node = tree->root;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkRbNode *w = p->left;
|
||||
if (is_red (w))
|
||||
{
|
||||
set_black (w);
|
||||
set_red (p);
|
||||
gtk_rb_node_rotate_right (tree, p);
|
||||
w = p->left;
|
||||
}
|
||||
if (is_black (w->right) && is_black (w->left))
|
||||
{
|
||||
set_red (w);
|
||||
node = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_black (w->left))
|
||||
{
|
||||
set_black (w->right);
|
||||
set_red (w);
|
||||
gtk_rb_node_rotate_left (tree, w);
|
||||
w = p->left;
|
||||
}
|
||||
w->red = p->red;
|
||||
set_black (p);
|
||||
set_black (w->left);
|
||||
gtk_rb_node_rotate_right (tree, p);
|
||||
node = tree->root;
|
||||
}
|
||||
}
|
||||
|
||||
p = parent (node);
|
||||
}
|
||||
|
||||
set_black (node);
|
||||
}
|
||||
|
||||
GtkRbTree *
|
||||
gtk_rb_tree_new_for_size (gsize element_size,
|
||||
gsize augment_size,
|
||||
GtkRbTreeAugmentFunc augment_func,
|
||||
GDestroyNotify clear_func,
|
||||
GDestroyNotify clear_augment_func)
|
||||
{
|
||||
GtkRbTree *tree;
|
||||
|
||||
tree = g_slice_new0 (GtkRbTree);
|
||||
tree->ref_count = 1;
|
||||
|
||||
tree->element_size = element_size;
|
||||
tree->augment_size = augment_size;
|
||||
tree->augment_func = augment_func;
|
||||
tree->clear_func = clear_func;
|
||||
tree->clear_augment_func = clear_augment_func;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
GtkRbTree *
|
||||
gtk_rb_tree_ref (GtkRbTree *tree)
|
||||
{
|
||||
tree->ref_count++;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_rb_tree_unref (GtkRbTree *tree)
|
||||
{
|
||||
tree->ref_count--;
|
||||
if (tree->ref_count > 0)
|
||||
return;
|
||||
|
||||
if (tree->root)
|
||||
gtk_rb_node_free_deep (tree, tree->root);
|
||||
|
||||
g_slice_free (GtkRbTree, tree);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_get_first (GtkRbTree *tree)
|
||||
{
|
||||
if (tree->root == NULL)
|
||||
return NULL;
|
||||
|
||||
return NODE_TO_POINTER (gtk_rb_node_get_first (tree->root));
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_get_last (GtkRbTree *tree)
|
||||
{
|
||||
if (tree->root == NULL)
|
||||
return NULL;
|
||||
|
||||
return NODE_TO_POINTER (gtk_rb_node_get_last (tree->root));
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_node_get_previous (gpointer node)
|
||||
{
|
||||
return NODE_TO_POINTER (gtk_rb_node_get_previous (NODE_FROM_POINTER (node)));
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_node_get_next (gpointer node)
|
||||
{
|
||||
return NODE_TO_POINTER (gtk_rb_node_get_next (NODE_FROM_POINTER (node)));
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_get_root (GtkRbTree *tree)
|
||||
{
|
||||
return NODE_TO_POINTER (tree->root);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_node_get_parent (gpointer node)
|
||||
{
|
||||
return NODE_TO_POINTER (parent (NODE_FROM_POINTER (node)));
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_node_get_left (gpointer node)
|
||||
{
|
||||
return NODE_TO_POINTER (NODE_FROM_POINTER (node)->left);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_node_get_right (gpointer node)
|
||||
{
|
||||
return NODE_TO_POINTER (NODE_FROM_POINTER (node)->right);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_get_augment (GtkRbTree *tree,
|
||||
gpointer node)
|
||||
{
|
||||
GtkRbNode *rbnode = NODE_FROM_POINTER (node);
|
||||
|
||||
gtk_rb_node_clean (tree, rbnode);
|
||||
|
||||
return NODE_TO_AUG_POINTER (tree, rbnode);
|
||||
}
|
||||
|
||||
GtkRbTree *
|
||||
gtk_rb_tree_node_get_tree (gpointer node)
|
||||
{
|
||||
return tree (NODE_FROM_POINTER (node));
|
||||
}
|
||||
|
||||
void
|
||||
gtk_rb_tree_node_mark_dirty (gpointer node)
|
||||
{
|
||||
gtk_rb_node_mark_dirty (NODE_FROM_POINTER (node), TRUE);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_insert_before (GtkRbTree *tree,
|
||||
gpointer node)
|
||||
{
|
||||
GtkRbNode *result;
|
||||
|
||||
|
||||
if (tree->root == NULL)
|
||||
{
|
||||
#ifdef DUMP_MODIFICATION
|
||||
g_print ("add (tree, 0); /* 0x%p */\n", tree);
|
||||
#endif /* DUMP_MODIFICATION */
|
||||
|
||||
g_assert (node == NULL);
|
||||
|
||||
result = gtk_rb_node_new (tree);
|
||||
tree->root = result;
|
||||
}
|
||||
else if (node == NULL)
|
||||
{
|
||||
return gtk_rb_tree_insert_after (tree, gtk_rb_tree_get_last (tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkRbNode *current = NODE_FROM_POINTER (node);
|
||||
|
||||
#ifdef DUMP_MODIFICATION
|
||||
g_print ("add (tree, %u); /* 0x%p */\n", position (tree, current), tree);
|
||||
#endif /* DUMP_MODIFICATION */
|
||||
|
||||
/* setup new node */
|
||||
result = gtk_rb_node_new (tree);
|
||||
|
||||
if (current->left)
|
||||
{
|
||||
current = gtk_rb_node_get_last (current->left);
|
||||
current->right = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
current->left = result;
|
||||
}
|
||||
set_parent (tree, result, current);
|
||||
gtk_rb_node_mark_dirty (current, TRUE);
|
||||
}
|
||||
|
||||
gtk_rb_tree_insert_fixup (tree, result);
|
||||
|
||||
return NODE_TO_POINTER (result);
|
||||
}
|
||||
|
||||
gpointer
|
||||
gtk_rb_tree_insert_after (GtkRbTree *tree,
|
||||
gpointer node)
|
||||
{
|
||||
GtkRbNode *current, *result;
|
||||
|
||||
if (node == NULL)
|
||||
return gtk_rb_tree_insert_before (tree, gtk_rb_tree_get_first (tree));
|
||||
|
||||
current = NODE_FROM_POINTER (node);
|
||||
|
||||
#ifdef DUMP_MODIFICATION
|
||||
g_print ("add (tree, %u); /* 0x%p */\n", position (tree, current) + 1, tree);
|
||||
#endif /* DUMP_MODIFICATION */
|
||||
|
||||
/* setup new node */
|
||||
result = gtk_rb_node_new (tree);
|
||||
|
||||
if (current->right)
|
||||
{
|
||||
current = gtk_rb_node_get_first (current->right);
|
||||
current->left = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
current->right = result;
|
||||
}
|
||||
set_parent (tree, result, current);
|
||||
gtk_rb_node_mark_dirty (current, TRUE);
|
||||
|
||||
gtk_rb_tree_insert_fixup (tree, result);
|
||||
|
||||
return NODE_TO_POINTER (result);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_rb_tree_remove (GtkRbTree *tree,
|
||||
gpointer node)
|
||||
{
|
||||
GtkRbNode *x, *y, *p, *real_node;
|
||||
|
||||
real_node = NODE_FROM_POINTER (node);
|
||||
|
||||
#ifdef DUMP_MODIFICATION
|
||||
g_print ("delete (tree, %u); /* 0x%p */\n", position (tree, real_node), tree);
|
||||
#endif /* DUMP_MODIFICATION */
|
||||
|
||||
y = real_node;
|
||||
if (y->left && y->right)
|
||||
{
|
||||
y = y->right;
|
||||
|
||||
while (y->left)
|
||||
y = y->left;
|
||||
}
|
||||
|
||||
/* x is y's only child, or nil */
|
||||
if (y->left)
|
||||
x = y->left;
|
||||
else
|
||||
x = y->right;
|
||||
|
||||
/* remove y from the parent chain */
|
||||
p = parent (y);
|
||||
if (x != NULL)
|
||||
set_parent (tree, x, p);
|
||||
if (p)
|
||||
{
|
||||
if (y == p->left)
|
||||
p->left = x;
|
||||
else
|
||||
p->right = x;
|
||||
gtk_rb_node_mark_dirty (p, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x == NULL)
|
||||
tree->root = NULL;
|
||||
}
|
||||
|
||||
/* We need to clean up the validity of the tree.
|
||||
*/
|
||||
if (is_black (y))
|
||||
gtk_rb_tree_remove_node_fixup (tree, x, p);
|
||||
|
||||
if (y != real_node)
|
||||
{
|
||||
/* Move the node over */
|
||||
if (is_red (real_node) != is_red (y))
|
||||
y->red = !y->red;
|
||||
|
||||
y->left = real_node->left;
|
||||
if (y->left)
|
||||
set_parent (tree, y->left, y);
|
||||
y->right = real_node->right;
|
||||
if (y->right)
|
||||
set_parent (tree, y->right, y);
|
||||
p = parent (real_node);
|
||||
set_parent (tree, y, p);
|
||||
if (p)
|
||||
{
|
||||
if (p->left == real_node)
|
||||
p->left = y;
|
||||
else
|
||||
p->right = y;
|
||||
gtk_rb_node_mark_dirty (p, TRUE);
|
||||
}
|
||||
gtk_rb_node_mark_dirty (y, TRUE);
|
||||
}
|
||||
|
||||
gtk_rb_node_free (tree, real_node);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_rb_tree_remove_all (GtkRbTree *tree)
|
||||
{
|
||||
#ifdef DUMP_MODIFICATION
|
||||
g_print ("delete_all (tree); /* 0x%p */\n", tree);
|
||||
#endif /* DUMP_MODIFICATION */
|
||||
|
||||
if (tree->root)
|
||||
gtk_rb_node_free_deep (tree, tree->root);
|
||||
|
||||
tree->root = NULL;
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* gtkrbtree.h
|
||||
* Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* A Red-Black Tree implementation used specifically by GtkTreeView.
|
||||
*/
|
||||
#ifndef __GTK_RB_TREE_H__
|
||||
#define __GTK_RB_TREE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
typedef struct _GtkRbTree GtkRbTree;
|
||||
|
||||
typedef void (* GtkRbTreeAugmentFunc) (GtkRbTree *tree,
|
||||
gpointer node_augment,
|
||||
gpointer node,
|
||||
gpointer left,
|
||||
gpointer right);
|
||||
|
||||
GtkRbTree * gtk_rb_tree_new_for_size (gsize element_size,
|
||||
gsize augment_size,
|
||||
GtkRbTreeAugmentFunc augment_func,
|
||||
GDestroyNotify clear_func,
|
||||
GDestroyNotify clear_augment_func);
|
||||
#define gtk_rb_tree_new(type, augment_type, augment_func, clear_func, clear_augment_func) \
|
||||
gtk_rb_tree_new_for_size (sizeof (type), sizeof (augment_type), (augment_func), (clear_func), (clear_augment_func))
|
||||
|
||||
GtkRbTree * gtk_rb_tree_ref (GtkRbTree *tree);
|
||||
void gtk_rb_tree_unref (GtkRbTree *tree);
|
||||
|
||||
gpointer gtk_rb_tree_get_root (GtkRbTree *tree);
|
||||
gpointer gtk_rb_tree_get_first (GtkRbTree *tree);
|
||||
gpointer gtk_rb_tree_get_last (GtkRbTree *tree);
|
||||
|
||||
gpointer gtk_rb_tree_node_get_previous (gpointer node);
|
||||
gpointer gtk_rb_tree_node_get_next (gpointer node);
|
||||
gpointer gtk_rb_tree_node_get_parent (gpointer node);
|
||||
gpointer gtk_rb_tree_node_get_left (gpointer node);
|
||||
gpointer gtk_rb_tree_node_get_right (gpointer node);
|
||||
GtkRbTree * gtk_rb_tree_node_get_tree (gpointer node);
|
||||
void gtk_rb_tree_node_mark_dirty (gpointer node);
|
||||
|
||||
gpointer gtk_rb_tree_get_augment (GtkRbTree *tree,
|
||||
gpointer node);
|
||||
|
||||
gpointer gtk_rb_tree_insert_before (GtkRbTree *tree,
|
||||
gpointer node);
|
||||
gpointer gtk_rb_tree_insert_after (GtkRbTree *tree,
|
||||
gpointer node);
|
||||
void gtk_rb_tree_remove (GtkRbTree *tree,
|
||||
gpointer node);
|
||||
void gtk_rb_tree_remove_all (GtkRbTree *tree);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
#endif /* __GTK_RB_TREE_H__ */
|
|
@ -1,529 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtkslicelistmodel.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkslicelistmodel
|
||||
* @title: GtkSliceListModel
|
||||
* @short_description: A list model that presents a slice out of a larger list
|
||||
* @see_also: #GListModel
|
||||
*
|
||||
* #GtkSliceListModel is a list model that takes a list model and presents a slice of
|
||||
* that model.
|
||||
*
|
||||
* This is useful when implementing paging by setting the size to the number of elements
|
||||
* per page and updating the offset whenever a different page is opened.
|
||||
*/
|
||||
|
||||
#define DEFAULT_SIZE 10
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
PROP_OFFSET,
|
||||
PROP_SIZE,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
struct _GtkSliceListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
guint offset;
|
||||
guint size;
|
||||
|
||||
guint n_items;
|
||||
};
|
||||
|
||||
struct _GtkSliceListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_slice_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_slice_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list);
|
||||
guint n_items;
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
/* XXX: This can be done without calling g_list_model_get_n_items() on the parent model
|
||||
* by checking if model.get_item(offset + size) != NULL */
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
if (n_items <= self->offset)
|
||||
return 0;
|
||||
|
||||
n_items -= self->offset;
|
||||
return MIN (n_items, self->size);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_slice_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
if (position >= self->size)
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (self->model, position + self->offset);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_slice_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_slice_list_model_get_n_items;
|
||||
iface->get_item = gtk_slice_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkSliceListModel, gtk_slice_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_slice_list_model_model_init))
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkSliceListModel *self)
|
||||
{
|
||||
if (position >= self->offset + self->size)
|
||||
return;
|
||||
|
||||
if (position < self->offset)
|
||||
{
|
||||
guint skip = MIN (removed, added);
|
||||
skip = MIN (skip, self->offset - position);
|
||||
|
||||
position += skip;
|
||||
removed -= skip;
|
||||
added -= skip;
|
||||
}
|
||||
|
||||
if (removed == added)
|
||||
{
|
||||
guint changed = removed;
|
||||
|
||||
if (changed == 0)
|
||||
return;
|
||||
|
||||
g_assert (position >= self->offset);
|
||||
position -= self->offset;
|
||||
changed = MIN (changed, self->size - position);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, changed, changed);
|
||||
}
|
||||
else
|
||||
{
|
||||
guint n_after, n_before;
|
||||
guint skip;
|
||||
|
||||
if (position > self->offset)
|
||||
skip = position - self->offset;
|
||||
else
|
||||
skip = 0;
|
||||
|
||||
n_after = g_list_model_get_n_items (self->model);
|
||||
n_before = n_after - added + removed;
|
||||
n_after = CLAMP (n_after, self->offset, self->offset + self->size) - self->offset;
|
||||
n_before = CLAMP (n_before, self->offset, self->offset + self->size) - self->offset;
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), skip, n_before - skip, n_after - skip);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_slice_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
gtk_slice_list_model_set_offset (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
gtk_slice_list_model_set_size (self, g_value_get_uint (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_OFFSET:
|
||||
g_value_set_uint (value, self->offset);
|
||||
break;
|
||||
|
||||
case PROP_SIZE:
|
||||
g_value_set_uint (value, self->size);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_clear_model (GtkSliceListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_slice_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (object);
|
||||
|
||||
gtk_slice_list_model_clear_model (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_slice_list_model_parent_class)->dispose (object);
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_class_init (GtkSliceListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_slice_list_model_set_property;
|
||||
gobject_class->get_property = gtk_slice_list_model_get_property;
|
||||
gobject_class->dispose = gtk_slice_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:model:
|
||||
*
|
||||
* Child model to take slice from
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("Child model to take slice from"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:offset:
|
||||
*
|
||||
* Offset of slice
|
||||
*/
|
||||
properties[PROP_OFFSET] =
|
||||
g_param_spec_uint ("offset",
|
||||
P_("Offset"),
|
||||
P_("Offset of slice"),
|
||||
0, G_MAXUINT, 0,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:size:
|
||||
*
|
||||
* Maximum size of slice
|
||||
*/
|
||||
properties[PROP_SIZE] =
|
||||
g_param_spec_uint ("size",
|
||||
P_("Size"),
|
||||
P_("Maximum size of slice"),
|
||||
0, G_MAXUINT, DEFAULT_SIZE,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_slice_list_model_init (GtkSliceListModel *self)
|
||||
{
|
||||
self->size = DEFAULT_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_new:
|
||||
* @model: (transfer none): The model to use
|
||||
* @offset: the offset of the slice
|
||||
* @size: maximum size of the slice
|
||||
*
|
||||
* Creates a new slice model that presents the slice from @offset to
|
||||
* @offset + @size our of the given @model.
|
||||
*
|
||||
* Returns: A new #GtkSliceListModel
|
||||
**/
|
||||
GtkSliceListModel *
|
||||
gtk_slice_list_model_new (GListModel *model,
|
||||
guint offset,
|
||||
guint size)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SLICE_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"offset", offset,
|
||||
"size", size,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_new_for_type:
|
||||
* @item_type: the type of items
|
||||
*
|
||||
* Creates a new empty #GtkSliceListModel for the given @item_type that
|
||||
* can be set up later.
|
||||
*
|
||||
* Returns: a new empty #GtkSliceListModel
|
||||
**/
|
||||
GtkSliceListModel *
|
||||
gtk_slice_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SLICE_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_set_model:
|
||||
* @self: a #GtkSliceListModel
|
||||
* @model: (allow-none): The model to be sliced
|
||||
*
|
||||
* Sets the model to show a slice of. The model's item type must conform
|
||||
* to @self's item type.
|
||||
*
|
||||
**/
|
||||
void
|
||||
gtk_slice_list_model_set_model (GtkSliceListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added;
|
||||
|
||||
g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_slice_list_model_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_slice_list_model_items_changed_cb), self);
|
||||
added = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
}
|
||||
else
|
||||
{
|
||||
added = 0;
|
||||
}
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_get_model:
|
||||
* @self: a #GtkSliceListModel
|
||||
*
|
||||
* Gets the model that is curently being used or %NULL if none.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model in use
|
||||
**/
|
||||
GListModel *
|
||||
gtk_slice_list_model_get_model (GtkSliceListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_set_offset:
|
||||
* @self: a #GtkSliceListModel
|
||||
* @offset: the new offset to use
|
||||
*
|
||||
* Sets the offset into the original model for this slice.
|
||||
*
|
||||
* If the offset is too large for the sliced model,
|
||||
* @self will end up empty.
|
||||
**/
|
||||
void
|
||||
gtk_slice_list_model_set_offset (GtkSliceListModel *self,
|
||||
guint offset)
|
||||
{
|
||||
guint before, after;
|
||||
|
||||
g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self));
|
||||
|
||||
if (self->offset == offset)
|
||||
return;
|
||||
|
||||
before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
|
||||
self->offset = offset;
|
||||
|
||||
after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
|
||||
if (before > 0 || after > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, before, after);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_OFFSET]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_get_offset:
|
||||
* @self: a #GtkSliceListModel
|
||||
*
|
||||
* Gets the offset set via gtk_slice_list_model_set_offset()
|
||||
*
|
||||
* Returns: The offset
|
||||
**/
|
||||
guint
|
||||
gtk_slice_list_model_get_offset (GtkSliceListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), 0);
|
||||
|
||||
return self->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_set_size:
|
||||
* @self: a #GtkSliceListModel
|
||||
* @size: the maximum size
|
||||
*
|
||||
* Sets the maximum size. @self will never have more items
|
||||
* than @size.
|
||||
*
|
||||
* It can however have fewer items if the offset is too large or
|
||||
* the model sliced from doesn't have enough items.
|
||||
*/
|
||||
void
|
||||
gtk_slice_list_model_set_size (GtkSliceListModel *self,
|
||||
guint size)
|
||||
{
|
||||
guint before, after;
|
||||
|
||||
g_return_if_fail (GTK_IS_SLICE_LIST_MODEL (self));
|
||||
|
||||
if (self->size == size)
|
||||
return;
|
||||
|
||||
before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
|
||||
self->size = size;
|
||||
|
||||
after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
|
||||
if (before > after)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), after, before - after, 0);
|
||||
else if (before < after)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), before, 0, after - before);
|
||||
/* else nothing */
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIZE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_get_size:
|
||||
* @self: a #GtkSliceListModel
|
||||
*
|
||||
* Gets the size set via gtk_slice_list_model_set_size().
|
||||
*
|
||||
* Returns: The size
|
||||
**/
|
||||
guint
|
||||
gtk_slice_list_model_get_size (GtkSliceListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SLICE_LIST_MODEL (self), DEFAULT_SIZE);
|
||||
|
||||
return self->size;
|
||||
}
|
||||
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SLICE_LIST_MODEL_H__
|
||||
#define __GTK_SLICE_LIST_MODEL_H__
|
||||
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SLICE_LIST_MODEL (gtk_slice_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkSliceListModel, gtk_slice_list_model, GTK, SLICE_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSliceListModel * gtk_slice_list_model_new (GListModel *model,
|
||||
guint offset,
|
||||
guint size);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSliceListModel * gtk_slice_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_slice_list_model_set_model (GtkSliceListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_slice_list_model_get_model (GtkSliceListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_slice_list_model_set_offset (GtkSliceListModel *self,
|
||||
guint offset);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_slice_list_model_get_offset (GtkSliceListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_slice_list_model_set_size (GtkSliceListModel *self,
|
||||
guint size);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_slice_list_model_get_size (GtkSliceListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SLICE_LIST_MODEL_H__ */
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtksorter.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtksorter
|
||||
* @title: GtkSorter
|
||||
* @Short_description: Sorting items
|
||||
* @See_also: #GtkSortListModel
|
||||
*
|
||||
* #GtkSorter is the way to describe sorting criteria.
|
||||
* Its primary user is #GtkSortListModel.
|
||||
*
|
||||
* The model will use a sorter to determine the order in which its items should appear
|
||||
* by calling gtk_sorter_compare() for pairs of items.
|
||||
*
|
||||
* Sorters may change their sorting behavior through their lifetime. In that case,
|
||||
* they call gtk_sorter_changed(), which will emit the #GtkSorter::changed signal to
|
||||
* notify that the sort order is no longer valid and should be updated by calling
|
||||
* gtk_sorter_compare() again.
|
||||
*
|
||||
* GTK provides various pre-made sorter implementations for common sorting operations.
|
||||
* #GtkColumnView has built-in support for sorting lists via the #GtkColumnViewColumn:sorter
|
||||
* property, where the user can change the sorting by clicking on list headers.
|
||||
*
|
||||
* Of course, in particular for large lists, it is also possible to subclass #GtkSorter
|
||||
* and provide one's own sorter.
|
||||
*/
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkSorter, gtk_sorter, G_TYPE_OBJECT)
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GtkOrdering
|
||||
gtk_sorter_default_compare (GtkSorter *self,
|
||||
gpointer item1,
|
||||
gpointer item2)
|
||||
{
|
||||
g_critical ("Sorter of type '%s' does not implement GtkSorter::compare", G_OBJECT_TYPE_NAME (self));
|
||||
|
||||
return GTK_ORDERING_EQUAL;
|
||||
}
|
||||
|
||||
static GtkSorterOrder
|
||||
gtk_sorter_default_get_order (GtkSorter *self)
|
||||
{
|
||||
return GTK_SORTER_ORDER_PARTIAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sorter_class_init (GtkSorterClass *class)
|
||||
{
|
||||
class->compare = gtk_sorter_default_compare;
|
||||
class->get_order = gtk_sorter_default_get_order;
|
||||
|
||||
/**
|
||||
* GtkSorter::changed:
|
||||
* @self: The #GtkSorter
|
||||
* @change: how the sorter changed
|
||||
*
|
||||
* This signal is emitted whenever the sorter changed. Users of the sorter
|
||||
* should then update the sort order again via gtk_sorter_compare().
|
||||
*
|
||||
* #GtkSortListModel handles this signal automatically.
|
||||
*
|
||||
* Depending on the @change parameter, it may be possible to update
|
||||
* the sort order without a full resorting. Refer to the #GtkSorterChange
|
||||
* documentation for details.
|
||||
*/
|
||||
signals[CHANGED] =
|
||||
g_signal_new (I_("changed"),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__ENUM,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_SORTER_CHANGE);
|
||||
g_signal_set_va_marshaller (signals[CHANGED],
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
g_cclosure_marshal_VOID__ENUMv);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sorter_init (GtkSorter *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sorter_compare:
|
||||
* @self: a #GtkSorter
|
||||
* @item1: (type GObject) (transfer none): first item to compare
|
||||
* @item2: (type GObject) (transfer none): second item to compare
|
||||
*
|
||||
* Compares two given items according to the sort order implemented
|
||||
* by the sorter.
|
||||
*
|
||||
* Sorters implement a partial order:
|
||||
* * It is reflexive, ie a = a
|
||||
* * It is antisymmetric, ie if a < b and b < a, then a = b
|
||||
* * It is transitive, ie given any 3 items with a ≤ b and b ≤ c,
|
||||
* then a ≤ c
|
||||
*
|
||||
* The sorter may signal it conforms to additional constraints
|
||||
* via the return value of gtk_sorter_get_order().
|
||||
*
|
||||
* Returns: %GTK_ORDERING_EQUAL if @item1 == @item2,
|
||||
* %GTK_ORDERING_SMALLER if @item1 < @item2,
|
||||
* %GTK_ORDERING_LARGER if @item1 > @item2
|
||||
*/
|
||||
GtkOrdering
|
||||
gtk_sorter_compare (GtkSorter *self,
|
||||
gpointer item1,
|
||||
gpointer item2)
|
||||
{
|
||||
GtkOrdering result;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SORTER (self), GTK_ORDERING_EQUAL);
|
||||
g_return_val_if_fail (item1 && item2, GTK_ORDERING_EQUAL);
|
||||
|
||||
if (item1 == item2)
|
||||
return GTK_ORDERING_EQUAL;
|
||||
|
||||
result = GTK_SORTER_GET_CLASS (self)->compare (self, item1, item2);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (result < -1 || result > 1)
|
||||
{
|
||||
g_critical ("A sorter of type \"%s\" returned %d, which is not a valid GtkOrdering result.\n"
|
||||
"Did you forget to call gtk_ordering_from_cmpfunc()?",
|
||||
G_OBJECT_TYPE_NAME (self), (int) result);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sorter_get_order:
|
||||
* @self: a #GtkSorter
|
||||
*
|
||||
* Gets the order that @self conforms to. See #GtkSorterOrder for details
|
||||
* of the possible return values.
|
||||
*
|
||||
* This function is intended to allow optimizations.
|
||||
*
|
||||
* Returns: The order
|
||||
**/
|
||||
GtkSorterOrder
|
||||
gtk_sorter_get_order (GtkSorter *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SORTER (self), GTK_SORTER_ORDER_PARTIAL);
|
||||
|
||||
return GTK_SORTER_GET_CLASS (self)->get_order (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sorter_changed:
|
||||
* @self: a #GtkSorter
|
||||
* @change: How the sorter changed
|
||||
*
|
||||
* Emits the #GtkSorter::changed signal to notify all users of the sorter
|
||||
* that it has changed. Users of the sorter should then update the sort
|
||||
* order via gtk_sorter_compare().
|
||||
*
|
||||
* Depending on the @change parameter, it may be possible to update
|
||||
* the sort order without a full resorting. Refer to the #GtkSorterChange
|
||||
* documentation for details.
|
||||
*
|
||||
* This function is intended for implementors of #GtkSorter subclasses and
|
||||
* should not be called from other functions.
|
||||
*/
|
||||
void
|
||||
gtk_sorter_changed (GtkSorter *self,
|
||||
GtkSorterChange change)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_SORTER (self));
|
||||
|
||||
g_signal_emit (self, signals[CHANGED], 0, change);
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2019 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SORTER_H__
|
||||
#define __GTK_SORTER_H__
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GtkSorterOrder:
|
||||
* @GTK_SORTER_ORDER_PARTIAL: A partial order. And #GtkOrdering is possible.
|
||||
* @GTK_SORTER_ORDER_INVALID: An invalid order. gtk_sorter_compare() will
|
||||
* always return %GTK_ORDERING_INVALID if both items are unequal.
|
||||
* @GTK_SORTER_ORDER_NONE: No order, all elements are considered equal.
|
||||
* gtk_sorter_compare() will only return %GTK_ORDERING_EQUAL or
|
||||
* %GTK_ORDERING_INVALID.
|
||||
* @GTK_SORTER_ORDER_TOTAL: A total order. gtk_sorter_compare() will only
|
||||
* return %GTK_ORDERING_EQUAL if an item is compared with itself. Two
|
||||
* different items will never cause this value to be returned.
|
||||
*
|
||||
* Describes the type of order that a #GtkSorter may describe.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_SORTER_ORDER_PARTIAL,
|
||||
GTK_SORTER_ORDER_NONE,
|
||||
GTK_SORTER_ORDER_TOTAL
|
||||
} GtkSorterOrder;
|
||||
|
||||
typedef enum {
|
||||
GTK_ORDERING_SMALLER = -1,
|
||||
GTK_ORDERING_EQUAL = 0,
|
||||
GTK_ORDERING_LARGER = 1
|
||||
} GtkOrdering;
|
||||
|
||||
/**
|
||||
* GtkSorterChange:
|
||||
* @GTK_SORTER_CHANGE_DIFFERENT: The sorter change cannot be described
|
||||
* by any of the other enumeration values
|
||||
* @GTK_SORTER_CHANGE_INVERTED: The sort order was inverted. Comparisons
|
||||
* that returned %GTK_ORDERING_SMALLER now return %GTK_ORDERING_LARGER
|
||||
* and vice versa. Other comparisons return the same values as before.
|
||||
* @GTK_SORTER_CHANGE_LESS_STRICT: The sorter is less strict: Comparisons
|
||||
* may now return %GTK_ORDERING_EQUAL that did not do so before.
|
||||
* @GTK_SORTER_CHANGE_MORE_STRICT: The sorter is more strict: Comparisons
|
||||
* that did return %GTK_ORDERING_EQUAL may not do so anymore.
|
||||
*
|
||||
* Describes changes in a sorter in more detail and allows users
|
||||
* to optimize resorting.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_SORTER_CHANGE_DIFFERENT,
|
||||
GTK_SORTER_CHANGE_INVERTED,
|
||||
GTK_SORTER_CHANGE_LESS_STRICT,
|
||||
GTK_SORTER_CHANGE_MORE_STRICT
|
||||
} GtkSorterChange;
|
||||
|
||||
#define GTK_TYPE_SORTER (gtk_sorter_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_DERIVABLE_TYPE (GtkSorter, gtk_sorter, GTK, SORTER, GObject)
|
||||
|
||||
/**
|
||||
* GtkSorterClass
|
||||
* @compare: Compare two items. See gtk_sorter_compare() for details.
|
||||
* @get_order: Get the #GtkSorderOrder that applies to the current sorter.
|
||||
* If unimplemented, it returns %GTK_SORTER_ORDER_PARTIAL.
|
||||
*
|
||||
* The virtual table for #GtkSorter.
|
||||
*/
|
||||
struct _GtkSorterClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
GtkOrdering (* compare) (GtkSorter *self,
|
||||
gpointer item1,
|
||||
gpointer item2);
|
||||
|
||||
/* optional */
|
||||
GtkSorterOrder (* get_order) (GtkSorter *self);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_gtk_reserved1) (void);
|
||||
void (*_gtk_reserved2) (void);
|
||||
void (*_gtk_reserved3) (void);
|
||||
void (*_gtk_reserved4) (void);
|
||||
void (*_gtk_reserved5) (void);
|
||||
void (*_gtk_reserved6) (void);
|
||||
void (*_gtk_reserved7) (void);
|
||||
void (*_gtk_reserved8) (void);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkOrdering gtk_sorter_compare (GtkSorter *self,
|
||||
gpointer item1,
|
||||
gpointer item2);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorterOrder gtk_sorter_get_order (GtkSorter *self);
|
||||
|
||||
/* for sorter implementations */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sorter_changed (GtkSorter *self,
|
||||
GtkSorterChange change);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SORTER_H__ */
|
||||
|
|
@ -1,595 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
/* #include "calls-config.h" */
|
||||
|
||||
#include "gtksortlistmodel.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtksortlistmodel
|
||||
* @title: GtkSortListModel
|
||||
* @short_description: A list model that sorts its items
|
||||
* @see_also: #GListModel, #GtkSorter
|
||||
*
|
||||
* #GtkSortListModel is a list model that takes a list model and
|
||||
* sorts its elements according to a #GtkSorter.
|
||||
*
|
||||
* #GtkSortListModel is a generic model and because of that it
|
||||
* cannot take advantage of any external knowledge when sorting.
|
||||
* If you run into performance issues with #GtkSortListModel, it
|
||||
* is strongly recommended that you write your own sorting list
|
||||
* model.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
PROP_SORTER,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
typedef struct _GtkSortListEntry GtkSortListEntry;
|
||||
|
||||
struct _GtkSortListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkSorter *sorter;
|
||||
|
||||
GSequence *sorted; /* NULL if known unsorted */
|
||||
GSequence *unsorted; /* NULL if known unsorted */
|
||||
};
|
||||
|
||||
struct _GtkSortListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _GtkSortListEntry
|
||||
{
|
||||
GSequenceIter *sorted_iter;
|
||||
GSequenceIter *unsorted_iter;
|
||||
gpointer item; /* holds ref */
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static void
|
||||
gtk_sort_list_entry_free (gpointer data)
|
||||
{
|
||||
GtkSortListEntry *entry = data;
|
||||
|
||||
g_object_unref (entry->item);
|
||||
|
||||
g_slice_free (GtkSortListEntry, entry);
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_sort_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_sort_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_sort_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (list);
|
||||
GSequenceIter *iter;
|
||||
GtkSortListEntry *entry;
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
if (self->unsorted == NULL)
|
||||
return g_list_model_get_item (self->model, position);
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->sorted, position);
|
||||
if (g_sequence_iter_is_end (iter))
|
||||
return NULL;
|
||||
|
||||
entry = g_sequence_get (iter);
|
||||
|
||||
return g_object_ref (entry->item);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_sort_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_sort_list_model_get_n_items;
|
||||
iface->get_item = gtk_sort_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkSortListModel, gtk_sort_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_sort_list_model_model_init))
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_remove_items (GtkSortListModel *self,
|
||||
guint position,
|
||||
guint n_items,
|
||||
guint *unmodified_start,
|
||||
guint *unmodified_end)
|
||||
{
|
||||
GSequenceIter *unsorted_iter;
|
||||
guint i, pos, start, end, length_before;
|
||||
|
||||
start = end = length_before = g_sequence_get_length (self->sorted);
|
||||
unsorted_iter = g_sequence_get_iter_at_pos (self->unsorted, position);
|
||||
|
||||
for (i = 0; i < n_items ; i++)
|
||||
{
|
||||
GtkSortListEntry *entry;
|
||||
GSequenceIter *next;
|
||||
|
||||
next = g_sequence_iter_next (unsorted_iter);
|
||||
|
||||
entry = g_sequence_get (unsorted_iter);
|
||||
pos = g_sequence_iter_get_position (entry->sorted_iter);
|
||||
start = MIN (start, pos);
|
||||
end = MIN (end, length_before - i - 1 - pos);
|
||||
|
||||
g_sequence_remove (entry->unsorted_iter);
|
||||
g_sequence_remove (entry->sorted_iter);
|
||||
|
||||
unsorted_iter = next;
|
||||
}
|
||||
|
||||
*unmodified_start = start;
|
||||
*unmodified_end = end;
|
||||
}
|
||||
|
||||
static int
|
||||
_sort_func (gconstpointer item1,
|
||||
gconstpointer item2,
|
||||
gpointer data)
|
||||
{
|
||||
GtkSortListEntry *entry1 = (GtkSortListEntry *) item1;
|
||||
GtkSortListEntry *entry2 = (GtkSortListEntry *) item2;
|
||||
GtkOrdering result;
|
||||
|
||||
result = gtk_sorter_compare (GTK_SORTER (data), entry1->item, entry2->item);
|
||||
|
||||
if (result == GTK_ORDERING_EQUAL)
|
||||
result = g_sequence_iter_compare (entry1->unsorted_iter, entry2->unsorted_iter);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_add_items (GtkSortListModel *self,
|
||||
guint position,
|
||||
guint n_items,
|
||||
guint *unmodified_start,
|
||||
guint *unmodified_end)
|
||||
{
|
||||
GSequenceIter *unsorted_end;
|
||||
guint i, pos, start, end, length_before;
|
||||
|
||||
unsorted_end = g_sequence_get_iter_at_pos (self->unsorted, position);
|
||||
start = end = length_before = g_sequence_get_length (self->sorted);
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
GtkSortListEntry *entry = g_slice_new0 (GtkSortListEntry);
|
||||
|
||||
entry->item = g_list_model_get_item (self->model, position + i);
|
||||
entry->unsorted_iter = g_sequence_insert_before (unsorted_end, entry);
|
||||
entry->sorted_iter = g_sequence_insert_sorted (self->sorted, entry, _sort_func, self->sorter);
|
||||
if (unmodified_start != NULL || unmodified_end != NULL)
|
||||
{
|
||||
pos = g_sequence_iter_get_position (entry->sorted_iter);
|
||||
start = MIN (start, pos);
|
||||
end = MIN (end, length_before + i - pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (unmodified_start)
|
||||
*unmodified_start = start;
|
||||
if (unmodified_end)
|
||||
*unmodified_end = end;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkSortListModel *self)
|
||||
{
|
||||
guint n_items, start, end, start2, end2;
|
||||
|
||||
if (removed == 0 && added == 0)
|
||||
return;
|
||||
|
||||
if (self->sorted == NULL)
|
||||
{
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_sort_list_model_remove_items (self, position, removed, &start, &end);
|
||||
gtk_sort_list_model_add_items (self, position, added, &start2, &end2);
|
||||
start = MIN (start, start2);
|
||||
end = MIN (end, end2);
|
||||
|
||||
n_items = g_sequence_get_length (self->sorted) - start - end;
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_items - added + removed, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_sort_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
gtk_sort_list_model_set_sorter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
g_value_set_object (value, self->sorter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gtk_sort_list_model_resort (GtkSortListModel *self);
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_sorter_changed_cb (GtkSorter *sorter,
|
||||
int change,
|
||||
GtkSortListModel *self)
|
||||
{
|
||||
gtk_sort_list_model_resort (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_clear_model (GtkSortListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_sort_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
g_clear_pointer (&self->sorted, g_sequence_free);
|
||||
g_clear_pointer (&self->unsorted, g_sequence_free);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_clear_sorter (GtkSortListModel *self)
|
||||
{
|
||||
if (self->sorter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->sorter, gtk_sort_list_model_sorter_changed_cb, self);
|
||||
g_clear_object (&self->sorter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (object);
|
||||
|
||||
gtk_sort_list_model_clear_model (self);
|
||||
gtk_sort_list_model_clear_sorter (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_sort_list_model_parent_class)->dispose (object);
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_class_init (GtkSortListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_sort_list_model_set_property;
|
||||
gobject_class->get_property = gtk_sort_list_model_get_property;
|
||||
gobject_class->dispose = gtk_sort_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSortListModel:sorter:
|
||||
*
|
||||
* The sorter for this model
|
||||
*/
|
||||
properties[PROP_SORTER] =
|
||||
g_param_spec_object ("sorter",
|
||||
P_("Sorter"),
|
||||
P_("The sorter for this model"),
|
||||
GTK_TYPE_SORTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSortListModel:item-type:
|
||||
*
|
||||
* The #GType for items of this model
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of items of this list"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSortListModel:model:
|
||||
*
|
||||
* The model being sorted
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("The model being sorted"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_init (GtkSortListModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_new:
|
||||
* @model: the model to sort
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Creates a new sort list model that uses the @sorter to sort @model.
|
||||
*
|
||||
* Returns: a new #GtkSortListModel
|
||||
**/
|
||||
GtkSortListModel *
|
||||
gtk_sort_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
GtkSortListModel *result;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (sorter == NULL || GTK_IS_SORTER (sorter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_SORT_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"sorter", sorter,
|
||||
NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_new_for_type:
|
||||
* @item_type: the type of the items that will be returned
|
||||
*
|
||||
* Creates a new empty sort list model set up to return items of type @item_type.
|
||||
* It is up to the application to set a proper sort function and model to ensure
|
||||
* the item type is matched.
|
||||
*
|
||||
* Returns: a new #GtkSortListModel
|
||||
**/
|
||||
GtkSortListModel *
|
||||
gtk_sort_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SORT_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_create_sequences (GtkSortListModel *self)
|
||||
{
|
||||
if (self->sorter == NULL || self->model == NULL)
|
||||
return;
|
||||
|
||||
self->sorted = g_sequence_new (gtk_sort_list_entry_free);
|
||||
self->unsorted = g_sequence_new (NULL);
|
||||
|
||||
gtk_sort_list_model_add_items (self, 0, g_list_model_get_n_items (self->model), NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_set_model:
|
||||
* @self: a #GtkSortListModel
|
||||
* @model: (allow-none): The model to be sorted
|
||||
*
|
||||
* Sets the model to be sorted. The @model's item type must conform to
|
||||
* the item type of @self.
|
||||
**/
|
||||
void
|
||||
gtk_sort_list_model_set_model (GtkSortListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added;
|
||||
|
||||
g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
if (model)
|
||||
{
|
||||
g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), self->item_type));
|
||||
}
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_sort_list_model_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_sort_list_model_items_changed_cb), self);
|
||||
added = g_list_model_get_n_items (model);
|
||||
|
||||
gtk_sort_list_model_create_sequences (self);
|
||||
}
|
||||
else
|
||||
added = 0;
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_get_model:
|
||||
* @self: a #GtkSortListModel
|
||||
*
|
||||
* Gets the model currently sorted or %NULL if none.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model that gets sorted
|
||||
**/
|
||||
GListModel *
|
||||
gtk_sort_list_model_get_model (GtkSortListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sort_list_model_resort (GtkSortListModel *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self));
|
||||
|
||||
if (self->sorted == NULL)
|
||||
return;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
if (n_items <= 1)
|
||||
return;
|
||||
|
||||
g_sequence_sort (self->sorted, _sort_func, self->sorter);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_set_sorter:
|
||||
* @self: a #GtkSortListModel
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Sets a new sorter on @self.
|
||||
*/
|
||||
void
|
||||
gtk_sort_list_model_set_sorter (GtkSortListModel *self,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self));
|
||||
g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
|
||||
|
||||
gtk_sort_list_model_clear_sorter (self);
|
||||
|
||||
if (sorter)
|
||||
{
|
||||
self->sorter = g_object_ref (sorter);
|
||||
g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sort_list_model_sorter_changed_cb), self);
|
||||
}
|
||||
|
||||
g_clear_pointer (&self->unsorted, g_sequence_free);
|
||||
g_clear_pointer (&self->sorted, g_sequence_free);
|
||||
|
||||
gtk_sort_list_model_create_sequences (self);
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
if (n_items > 1)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_get_sorter:
|
||||
* @self: a #GtkSortLisTModel
|
||||
*
|
||||
* Gets the sorter that is used to sort @self.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the sorter of #self
|
||||
*/
|
||||
GtkSorter *
|
||||
gtk_sort_list_model_get_sorter (GtkSortListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SORT_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->sorter;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SORT_LIST_MODEL_H__
|
||||
#define __GTK_SORT_LIST_MODEL_H__
|
||||
|
||||
|
||||
#define GTK_COMPILATION
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include "gtksorter.h"
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SORT_LIST_MODEL (gtk_sort_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkSortListModel, gtk_sort_list_model, GTK, SORT_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSortListModel * gtk_sort_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSortListModel * gtk_sort_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sort_list_model_set_sorter (GtkSortListModel *self,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_sort_list_model_get_sorter (GtkSortListModel *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sort_list_model_set_model (GtkSortListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_sort_list_model_get_model (GtkSortListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SORT_LIST_MODEL_H__ */
|
|
@ -1,89 +0,0 @@
|
|||
#include <gtk/gtk.h>
|
||||
#include "gtkprivate.h"
|
||||
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/* enumerations from "gtksorter.h" */
|
||||
GType
|
||||
gtk_sorter_order_get_type (void)
|
||||
{
|
||||
static gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const GEnumValue values[] = {
|
||||
{ GTK_SORTER_ORDER_PARTIAL, "GTK_SORTER_ORDER_PARTIAL", "partial" },
|
||||
{ GTK_SORTER_ORDER_NONE, "GTK_SORTER_ORDER_NONE", "none" },
|
||||
{ GTK_SORTER_ORDER_TOTAL, "GTK_SORTER_ORDER_TOTAL", "total" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_enum_register_static (g_intern_static_string ("GtkSorterOrder"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
GType
|
||||
gtk_sorter_change_get_type (void)
|
||||
{
|
||||
static gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const GEnumValue values[] = {
|
||||
{ GTK_SORTER_CHANGE_DIFFERENT, "GTK_SORTER_CHANGE_DIFFERENT", "different" },
|
||||
{ GTK_SORTER_CHANGE_INVERTED, "GTK_SORTER_CHANGE_INVERTED", "inverted" },
|
||||
{ GTK_SORTER_CHANGE_LESS_STRICT, "GTK_SORTER_CHANGE_LESS_STRICT", "less-strict" },
|
||||
{ GTK_SORTER_CHANGE_MORE_STRICT, "GTK_SORTER_CHANGE_MORE_STRICT", "more-strict" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_enum_register_static (g_intern_static_string ("GtkSorterChange"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
|
||||
/* enumerations from "gtkfilter.h" */
|
||||
GType
|
||||
gtk_filter_match_get_type (void)
|
||||
{
|
||||
static gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const GEnumValue values[] = {
|
||||
{ GTK_FILTER_MATCH_SOME, "GTK_FILTER_MATCH_SOME", "some" },
|
||||
{ GTK_FILTER_MATCH_NONE, "GTK_FILTER_MATCH_NONE", "none" },
|
||||
{ GTK_FILTER_MATCH_ALL, "GTK_FILTER_MATCH_ALL", "all" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_enum_register_static (g_intern_static_string ("GtkFilterMatch"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
GType
|
||||
gtk_filter_change_get_type (void)
|
||||
{
|
||||
static gsize g_define_type_id__volatile = 0;
|
||||
|
||||
if (g_once_init_enter (&g_define_type_id__volatile))
|
||||
{
|
||||
static const GEnumValue values[] = {
|
||||
{ GTK_FILTER_CHANGE_DIFFERENT, "GTK_FILTER_CHANGE_DIFFERENT", "different" },
|
||||
{ GTK_FILTER_CHANGE_LESS_STRICT, "GTK_FILTER_CHANGE_LESS_STRICT", "less-strict" },
|
||||
{ GTK_FILTER_CHANGE_MORE_STRICT, "GTK_FILTER_CHANGE_MORE_STRICT", "more-strict" },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType g_define_type_id =
|
||||
g_enum_register_static (g_intern_static_string ("GtkFilterChange"), values);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
|
||||
return g_define_type_id__volatile;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
#include <glib-object.h>
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
#include "gtksorter.h"
|
||||
#include "gtkfilter.h"
|
||||
|
||||
/* enumerations from "gtksorter.h" */
|
||||
GDK_AVAILABLE_IN_ALL GType gtk_sorter_order_get_type (void) G_GNUC_CONST;
|
||||
#define GTK_TYPE_SORTER_ORDER (gtk_sorter_order_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL GType gtk_sorter_change_get_type (void) G_GNUC_CONST;
|
||||
#define GTK_TYPE_SORTER_CHANGE (gtk_sorter_change_get_type ())
|
||||
|
||||
/* enumerations from "gtkfilter.h" */
|
||||
GDK_AVAILABLE_IN_ALL GType gtk_filter_match_get_type (void) G_GNUC_CONST;
|
||||
#define GTK_TYPE_FILTER_MATCH (gtk_filter_match_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL GType gtk_filter_change_get_type (void) G_GNUC_CONST;
|
||||
#define GTK_TYPE_FILTER_CHANGE (gtk_filter_change_get_type ())
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2022 Purism SPC
|
||||
#
|
||||
# This file is part of Calls.
|
||||
#
|
||||
# Calls is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Calls is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
|
||||
gtklistmodel_sources = files([
|
||||
'gtkmodels.h',
|
||||
'gtkcustomfilter.c', 'gtkcustomfilter.h',
|
||||
'gtkcustomsorter.c', 'gtkcustomsorter.h',
|
||||
'gtkfilter.c', 'gtkfilter.h',
|
||||
'gtkfilterlistmodel.c', 'gtkfilterlistmodel.h',
|
||||
'gtkflattenlistmodel.c', 'gtkflattenlistmodel.h',
|
||||
'gtkintl.h',
|
||||
'gtkprivate.h',
|
||||
'gtkrbtree.c',
|
||||
'gtkrbtreeprivate.h',
|
||||
'gtkslicelistmodel.c', 'gtkslicelistmodel.h',
|
||||
'gtksorter.c', 'gtksorter.h',
|
||||
'gtksortlistmodel.c', 'gtksortlistmodel.h',
|
||||
'gtktypebuiltins.c', 'gtktypebuiltins.h',
|
||||
])
|
|
@ -26,7 +26,7 @@ gnome = import('gnome')
|
|||
|
||||
subdir('dbus')
|
||||
|
||||
src_include = include_directories('.', 'gtklistmodels')
|
||||
src_include = include_directories('.')
|
||||
calls_includes = [ top_include, src_include ]
|
||||
|
||||
calls_deps = [ dependency('gobject-2.0', version: '>= 2.58'),
|
||||
|
@ -86,8 +86,6 @@ calls_generated_sources = [
|
|||
generated_dbus_sources,
|
||||
]
|
||||
|
||||
subdir('gtklistmodels')
|
||||
|
||||
calls_sources = files([
|
||||
'calls-account.c', 'calls-account.h',
|
||||
'calls-account-overview.c', 'calls-account-overview.h',
|
||||
|
@ -126,7 +124,7 @@ calls_sources = files([
|
|||
'calls-ui-call-data.c', 'calls-ui-call-data.h',
|
||||
'calls-ussd.c', 'calls-ussd.h',
|
||||
'calls-util.c', 'calls-util.h',
|
||||
]) + calls_generated_sources + gtklistmodel_sources
|
||||
]) + calls_generated_sources
|
||||
|
||||
calls_config_data = config_data
|
||||
|
||||
|
|
Loading…
Reference in a new issue