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