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