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