mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 05:50:10 +00:00
Add GtkStringSorter
This is a GtkSorter implementation collating strings
This commit is contained in:
parent
e74a9d09e6
commit
6d68c536f3
@ -63,6 +63,7 @@
|
||||
<section>
|
||||
<xi:include href="xml/gtksorter.xml" />
|
||||
<xi:include href="xml/gtkcustomsorter.xml" />
|
||||
<xi:include href="xml/gtkstringsorter.xml" />
|
||||
</section>
|
||||
<xi:include href="xml/gtkselectionmodel.xml" />
|
||||
<xi:include href="xml/gtknoselection.xml" />
|
||||
|
@ -2441,6 +2441,25 @@ GTK_SORTER_GET_CLASS
|
||||
gtk_sorter_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkstringsorter</FILE>
|
||||
<TITLE>GtkStringSorter</TITLE>
|
||||
GtkStringSorter
|
||||
gtk_string_sorter_new
|
||||
gtk_string_sorter_get_expression
|
||||
gtk_string_sorter_set_expression
|
||||
gtk_string_sorter_get_ignore_case
|
||||
gtk_string_sorter_set_ignore_case
|
||||
<SUBSECTION Standard>
|
||||
GTK_STRING_SORTER
|
||||
GTK_IS_STRING_SORTER
|
||||
GTK_TYPE_STRING_SORTER
|
||||
GTK_IS_STRING_SORTER_CLASS
|
||||
GTK_STRING_SORTER_GET_CLASS
|
||||
<SUBSECTION Private>
|
||||
gtk_string_sorter_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkcustomsorter</FILE>
|
||||
<TITLE>GtkCustomSorter</TITLE>
|
||||
|
@ -195,6 +195,7 @@ gtk_stack_sidebar_get_type
|
||||
gtk_stack_switcher_get_type
|
||||
gtk_statusbar_get_type
|
||||
gtk_string_filter_get_type
|
||||
gtk_string_sorter_get_type
|
||||
gtk_switch_get_type
|
||||
gtk_level_bar_get_type
|
||||
gtk_style_context_get_type
|
||||
|
@ -226,6 +226,7 @@
|
||||
#include <gtk/gtkstackswitcher.h>
|
||||
#include <gtk/gtkstatusbar.h>
|
||||
#include <gtk/gtkstringfilter.h>
|
||||
#include <gtk/gtkstringsorter.h>
|
||||
#include <gtk/gtkstylecontext.h>
|
||||
#include <gtk/gtkstyleprovider.h>
|
||||
#include <gtk/gtkswitch.h>
|
||||
|
351
gtk/gtkstringsorter.c
Normal file
351
gtk/gtkstringsorter.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include "gtkstringsorter.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkstringsorter
|
||||
* @Title: GtkStringSorter
|
||||
* @Short_description: Sort by comparing strings
|
||||
* @See_also: #GtkExpression
|
||||
*
|
||||
* GtkStringSorter is a #GtkSorter that compares strings. It does the
|
||||
* comparison in a linguistically correct way using the current locale by
|
||||
* normalizing Unicode strings and possibly case-folding them before
|
||||
* performing the comparison.
|
||||
*
|
||||
* To obtain the strings to compare, this sorter evaluates a #GtkExpression.
|
||||
*/
|
||||
|
||||
struct _GtkStringSorter
|
||||
{
|
||||
GtkSorter parent_instance;
|
||||
|
||||
gboolean ignore_case;
|
||||
|
||||
GtkExpression *expression;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_EXPRESSION,
|
||||
PROP_IGNORE_CASE,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkStringSorter, gtk_string_sorter, GTK_TYPE_SORTER)
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static GtkOrdering
|
||||
gtk_string_sorter_compare (GtkSorter *sorter,
|
||||
gpointer item1,
|
||||
gpointer item2)
|
||||
{
|
||||
GtkStringSorter *self = GTK_STRING_SORTER (sorter);
|
||||
GValue value1 = G_VALUE_INIT;
|
||||
GValue value2 = G_VALUE_INIT;
|
||||
const char *s1, *s2;
|
||||
gboolean res1, res2;
|
||||
GtkOrdering result;
|
||||
|
||||
if (self->expression == NULL)
|
||||
return GTK_ORDERING_EQUAL;
|
||||
|
||||
res1 = gtk_expression_evaluate (self->expression, item1, &value1);
|
||||
res2 = gtk_expression_evaluate (self->expression, item2, &value2);
|
||||
|
||||
/* If items don't evaluate, order them at the end, so they aren't
|
||||
* in the way. */
|
||||
if (!res1)
|
||||
{
|
||||
result = res2 ? GTK_ORDERING_LARGER : GTK_ORDERING_EQUAL;
|
||||
goto out;
|
||||
}
|
||||
else if (!res2)
|
||||
{
|
||||
result = GTK_ORDERING_SMALLER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
s1 = g_value_get_string (&value1);
|
||||
s2 = g_value_get_string (&value2);
|
||||
|
||||
/* If strings are NULL, order them before "". */
|
||||
if (s1 == NULL)
|
||||
{
|
||||
result = s2 == NULL ? GTK_ORDERING_EQUAL : GTK_ORDERING_SMALLER;
|
||||
goto out;
|
||||
}
|
||||
else if (s2 == NULL)
|
||||
{
|
||||
result = GTK_ORDERING_LARGER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (self->ignore_case)
|
||||
{
|
||||
char *t1, *t2;
|
||||
|
||||
t1 = g_utf8_casefold (s1, -1);
|
||||
t2 = g_utf8_casefold (s2, -1);
|
||||
|
||||
result = gtk_ordering_from_cmpfunc (g_utf8_collate (t1, t2));
|
||||
|
||||
g_free (t1);
|
||||
g_free (t2);
|
||||
}
|
||||
else
|
||||
result = gtk_ordering_from_cmpfunc (g_utf8_collate (s1, s2));
|
||||
|
||||
out:
|
||||
g_value_unset (&value1);
|
||||
g_value_unset (&value2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GtkSorterOrder
|
||||
gtk_string_sorter_get_order (GtkSorter *sorter)
|
||||
{
|
||||
GtkStringSorter *self = GTK_STRING_SORTER (sorter);
|
||||
|
||||
if (self->expression == NULL)
|
||||
return GTK_SORTER_ORDER_NONE;
|
||||
|
||||
return GTK_SORTER_ORDER_PARTIAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_sorter_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkStringSorter *self = GTK_STRING_SORTER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_EXPRESSION:
|
||||
gtk_string_sorter_set_expression (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_IGNORE_CASE:
|
||||
gtk_string_sorter_set_ignore_case (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_sorter_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkStringSorter *self = GTK_STRING_SORTER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_EXPRESSION:
|
||||
g_value_set_boxed (value, self->expression);
|
||||
break;
|
||||
|
||||
case PROP_IGNORE_CASE:
|
||||
g_value_set_boolean (value, self->ignore_case);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_sorter_dispose (GObject *object)
|
||||
{
|
||||
GtkStringSorter *self = GTK_STRING_SORTER (object);
|
||||
|
||||
g_clear_pointer (&self->expression, gtk_expression_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_string_sorter_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_sorter_class_init (GtkStringSorterClass *class)
|
||||
{
|
||||
GtkSorterClass *sorter_class = GTK_SORTER_CLASS (class);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
sorter_class->compare = gtk_string_sorter_compare;
|
||||
sorter_class->get_order = gtk_string_sorter_get_order;
|
||||
|
||||
object_class->get_property = gtk_string_sorter_get_property;
|
||||
object_class->set_property = gtk_string_sorter_set_property;
|
||||
object_class->dispose = gtk_string_sorter_dispose;
|
||||
|
||||
/**
|
||||
* GtkStringSorter:expression:
|
||||
*
|
||||
* The expression to evalute on item to get a string to compare with
|
||||
*/
|
||||
properties[PROP_EXPRESSION] =
|
||||
g_param_spec_boxed ("expression",
|
||||
P_("Expression"),
|
||||
P_("Expression to compare with"),
|
||||
GTK_TYPE_EXPRESSION,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkStringSorter:ignore-case:
|
||||
*
|
||||
* If matching is case sensitive
|
||||
*/
|
||||
properties[PROP_IGNORE_CASE] =
|
||||
g_param_spec_boolean ("ignore-case",
|
||||
P_("Ignore case"),
|
||||
P_("If matching is case sensitive"),
|
||||
TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_sorter_init (GtkStringSorter *self)
|
||||
{
|
||||
self->ignore_case = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_sorter_new:
|
||||
* @expression: (transfer full) (nullable): The expression to evaluate
|
||||
*
|
||||
* Creates a new string sorter that compares items using the given
|
||||
* @expression.
|
||||
*
|
||||
* Unless an expression is set on it, this sorter will always
|
||||
* compare items as invalid.
|
||||
*
|
||||
* Returns: a new #GtkSorter
|
||||
*/
|
||||
GtkSorter *
|
||||
gtk_string_sorter_new (GtkExpression *expression)
|
||||
{
|
||||
GtkSorter *result;
|
||||
|
||||
result = g_object_new (GTK_TYPE_STRING_SORTER,
|
||||
"expression", expression,
|
||||
NULL);
|
||||
|
||||
g_clear_pointer (&expression, gtk_expression_unref);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_sorter_get_expression:
|
||||
* @self: a #GtkStringSorter
|
||||
*
|
||||
* Gets the expression that is evaluated to obtain strings from items.
|
||||
*
|
||||
* Returns: (nullable): a #GtkExpression, or %NULL
|
||||
*/
|
||||
GtkExpression *
|
||||
gtk_string_sorter_get_expression (GtkStringSorter *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_STRING_SORTER (self), NULL);
|
||||
|
||||
return self->expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_sorter_set_expression:
|
||||
* @self: a #GtkStringSorter
|
||||
* @expression: (nullable) (transfer none): a #GtkExpression, or %NULL
|
||||
*
|
||||
* Sets the expression that is evaluated to obtain strings from items.
|
||||
*
|
||||
* The expression must have the type G_TYPE_STRING.
|
||||
*/
|
||||
void
|
||||
gtk_string_sorter_set_expression (GtkStringSorter *self,
|
||||
GtkExpression *expression)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_STRING_SORTER (self));
|
||||
g_return_if_fail (expression == NULL || gtk_expression_get_value_type (expression) == G_TYPE_STRING);
|
||||
|
||||
if (self->expression == expression)
|
||||
return;
|
||||
|
||||
g_clear_pointer (&self->expression, gtk_expression_unref);
|
||||
if (expression)
|
||||
self->expression = gtk_expression_ref (expression);
|
||||
|
||||
gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_sorter_get_ignore_case:
|
||||
* @self: a #GtkStringSorter
|
||||
*
|
||||
* Gets whether the sorter ignores case differences.
|
||||
*
|
||||
* Returns: %TRUE if @self is ignoring case differences
|
||||
*/
|
||||
gboolean
|
||||
gtk_string_sorter_get_ignore_case (GtkStringSorter *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_STRING_SORTER (self), TRUE);
|
||||
|
||||
return self->ignore_case;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_sorter_set_ignore_case:
|
||||
* @self: a #GtkStringSorter
|
||||
*
|
||||
* Sets whether the sorter will ignore case differences.
|
||||
*/
|
||||
void
|
||||
gtk_string_sorter_set_ignore_case (GtkStringSorter *self,
|
||||
gboolean ignore_case)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_STRING_SORTER (self));
|
||||
|
||||
if (self->ignore_case == ignore_case)
|
||||
return;
|
||||
|
||||
self->ignore_case = ignore_case;
|
||||
|
||||
gtk_sorter_changed (GTK_SORTER (self), ignore_case ? GTK_SORTER_CHANGE_LESS_STRICT : GTK_SORTER_CHANGE_MORE_STRICT);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_IGNORE_CASE]);
|
||||
}
|
52
gtk/gtkstringsorter.h
Normal file
52
gtk/gtkstringsorter.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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_STRING_SORTER_H__
|
||||
#define __GTK_STRING_SORTER_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtkexpression.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_STRING_SORTER (gtk_string_sorter_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkStringSorter, gtk_string_sorter, GTK, STRING_SORTER, GtkSorter)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_string_sorter_new (GtkExpression *expression);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkExpression * gtk_string_sorter_get_expression (GtkStringSorter *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_sorter_set_expression (GtkStringSorter *self,
|
||||
GtkExpression *expression);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_string_sorter_get_ignore_case (GtkStringSorter *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_sorter_set_ignore_case (GtkStringSorter *self,
|
||||
gboolean ignore_case);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_STRING_SORTER_H__ */
|
@ -356,6 +356,7 @@ gtk_public_sources = files([
|
||||
'gtkstackswitcher.c',
|
||||
'gtkstatusbar.c',
|
||||
'gtkstringfilter.c',
|
||||
'gtkstringsorter.c',
|
||||
'gtkstylecontext.c',
|
||||
'gtkstyleprovider.c',
|
||||
'gtkswitch.c',
|
||||
@ -604,6 +605,7 @@ gtk_public_headers = files([
|
||||
'gtkstackswitcher.h',
|
||||
'gtkstatusbar.h',
|
||||
'gtkstringfilter.h',
|
||||
'gtkstringsorter.h',
|
||||
'gtkstylecontext.h',
|
||||
'gtkstyleprovider.h',
|
||||
'gtkswitch.h',
|
||||
|
Loading…
Reference in New Issue
Block a user