581 lines
16 KiB
C
581 lines
16 KiB
C
/*
|
|
* e-table-sort-info.c
|
|
*
|
|
* This program 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) version 3.
|
|
*
|
|
* This program 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 the program; if not, see <http://www.gnu.org/licenses/>
|
|
*
|
|
*/
|
|
|
|
#include "e-table-sort-info.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "e-table-specification.h"
|
|
#include "e-xml-utils.h"
|
|
|
|
#define E_TABLE_SORT_INFO_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE \
|
|
((obj), E_TYPE_TABLE_SORT_INFO, ETableSortInfoPrivate))
|
|
|
|
struct _ETableSortInfoPrivate {
|
|
GWeakRef specification;
|
|
GArray *groupings;
|
|
GArray *sortings;
|
|
gboolean can_group;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_SPECIFICATION
|
|
};
|
|
|
|
enum {
|
|
SORT_INFO_CHANGED,
|
|
GROUP_INFO_CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
G_DEFINE_TYPE (ETableSortInfo , e_table_sort_info, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
table_sort_info_set_specification (ETableSortInfo *sort_info,
|
|
ETableSpecification *specification)
|
|
{
|
|
g_return_if_fail (E_IS_TABLE_SPECIFICATION (specification));
|
|
|
|
g_weak_ref_set (&sort_info->priv->specification, specification);
|
|
}
|
|
|
|
static void
|
|
table_sort_info_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (property_id) {
|
|
case PROP_SPECIFICATION:
|
|
table_sort_info_set_specification (
|
|
E_TABLE_SORT_INFO (object),
|
|
g_value_get_object (value));
|
|
return;
|
|
}
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
|
|
static void
|
|
table_sort_info_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (property_id) {
|
|
case PROP_SPECIFICATION:
|
|
g_value_take_object (
|
|
value,
|
|
e_table_sort_info_ref_specification (
|
|
E_TABLE_SORT_INFO (object)));
|
|
return;
|
|
}
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
}
|
|
|
|
static void
|
|
table_sort_info_dispose (GObject *object)
|
|
{
|
|
ETableSortInfoPrivate *priv;
|
|
|
|
priv = E_TABLE_SORT_INFO_GET_PRIVATE (object);
|
|
|
|
g_weak_ref_set (&priv->specification, NULL);
|
|
|
|
g_array_set_size (priv->groupings, 0);
|
|
g_array_set_size (priv->sortings, 0);
|
|
|
|
/* Chain up to parent's dispose() method. */
|
|
G_OBJECT_CLASS (e_table_sort_info_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
table_sort_info_finalize (GObject *object)
|
|
{
|
|
ETableSortInfoPrivate *priv;
|
|
|
|
priv = E_TABLE_SORT_INFO_GET_PRIVATE (object);
|
|
|
|
g_array_free (priv->groupings, TRUE);
|
|
g_array_free (priv->sortings, TRUE);
|
|
|
|
/* Chain up to parent's finalize() method. */
|
|
G_OBJECT_CLASS (e_table_sort_info_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
e_table_sort_info_class_init (ETableSortInfoClass *class)
|
|
{
|
|
GObjectClass * object_class;
|
|
|
|
g_type_class_add_private (class, sizeof (ETableSortInfoPrivate));
|
|
|
|
object_class = G_OBJECT_CLASS (class);
|
|
object_class->set_property = table_sort_info_set_property;
|
|
object_class->get_property = table_sort_info_get_property;
|
|
object_class->dispose = table_sort_info_dispose;
|
|
object_class->finalize = table_sort_info_finalize;
|
|
|
|
g_object_class_install_property (
|
|
object_class,
|
|
PROP_SPECIFICATION,
|
|
g_param_spec_object (
|
|
"specification",
|
|
"Table Specification",
|
|
"Specification for the table state",
|
|
E_TYPE_TABLE_SPECIFICATION,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS));
|
|
|
|
signals[SORT_INFO_CHANGED] = g_signal_new (
|
|
"sort_info_changed",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ETableSortInfoClass, sort_info_changed),
|
|
(GSignalAccumulator) NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
signals[GROUP_INFO_CHANGED] = g_signal_new (
|
|
"group_info_changed",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ETableSortInfoClass, group_info_changed),
|
|
(GSignalAccumulator) NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
}
|
|
|
|
static void
|
|
e_table_sort_info_init (ETableSortInfo *sort_info)
|
|
{
|
|
sort_info->priv = E_TABLE_SORT_INFO_GET_PRIVATE (sort_info);
|
|
|
|
sort_info->priv->groupings = g_array_new (
|
|
FALSE, TRUE, sizeof (ETableSortColumn));
|
|
sort_info->priv->sortings = g_array_new (
|
|
FALSE, TRUE, sizeof (ETableSortColumn));
|
|
|
|
sort_info->priv->can_group = TRUE;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_new:
|
|
* @specification: an #ETableSpecification
|
|
*
|
|
* This creates a new #ETableSortInfo object that contains no
|
|
* grouping and no sorting defined as of yet. This object is used
|
|
* to keep track of multi-level sorting and multi-level grouping of
|
|
* an #ETable.
|
|
*
|
|
* Returns: A new #ETableSortInfo object
|
|
*/
|
|
ETableSortInfo *
|
|
e_table_sort_info_new (ETableSpecification *specification)
|
|
{
|
|
g_return_val_if_fail (E_IS_TABLE_SPECIFICATION (specification), NULL);
|
|
|
|
return g_object_new (
|
|
E_TYPE_TABLE_SORT_INFO,
|
|
"specification", specification, NULL);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_ref_specification:
|
|
* @sort_info: an #ETableSortInfo
|
|
*
|
|
* Returns the #ETableSpecification passed to e_table_sort_info_new().
|
|
*
|
|
* The returned #ETableSpecification is referenced for thread-safety and must
|
|
* be unreferenced with g_object_unref() when finished with it.
|
|
*
|
|
* Returns: an #ETableSpecification
|
|
**/
|
|
ETableSpecification *
|
|
e_table_sort_info_ref_specification (ETableSortInfo *sort_info)
|
|
{
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), NULL);
|
|
|
|
return g_weak_ref_get (&sort_info->priv->specification);
|
|
}
|
|
|
|
gboolean
|
|
e_table_sort_info_get_can_group (ETableSortInfo *sort_info)
|
|
{
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), FALSE);
|
|
|
|
return sort_info->priv->can_group;
|
|
}
|
|
|
|
void
|
|
e_table_sort_info_set_can_group (ETableSortInfo *sort_info,
|
|
gboolean can_group)
|
|
{
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
sort_info->priv->can_group = can_group;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_grouping_get_count:
|
|
* @sort_info: an #ETableSortInfo
|
|
*
|
|
* Returns: the number of grouping criteria in the object.
|
|
*/
|
|
guint
|
|
e_table_sort_info_grouping_get_count (ETableSortInfo *sort_info)
|
|
{
|
|
guint count = 0;
|
|
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), 0);
|
|
|
|
if (e_table_sort_info_get_can_group (sort_info))
|
|
count = sort_info->priv->groupings->len;
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_grouping_truncate:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @length: position where the truncation happens.
|
|
*
|
|
* This routine can be used to reduce or grow the number of grouping
|
|
* criteria in the object.
|
|
*/
|
|
void
|
|
e_table_sort_info_grouping_truncate (ETableSortInfo *sort_info,
|
|
guint length)
|
|
{
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
g_array_set_size (sort_info->priv->groupings, length);
|
|
|
|
g_signal_emit (sort_info, signals[GROUP_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_grouping_get_nth:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @n: Item information to fetch.
|
|
*
|
|
* Returns: the description of the @n-th grouping criteria in the @info object.
|
|
*/
|
|
ETableSortColumn
|
|
e_table_sort_info_grouping_get_nth (ETableSortInfo *sort_info,
|
|
guint n)
|
|
{
|
|
ETableSortColumn column = { 0, 0 };
|
|
GArray *array;
|
|
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), column);
|
|
|
|
array = sort_info->priv->groupings;
|
|
|
|
if (!e_table_sort_info_get_can_group (sort_info))
|
|
return column;
|
|
|
|
if (n < array->len)
|
|
column = g_array_index (array, ETableSortColumn, n);
|
|
|
|
return column;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_grouping_set_nth:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @n: Item information to fetch.
|
|
* @column: new values for the grouping
|
|
*
|
|
* Sets the grouping criteria for index @n to be given by @column
|
|
* (a column number and whether it is ascending or descending).
|
|
*/
|
|
void
|
|
e_table_sort_info_grouping_set_nth (ETableSortInfo *sort_info,
|
|
guint n,
|
|
ETableSortColumn column)
|
|
{
|
|
ETableSortColumn *array_element;
|
|
GArray *array;
|
|
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
array = sort_info->priv->groupings;
|
|
g_array_set_size (array, MAX (n + 1, array->len));
|
|
|
|
array_element = &g_array_index (array, ETableSortColumn, n);
|
|
*array_element = column;
|
|
|
|
g_signal_emit (sort_info, signals[GROUP_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_get_count:
|
|
* @sort_info: an #ETableSortInfo
|
|
*
|
|
* Returns: the number of sorting criteria in the object.
|
|
*/
|
|
guint
|
|
e_table_sort_info_sorting_get_count (ETableSortInfo *sort_info)
|
|
{
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), 0);
|
|
|
|
return sort_info->priv->sortings->len;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_sorting_remove:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @n: the index of the element to remove
|
|
*
|
|
* Removes the sorting element at the given index. The following sorting
|
|
* elements are moved down one place.
|
|
**/
|
|
void
|
|
e_table_sort_info_sorting_remove (ETableSortInfo *sort_info,
|
|
guint n)
|
|
{
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
g_array_remove_index (sort_info->priv->sortings, n);
|
|
|
|
g_signal_emit (sort_info, signals[SORT_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_sorting_truncate:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @length: position where the truncation happens.
|
|
*
|
|
* This routine can be used to reduce or grow the number of sort
|
|
* criteria in the object.
|
|
*/
|
|
void
|
|
e_table_sort_info_sorting_truncate (ETableSortInfo *sort_info,
|
|
guint length)
|
|
{
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
g_array_set_size (sort_info->priv->sortings, length);
|
|
|
|
g_signal_emit (sort_info, signals[SORT_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_sorting_get_nth:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @n: Item information to fetch.
|
|
*
|
|
* Returns: the description of the @n-th grouping criteria in the @info object.
|
|
*/
|
|
ETableSortColumn
|
|
e_table_sort_info_sorting_get_nth (ETableSortInfo *sort_info,
|
|
guint n)
|
|
{
|
|
ETableSortColumn column = { 0, 0 };
|
|
GArray *array;
|
|
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), column);
|
|
|
|
array = sort_info->priv->sortings;
|
|
|
|
if (n < array->len)
|
|
column = g_array_index (array, ETableSortColumn, n);
|
|
|
|
return column;
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_sorting_set_nth:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @n: Item information to fetch.
|
|
* @column: new values for the sorting
|
|
*
|
|
* Sets the sorting criteria for index @n to be given by @column (a
|
|
* column number and whether it is ascending or descending).
|
|
*/
|
|
void
|
|
e_table_sort_info_sorting_set_nth (ETableSortInfo *sort_info,
|
|
guint n,
|
|
ETableSortColumn column)
|
|
{
|
|
ETableSortColumn *array_element;
|
|
GArray *array;
|
|
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
|
|
array = sort_info->priv->sortings;
|
|
g_array_set_size (array, MAX (n + 1, array->len));
|
|
|
|
array_element = &g_array_index (array, ETableSortColumn, n);
|
|
*array_element = column;
|
|
|
|
g_signal_emit (sort_info, signals[SORT_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_load_from_node:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @node: pointer to the xmlNode that describes the sorting and grouping information
|
|
* @state_version:
|
|
*
|
|
* This loads the state for the #ETableSortInfo object @info from the
|
|
* xml node @node.
|
|
*/
|
|
void
|
|
e_table_sort_info_load_from_node (ETableSortInfo *sort_info,
|
|
xmlNode *node,
|
|
gdouble state_version)
|
|
{
|
|
guint i;
|
|
xmlNode *grouping;
|
|
|
|
g_return_if_fail (E_IS_TABLE_SORT_INFO (sort_info));
|
|
g_return_if_fail (node != NULL);
|
|
|
|
if (state_version <= 0.05) {
|
|
i = 0;
|
|
for (grouping = node->xmlChildrenNode; grouping && !strcmp ((gchar *) grouping->name, "group"); grouping = grouping->xmlChildrenNode) {
|
|
ETableSortColumn column;
|
|
column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
|
|
column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
|
|
e_table_sort_info_grouping_set_nth (sort_info, i++, column);
|
|
}
|
|
i = 0;
|
|
for (; grouping && !strcmp ((gchar *) grouping->name, "leaf"); grouping = grouping->xmlChildrenNode) {
|
|
ETableSortColumn column;
|
|
column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
|
|
column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
|
|
e_table_sort_info_sorting_set_nth (sort_info, i++, column);
|
|
}
|
|
} else {
|
|
guint gcnt = 0;
|
|
guint scnt = 0;
|
|
for (grouping = node->children; grouping; grouping = grouping->next) {
|
|
ETableSortColumn column;
|
|
|
|
if (grouping->type != XML_ELEMENT_NODE)
|
|
continue;
|
|
|
|
if (!strcmp ((gchar *) grouping->name, "group")) {
|
|
column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
|
|
column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
|
|
e_table_sort_info_grouping_set_nth (sort_info, gcnt++, column);
|
|
} else if (!strcmp ((gchar *) grouping->name, "leaf")) {
|
|
column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
|
|
column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
|
|
e_table_sort_info_sorting_set_nth (sort_info, scnt++, column);
|
|
}
|
|
}
|
|
}
|
|
g_signal_emit (sort_info, signals[SORT_INFO_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* e_table_sort_info_save_to_node:
|
|
* @sort_info: an #ETableSortInfo
|
|
* @parent: xmlNode that will be hosting the saved state of the @info object.
|
|
*
|
|
* This function is used
|
|
*
|
|
* Returns: the node that has been appended to @parent as a child containing
|
|
* the sorting and grouping information for this ETableSortInfo object.
|
|
*/
|
|
xmlNode *
|
|
e_table_sort_info_save_to_node (ETableSortInfo *sort_info,
|
|
xmlNode *parent)
|
|
{
|
|
xmlNode *grouping;
|
|
guint sort_count;
|
|
guint group_count;
|
|
guint i;
|
|
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), NULL);
|
|
|
|
sort_count = e_table_sort_info_sorting_get_count (sort_info);
|
|
group_count = e_table_sort_info_grouping_get_count (sort_info);
|
|
|
|
grouping = xmlNewChild (parent, NULL, (const guchar *)"grouping", NULL);
|
|
|
|
for (i = 0; i < group_count; i++) {
|
|
ETableSortColumn column;
|
|
xmlNode *new_node;
|
|
|
|
column = e_table_sort_info_grouping_get_nth (sort_info, i);
|
|
new_node = xmlNewChild (grouping, NULL, (const guchar *)"group", NULL);
|
|
|
|
e_xml_set_integer_prop_by_name (new_node, (const guchar *)"column", column.column);
|
|
e_xml_set_bool_prop_by_name (new_node, (const guchar *)"ascending", column.ascending);
|
|
}
|
|
|
|
for (i = 0; i < sort_count; i++) {
|
|
ETableSortColumn column;
|
|
xmlNode *new_node;
|
|
|
|
column = e_table_sort_info_sorting_get_nth (sort_info, i);
|
|
new_node = xmlNewChild (grouping, NULL, (const guchar *)"leaf", NULL);
|
|
|
|
e_xml_set_integer_prop_by_name (new_node, (const guchar *)"column", column.column);
|
|
e_xml_set_bool_prop_by_name (new_node, (const guchar *)"ascending", column.ascending);
|
|
}
|
|
|
|
return grouping;
|
|
}
|
|
|
|
ETableSortInfo *
|
|
e_table_sort_info_duplicate (ETableSortInfo *sort_info)
|
|
{
|
|
ETableSpecification *specification;
|
|
ETableSortInfo *new_info;
|
|
|
|
g_return_val_if_fail (E_IS_TABLE_SORT_INFO (sort_info), NULL);
|
|
|
|
specification = e_table_sort_info_ref_specification (sort_info);
|
|
new_info = e_table_sort_info_new (specification);
|
|
g_object_unref (specification);
|
|
|
|
g_array_set_size (
|
|
new_info->priv->groupings,
|
|
sort_info->priv->groupings->len);
|
|
memmove (
|
|
new_info->priv->groupings->data,
|
|
sort_info->priv->groupings->data,
|
|
sort_info->priv->groupings->len *
|
|
g_array_get_element_size (sort_info->priv->groupings));
|
|
|
|
g_array_set_size (
|
|
new_info->priv->sortings,
|
|
sort_info->priv->sortings->len);
|
|
memmove (
|
|
new_info->priv->sortings->data,
|
|
sort_info->priv->sortings->data,
|
|
sort_info->priv->sortings->len *
|
|
g_array_get_element_size (sort_info->priv->sortings));
|
|
|
|
new_info->priv->can_group = sort_info->priv->can_group;
|
|
|
|
return new_info;
|
|
}
|
|
|