evolution-3.6.4/widgets/table/e-table-sort-info.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Chris Lahey <clahey@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #include <string.h>
 28 
 29 #include "e-util/e-util.h"
 30 #include "libevolution-utils/e-xml-utils.h"
 31 
 32 #include "e-table-sort-info.h"
 33 
 34 #define ETM_CLASS(e) (E_TABLE_SORT_INFO_GET_CLASS (e))
 35 
 36 G_DEFINE_TYPE (ETableSortInfo , e_table_sort_info, G_TYPE_OBJECT)
 37 
 38 enum {
 39 	SORT_INFO_CHANGED,
 40 	GROUP_INFO_CHANGED,
 41 	LAST_SIGNAL
 42 };
 43 
 44 static guint e_table_sort_info_signals[LAST_SIGNAL] = { 0, };
 45 
 46 static void
 47 etsi_finalize (GObject *object)
 48 {
 49 	ETableSortInfo *etsi = E_TABLE_SORT_INFO (object);
 50 
 51 	if (etsi->groupings)
 52 		g_free (etsi->groupings);
 53 	etsi->groupings = NULL;
 54 
 55 	if (etsi->sortings)
 56 		g_free (etsi->sortings);
 57 	etsi->sortings = NULL;
 58 
 59 	G_OBJECT_CLASS (e_table_sort_info_parent_class)->finalize (object);
 60 }
 61 
 62 static void
 63 e_table_sort_info_init (ETableSortInfo *info)
 64 {
 65 	info->group_count = 0;
 66 	info->groupings = NULL;
 67 	info->sort_count = 0;
 68 	info->sortings = NULL;
 69 	info->frozen = 0;
 70 	info->sort_info_changed = 0;
 71 	info->group_info_changed = 0;
 72 	info->can_group = 1;
 73 }
 74 
 75 static void
 76 e_table_sort_info_class_init (ETableSortInfoClass *class)
 77 {
 78 	GObjectClass * object_class = G_OBJECT_CLASS (class);
 79 
 80 	object_class->finalize = etsi_finalize;
 81 
 82 	e_table_sort_info_signals[SORT_INFO_CHANGED] = g_signal_new (
 83 		"sort_info_changed",
 84 		G_TYPE_FROM_CLASS (object_class),
 85 		G_SIGNAL_RUN_LAST,
 86 		G_STRUCT_OFFSET (ETableSortInfoClass, sort_info_changed),
 87 		(GSignalAccumulator) NULL, NULL,
 88 		g_cclosure_marshal_VOID__VOID,
 89 		G_TYPE_NONE, 0);
 90 
 91 	e_table_sort_info_signals[GROUP_INFO_CHANGED] = g_signal_new (
 92 		"group_info_changed",
 93 		G_TYPE_FROM_CLASS (object_class),
 94 		G_SIGNAL_RUN_LAST,
 95 		G_STRUCT_OFFSET (ETableSortInfoClass, group_info_changed),
 96 		(GSignalAccumulator) NULL, NULL,
 97 		g_cclosure_marshal_VOID__VOID,
 98 		G_TYPE_NONE, 0);
 99 
100 	class->sort_info_changed = NULL;
101 	class->group_info_changed = NULL;
102 }
103 
104 static void
105 e_table_sort_info_sort_info_changed (ETableSortInfo *info)
106 {
107 	g_return_if_fail (info != NULL);
108 	g_return_if_fail (E_IS_TABLE_SORT_INFO (info));
109 
110 	if (info->frozen) {
111 		info->sort_info_changed = 1;
112 	} else {
113 		g_signal_emit (info, e_table_sort_info_signals[SORT_INFO_CHANGED], 0);
114 	}
115 }
116 
117 static void
118 e_table_sort_info_group_info_changed (ETableSortInfo *info)
119 {
120 	g_return_if_fail (info != NULL);
121 	g_return_if_fail (E_IS_TABLE_SORT_INFO (info));
122 
123 	if (info->frozen) {
124 		info->group_info_changed = 1;
125 	} else {
126 		g_signal_emit (info, e_table_sort_info_signals[GROUP_INFO_CHANGED], 0);
127 	}
128 }
129 
130 /**
131  * e_table_sort_info_freeze:
132  * @info: The ETableSortInfo object
133  *
134  * This functions allows the programmer to cluster various changes to the
135  * ETableSortInfo (grouping and sorting) without having the object emit
136  * "group_info_changed" or "sort_info_changed" signals on each change.
137  *
138  * To thaw, invoke the e_table_sort_info_thaw() function, which will
139  * trigger any signals that might have been queued.
140  */
141 void
142 e_table_sort_info_freeze (ETableSortInfo *info)
143 {
144 	info->frozen++;
145 }
146 
147 /**
148  * e_table_sort_info_thaw:
149  * @info: The ETableSortInfo object
150  *
151  * This functions allows the programmer to cluster various changes to the
152  * ETableSortInfo (grouping and sorting) without having the object emit
153  * "group_info_changed" or "sort_info_changed" signals on each change.
154  *
155  * This function will flush any pending signals that might be emited by
156  * this object.
157  */
158 void
159 e_table_sort_info_thaw (ETableSortInfo *info)
160 {
161 	info->frozen--;
162 	if (info->frozen != 0)
163 		return;
164 
165 	if (info->sort_info_changed) {
166 		info->sort_info_changed = 0;
167 		e_table_sort_info_sort_info_changed (info);
168 	}
169 	if (info->group_info_changed) {
170 		info->group_info_changed = 0;
171 		e_table_sort_info_group_info_changed (info);
172 	}
173 }
174 
175 /**
176  * e_table_sort_info_grouping_get_count:
177  * @info: The ETableSortInfo object
178  *
179  * Returns: the number of grouping criteria in the object.
180  */
181 guint
182 e_table_sort_info_grouping_get_count (ETableSortInfo *info)
183 {
184 	if (info->can_group)
185 		return info->group_count;
186 	else
187 		return 0;
188 }
189 
190 static void
191 e_table_sort_info_grouping_real_truncate (ETableSortInfo *info,
192                                           gint length)
193 {
194 	if (length < info->group_count) {
195 		info->group_count = length;
196 	}
197 	if (length > info->group_count) {
198 		info->groupings = g_realloc (info->groupings, length * sizeof (ETableSortColumn));
199 		info->group_count = length;
200 	}
201 }
202 
203 /**
204  * e_table_sort_info_grouping_truncate:
205  * @info: The ETableSortInfo object
206  * @lenght: position where the truncation happens.
207  *
208  * This routine can be used to reduce or grow the number of grouping
209  * criteria in the object.
210  */
211 void
212 e_table_sort_info_grouping_truncate (ETableSortInfo *info,
213                                      gint length)
214 {
215 	e_table_sort_info_grouping_real_truncate (info, length);
216 	e_table_sort_info_group_info_changed (info);
217 }
218 
219 /**
220  * e_table_sort_info_grouping_get_nth:
221  * @info: The ETableSortInfo object
222  * @n: Item information to fetch.
223  *
224  * Returns: the description of the @n-th grouping criteria in the @info object.
225  */
226 ETableSortColumn
227 e_table_sort_info_grouping_get_nth (ETableSortInfo *info,
228                                     gint n)
229 {
230 	if (info->can_group && n < info->group_count) {
231 		return info->groupings[n];
232 	} else {
233 		ETableSortColumn fake = {0, 0};
234 		return fake;
235 	}
236 }
237 
238 /**
239  * e_table_sort_info_grouping_set_nth:
240  * @info: The ETableSortInfo object
241  * @n: Item information to fetch.
242  * @column: new values for the grouping
243  *
244  * Sets the grouping criteria for index @n to be given by @column (a column number and
245  * whether it is ascending or descending).
246  */
247 void
248 e_table_sort_info_grouping_set_nth (ETableSortInfo *info,
249                                     gint n,
250                                     ETableSortColumn column)
251 {
252 	if (n >= info->group_count) {
253 		e_table_sort_info_grouping_real_truncate (info, n + 1);
254 	}
255 	info->groupings[n] = column;
256 	e_table_sort_info_group_info_changed (info);
257 }
258 
259 /**
260  * e_table_sort_info_get_count:
261  * @info: The ETableSortInfo object
262  *
263  * Returns: the number of sorting criteria in the object.
264  */
265 guint
266 e_table_sort_info_sorting_get_count (ETableSortInfo *info)
267 {
268 	return info->sort_count;
269 }
270 
271 static void
272 e_table_sort_info_sorting_real_truncate (ETableSortInfo *info,
273                                          gint length)
274 {
275 	if (length < info->sort_count) {
276 		info->sort_count = length;
277 	}
278 	if (length > info->sort_count) {
279 		info->sortings = g_realloc (info->sortings, length * sizeof (ETableSortColumn));
280 		info->sort_count = length;
281 	}
282 }
283 
284 /**
285  * e_table_sort_info_sorting_truncate:
286  * @info: The ETableSortInfo object
287  * @lenght: position where the truncation happens.
288  *
289  * This routine can be used to reduce or grow the number of sort
290  * criteria in the object.
291  */
292 void
293 e_table_sort_info_sorting_truncate (ETableSortInfo *info,
294                                     gint length)
295 {
296 	e_table_sort_info_sorting_real_truncate  (info, length);
297 	e_table_sort_info_sort_info_changed (info);
298 }
299 
300 /**
301  * e_table_sort_info_sorting_get_nth:
302  * @info: The ETableSortInfo object
303  * @n: Item information to fetch.
304  *
305  * Returns: the description of the @n-th grouping criteria in the @info object.
306  */
307 ETableSortColumn
308 e_table_sort_info_sorting_get_nth (ETableSortInfo *info,
309                                    gint n)
310 {
311 	if (n < info->sort_count) {
312 		return info->sortings[n];
313 	} else {
314 		ETableSortColumn fake = {0, 0};
315 		return fake;
316 	}
317 }
318 
319 /**
320  * e_table_sort_info_sorting_get_nth:
321  * @info: The ETableSortInfo object
322  * @n: Item information to fetch.
323  * @column: new values for the sorting
324  *
325  * Sets the sorting criteria for index @n to be given by @column (a
326  * column number and whether it is ascending or descending).
327  */
328 void
329 e_table_sort_info_sorting_set_nth (ETableSortInfo *info,
330                                    gint n,
331                                    ETableSortColumn column)
332 {
333 	if (n >= info->sort_count) {
334 		e_table_sort_info_sorting_real_truncate (info, n + 1);
335 	}
336 	info->sortings[n] = column;
337 	e_table_sort_info_sort_info_changed (info);
338 }
339 
340 /**
341  * e_table_sort_info_new:
342  *
343  * This creates a new e_table_sort_info object that contains no
344  * grouping and no sorting defined as of yet.  This object is used
345  * to keep track of multi-level sorting and multi-level grouping of
346  * the ETable.
347  *
348  * Returns: A new %ETableSortInfo object
349  */
350 ETableSortInfo *
351 e_table_sort_info_new (void)
352 {
353 	return g_object_new (E_TYPE_TABLE_SORT_INFO, NULL);
354 }
355 
356 /**
357  * e_table_sort_info_load_from_node:
358  * @info: The ETableSortInfo object
359  * @node: pointer to the xmlNode that describes the sorting and grouping information
360  * @state_version:
361  *
362  * This loads the state for the %ETableSortInfo object @info from the
363  * xml node @node.
364  */
365 void
366 e_table_sort_info_load_from_node (ETableSortInfo *info,
367                                   xmlNode *node,
368                                   gdouble state_version)
369 {
370 	gint i;
371 	xmlNode *grouping;
372 
373 	if (state_version <= 0.05) {
374 		i = 0;
375 		for (grouping = node->xmlChildrenNode; grouping && !strcmp ((gchar *) grouping->name, "group"); grouping = grouping->xmlChildrenNode) {
376 			ETableSortColumn column;
377 			column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
378 			column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
379 			e_table_sort_info_grouping_set_nth (info, i++, column);
380 		}
381 		i = 0;
382 		for (; grouping && !strcmp ((gchar *) grouping->name, "leaf"); grouping = grouping->xmlChildrenNode) {
383 			ETableSortColumn column;
384 			column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
385 			column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
386 			e_table_sort_info_sorting_set_nth (info, i++, column);
387 		}
388 	} else {
389 		gint gcnt = 0;
390 		gint scnt = 0;
391 		for (grouping = node->children; grouping; grouping = grouping->next) {
392 			ETableSortColumn column;
393 
394 			if (grouping->type != XML_ELEMENT_NODE)
395 				continue;
396 
397 			if (!strcmp ((gchar *) grouping->name, "group")) {
398 				column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
399 				column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
400 				e_table_sort_info_grouping_set_nth (info, gcnt++, column);
401 			} else if (!strcmp ((gchar *) grouping->name, "leaf")) {
402 				column.column = e_xml_get_integer_prop_by_name (grouping, (const guchar *)"column");
403 				column.ascending = e_xml_get_bool_prop_by_name (grouping, (const guchar *)"ascending");
404 				e_table_sort_info_sorting_set_nth (info, scnt++, column);
405 			}
406 		}
407 	}
408 	g_signal_emit (info, e_table_sort_info_signals[SORT_INFO_CHANGED], 0);
409 }
410 
411 /**
412  * e_table_sort_info_save_to_node:
413  * @info: The ETableSortInfo object
414  * @parent: xmlNode that will be hosting the saved state of the @info object.
415  *
416  * This function is used
417  *
418  * Returns: the node that has been appended to @parent as a child containing
419  * the sorting and grouping information for this ETableSortInfo object.
420  */
421 xmlNode *
422 e_table_sort_info_save_to_node (ETableSortInfo *info,
423                                 xmlNode *parent)
424 {
425 	xmlNode *grouping;
426 	gint i;
427 	const gint sort_count = e_table_sort_info_sorting_get_count (info);
428 	const gint group_count = e_table_sort_info_grouping_get_count (info);
429 
430 	grouping = xmlNewChild (parent, NULL, (const guchar *)"grouping", NULL);
431 
432 	for (i = 0; i < group_count; i++) {
433 		ETableSortColumn column = e_table_sort_info_grouping_get_nth (info, i);
434 		xmlNode *new_node = xmlNewChild (grouping, NULL, (const guchar *)"group", NULL);
435 
436 		e_xml_set_integer_prop_by_name (new_node, (const guchar *)"column", column.column);
437 		e_xml_set_bool_prop_by_name (new_node, (const guchar *)"ascending", column.ascending);
438 	}
439 
440 	for (i = 0; i < sort_count; i++) {
441 		ETableSortColumn column = e_table_sort_info_sorting_get_nth (info, i);
442 		xmlNode *new_node = xmlNewChild (grouping, NULL, (const guchar *)"leaf", NULL);
443 
444 		e_xml_set_integer_prop_by_name (new_node, (const guchar *)"column", column.column);
445 		e_xml_set_bool_prop_by_name (new_node, (const guchar *)"ascending", column.ascending);
446 	}
447 
448 	return grouping;
449 }
450 
451 ETableSortInfo *
452 e_table_sort_info_duplicate (ETableSortInfo *info)
453 {
454 	ETableSortInfo *new_info;
455 
456 	new_info = e_table_sort_info_new ();
457 
458 	new_info->group_count = info->group_count;
459 	new_info->groupings = g_new (ETableSortColumn, new_info->group_count);
460 	memmove (new_info->groupings, info->groupings, sizeof (ETableSortColumn) * new_info->group_count);
461 
462 	new_info->sort_count = info->sort_count;
463 	new_info->sortings = g_new (ETableSortColumn, new_info->sort_count);
464 	memmove (new_info->sortings, info->sortings, sizeof (ETableSortColumn) * new_info->sort_count);
465 
466 	new_info->can_group = info->can_group;
467 
468 	return new_info;
469 }
470 
471 void
472 e_table_sort_info_set_can_group (ETableSortInfo *info,
473                                  gboolean can_group)
474 {
475 	info->can_group = can_group;
476 }
477 
478 gboolean
479 e_table_sort_info_get_can_group (ETableSortInfo *info)
480 {
481 	return info->can_group;
482 }