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 }