]> Pileus Git - ~andy/gtk/blob - gtk/gtktreedatalist.c
entrycompletion: Don't reconnect signals all the time
[~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, see <http://www.gnu.org/licenses/>.
16  * 
17  * This file contains code shared between GtkTreeStore and GtkListStore.  Please
18  * do not use it.
19  */
20
21 #include "config.h"
22 #include "gtktreedatalist.h"
23 #include <string.h>
24
25 /* node allocation
26  */
27 GtkTreeDataList *
28 _gtk_tree_data_list_alloc (void)
29 {
30   GtkTreeDataList *list;
31
32   list = g_slice_new0 (GtkTreeDataList);
33
34   return list;
35 }
36
37 void
38 _gtk_tree_data_list_free (GtkTreeDataList *list,
39                           GType           *column_headers)
40 {
41   GtkTreeDataList *tmp, *next;
42   gint i = 0;
43
44   tmp = list;
45
46   while (tmp)
47     {
48       next = tmp->next;
49       if (g_type_is_a (column_headers [i], G_TYPE_STRING))
50         g_free ((gchar *) tmp->data.v_pointer);
51       else if (g_type_is_a (column_headers [i], G_TYPE_OBJECT) && tmp->data.v_pointer != NULL)
52         g_object_unref (tmp->data.v_pointer);
53       else if (g_type_is_a (column_headers [i], G_TYPE_BOXED) && tmp->data.v_pointer != NULL)
54         g_boxed_free (column_headers [i], (gpointer) tmp->data.v_pointer);
55       else if (g_type_is_a (column_headers [i], G_TYPE_VARIANT) && tmp->data.v_pointer != NULL)
56         g_variant_unref ((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_VARIANT,
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_schar (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_VARIANT:
177       g_value_set_variant (value, (gpointer) list->data.v_pointer);
178       break;
179     case G_TYPE_OBJECT:
180       g_value_set_object (value, (GObject *) list->data.v_pointer);
181       break;
182     default:
183       g_warning ("%s: Unsupported type (%s) retrieved.", G_STRLOC, g_type_name (value->g_type));
184       break;
185     }
186 }
187
188 void
189 _gtk_tree_data_list_value_to_node (GtkTreeDataList *list,
190                                    GValue          *value)
191 {
192   switch (get_fundamental_type (G_VALUE_TYPE (value)))
193     {
194     case G_TYPE_BOOLEAN:
195       list->data.v_int = g_value_get_boolean (value);
196       break;
197     case G_TYPE_CHAR:
198       list->data.v_char = g_value_get_schar (value);
199       break;
200     case G_TYPE_UCHAR:
201       list->data.v_uchar = g_value_get_uchar (value);
202       break;
203     case G_TYPE_INT:
204       list->data.v_int = g_value_get_int (value);
205       break;
206     case G_TYPE_UINT:
207       list->data.v_uint = g_value_get_uint (value);
208       break;
209     case G_TYPE_LONG:
210       list->data.v_long = g_value_get_long (value);
211       break;
212     case G_TYPE_ULONG:
213       list->data.v_ulong = g_value_get_ulong (value);
214       break;
215     case G_TYPE_INT64:
216       list->data.v_int64 = g_value_get_int64 (value);
217       break;
218     case G_TYPE_UINT64:
219       list->data.v_uint64 = g_value_get_uint64 (value);
220       break;
221     case G_TYPE_ENUM:
222       list->data.v_int = g_value_get_enum (value);
223       break;
224     case G_TYPE_FLAGS:
225       list->data.v_uint = g_value_get_flags (value);
226       break;
227     case G_TYPE_POINTER:
228       list->data.v_pointer = g_value_get_pointer (value);
229       break;
230     case G_TYPE_FLOAT:
231       list->data.v_float = g_value_get_float (value);
232       break;
233     case G_TYPE_DOUBLE:
234       list->data.v_double = g_value_get_double (value);
235       break;
236     case G_TYPE_STRING:
237       g_free (list->data.v_pointer);
238       list->data.v_pointer = g_value_dup_string (value);
239       break;
240     case G_TYPE_OBJECT:
241       if (list->data.v_pointer)
242         g_object_unref (list->data.v_pointer);
243       list->data.v_pointer = g_value_dup_object (value);
244       break;
245     case G_TYPE_BOXED:
246       if (list->data.v_pointer)
247         g_boxed_free (G_VALUE_TYPE (value), list->data.v_pointer);
248       list->data.v_pointer = g_value_dup_boxed (value);
249       break;
250     case G_TYPE_VARIANT:
251       if (list->data.v_pointer)
252         g_variant_unref (list->data.v_pointer);
253       list->data.v_pointer = g_value_dup_variant (value);
254       break;
255     default:
256       g_warning ("%s: Unsupported type (%s) stored.", G_STRLOC, g_type_name (G_VALUE_TYPE (value)));
257       break;
258     }
259 }
260
261 GtkTreeDataList *
262 _gtk_tree_data_list_node_copy (GtkTreeDataList *list,
263                                GType            type)
264 {
265   GtkTreeDataList *new_list;
266
267   g_return_val_if_fail (list != NULL, NULL);
268   
269   new_list = _gtk_tree_data_list_alloc ();
270   new_list->next = NULL;
271
272   switch (get_fundamental_type (type))
273     {
274     case G_TYPE_BOOLEAN:
275     case G_TYPE_CHAR:
276     case G_TYPE_UCHAR:
277     case G_TYPE_INT:
278     case G_TYPE_UINT:
279     case G_TYPE_LONG:
280     case G_TYPE_ULONG:
281     case G_TYPE_INT64:
282     case G_TYPE_UINT64:
283     case G_TYPE_ENUM:
284     case G_TYPE_FLAGS:
285     case G_TYPE_POINTER:
286     case G_TYPE_FLOAT:
287     case G_TYPE_DOUBLE:
288       new_list->data = list->data;
289       break;
290     case G_TYPE_STRING:
291       new_list->data.v_pointer = g_strdup (list->data.v_pointer);
292       break;
293     case G_TYPE_OBJECT:
294     case G_TYPE_INTERFACE:
295       new_list->data.v_pointer = list->data.v_pointer;
296       if (new_list->data.v_pointer)
297         g_object_ref (new_list->data.v_pointer);
298       break;
299     case G_TYPE_BOXED:
300       if (list->data.v_pointer)
301         new_list->data.v_pointer = g_boxed_copy (type, list->data.v_pointer);
302       else
303         new_list->data.v_pointer = NULL;
304       break;
305     case G_TYPE_VARIANT:
306       if (list->data.v_pointer)
307         new_list->data.v_pointer = g_variant_ref (list->data.v_pointer);
308       else
309         new_list->data.v_pointer = NULL;
310       break;
311     default:
312       g_warning ("Unsupported node type (%s) copied.", g_type_name (type));
313       break;
314     }
315
316   return new_list;
317 }
318
319 gint
320 _gtk_tree_data_list_compare_func (GtkTreeModel *model,
321                                   GtkTreeIter  *a,
322                                   GtkTreeIter  *b,
323                                   gpointer      user_data)
324 {
325   gint column = GPOINTER_TO_INT (user_data);
326   GType type = gtk_tree_model_get_column_type (model, column);
327   GValue a_value = G_VALUE_INIT;
328   GValue b_value = G_VALUE_INIT;
329   gint retval;
330   const gchar *stra, *strb;
331
332   gtk_tree_model_get_value (model, a, column, &a_value);
333   gtk_tree_model_get_value (model, b, column, &b_value);
334
335   switch (get_fundamental_type (type))
336     {
337     case G_TYPE_BOOLEAN:
338       if (g_value_get_boolean (&a_value) < g_value_get_boolean (&b_value))
339         retval = -1;
340       else if (g_value_get_boolean (&a_value) == g_value_get_boolean (&b_value))
341         retval = 0;
342       else
343         retval = 1;
344       break;
345     case G_TYPE_CHAR:
346       if (g_value_get_schar (&a_value) < g_value_get_schar (&b_value))
347         retval = -1;
348       else if (g_value_get_schar (&a_value) == g_value_get_schar (&b_value))
349         retval = 0;
350       else
351         retval = 1;
352       break;
353     case G_TYPE_UCHAR:
354       if (g_value_get_uchar (&a_value) < g_value_get_uchar (&b_value))
355         retval = -1;
356       else if (g_value_get_uchar (&a_value) == g_value_get_uchar (&b_value))
357         retval = 0;
358       else
359         retval = 1;
360       break;
361     case G_TYPE_INT:
362       if (g_value_get_int (&a_value) < g_value_get_int (&b_value))
363         retval = -1;
364       else if (g_value_get_int (&a_value) == g_value_get_int (&b_value))
365         retval = 0;
366       else
367         retval = 1;
368       break;
369     case G_TYPE_UINT:
370       if (g_value_get_uint (&a_value) < g_value_get_uint (&b_value))
371         retval = -1;
372       else if (g_value_get_uint (&a_value) == g_value_get_uint (&b_value))
373         retval = 0;
374       else
375         retval = 1;
376       break;
377     case G_TYPE_LONG:
378       if (g_value_get_long (&a_value) < g_value_get_long (&b_value))
379         retval = -1;
380       else if (g_value_get_long (&a_value) == g_value_get_long (&b_value))
381         retval = 0;
382       else
383         retval = 1;
384       break;
385     case G_TYPE_ULONG:
386       if (g_value_get_ulong (&a_value) < g_value_get_ulong (&b_value))
387         retval = -1;
388       else if (g_value_get_ulong (&a_value) == g_value_get_ulong (&b_value))
389         retval = 0;
390       else
391         retval = 1;
392       break;
393     case G_TYPE_INT64:
394       if (g_value_get_int64 (&a_value) < g_value_get_int64 (&b_value))
395         retval = -1;
396       else if (g_value_get_int64 (&a_value) == g_value_get_int64 (&b_value))
397         retval = 0;
398       else
399         retval = 1;
400       break;
401     case G_TYPE_UINT64:
402       if (g_value_get_uint64 (&a_value) < g_value_get_uint64 (&b_value))
403         retval = -1;
404       else if (g_value_get_uint64 (&a_value) == g_value_get_uint64 (&b_value))
405         retval = 0;
406       else
407         retval = 1;
408       break;
409     case G_TYPE_ENUM:
410       /* this is somewhat bogus. */
411       if (g_value_get_enum (&a_value) < g_value_get_enum (&b_value))
412         retval = -1;
413       else if (g_value_get_enum (&a_value) == g_value_get_enum (&b_value))
414         retval = 0;
415       else
416         retval = 1;
417       break;
418     case G_TYPE_FLAGS:
419       /* this is even more bogus. */
420       if (g_value_get_flags (&a_value) < g_value_get_flags (&b_value))
421         retval = -1;
422       else if (g_value_get_flags (&a_value) == g_value_get_flags (&b_value))
423         retval = 0;
424       else
425         retval = 1;
426       break;
427     case G_TYPE_FLOAT:
428       if (g_value_get_float (&a_value) < g_value_get_float (&b_value))
429         retval = -1;
430       else if (g_value_get_float (&a_value) == g_value_get_float (&b_value))
431         retval = 0;
432       else
433         retval = 1;
434       break;
435     case G_TYPE_DOUBLE:
436       if (g_value_get_double (&a_value) < g_value_get_double (&b_value))
437         retval = -1;
438       else if (g_value_get_double (&a_value) == g_value_get_double (&b_value))
439         retval = 0;
440       else
441         retval = 1;
442       break;
443     case G_TYPE_STRING:
444       stra = g_value_get_string (&a_value);
445       strb = g_value_get_string (&b_value);
446       if (stra == NULL) stra = "";
447       if (strb == NULL) strb = "";
448       retval = g_utf8_collate (stra, strb);
449       break;
450     case G_TYPE_VARIANT:
451     case G_TYPE_POINTER:
452     case G_TYPE_BOXED:
453     case G_TYPE_OBJECT:
454     default:
455       g_warning ("Attempting to sort on invalid type %s\n", g_type_name (type));
456       retval = FALSE;
457       break;
458     }
459
460   g_value_unset (&a_value);
461   g_value_unset (&b_value);
462
463   return retval;
464 }
465
466
467 GList *
468 _gtk_tree_data_list_header_new (gint   n_columns,
469                                 GType *types)
470 {
471   GList *retval = NULL;
472
473   gint i;
474
475   for (i = 0; i < n_columns; i ++)
476     {
477       GtkTreeDataSortHeader *header;
478
479       header = g_slice_new (GtkTreeDataSortHeader);
480
481       retval = g_list_prepend (retval, header);
482       header->sort_column_id = i;
483       header->func = _gtk_tree_data_list_compare_func;
484       header->destroy = NULL;
485       header->data = GINT_TO_POINTER (i);
486     }
487   return g_list_reverse (retval);
488 }
489
490 void
491 _gtk_tree_data_list_header_free (GList *list)
492 {
493   GList *tmp;
494
495   for (tmp = list; tmp; tmp = tmp->next)
496     {
497       GtkTreeDataSortHeader *header = (GtkTreeDataSortHeader *) tmp->data;
498
499       if (header->destroy)
500         {
501           GDestroyNotify d = header->destroy;
502
503           header->destroy = NULL;
504           d (header->data);
505         }
506
507       g_slice_free (GtkTreeDataSortHeader, header);
508     }
509   g_list_free (list);
510 }
511
512 GtkTreeDataSortHeader *
513 _gtk_tree_data_list_get_header (GList   *header_list,
514                                 gint     sort_column_id)
515 {
516   GtkTreeDataSortHeader *header = NULL;
517
518   for (; header_list; header_list = header_list->next)
519     {
520       header = (GtkTreeDataSortHeader*) header_list->data;
521       if (header->sort_column_id == sort_column_id)
522         return header;
523     }
524   return NULL;
525 }
526
527
528 GList *
529 _gtk_tree_data_list_set_header (GList                  *header_list,
530                                 gint                    sort_column_id,
531                                 GtkTreeIterCompareFunc  func,
532                                 gpointer                data,
533                                 GDestroyNotify          destroy)
534 {
535   GList *list = header_list;
536   GtkTreeDataSortHeader *header = NULL;
537
538   for (; list; list = list->next)
539     {
540       header = (GtkTreeDataSortHeader*) list->data;
541       if (header->sort_column_id == sort_column_id)
542         break;
543       header = NULL;
544
545       if (list->next == NULL)
546         break;
547     }
548   
549   if (header == NULL)
550     {
551       header = g_slice_new0 (GtkTreeDataSortHeader);
552       header->sort_column_id = sort_column_id;
553       if (list)
554         list = g_list_append (list, header);
555       else
556         header_list = g_list_append (header_list, header);
557     }
558
559   if (header->destroy)
560     {
561       GDestroyNotify d = header->destroy;
562       
563       header->destroy = NULL;
564       d (header->data);
565     }
566   
567   header->func = func;
568   header->data = data;
569   header->destroy = destroy;
570
571   return header_list;
572 }