]> Pileus Git - ~andy/gtk/blob - gtk/gtktreedatalist.c
maybe fix #64160 Also, forgot to save gtktreeview.h
[~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   memset (list, 0, sizeof (GtkTreeDataList));
43
44   return list;
45 }
46
47 void
48 _gtk_tree_data_list_free (GtkTreeDataList *list,
49                           GType           *column_headers)
50 {
51   GtkTreeDataList *tmp, *next;
52   gint i = 0;
53
54   tmp = list;
55
56   while (tmp)
57     {
58       next = tmp->next;
59       if (g_type_is_a (column_headers [i], G_TYPE_STRING))
60         g_free ((gchar *) tmp->data.v_pointer);
61       else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT) && tmp->data.v_pointer != NULL)
62         g_object_unref (G_OBJECT (tmp->data.v_pointer));
63       else if (g_type_is_a (column_headers [i], G_TYPE_BOXED) && tmp->data.v_pointer != NULL)
64         g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
65
66       g_mem_chunk_free (tree_chunk, tmp);
67       i++;
68       tmp = next;
69     }
70 }
71
72 gboolean
73 _gtk_tree_data_list_check_type (GType type)
74 {
75   gint i = 0;
76   static GType type_list[] =
77   {
78     G_TYPE_BOOLEAN,
79     G_TYPE_CHAR,
80     G_TYPE_UCHAR,
81     G_TYPE_INT,
82     G_TYPE_UINT,
83     G_TYPE_ENUM,
84     G_TYPE_FLAGS,
85     G_TYPE_FLOAT,
86     G_TYPE_DOUBLE,
87     G_TYPE_STRING,
88     G_TYPE_POINTER,
89     G_TYPE_BOXED,
90     G_TYPE_OBJECT,
91     G_TYPE_INVALID
92   };
93
94   if (! G_TYPE_IS_VALUE_TYPE (type))
95     return FALSE;
96
97
98   while (type_list[i] != G_TYPE_INVALID)
99     {
100       if (g_type_is_a (type, type_list[i]))
101         return TRUE;
102       i++;
103     }
104   return FALSE;
105 }
106
107
108 void
109 _gtk_tree_data_list_node_to_value (GtkTreeDataList *list,
110                                    GType            type,
111                                    GValue          *value)
112 {
113   g_value_init (value, type);
114
115   switch (G_TYPE_FUNDAMENTAL (type))
116     {
117     case G_TYPE_BOOLEAN:
118       g_value_set_boolean (value, (gboolean) list->data.v_int);
119       break;
120     case G_TYPE_CHAR:
121       g_value_set_char (value, (gchar) list->data.v_char);
122       break;
123     case G_TYPE_UCHAR:
124       g_value_set_uchar (value, (guchar) list->data.v_uchar);
125       break;
126     case G_TYPE_INT:
127       g_value_set_int (value, (gint) list->data.v_int);
128       break;
129     case G_TYPE_UINT:
130       g_value_set_uint (value, (guint) list->data.v_uint);
131       break;
132     case G_TYPE_ENUM:
133       g_value_set_enum (value, list->data.v_int);
134       break;
135     case G_TYPE_FLAGS:
136       g_value_set_flags (value, (int) list->data.v_int);
137       break;
138     case G_TYPE_FLOAT:
139       g_value_set_float (value, (gfloat) list->data.v_float);
140       break;
141     case G_TYPE_DOUBLE:
142       g_value_set_double (value, (gdouble) list->data.v_double);
143       break;
144     case G_TYPE_STRING:
145       g_value_set_string (value, (gchar *) list->data.v_pointer);
146       break;
147     case G_TYPE_POINTER:
148       g_value_set_pointer (value, (gpointer) list->data.v_pointer);
149       break;
150     case G_TYPE_BOXED:
151       g_value_set_boxed (value, (gpointer) list->data.v_pointer);
152       break;
153     case G_TYPE_OBJECT:
154       g_value_set_object (value, (GObject *) list->data.v_pointer);
155       break;
156     default:
157       g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
158       break;
159     }
160 }
161
162 void
163 _gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
164                                    GValue          *value)
165 {
166   switch (G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)))
167     {
168     case G_TYPE_BOOLEAN:
169       list->data.v_int = g_value_get_boolean (value);
170       break;
171     case G_TYPE_CHAR:
172       list->data.v_char = g_value_get_char (value);
173       break;
174     case G_TYPE_UCHAR:
175       list->data.v_uchar = g_value_get_uchar (value);
176       break;
177     case G_TYPE_INT:
178       list->data.v_int = g_value_get_int (value);
179       break;
180     case G_TYPE_ENUM:
181       list->data.v_int = g_value_get_enum (value);
182       break;
183     case G_TYPE_FLAGS:
184       list->data.v_int = g_value_get_flags (value);
185       break;
186     case G_TYPE_UINT:
187       list->data.v_uint = g_value_get_uint (value);
188       break;
189     case G_TYPE_POINTER:
190       list->data.v_pointer = g_value_get_pointer (value);
191       break;
192     case G_TYPE_FLOAT:
193       list->data.v_float = g_value_get_float (value);
194       break;
195     case G_TYPE_DOUBLE:
196       list->data.v_double = g_value_get_double (value);
197       break;
198     case G_TYPE_STRING:
199       list->data.v_pointer = g_value_dup_string (value);
200       break;
201     case G_TYPE_OBJECT:
202       list->data.v_pointer = g_value_dup_object (value);
203       break;
204     case G_TYPE_BOXED:
205       list->data.v_pointer = g_value_dup_boxed (value);
206       break;
207     default:
208       g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
209       break;
210     }
211 }
212
213 GtkTreeDataList *
214 _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
215                                GType            type)
216 {
217   GtkTreeDataList *new_list;
218
219   g_return_val_if_fail (list != NULL, NULL);
220   
221   new_list = _gtk_tree_data_list_alloc ();
222   new_list->next = NULL;
223
224   switch (G_TYPE_FUNDAMENTAL (type))
225     {
226     case G_TYPE_UINT:
227     case G_TYPE_INT:
228     case G_TYPE_UCHAR:
229     case G_TYPE_CHAR:
230     case G_TYPE_BOOLEAN:
231     case G_TYPE_POINTER:
232     case G_TYPE_FLOAT:
233     case G_TYPE_DOUBLE:
234       new_list->data = list->data;
235       break;
236     case G_TYPE_STRING:
237       new_list->data.v_pointer = g_strdup (list->data.v_pointer);
238       break;
239     case G_TYPE_OBJECT:
240       new_list->data.v_pointer = list->data.v_pointer;
241       if (new_list->data.v_pointer)
242         g_object_ref (G_OBJECT (new_list->data.v_pointer));
243       break;
244     case G_TYPE_BOXED:
245       if (list->data.v_pointer)
246         new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
247       else
248         new_list->data.v_pointer = NULL;
249       break;
250     default:
251       g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
252       break;
253     }
254
255   return new_list;
256 }
257
258 gint
259 gtk_tree_data_list_compare_func (GtkTreeModel *model,
260                                  GtkTreeIter  *a,
261                                  GtkTreeIter  *b,
262                                  gpointer      user_data)
263 {
264   gint column = GPOINTER_TO_INT (user_data);
265   GType type = gtk_tree_model_get_column_type (model, column);
266   GValue a_value = {0, };
267   GValue b_value = {0, };
268   gint retval;
269   const gchar *stra, *strb;
270
271   gtk_tree_model_get_value (model, a, column, &a_value);
272   gtk_tree_model_get_value (model, b, column, &b_value);
273
274   switch (G_TYPE_FUNDAMENTAL (type))
275     {
276     case G_TYPE_BOOLEAN:
277       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
278       break;
279     case G_TYPE_CHAR:
280       retval = (g_value_get_char (&a_value) < g_value_get_char (&b_value));
281       break;
282     case G_TYPE_UCHAR:
283       retval = (g_value_get_uchar (&a_value) < g_value_get_uchar (&b_value));
284       break;
285     case G_TYPE_INT:
286       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
287       break;
288     case G_TYPE_UINT:
289       retval = (g_value_get_uint (&a_value) < g_value_get_uint (&b_value));
290       break;
291     case G_TYPE_ENUM:
292       /* this is somewhat bogus. */
293       retval = (g_value_get_int (&a_value) < g_value_get_int (&b_value));
294       break;
295     case G_TYPE_FLAGS:
296       retval = (g_value_get_uint (&a_value) < g_value_get_uint (&b_value));
297       break;
298     case G_TYPE_FLOAT:
299       retval = (g_value_get_float (&a_value) < g_value_get_float (&b_value));
300       break;
301     case G_TYPE_DOUBLE:
302       retval = (g_value_get_double (&a_value) < g_value_get_double (&b_value));
303       break;
304     case G_TYPE_STRING:
305       stra = g_value_get_string (&a_value);
306       strb = g_value_get_string (&b_value);
307       if (stra == NULL) stra = "";
308       if (strb == NULL) strb = "";
309       retval = g_utf8_collate (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 }