]> Pileus Git - ~andy/gtk/blob - gtk/gtktreedatalist.c
Include "config.h" instead of <config.h> Command used: find -name
[~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       g_free (list->data.v_pointer);
235       list->data.v_pointer = g_value_dup_string (value);
236       break;
237     case G_TYPE_OBJECT:
238       if (list->data.v_pointer)
239         g_object_unref (list->data.v_pointer);
240       list->data.v_pointer = g_value_dup_object (value);
241       break;
242     case G_TYPE_BOXED:
243       if (list->data.v_pointer)
244         g_boxed_free (G_VALUE_TYPE (value), list->data.v_pointer);
245       list->data.v_pointer = g_value_dup_boxed (value);
246       break;
247     default:
248       g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
249       break;
250     }
251 }
252
253 GtkTreeDataList *
254 _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
255                                GType            type)
256 {
257   GtkTreeDataList *new_list;
258
259   g_return_val_if_fail (list != NULL, NULL);
260   
261   new_list = _gtk_tree_data_list_alloc ();
262   new_list->next = NULL;
263
264   switch (get_fundamental_type (type))
265     {
266     case G_TYPE_BOOLEAN:
267     case G_TYPE_CHAR:
268     case G_TYPE_UCHAR:
269     case G_TYPE_INT:
270     case G_TYPE_UINT:
271     case G_TYPE_LONG:
272     case G_TYPE_ULONG:
273     case G_TYPE_INT64:
274     case G_TYPE_UINT64:
275     case G_TYPE_ENUM:
276     case G_TYPE_FLAGS:
277     case G_TYPE_POINTER:
278     case G_TYPE_FLOAT:
279     case G_TYPE_DOUBLE:
280       new_list->data = list->data;
281       break;
282     case G_TYPE_STRING:
283       new_list->data.v_pointer = g_strdup (list->data.v_pointer);
284       break;
285     case G_TYPE_OBJECT:
286     case G_TYPE_INTERFACE:
287       new_list->data.v_pointer = list->data.v_pointer;
288       if (new_list->data.v_pointer)
289         g_object_ref (new_list->data.v_pointer);
290       break;
291     case G_TYPE_BOXED:
292       if (list->data.v_pointer)
293         new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
294       else
295         new_list->data.v_pointer = NULL;
296       break;
297     default:
298       g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
299       break;
300     }
301
302   return new_list;
303 }
304
305 gint
306 _gtk_tree_data_list_compare_func (GtkTreeModel *model,
307                                   GtkTreeIter  *a,
308                                   GtkTreeIter  *b,
309                                   gpointer      user_data)
310 {
311   gint column = GPOINTER_TO_INT (user_data);
312   GType type = gtk_tree_model_get_column_type (model, column);
313   GValue a_value = {0, };
314   GValue b_value = {0, };
315   gint retval;
316   const gchar *stra, *strb;
317
318   gtk_tree_model_get_value (model, a, column, &a_value);
319   gtk_tree_model_get_value (model, b, column, &b_value);
320
321   switch (get_fundamental_type (type))
322     {
323     case G_TYPE_BOOLEAN:
324       if (g_value_get_boolean (&a_value) < g_value_get_boolean (&b_value))
325         retval = -1;
326       else if (g_value_get_boolean (&a_value) == g_value_get_boolean (&b_value))
327         retval = 0;
328       else
329         retval = 1;
330       break;
331     case G_TYPE_CHAR:
332       if (g_value_get_char (&a_value) < g_value_get_char (&b_value))
333         retval = -1;
334       else if (g_value_get_char (&a_value) == g_value_get_char (&b_value))
335         retval = 0;
336       else
337         retval = 1;
338       break;
339     case G_TYPE_UCHAR:
340       if (g_value_get_uchar (&a_value) < g_value_get_uchar (&b_value))
341         retval = -1;
342       else if (g_value_get_uchar (&a_value) == g_value_get_uchar (&b_value))
343         retval = 0;
344       else
345         retval = 1;
346       break;
347     case G_TYPE_INT:
348       if (g_value_get_int (&a_value) < g_value_get_int (&b_value))
349         retval = -1;
350       else if (g_value_get_int (&a_value) == g_value_get_int (&b_value))
351         retval = 0;
352       else
353         retval = 1;
354       break;
355     case G_TYPE_UINT:
356       if (g_value_get_uint (&a_value) < g_value_get_uint (&b_value))
357         retval = -1;
358       else if (g_value_get_uint (&a_value) == g_value_get_uint (&b_value))
359         retval = 0;
360       else
361         retval = 1;
362       break;
363     case G_TYPE_LONG:
364       if (g_value_get_long (&a_value) < g_value_get_long (&b_value))
365         retval = -1;
366       else if (g_value_get_long (&a_value) == g_value_get_long (&b_value))
367         retval = 0;
368       else
369         retval = 1;
370       break;
371     case G_TYPE_ULONG:
372       if (g_value_get_ulong (&a_value) < g_value_get_ulong (&b_value))
373         retval = -1;
374       else if (g_value_get_ulong (&a_value) == g_value_get_ulong (&b_value))
375         retval = 0;
376       else
377         retval = 1;
378       break;
379     case G_TYPE_INT64:
380       if (g_value_get_int64 (&a_value) < g_value_get_int64 (&b_value))
381         retval = -1;
382       else if (g_value_get_int64 (&a_value) == g_value_get_int64 (&b_value))
383         retval = 0;
384       else
385         retval = 1;
386       break;
387     case G_TYPE_UINT64:
388       if (g_value_get_uint64 (&a_value) < g_value_get_uint64 (&b_value))
389         retval = -1;
390       else if (g_value_get_uint64 (&a_value) == g_value_get_uint64 (&b_value))
391         retval = 0;
392       else
393         retval = 1;
394       break;
395     case G_TYPE_ENUM:
396       /* this is somewhat bogus. */
397       if (g_value_get_enum (&a_value) < g_value_get_enum (&b_value))
398         retval = -1;
399       else if (g_value_get_enum (&a_value) == g_value_get_enum (&b_value))
400         retval = 0;
401       else
402         retval = 1;
403       break;
404     case G_TYPE_FLAGS:
405       /* this is even more bogus. */
406       if (g_value_get_flags (&a_value) < g_value_get_flags (&b_value))
407         retval = -1;
408       else if (g_value_get_flags (&a_value) == g_value_get_flags (&b_value))
409         retval = 0;
410       else
411         retval = 1;
412       break;
413     case G_TYPE_FLOAT:
414       if (g_value_get_float (&a_value) < g_value_get_float (&b_value))
415         retval = -1;
416       else if (g_value_get_float (&a_value) == g_value_get_float (&b_value))
417         retval = 0;
418       else
419         retval = 1;
420       break;
421     case G_TYPE_DOUBLE:
422       if (g_value_get_double (&a_value) < g_value_get_double (&b_value))
423         retval = -1;
424       else if (g_value_get_double (&a_value) == g_value_get_double (&b_value))
425         retval = 0;
426       else
427         retval = 1;
428       break;
429     case G_TYPE_STRING:
430       stra = g_value_get_string (&a_value);
431       strb = g_value_get_string (&b_value);
432       if (stra == NULL) stra = "";
433       if (strb == NULL) strb = "";
434       retval = g_utf8_collate (stra, strb);
435       break;
436     case G_TYPE_POINTER:
437     case G_TYPE_BOXED:
438     case G_TYPE_OBJECT:
439     default:
440       g_warning ("Attempting to sort on invalid type %s\n", g_type_name (type));
441       retval = FALSE;
442       break;
443     }
444
445   g_value_unset (&a_value);
446   g_value_unset (&b_value);
447
448   return retval;
449 }
450
451
452 GList *
453 _gtk_tree_data_list_header_new (gint   n_columns,
454                                 GType *types)
455 {
456   GList *retval = NULL;
457
458   gint i;
459
460   for (i = 0; i < n_columns; i ++)
461     {
462       GtkTreeDataSortHeader *header;
463
464       header = g_slice_new (GtkTreeDataSortHeader);
465
466       retval = g_list_prepend (retval, header);
467       header->sort_column_id = i;
468       header->func = _gtk_tree_data_list_compare_func;
469       header->destroy = NULL;
470       header->data = GINT_TO_POINTER (i);
471     }
472   return g_list_reverse (retval);
473 }
474
475 void
476 _gtk_tree_data_list_header_free (GList *list)
477 {
478   GList *tmp;
479
480   for (tmp = list; tmp; tmp = tmp->next)
481     {
482       GtkTreeDataSortHeader *header = (GtkTreeDataSortHeader *) tmp->data;
483
484       if (header->destroy)
485         {
486           GDestroyNotify d = header->destroy;
487
488           header->destroy = NULL;
489           d (header->data);
490         }
491
492       g_slice_free (GtkTreeDataSortHeader, header);
493     }
494   g_list_free (list);
495 }
496
497 GtkTreeDataSortHeader *
498 _gtk_tree_data_list_get_header (GList   *header_list,
499                                 gint     sort_column_id)
500 {
501   GtkTreeDataSortHeader *header = NULL;
502
503   for (; header_list; header_list = header_list->next)
504     {
505       header = (GtkTreeDataSortHeader*) header_list->data;
506       if (header->sort_column_id == sort_column_id)
507         return header;
508     }
509   return NULL;
510 }
511
512
513 GList *
514 _gtk_tree_data_list_set_header (GList                  *header_list,
515                                 gint                    sort_column_id,
516                                 GtkTreeIterCompareFunc  func,
517                                 gpointer                data,
518                                 GDestroyNotify          destroy)
519 {
520   GList *list = header_list;
521   GtkTreeDataSortHeader *header = NULL;
522
523   for (; list; list = list->next)
524     {
525       header = (GtkTreeDataSortHeader*) list->data;
526       if (header->sort_column_id == sort_column_id)
527         break;
528       header = NULL;
529
530       if (list->next == NULL)
531         break;
532     }
533   
534   if (header == NULL)
535     {
536       header = g_slice_new0 (GtkTreeDataSortHeader);
537       header->sort_column_id = sort_column_id;
538       if (list)
539         list = g_list_append (list, header);
540       else
541         header_list = g_list_append (header_list, header);
542     }
543
544   if (header->destroy)
545     {
546       GDestroyNotify d = header->destroy;
547       
548       header->destroy = NULL;
549       d (header->data);
550     }
551   
552   header->func = func;
553   header->data = data;
554   header->destroy = destroy;
555
556   return header_list;
557 }