]> Pileus Git - ~andy/gtk/blob - gtk/gtktreedatalist.c
Initial work on implementing the GtkTreeSortable interface. Basicaly a big
[~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 "gtktreedatalist.h"
24 #include <string.h>
25 static GMemChunk *tree_chunk = NULL;
26 #define TREE_CHUNK_PREALLOCS 64
27
28 /* node allocation
29  */
30 GtkTreeDataList *
31 _gtk_tree_data_list_alloc (void)
32 {
33   GtkTreeDataList *list;
34
35   if (tree_chunk == NULL)
36     tree_chunk = g_mem_chunk_new ("treedatalist mem chunk",
37                                   sizeof (GtkTreeDataList),
38                                   sizeof (GtkTreeDataList) * TREE_CHUNK_PREALLOCS,
39                                   G_ALLOC_AND_FREE);
40
41   list = g_chunk_new (GtkTreeDataList, tree_chunk);
42
43   return list;
44 }
45
46 void
47 _gtk_tree_data_list_free (GtkTreeDataList *list,
48                           GType           *column_headers)
49 {
50   GtkTreeDataList *tmp, *next;
51   gint i = 0;
52
53   tmp = list;
54
55   while (tmp)
56     {
57       next = tmp->next;
58       if (g_type_is_a (column_headers [i], G_TYPE_STRING))
59         g_free ((gchar *) tmp->data.v_pointer);
60       else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT))
61         g_object_unref (G_OBJECT (tmp->data.v_pointer));
62       else if (g_type_is_a (column_headers [i], G_TYPE_BOXED))
63         g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
64
65       g_mem_chunk_free (tree_chunk, tmp);
66       i++;
67       tmp = next;
68     }
69 }
70
71 gboolean
72 _gtk_tree_data_list_check_type (GType type)
73 {
74   gint i = 0;
75   static GType type_list[] =
76   {
77     G_TYPE_BOOLEAN,
78     G_TYPE_CHAR,
79     G_TYPE_UCHAR,
80     G_TYPE_INT,
81     G_TYPE_UINT,
82     G_TYPE_ENUM,
83     G_TYPE_FLAGS,
84     G_TYPE_FLOAT,
85     G_TYPE_DOUBLE,
86     G_TYPE_STRING,
87     G_TYPE_POINTER,
88     G_TYPE_BOXED,
89     G_TYPE_OBJECT,
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 void
107 _gtk_tree_data_list_node_to_value (GtkTreeDataList *list,
108                                    GType            type,
109                                    GValue          *value)
110 {
111   g_value_init (value, type);
112
113   switch (G_TYPE_FUNDAMENTAL (type))
114     {
115     case G_TYPE_BOOLEAN:
116       g_value_set_boolean (value, (gboolean) list->data.v_int);
117       break;
118     case G_TYPE_CHAR:
119       g_value_set_char (value, (gchar) list->data.v_char);
120       break;
121     case G_TYPE_UCHAR:
122       g_value_set_uchar (value, (guchar) list->data.v_uchar);
123       break;
124     case G_TYPE_INT:
125       g_value_set_int (value, (gint) list->data.v_int);
126       break;
127     case G_TYPE_UINT:
128       g_value_set_uint (value, (guint) list->data.v_uint);
129       break;
130     case G_TYPE_ENUM:
131       g_value_set_enum (value, list->data.v_int);
132       break;
133     case G_TYPE_FLAGS:
134       g_value_set_flags (value, (int) list->data.v_int);
135       break;
136     case G_TYPE_FLOAT:
137       g_value_set_float (value, (gfloat) list->data.v_float);
138       break;
139     case G_TYPE_DOUBLE:
140       g_value_set_double (value, (gdouble) list->data.v_double);
141       break;
142     case G_TYPE_STRING:
143       g_value_set_string (value, (gchar *) list->data.v_pointer);
144       break;
145     case G_TYPE_POINTER:
146       g_value_set_pointer (value, (gpointer) list->data.v_pointer);
147       break;
148     case G_TYPE_BOXED:
149       g_value_set_boxed (value, (gpointer) list->data.v_pointer);
150       break;
151     case G_TYPE_OBJECT:
152       g_value_set_object (value, (GObject *) list->data.v_pointer);
153       break;
154     default:
155       g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
156       break;
157     }
158 }
159
160 void
161 _gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
162                                    GValue          *value)
163 {
164   switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
165     {
166     case G_TYPE_BOOLEAN:
167       list->data.v_int = g_value_get_boolean (value);
168       break;
169     case G_TYPE_CHAR:
170       list->data.v_char = g_value_get_char (value);
171       break;
172     case G_TYPE_UCHAR:
173       list->data.v_uchar = g_value_get_uchar (value);
174       break;
175     case G_TYPE_INT:
176       list->data.v_int = g_value_get_int (value);
177       break;
178     case G_TYPE_ENUM:
179       list->data.v_int = g_value_get_enum (value);
180       break;
181     case G_TYPE_FLAGS:
182       list->data.v_int = g_value_get_flags (value);
183       break;
184     case G_TYPE_UINT:
185       list->data.v_uint = g_value_get_uint (value);
186       break;
187     case G_TYPE_POINTER:
188       list->data.v_pointer = g_value_get_pointer (value);
189       break;
190     case G_TYPE_FLOAT:
191       list->data.v_float = g_value_get_float (value);
192       break;
193     case G_TYPE_DOUBLE:
194       list->data.v_double = g_value_get_double (value);
195       break;
196     case G_TYPE_STRING:
197       list->data.v_pointer = g_value_dup_string (value);
198       break;
199     case G_TYPE_OBJECT:
200       list->data.v_pointer = g_value_dup_object (value);
201       break;
202     case G_TYPE_BOXED:
203       list->data.v_pointer = g_value_dup_boxed (value);
204       break;
205     default:
206       g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
207       break;
208     }
209 }
210
211 GtkTreeDataList *
212 _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
213                                GType            type)
214 {
215   GtkTreeDataList *new_list;
216
217   g_return_val_if_fail (list != NULL, NULL);
218   
219   new_list = _gtk_tree_data_list_alloc ();
220   new_list->next = NULL;
221
222   switch (G_TYPE_FUNDAMENTAL (type))
223     {
224     case G_TYPE_UINT:
225     case G_TYPE_INT:
226     case G_TYPE_UCHAR:
227     case G_TYPE_CHAR:
228     case G_TYPE_BOOLEAN:
229     case G_TYPE_POINTER:
230     case G_TYPE_FLOAT:
231     case G_TYPE_DOUBLE:
232       new_list->data = list->data;
233       break;
234     case G_TYPE_STRING:
235       new_list->data.v_pointer = g_strdup (list->data.v_pointer);
236       break;
237     case G_TYPE_OBJECT:
238       new_list->data.v_pointer = list->data.v_pointer;
239       if (new_list->data.v_pointer)
240         g_object_ref (G_OBJECT (new_list->data.v_pointer));
241       break;
242     case G_TYPE_BOXED:
243       if (list->data.v_pointer)
244         new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
245       else
246         new_list->data.v_pointer = NULL;
247       break;
248     default:
249       g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
250       break;
251     }
252
253   return new_list;
254 }
255
256 gint
257 gtk_tree_data_list_compare_func (GtkTreeModel *model,
258                                  GtkTreeIter  *a,
259                                  GtkTreeIter  *b,
260                                  gpointer      user_data)
261 {
262   gint column = GPOINTER_TO_INT (user_data);
263   GType type = gtk_tree_model_get_column_type (model, column);
264   GValue a_value = {0, };
265   GValue b_value = {0, };
266   gint retval;
267   gchar *stra, *strb;
268
269   gtk_tree_model_get_value (model, a, column, &a_value);
270   gtk_tree_model_get_value (model, b, column, &b_value);
271
272   switch (G_TYPE_FUNDAMENTAL (type))
273     {
274     case G_TYPE_BOOLEAN:
275       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
276       break;
277     case G_TYPE_CHAR:
278       retval = (g_value_get_char (&a_value) < g_value_get_char (&b_value));
279       break;
280     case G_TYPE_UCHAR:
281       retval = (g_value_get_uchar (&a_value) < g_value_get_uchar (&b_value));
282       break;
283     case G_TYPE_INT:
284       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
285       break;
286     case G_TYPE_UINT:
287       retval = (g_value_get_uint (&a_value) < g_value_get_uint (&b_value));
288       break;
289     case G_TYPE_ENUM:
290       /* this is somewhat bogus. */
291       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
292       break;
293     case G_TYPE_FLAGS:
294       retval = (g_value_get_uint (&a_value) < g_value_get_uint (&b_value));
295       break;
296     case G_TYPE_FLOAT:
297       retval = (g_value_get_float (&a_value) < g_value_get_float (&b_value));
298       break;
299     case G_TYPE_DOUBLE:
300       retval = (g_value_get_double (&a_value) < g_value_get_double (&b_value));
301       break;
302     case G_TYPE_STRING:
303       stra = g_value_get_string (&a_value);
304       strb = g_value_get_string (&b_value);
305       if (stra == NULL)
306         stra = "";
307       if (strb == NULL)
308         strb = "";
309       retval = strcmp (stra, strb);
310       break;
311     case G_TYPE_POINTER:
312     case G_TYPE_BOXED:
313     case G_TYPE_OBJECT:
314     default:
315       g_warning ("Attempting to sort on invalid type %s\n", g_type_name (type));
316       retval = FALSE;
317       break;
318     }
319
320   g_value_unset (&a_value);
321   g_value_unset (&b_value);
322
323   return retval;
324 }
325
326
327 GList *
328 _gtk_tree_data_list_header_new (gint   n_columns,
329                                 GType *types)
330 {
331   GList *retval = NULL;
332
333   gint i;
334
335   for (i = 0; i < n_columns; i ++)
336     {
337       GtkTreeDataSortHeader *header;
338
339       header = g_new (GtkTreeDataSortHeader, 1);
340
341       retval = g_list_prepend (retval, header);
342       header->sort_column_id = i;
343       header->func = gtk_tree_data_list_compare_func;
344       header->destroy = NULL;
345       header->data = GINT_TO_POINTER (i);
346     }
347   return g_list_reverse (retval);
348 }
349
350 void
351 _gtk_tree_data_list_header_free (GList *list)
352 {
353   GList *tmp;
354
355   for (tmp = list; tmp; tmp = tmp->next)
356     {
357       GtkTreeDataSortHeader *header = (GtkTreeDataSortHeader *) tmp->data;
358
359       if (header->destroy)
360         (* header->destroy) (header->data);
361
362       g_free (header);
363     }
364   g_list_free (list);
365 }
366
367 GtkTreeDataSortHeader *
368 _gtk_tree_data_list_get_header (GList *header_list,
369                                 gint   sort_column_id)
370 {
371   GtkTreeDataSortHeader *header = NULL;
372
373   for (; header_list; header_list = header_list->next)
374     {
375       header = (GtkTreeDataSortHeader*) header_list->data;
376       if (header->sort_column_id == sort_column_id)
377         return header;
378     }
379   return NULL;
380 }