1/* gtktreedatalist.c
2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * This file contains code shared between GtkTreeStore and GtkListStore. Please
18 * do not use it.
19 */
20
21#include "config.h"
22#include "gtktreedatalist.h"
23#include <string.h>
24
25/* node allocation
26 */
27GtkTreeDataList *
28_gtk_tree_data_list_alloc (void)
29{
30 GtkTreeDataList *list;
31
32 list = g_slice_new0 (GtkTreeDataList);
33
34 return list;
35}
36
37void
38_gtk_tree_data_list_free (GtkTreeDataList *list,
39 GType *column_headers)
40{
41 GtkTreeDataList *tmp, *next;
42 int i = 0;
43
44 tmp = list;
45
46 while (tmp)
47 {
48 next = tmp->next;
49 if (g_type_is_a (type: column_headers [i], G_TYPE_STRING))
50 g_free (mem: (char *) tmp->data.v_pointer);
51 else if (g_type_is_a (type: column_headers [i], G_TYPE_OBJECT) && tmp->data.v_pointer != NULL)
52 g_object_unref (object: tmp->data.v_pointer);
53 else if (g_type_is_a (type: column_headers [i], G_TYPE_BOXED) && tmp->data.v_pointer != NULL)
54 g_boxed_free (boxed_type: column_headers [i], boxed: (gpointer) tmp->data.v_pointer);
55 else if (g_type_is_a (type: column_headers [i], G_TYPE_VARIANT) && tmp->data.v_pointer != NULL)
56 g_variant_unref (value: (gpointer) tmp->data.v_pointer);
57
58 g_slice_free (GtkTreeDataList, tmp);
59 i++;
60 tmp = next;
61 }
62}
63
64gboolean
65_gtk_tree_data_list_check_type (GType type)
66{
67 int i = 0;
68 static const GType type_list[] =
69 {
70 G_TYPE_BOOLEAN,
71 G_TYPE_CHAR,
72 G_TYPE_UCHAR,
73 G_TYPE_INT,
74 G_TYPE_UINT,
75 G_TYPE_LONG,
76 G_TYPE_ULONG,
77 G_TYPE_INT64,
78 G_TYPE_UINT64,
79 G_TYPE_ENUM,
80 G_TYPE_FLAGS,
81 G_TYPE_FLOAT,
82 G_TYPE_DOUBLE,
83 G_TYPE_STRING,
84 G_TYPE_POINTER,
85 G_TYPE_BOXED,
86 G_TYPE_OBJECT,
87 G_TYPE_VARIANT,
88 G_TYPE_INVALID
89 };
90
91 if (! G_TYPE_IS_VALUE_TYPE (type))
92 return FALSE;
93
94
95 while (type_list[i] != G_TYPE_INVALID)
96 {
97 if (g_type_is_a (type, is_a_type: type_list[i]))
98 return TRUE;
99 i++;
100 }
101 return FALSE;
102}
103
104static inline GType
105get_fundamental_type (GType type)
106{
107 GType result;
108
109 result = G_TYPE_FUNDAMENTAL (type);
110
111 if (result == G_TYPE_INTERFACE)
112 {
113 if (g_type_is_a (type, G_TYPE_OBJECT))
114 result = G_TYPE_OBJECT;
115 }
116
117 return result;
118}
119void
120_gtk_tree_data_list_node_to_value (GtkTreeDataList *list,
121 GType type,
122 GValue *value)
123{
124 g_value_init (value, g_type: type);
125
126 switch (get_fundamental_type (type))
127 {
128 case G_TYPE_BOOLEAN:
129 g_value_set_boolean (value, v_boolean: (gboolean) list->data.v_int);
130 break;
131 case G_TYPE_CHAR:
132 g_value_set_schar (value, v_char: (char) list->data.v_char);
133 break;
134 case G_TYPE_UCHAR:
135 g_value_set_uchar (value, v_uchar: (guchar) list->data.v_uchar);
136 break;
137 case G_TYPE_INT:
138 g_value_set_int (value, v_int: (int) list->data.v_int);
139 break;
140 case G_TYPE_UINT:
141 g_value_set_uint (value, v_uint: (guint) list->data.v_uint);
142 break;
143 case G_TYPE_LONG:
144 g_value_set_long (value, v_long: list->data.v_long);
145 break;
146 case G_TYPE_ULONG:
147 g_value_set_ulong (value, v_ulong: list->data.v_ulong);
148 break;
149 case G_TYPE_INT64:
150 g_value_set_int64 (value, v_int64: list->data.v_int64);
151 break;
152 case G_TYPE_UINT64:
153 g_value_set_uint64 (value, v_uint64: list->data.v_uint64);
154 break;
155 case G_TYPE_ENUM:
156 g_value_set_enum (value, v_enum: list->data.v_int);
157 break;
158 case G_TYPE_FLAGS:
159 g_value_set_flags (value, v_flags: list->data.v_uint);
160 break;
161 case G_TYPE_FLOAT:
162 g_value_set_float (value, v_float: (float) list->data.v_float);
163 break;
164 case G_TYPE_DOUBLE:
165 g_value_set_double (value, v_double: (double) list->data.v_double);
166 break;
167 case G_TYPE_STRING:
168 g_value_set_string (value, v_string: (char *) list->data.v_pointer);
169 break;
170 case G_TYPE_POINTER:
171 g_value_set_pointer (value, v_pointer: (gpointer) list->data.v_pointer);
172 break;
173 case G_TYPE_BOXED:
174 g_value_set_boxed (value, v_boxed: (gpointer) list->data.v_pointer);
175 break;
176 case G_TYPE_VARIANT:
177 g_value_set_variant (value, variant: (gpointer) list->data.v_pointer);
178 break;
179 case G_TYPE_OBJECT:
180 g_value_set_object (value, v_object: (GObject *) list->data.v_pointer);
181 break;
182 default:
183 g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
184 break;
185 }
186}
187
188void
189_gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
190 GValue *value)
191{
192 switch (get_fundamental_type (G_VALUE_TYPE (value)))
193 {
194 case G_TYPE_BOOLEAN:
195 list->data.v_int = g_value_get_boolean (value);
196 break;
197 case G_TYPE_CHAR:
198 list->data.v_char = g_value_get_schar (value);
199 break;
200 case G_TYPE_UCHAR:
201 list->data.v_uchar = g_value_get_uchar (value);
202 break;
203 case G_TYPE_INT:
204 list->data.v_int = g_value_get_int (value);
205 break;
206 case G_TYPE_UINT:
207 list->data.v_uint = g_value_get_uint (value);
208 break;
209 case G_TYPE_LONG:
210 list->data.v_long = g_value_get_long (value);
211 break;
212 case G_TYPE_ULONG:
213 list->data.v_ulong = g_value_get_ulong (value);
214 break;
215 case G_TYPE_INT64:
216 list->data.v_int64 = g_value_get_int64 (value);
217 break;
218 case G_TYPE_UINT64:
219 list->data.v_uint64 = g_value_get_uint64 (value);
220 break;
221 case G_TYPE_ENUM:
222 list->data.v_int = g_value_get_enum (value);
223 break;
224 case G_TYPE_FLAGS:
225 list->data.v_uint = g_value_get_flags (value);
226 break;
227 case G_TYPE_POINTER:
228 list->data.v_pointer = g_value_get_pointer (value);
229 break;
230 case G_TYPE_FLOAT:
231 list->data.v_float = g_value_get_float (value);
232 break;
233 case G_TYPE_DOUBLE:
234 list->data.v_double = g_value_get_double (value);
235 break;
236 case G_TYPE_STRING:
237 g_free (mem: list->data.v_pointer);
238 list->data.v_pointer = g_value_dup_string (value);
239 break;
240 case G_TYPE_OBJECT:
241 if (list->data.v_pointer)
242 g_object_unref (object: list->data.v_pointer);
243 list->data.v_pointer = g_value_dup_object (value);
244 break;
245 case G_TYPE_BOXED:
246 if (list->data.v_pointer)
247 g_boxed_free (G_VALUE_TYPE (value), boxed: list->data.v_pointer);
248 list->data.v_pointer = g_value_dup_boxed (value);
249 break;
250 case G_TYPE_VARIANT:
251 if (list->data.v_pointer)
252 g_variant_unref (value: list->data.v_pointer);
253 list->data.v_pointer = g_value_dup_variant (value);
254 break;
255 default:
256 g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
257 break;
258 }
259}
260
261GtkTreeDataList *
262_gtk_tree_data_list_node_copy (GtkTreeDataList *list,
263 GType type)
264{
265 GtkTreeDataList *new_list;
266
267 g_return_val_if_fail (list != NULL, NULL);
268
269 new_list = _gtk_tree_data_list_alloc ();
270 new_list->next = NULL;
271
272 switch (get_fundamental_type (type))
273 {
274 case G_TYPE_BOOLEAN:
275 case G_TYPE_CHAR:
276 case G_TYPE_UCHAR:
277 case G_TYPE_INT:
278 case G_TYPE_UINT:
279 case G_TYPE_LONG:
280 case G_TYPE_ULONG:
281 case G_TYPE_INT64:
282 case G_TYPE_UINT64:
283 case G_TYPE_ENUM:
284 case G_TYPE_FLAGS:
285 case G_TYPE_POINTER:
286 case G_TYPE_FLOAT:
287 case G_TYPE_DOUBLE:
288 new_list->data = list->data;
289 break;
290 case G_TYPE_STRING:
291 new_list->data.v_pointer = g_strdup (str: list->data.v_pointer);
292 break;
293 case G_TYPE_OBJECT:
294 case G_TYPE_INTERFACE:
295 new_list->data.v_pointer = list->data.v_pointer;
296 if (new_list->data.v_pointer)
297 g_object_ref (new_list->data.v_pointer);
298 break;
299 case G_TYPE_BOXED:
300 if (list->data.v_pointer)
301 new_list->data.v_pointer = g_boxed_copy (boxed_type: type, src_boxed: list->data.v_pointer);
302 else
303 new_list->data.v_pointer = NULL;
304 break;
305 case G_TYPE_VARIANT:
306 if (list->data.v_pointer)
307 new_list->data.v_pointer = g_variant_ref (value: list->data.v_pointer);
308 else
309 new_list->data.v_pointer = NULL;
310 break;
311 default:
312 g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
313 break;
314 }
315
316 return new_list;
317}
318
319int
320_gtk_tree_data_list_compare_func (GtkTreeModel *model,
321 GtkTreeIter *a,
322 GtkTreeIter *b,
323 gpointer user_data)
324{
325 int column = GPOINTER_TO_INT (user_data);
326 GType type = gtk_tree_model_get_column_type (tree_model: model, index_: column);
327 GValue a_value = G_VALUE_INIT;
328 GValue b_value = G_VALUE_INIT;
329 int retval;
330 const char *stra, *strb;
331
332 gtk_tree_model_get_value (tree_model: model, iter: a, column, value: &a_value);
333 gtk_tree_model_get_value (tree_model: model, iter: b, column, value: &b_value);
334
335 switch (get_fundamental_type (type))
336 {
337 case G_TYPE_BOOLEAN:
338 if (g_value_get_boolean (value: &a_value) < g_value_get_boolean (value: &b_value))
339 retval = -1;
340 else if (g_value_get_boolean (value: &a_value) == g_value_get_boolean (value: &b_value))
341 retval = 0;
342 else
343 retval = 1;
344 break;
345 case G_TYPE_CHAR:
346 if (g_value_get_schar (value: &a_value) < g_value_get_schar (value: &b_value))
347 retval = -1;
348 else if (g_value_get_schar (value: &a_value) == g_value_get_schar (value: &b_value))
349 retval = 0;
350 else
351 retval = 1;
352 break;
353 case G_TYPE_UCHAR:
354 if (g_value_get_uchar (value: &a_value) < g_value_get_uchar (value: &b_value))
355 retval = -1;
356 else if (g_value_get_uchar (value: &a_value) == g_value_get_uchar (value: &b_value))
357 retval = 0;
358 else
359 retval = 1;
360 break;
361 case G_TYPE_INT:
362 if (g_value_get_int (value: &a_value) < g_value_get_int (value: &b_value))
363 retval = -1;
364 else if (g_value_get_int (value: &a_value) == g_value_get_int (value: &b_value))
365 retval = 0;
366 else
367 retval = 1;
368 break;
369 case G_TYPE_UINT:
370 if (g_value_get_uint (value: &a_value) < g_value_get_uint (value: &b_value))
371 retval = -1;
372 else if (g_value_get_uint (value: &a_value) == g_value_get_uint (value: &b_value))
373 retval = 0;
374 else
375 retval = 1;
376 break;
377 case G_TYPE_LONG:
378 if (g_value_get_long (value: &a_value) < g_value_get_long (value: &b_value))
379 retval = -1;
380 else if (g_value_get_long (value: &a_value) == g_value_get_long (value: &b_value))
381 retval = 0;
382 else
383 retval = 1;
384 break;
385 case G_TYPE_ULONG:
386 if (g_value_get_ulong (value: &a_value) < g_value_get_ulong (value: &b_value))
387 retval = -1;
388 else if (g_value_get_ulong (value: &a_value) == g_value_get_ulong (value: &b_value))
389 retval = 0;
390 else
391 retval = 1;
392 break;
393 case G_TYPE_INT64:
394 if (g_value_get_int64 (value: &a_value) < g_value_get_int64 (value: &b_value))
395 retval = -1;
396 else if (g_value_get_int64 (value: &a_value) == g_value_get_int64 (value: &b_value))
397 retval = 0;
398 else
399 retval = 1;
400 break;
401 case G_TYPE_UINT64:
402 if (g_value_get_uint64 (value: &a_value) < g_value_get_uint64 (value: &b_value))
403 retval = -1;
404 else if (g_value_get_uint64 (value: &a_value) == g_value_get_uint64 (value: &b_value))
405 retval = 0;
406 else
407 retval = 1;
408 break;
409 case G_TYPE_ENUM:
410 /* this is somewhat bogus. */
411 if (g_value_get_enum (value: &a_value) < g_value_get_enum (value: &b_value))
412 retval = -1;
413 else if (g_value_get_enum (value: &a_value) == g_value_get_enum (value: &b_value))
414 retval = 0;
415 else
416 retval = 1;
417 break;
418 case G_TYPE_FLAGS:
419 /* this is even more bogus. */
420 if (g_value_get_flags (value: &a_value) < g_value_get_flags (value: &b_value))
421 retval = -1;
422 else if (g_value_get_flags (value: &a_value) == g_value_get_flags (value: &b_value))
423 retval = 0;
424 else
425 retval = 1;
426 break;
427 case G_TYPE_FLOAT:
428 if (g_value_get_float (value: &a_value) < g_value_get_float (value: &b_value))
429 retval = -1;
430 else if (g_value_get_float (value: &a_value) == g_value_get_float (value: &b_value))
431 retval = 0;
432 else
433 retval = 1;
434 break;
435 case G_TYPE_DOUBLE:
436 if (g_value_get_double (value: &a_value) < g_value_get_double (value: &b_value))
437 retval = -1;
438 else if (g_value_get_double (value: &a_value) == g_value_get_double (value: &b_value))
439 retval = 0;
440 else
441 retval = 1;
442 break;
443 case G_TYPE_STRING:
444 stra = g_value_get_string (value: &a_value);
445 strb = g_value_get_string (value: &b_value);
446 if (stra == NULL) stra = "";
447 if (strb == NULL) strb = "";
448 retval = g_utf8_collate (str1: stra, str2: strb);
449 break;
450 case G_TYPE_VARIANT:
451 case G_TYPE_POINTER:
452 case G_TYPE_BOXED:
453 case G_TYPE_OBJECT:
454 default:
455 g_warning ("Attempting to sort on invalid type %s", g_type_name (type));
456 retval = FALSE;
457 break;
458 }
459
460 g_value_unset (value: &a_value);
461 g_value_unset (value: &b_value);
462
463 return retval;
464}
465
466
467GList *
468_gtk_tree_data_list_header_new (int n_columns,
469 GType *types)
470{
471 GList *retval = NULL;
472
473 int i;
474
475 for (i = 0; i < n_columns; i ++)
476 {
477 GtkTreeDataSortHeader *header;
478
479 header = g_slice_new (GtkTreeDataSortHeader);
480
481 retval = g_list_prepend (list: retval, data: header);
482 header->sort_column_id = i;
483 header->func = _gtk_tree_data_list_compare_func;
484 header->destroy = NULL;
485 header->data = GINT_TO_POINTER (i);
486 }
487 return g_list_reverse (list: retval);
488}
489
490void
491_gtk_tree_data_list_header_free (GList *list)
492{
493 GList *tmp;
494
495 for (tmp = list; tmp; tmp = tmp->next)
496 {
497 GtkTreeDataSortHeader *header = (GtkTreeDataSortHeader *) tmp->data;
498
499 if (header->destroy)
500 {
501 GDestroyNotify d = header->destroy;
502
503 header->destroy = NULL;
504 d (header->data);
505 }
506
507 g_slice_free (GtkTreeDataSortHeader, header);
508 }
509 g_list_free (list);
510}
511
512GtkTreeDataSortHeader *
513_gtk_tree_data_list_get_header (GList *header_list,
514 int sort_column_id)
515{
516 GtkTreeDataSortHeader *header = NULL;
517
518 for (; header_list; header_list = header_list->next)
519 {
520 header = (GtkTreeDataSortHeader*) header_list->data;
521 if (header->sort_column_id == sort_column_id)
522 return header;
523 }
524 return NULL;
525}
526
527
528GList *
529_gtk_tree_data_list_set_header (GList *header_list,
530 int sort_column_id,
531 GtkTreeIterCompareFunc func,
532 gpointer data,
533 GDestroyNotify destroy)
534{
535 GList *list = header_list;
536 GtkTreeDataSortHeader *header = NULL;
537
538 for (; list; list = list->next)
539 {
540 header = (GtkTreeDataSortHeader*) list->data;
541 if (header->sort_column_id == sort_column_id)
542 break;
543 header = NULL;
544
545 if (list->next == NULL)
546 break;
547 }
548
549 if (header == NULL)
550 {
551 header = g_slice_new0 (GtkTreeDataSortHeader);
552 header->sort_column_id = sort_column_id;
553 if (list)
554 list = g_list_append (list, data: header);
555 else
556 header_list = g_list_append (list: header_list, data: header);
557 }
558
559 if (header->destroy)
560 {
561 GDestroyNotify d = header->destroy;
562
563 header->destroy = NULL;
564 d (header->data);
565 }
566
567 header->func = func;
568 header->data = data;
569 header->destroy = destroy;
570
571 return header_list;
572}
573

source code of gtk/gtk/gtktreedatalist.c