]> Pileus Git - ~andy/gtk/blob - gtk/gtktreedatalist.c
Make PLT-reduction work with gcc4, and don't include everything in
[~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 static GMemChunk *tree_chunk = NULL;
28 #define TREE_CHUNK_PREALLOCS 64
29
30 /* node allocation
31  */
32 GtkTreeDataList *
33 _gtk_tree_data_list_alloc (void)
34 {
35   GtkTreeDataList *list;
36
37   if (tree_chunk == NULL)
38     tree_chunk = g_mem_chunk_new ("treedatalist mem chunk",
39                                   sizeof (GtkTreeDataList),
40                                   sizeof (GtkTreeDataList) * TREE_CHUNK_PREALLOCS,
41                                   G_ALLOC_AND_FREE);
42
43   list = g_chunk_new (GtkTreeDataList, tree_chunk);
44   memset (list, 0, sizeof (GtkTreeDataList));
45
46   return list;
47 }
48
49 void
50 _gtk_tree_data_list_free (GtkTreeDataList *list,
51                           GType           *column_headers)
52 {
53   GtkTreeDataList *tmp, *next;
54   gint i = 0;
55
56   tmp = list;
57
58   while (tmp)
59     {
60       next = tmp->next;
61       if (g_type_is_a (column_headers [i], G_TYPE_STRING))
62         g_free ((gchar *) tmp->data.v_pointer);
63       else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT) && tmp->data.v_pointer != NULL)
64         g_object_unref (tmp->data.v_pointer);
65       else if (g_type_is_a (column_headers [i], G_TYPE_BOXED) && tmp->data.v_pointer != NULL)
66         g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
67
68       g_mem_chunk_free (tree_chunk, tmp);
69       i++;
70       tmp = next;
71     }
72 }
73
74 gboolean
75 _gtk_tree_data_list_check_type (GType type)
76 {
77   gint i = 0;
78   static const GType type_list[] =
79   {
80     G_TYPE_BOOLEAN,
81     G_TYPE_CHAR,
82     G_TYPE_UCHAR,
83     G_TYPE_INT,
84     G_TYPE_UINT,
85     G_TYPE_LONG,
86     G_TYPE_ULONG,
87     G_TYPE_INT64,
88     G_TYPE_UINT64,
89     G_TYPE_ENUM,
90     G_TYPE_FLAGS,
91     G_TYPE_FLOAT,
92     G_TYPE_DOUBLE,
93     G_TYPE_STRING,
94     G_TYPE_POINTER,
95     G_TYPE_BOXED,
96     G_TYPE_OBJECT,
97     G_TYPE_INVALID
98   };
99
100   if (! G_TYPE_IS_VALUE_TYPE (type))
101     return FALSE;
102
103
104   while (type_list[i] != G_TYPE_INVALID)
105     {
106       if (g_type_is_a (type, type_list[i]))
107         return TRUE;
108       i++;
109     }
110   return FALSE;
111 }
112
113 static inline GType
114 get_fundamental_type (GType type)
115 {
116   GType result;
117
118   result = G_TYPE_FUNDAMENTAL (type);
119
120   if (result == G_TYPE_INTERFACE)
121     {
122       if (g_type_is_a (type, G_TYPE_OBJECT))
123         result = G_TYPE_OBJECT;
124     }
125
126   return result;
127 }
128 void
129 _gtk_tree_data_list_node_to_value (GtkTreeDataList *list,
130                                    GType            type,
131                                    GValue          *value)
132 {
133   g_value_init (value, type);
134
135   switch (get_fundamental_type (type))
136     {
137     case G_TYPE_BOOLEAN:
138       g_value_set_boolean (value, (gboolean) list->data.v_int);
139       break;
140     case G_TYPE_CHAR:
141       g_value_set_char (value, (gchar) list->data.v_char);
142       break;
143     case G_TYPE_UCHAR:
144       g_value_set_uchar (value, (guchar) list->data.v_uchar);
145       break;
146     case G_TYPE_INT:
147       g_value_set_int (value, (gint) list->data.v_int);
148       break;
149     case G_TYPE_UINT:
150       g_value_set_uint (value, (guint) list->data.v_uint);
151       break;
152     case G_TYPE_LONG:
153       g_value_set_long (value, list->data.v_long);
154       break;
155     case G_TYPE_ULONG:
156       g_value_set_ulong (value, list->data.v_ulong);
157       break;
158     case G_TYPE_INT64:
159       g_value_set_int64 (value, list->data.v_int64);
160       break;
161     case G_TYPE_UINT64:
162       g_value_set_uint64 (value, list->data.v_uint64);
163       break;
164     case G_TYPE_ENUM:
165       g_value_set_enum (value, list->data.v_int);
166       break;
167     case G_TYPE_FLAGS:
168       g_value_set_flags (value, list->data.v_uint);
169       break;
170     case G_TYPE_FLOAT:
171       g_value_set_float (value, (gfloat) list->data.v_float);
172       break;
173     case G_TYPE_DOUBLE:
174       g_value_set_double (value, (gdouble) list->data.v_double);
175       break;
176     case G_TYPE_STRING:
177       g_value_set_string (value, (gchar *) list->data.v_pointer);
178       break;
179     case G_TYPE_POINTER:
180       g_value_set_pointer (value, (gpointer) list->data.v_pointer);
181       break;
182     case G_TYPE_BOXED:
183       g_value_set_boxed (value, (gpointer) list->data.v_pointer);
184       break;
185     case G_TYPE_OBJECT:
186       g_value_set_object (value, (GObject *) list->data.v_pointer);
187       break;
188     default:
189       g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
190       break;
191     }
192 }
193
194 void
195 _gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
196                                    GValue          *value)
197 {
198   switch (get_fundamental_type (G_VALUE_TYPE (value)))
199     {
200     case G_TYPE_BOOLEAN:
201       list->data.v_int = g_value_get_boolean (value);
202       break;
203     case G_TYPE_CHAR:
204       list->data.v_char = g_value_get_char (value);
205       break;
206     case G_TYPE_UCHAR:
207       list->data.v_uchar = g_value_get_uchar (value);
208       break;
209     case G_TYPE_INT:
210       list->data.v_int = g_value_get_int (value);
211       break;
212     case G_TYPE_UINT:
213       list->data.v_uint = g_value_get_uint (value);
214       break;
215     case G_TYPE_LONG:
216       list->data.v_long = g_value_get_long (value);
217       break;
218     case G_TYPE_ULONG:
219       list->data.v_ulong = g_value_get_ulong (value);
220       break;
221     case G_TYPE_INT64:
222       list->data.v_int64 = g_value_get_int64 (value);
223       break;
224     case G_TYPE_UINT64:
225       list->data.v_uint64 = g_value_get_uint64 (value);
226       break;
227     case G_TYPE_ENUM:
228       list->data.v_int = g_value_get_enum (value);
229       break;
230     case G_TYPE_FLAGS:
231       list->data.v_uint = g_value_get_flags (value);
232       break;
233     case G_TYPE_POINTER:
234       list->data.v_pointer = g_value_get_pointer (value);
235       break;
236     case G_TYPE_FLOAT:
237       list->data.v_float = g_value_get_float (value);
238       break;
239     case G_TYPE_DOUBLE:
240       list->data.v_double = g_value_get_double (value);
241       break;
242     case G_TYPE_STRING:
243       if (list->data.v_pointer)
244         g_free (list->data.v_pointer);
245       list->data.v_pointer = g_value_dup_string (value);
246       break;
247     case G_TYPE_OBJECT:
248       if (list->data.v_pointer)
249         g_object_unref (list->data.v_pointer);
250       list->data.v_pointer = g_value_dup_object (value);
251       break;
252     case G_TYPE_BOXED:
253       if (list->data.v_pointer)
254         g_boxed_free (G_VALUE_TYPE (value), list->data.v_pointer);
255       list->data.v_pointer = g_value_dup_boxed (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     default:
308       g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
309       break;
310     }
311
312   return new_list;
313 }
314
315 gint
316 _gtk_tree_data_list_compare_func (GtkTreeModel *model,
317                                   GtkTreeIter  *a,
318                                   GtkTreeIter  *b,
319                                   gpointer      user_data)
320 {
321   gint column = GPOINTER_TO_INT (user_data);
322   GType type = gtk_tree_model_get_column_type (model, column);
323   GValue a_value = {0, };
324   GValue b_value = {0, };
325   gint retval;
326   const gchar *stra, *strb;
327
328   gtk_tree_model_get_value (model, a, column, &a_value);
329   gtk_tree_model_get_value (model, b, column, &b_value);
330
331   switch (get_fundamental_type (type))
332     {
333     case G_TYPE_BOOLEAN:
334       if (g_value_get_boolean (&a_value) < g_value_get_boolean (&b_value))
335         retval = -1;
336       else if (g_value_get_boolean (&a_value) == g_value_get_boolean (&b_value))
337         retval = 0;
338       else
339         retval = 1;
340       break;
341     case G_TYPE_CHAR:
342       if (g_value_get_char (&a_value) < g_value_get_char (&b_value))
343         retval = -1;
344       else if (g_value_get_char (&a_value) == g_value_get_char (&b_value))
345         retval = 0;
346       else
347         retval = 1;
348       break;
349     case G_TYPE_UCHAR:
350       if (g_value_get_uchar (&a_value) < g_value_get_uchar (&b_value))
351         retval = -1;
352       else if (g_value_get_uchar (&a_value) == g_value_get_uchar (&b_value))
353         retval = 0;
354       else
355         retval = 1;
356       break;
357     case G_TYPE_INT:
358       if (g_value_get_int (&a_value) < g_value_get_int (&b_value))
359         retval = -1;
360       else if (g_value_get_int (&a_value) == g_value_get_int (&b_value))
361         retval = 0;
362       else
363         retval = 1;
364       break;
365     case G_TYPE_UINT:
366       if (g_value_get_uint (&a_value) < g_value_get_uint (&b_value))
367         retval = -1;
368       else if (g_value_get_uint (&a_value) == g_value_get_uint (&b_value))
369         retval = 0;
370       else
371         retval = 1;
372       break;
373     case G_TYPE_LONG:
374       if (g_value_get_long (&a_value) < g_value_get_long (&b_value))
375         retval = -1;
376       else if (g_value_get_long (&a_value) == g_value_get_long (&b_value))
377         retval = 0;
378       else
379         retval = 1;
380       break;
381     case G_TYPE_ULONG:
382       if (g_value_get_ulong (&a_value) < g_value_get_ulong (&b_value))
383         retval = -1;
384       else if (g_value_get_ulong (&a_value) == g_value_get_ulong (&b_value))
385         retval = 0;
386       else
387         retval = 1;
388       break;
389     case G_TYPE_INT64:
390       if (g_value_get_int64 (&a_value) < g_value_get_int64 (&b_value))
391         retval = -1;
392       else if (g_value_get_int64 (&a_value) == g_value_get_int64 (&b_value))
393         retval = 0;
394       else
395         retval = 1;
396       break;
397     case G_TYPE_UINT64:
398       if (g_value_get_uint64 (&a_value) < g_value_get_uint64 (&b_value))
399         retval = -1;
400       else if (g_value_get_uint64 (&a_value) == g_value_get_uint64 (&b_value))
401         retval = 0;
402       else
403         retval = 1;
404       break;
405     case G_TYPE_ENUM:
406       /* this is somewhat bogus. */
407       if (g_value_get_enum (&a_value) < g_value_get_enum (&b_value))
408         retval = -1;
409       else if (g_value_get_enum (&a_value) == g_value_get_enum (&b_value))
410         retval = 0;
411       else
412         retval = 1;
413       break;
414     case G_TYPE_FLAGS:
415       /* this is even more bogus. */
416       if (g_value_get_flags (&a_value) < g_value_get_flags (&b_value))
417         retval = -1;
418       else if (g_value_get_flags (&a_value) == g_value_get_flags (&b_value))
419         retval = 0;
420       else
421         retval = 1;
422       break;
423     case G_TYPE_FLOAT:
424       if (g_value_get_float (&a_value) < g_value_get_float (&b_value))
425         retval = -1;
426       else if (g_value_get_float (&a_value) == g_value_get_float (&b_value))
427         retval = 0;
428       else
429         retval = 1;
430       break;
431     case G_TYPE_DOUBLE:
432       if (g_value_get_double (&a_value) < g_value_get_double (&b_value))
433         retval = -1;
434       else if (g_value_get_double (&a_value) == g_value_get_double (&b_value))
435         retval = 0;
436       else
437         retval = 1;
438       break;
439     case G_TYPE_STRING:
440       stra = g_value_get_string (&a_value);
441       strb = g_value_get_string (&b_value);
442       if (stra == NULL) stra = "";
443       if (strb == NULL) strb = "";
444       retval = g_utf8_collate (stra, strb);
445       break;
446     case G_TYPE_POINTER:
447     case G_TYPE_BOXED:
448     case G_TYPE_OBJECT:
449     default:
450       g_warning ("Attempting to sort on invalid type %s\n", g_type_name (type));
451       retval = FALSE;
452       break;
453     }
454
455   g_value_unset (&a_value);
456   g_value_unset (&b_value);
457
458   return retval;
459 }
460
461
462 GList *
463 _gtk_tree_data_list_header_new (gint   n_columns,
464                                 GType *types)
465 {
466   GList *retval = NULL;
467
468   gint i;
469
470   for (i = 0; i < n_columns; i ++)
471     {
472       GtkTreeDataSortHeader *header;
473
474       header = g_new (GtkTreeDataSortHeader, 1);
475
476       retval = g_list_prepend (retval, header);
477       header->sort_column_id = i;
478       header->func = _gtk_tree_data_list_compare_func;
479       header->destroy = NULL;
480       header->data = GINT_TO_POINTER (i);
481     }
482   return g_list_reverse (retval);
483 }
484
485 void
486 _gtk_tree_data_list_header_free (GList *list)
487 {
488   GList *tmp;
489
490   for (tmp = list; tmp; tmp = tmp->next)
491     {
492       GtkTreeDataSortHeader *header = (GtkTreeDataSortHeader *) tmp->data;
493
494       if (header->destroy)
495         {
496           GtkDestroyNotify d = header->destroy;
497
498           header->destroy = NULL;
499           d (header->data);
500         }
501
502       g_free (header);
503     }
504   g_list_free (list);
505 }
506
507 GtkTreeDataSortHeader *
508 _gtk_tree_data_list_get_header (GList *header_list,
509                                 gint   sort_column_id)
510 {
511   GtkTreeDataSortHeader *header = NULL;
512
513   for (; header_list; header_list = header_list->next)
514     {
515       header = (GtkTreeDataSortHeader*) header_list->data;
516       if (header->sort_column_id == sort_column_id)
517         return header;
518     }
519   return NULL;
520 }