]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
Changed to have the list become non-italic when the demo window is
[~andy/gtk] / gtk / gtkliststore.c
1 /* gtkliststore.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
20 #include <string.h>
21 #include "gtktreemodel.h"
22 #include "gtkliststore.h"
23 #include "gtktreedatalist.h"
24 #include "gtksignal.h"
25
26 #define G_SLIST(x) ((GSList *) x)
27
28 enum {
29   CHANGED,
30   INSERTED,
31   CHILD_TOGGLED,
32   DELETED,
33   LAST_SIGNAL
34 };
35
36 static guint list_store_signals[LAST_SIGNAL] = { 0 };
37
38 static void         gtk_list_store_init            (GtkListStore      *list_store);
39 static void         gtk_list_store_class_init      (GtkListStoreClass *class);
40 static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
41 static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
42 static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
43 static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
44                                                     gint               index);
45 static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
46                                                     GtkTreeIter       *iter,
47                                                     GtkTreePath       *path);
48 static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
49                                                     GtkTreeIter       *iter);
50 static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
51                                                     GtkTreeIter       *iter,
52                                                     gint               column,
53                                                     GValue            *value);
54 static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
55                                                     GtkTreeIter       *iter);
56 static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
57                                                     GtkTreeIter       *iter,
58                                                     GtkTreeIter       *parent);
59 static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
60                                                     GtkTreeIter       *iter);
61 static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
62                                                     GtkTreeIter       *iter);
63 static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
64                                                     GtkTreeIter       *iter,
65                                                     GtkTreeIter       *parent,
66                                                     gint               n);
67 static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
68                                                     GtkTreeIter       *iter,
69                                                     GtkTreeIter       *child);
70
71
72 GtkType
73 gtk_list_store_get_type (void)
74 {
75   static GtkType list_store_type = 0;
76
77   if (!list_store_type)
78     {
79       static const GTypeInfo list_store_info =
80       {
81         sizeof (GtkListStoreClass),
82         NULL,           /* base_init */
83         NULL,           /* base_finalize */
84         (GClassInitFunc) gtk_list_store_class_init,
85         NULL,           /* class_finalize */
86         NULL,           /* class_data */
87         sizeof (GtkListStore),
88         0,
89         (GInstanceInitFunc) gtk_list_store_init,
90       };
91
92       static const GInterfaceInfo tree_model_info =
93       {
94         (GInterfaceInitFunc) gtk_list_store_tree_model_init,
95         NULL,
96         NULL
97       };
98
99       list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
100       g_type_add_interface_static (list_store_type,
101                                    GTK_TYPE_TREE_MODEL,
102                                    &tree_model_info);
103     }
104
105   return list_store_type;
106 }
107
108 static void
109 gtk_list_store_class_init (GtkListStoreClass *class)
110 {
111   GtkObjectClass *object_class;
112
113   object_class = (GtkObjectClass*) class;
114
115   list_store_signals[CHANGED] =
116     gtk_signal_new ("changed",
117                     GTK_RUN_FIRST,
118                     GTK_CLASS_TYPE (object_class),
119                     GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
120                     gtk_marshal_VOID__BOXED_BOXED,
121                     G_TYPE_NONE, 2,
122                     GTK_TYPE_TREE_PATH,
123                     GTK_TYPE_TREE_ITER);
124   list_store_signals[INSERTED] =
125     gtk_signal_new ("inserted",
126                     GTK_RUN_FIRST,
127                     GTK_CLASS_TYPE (object_class),
128                     GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
129                     gtk_marshal_VOID__BOXED_BOXED,
130                     G_TYPE_NONE, 2,
131                     GTK_TYPE_TREE_PATH,
132                     GTK_TYPE_TREE_ITER);
133   list_store_signals[CHILD_TOGGLED] =
134     gtk_signal_new ("child_toggled",
135                     GTK_RUN_FIRST,
136                     GTK_CLASS_TYPE (object_class),
137                     GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
138                     gtk_marshal_VOID__BOXED_BOXED,
139                     G_TYPE_NONE, 2,
140                     GTK_TYPE_TREE_PATH,
141                     GTK_TYPE_TREE_ITER);
142   list_store_signals[DELETED] =
143     gtk_signal_new ("deleted",
144                     GTK_RUN_FIRST,
145                     GTK_CLASS_TYPE (object_class),
146                     GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
147                     gtk_marshal_VOID__BOXED,
148                     G_TYPE_NONE, 1,
149                     GTK_TYPE_TREE_PATH);
150
151
152   gtk_object_class_add_signals (object_class, list_store_signals, LAST_SIGNAL);
153 }
154
155 static void
156 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
157 {
158   iface->get_flags = gtk_list_store_get_flags;
159   iface->get_n_columns = gtk_list_store_get_n_columns;
160   iface->get_column_type = gtk_list_store_get_column_type;
161   iface->get_iter = gtk_list_store_get_iter;
162   iface->get_path = gtk_list_store_get_path;
163   iface->get_value = gtk_list_store_get_value;
164   iface->iter_next = gtk_list_store_iter_next;
165   iface->iter_children = gtk_list_store_iter_children;
166   iface->iter_has_child = gtk_list_store_iter_has_child;
167   iface->iter_n_children = gtk_list_store_iter_n_children;
168   iface->iter_nth_child = gtk_list_store_iter_nth_child;
169   iface->iter_parent = gtk_list_store_iter_parent;
170 }
171
172 static void
173 gtk_list_store_init (GtkListStore *list_store)
174 {
175   list_store->root = NULL;
176   list_store->stamp = g_random_int ();
177 }
178
179 GtkListStore *
180 gtk_list_store_new (void)
181 {
182   return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
183 }
184
185 GtkListStore *
186 gtk_list_store_new_with_types (gint n_columns,
187                                ...)
188 {
189   GtkListStore *retval;
190   va_list args;
191   gint i;
192
193   g_return_val_if_fail (n_columns > 0, NULL);
194
195   retval = gtk_list_store_new ();
196   gtk_list_store_set_n_columns (retval, n_columns);
197
198   va_start (args, n_columns);
199
200   for (i = 0; i < n_columns; i++)
201     gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
202
203   va_end (args);
204
205   return retval;
206 }
207
208 void
209 gtk_list_store_set_n_columns (GtkListStore *list_store,
210                               gint          n_columns)
211 {
212   GType *new_columns;
213
214   g_return_if_fail (list_store != NULL);
215   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
216   g_return_if_fail (n_columns > 0);
217
218   if (list_store->n_columns == n_columns)
219     return;
220
221   new_columns = g_new0 (GType, n_columns);
222   if (list_store->column_headers)
223     {
224       /* copy the old header orders over */
225       if (n_columns >= list_store->n_columns)
226         memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
227       else
228         memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
229
230       g_free (list_store->column_headers);
231     }
232
233   list_store->column_headers = new_columns;
234   list_store->n_columns = n_columns;
235 }
236
237 void
238 gtk_list_store_set_column_type (GtkListStore *list_store,
239                                 gint          column,
240                                 GType         type)
241 {
242   g_return_if_fail (list_store != NULL);
243   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
244   g_return_if_fail (column >=0 && column < list_store->n_columns);
245
246   list_store->column_headers[column] = type;
247 }
248
249 /* Fulfill the GtkTreeModel requirements */
250 static guint
251 gtk_list_store_get_flags (GtkTreeModel *tree_model)
252 {
253   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
254
255   return GTK_TREE_MODEL_ITERS_PERSIST;
256 }
257
258 static gint
259 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
260 {
261   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
262
263   return GTK_LIST_STORE (tree_model)->n_columns;
264 }
265
266 static GType
267 gtk_list_store_get_column_type (GtkTreeModel *tree_model,
268                                 gint          index)
269 {
270   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
271   g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
272                         index >= 0, G_TYPE_INVALID);
273
274   return GTK_LIST_STORE (tree_model)->column_headers[index];
275 }
276
277 static gboolean
278 gtk_list_store_get_iter (GtkTreeModel *tree_model,
279                          GtkTreeIter  *iter,
280                          GtkTreePath  *path)
281 {
282   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
283   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
284   
285   iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
286   iter->tree_node = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
287                                  gtk_tree_path_get_indices (path)[0]);
288
289   return iter->tree_node != NULL;
290 }
291
292 static GtkTreePath *
293 gtk_list_store_get_path (GtkTreeModel *tree_model,
294                          GtkTreeIter  *iter)
295 {
296   GtkTreePath *retval;
297   GSList *list;
298   gint i = 0;
299
300   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
301   g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
302
303   for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
304     {
305       if (list == G_SLIST (iter->tree_node))
306         break;
307       i++;
308     }
309   if (list == NULL)
310     return NULL;
311
312   retval = gtk_tree_path_new ();
313   gtk_tree_path_append_index (retval, i);
314   return retval;
315 }
316
317 static void
318 gtk_list_store_get_value (GtkTreeModel *tree_model,
319                           GtkTreeIter  *iter,
320                           gint          column,
321                           GValue       *value)
322 {
323   GtkTreeDataList *list;
324   gint tmp_column = column;
325
326   g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
327   g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
328   g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
329
330   list = G_SLIST (iter->tree_node)->data;
331
332   while (tmp_column-- > 0 && list)
333     list = list->next;
334
335   if (list == NULL)
336     g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
337   else
338     _gtk_tree_data_list_node_to_value (list,
339                                        GTK_LIST_STORE (tree_model)->column_headers[column],
340                                        value);
341 }
342
343 static gboolean
344 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
345                           GtkTreeIter   *iter)
346 {
347   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
348   g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
349
350   iter->tree_node = G_SLIST (iter->tree_node)->next;
351
352   return (iter->tree_node != NULL);
353 }
354
355 static gboolean
356 gtk_list_store_iter_children (GtkTreeModel *tree_model,
357                               GtkTreeIter  *iter,
358                               GtkTreeIter  *parent)
359 {
360   iter->stamp = 0;
361   iter->tree_node = NULL;
362
363   return FALSE;
364 }
365
366 static gboolean
367 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
368                                GtkTreeIter  *iter)
369 {
370   return FALSE;
371 }
372
373 static gint
374 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
375                                 GtkTreeIter  *iter)
376 {
377   if (iter == NULL)
378     return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root));
379
380   return 0;
381 }
382
383 static gboolean
384 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
385                                GtkTreeIter  *iter,
386                                GtkTreeIter  *parent,
387                                gint          n)
388 {
389   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
390
391   if (parent)
392     {
393       g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE);
394       iter->stamp = 0;
395       iter->tree_node = NULL;
396
397       return FALSE;
398     }
399
400   iter->tree_node = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
401   if (iter->tree_node)
402     iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
403   else
404     iter->stamp = 0;
405
406   return (iter->tree_node != NULL);
407 }
408
409 static gboolean
410 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
411                             GtkTreeIter  *iter,
412                             GtkTreeIter  *child)
413 {
414   iter->stamp = 0;
415   iter->tree_node = NULL;
416
417   return FALSE;
418 }
419
420 /* Public accessors */
421 /* This is a somewhat inelegant function that does a lot of list
422  * manipulations on it's own.
423  */
424 void
425 gtk_list_store_set_cell (GtkListStore *list_store,
426                          GtkTreeIter  *iter,
427                          gint          column,
428                          GValue       *value)
429 {
430   GtkTreeDataList *list;
431   GtkTreeDataList *prev;
432
433   g_return_if_fail (list_store != NULL);
434   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
435   g_return_if_fail (iter != NULL);
436   g_return_if_fail (column >= 0 && column < list_store->n_columns);
437
438   prev = list = G_SLIST (iter->tree_node)->data;
439
440   while (list != NULL)
441     {
442       if (column == 0)
443         {
444           _gtk_tree_data_list_value_to_node (list, value);
445           gtk_signal_emit_by_name (GTK_OBJECT (list_store),
446                                    "changed",
447                                    NULL, iter);
448           return;
449         }
450
451       column--;
452       prev = list;
453       list = list->next;
454     }
455
456   if (G_SLIST (iter->tree_node)->data == NULL)
457     {
458       G_SLIST (iter->tree_node)->data = list = _gtk_tree_data_list_alloc ();
459       list->next = NULL;
460     }
461   else
462     {
463       list = prev->next = _gtk_tree_data_list_alloc ();
464       list->next = NULL;
465     }
466
467   while (column != 0)
468     {
469       list->next = _gtk_tree_data_list_alloc ();
470       list = list->next;
471       list->next = NULL;
472       column --;
473     }
474   _gtk_tree_data_list_value_to_node (list, value);
475   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
476                            "changed",
477                            NULL, iter);
478 }
479
480 void
481 gtk_list_store_remove (GtkListStore *list_store,
482                        GtkTreeIter  *iter)
483 {
484   GtkTreePath *path;
485
486   g_return_if_fail (list_store != NULL);
487   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
488
489   if (G_SLIST (iter->tree_node)->data)
490     _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->tree_node)->data,
491                               list_store->column_headers);
492
493   path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
494   list_store->root = g_slist_remove_link (G_SLIST (list_store->root),
495                                           G_SLIST (iter->tree_node));
496   list_store->stamp ++;
497   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
498                            "deleted",
499                            path);
500   gtk_tree_path_free (path);
501 }
502
503 void
504 gtk_list_store_insert (GtkListStore *list_store,
505                        GtkTreeIter  *iter,
506                        gint          position)
507 {
508   GSList *list;
509   GtkTreePath *path;
510
511   g_return_if_fail (list_store != NULL);
512   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
513   g_return_if_fail (iter != NULL);
514   g_return_if_fail (position < 0);
515
516   if (position == 0)
517     {
518       gtk_list_store_prepend (list_store, iter);
519       return;
520     }
521
522   iter->stamp = list_store->stamp;
523   iter->tree_node = g_slist_alloc ();
524
525   list = g_slist_nth (G_SLIST (list_store->root), position - 1);
526   if (list)
527     {
528       G_SLIST (iter->tree_node)->next = list->next;
529       list->next = G_SLIST (iter->tree_node)->next;
530     }
531   path = gtk_tree_path_new ();
532   gtk_tree_path_append_index (path, position);
533   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
534                            "inserted",
535                            path, iter);
536   gtk_tree_path_free (path);
537 }
538
539 void
540 gtk_list_store_insert_before (GtkListStore *list_store,
541                               GtkTreeIter  *iter,
542                               GtkTreeIter  *sibling)
543 {
544   GtkTreePath *path;
545   GSList *list, *prev;
546   gint i = 0;
547
548   g_return_if_fail (list_store != NULL);
549   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
550   g_return_if_fail (iter != NULL);
551   g_return_if_fail (G_SLIST (iter)->next == NULL);
552
553   if (sibling == NULL)
554     {
555       gtk_list_store_append (list_store, iter);
556       return;
557     }
558
559   iter->stamp = list_store->stamp;
560   iter->tree_node = g_slist_alloc ();
561
562   prev = list = list_store->root;
563   while (list && list != sibling->tree_node)
564     {
565       prev = list;
566       list = list->next;
567       i++;
568     }
569   
570   if (prev)
571     {
572       prev->next = iter->tree_node;
573     }
574   else
575     {
576       G_SLIST (iter->tree_node)->next = list_store->root;
577       list_store->root = iter->tree_node;
578     }
579
580   path = gtk_tree_path_new ();
581   gtk_tree_path_append_index (path, i);
582   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
583                            "inserted",
584                            path, iter);
585   gtk_tree_path_free (path);
586 }
587
588 void
589 gtk_list_store_insert_after (GtkListStore *list_store,
590                              GtkTreeIter  *iter,
591                              GtkTreeIter  *sibling)
592 {
593   GtkTreePath *path;
594   GSList *list;
595   gint i = 0;
596
597   g_return_if_fail (list_store != NULL);
598   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
599   g_return_if_fail (iter == NULL);
600   if (sibling)
601     g_return_if_fail (sibling->stamp == list_store->stamp);
602
603   if (sibling == NULL)
604     {
605       gtk_list_store_prepend (list_store, iter);
606       return;
607     }
608
609   for (list = list_store->root; list && list != sibling->tree_node; list = list->next)
610     i++;
611
612   g_return_if_fail (list != NULL);
613
614   iter->stamp = list_store->stamp;
615   iter->tree_node = g_slist_alloc ();
616
617   G_SLIST (iter->tree_node)->next = G_SLIST (sibling->tree_node)->next;
618   G_SLIST (sibling)->next = G_SLIST (iter);
619
620   path = gtk_tree_path_new ();
621   gtk_tree_path_append_index (path, i);
622   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
623                            "inserted",
624                            path, iter);
625   gtk_tree_path_free (path);
626 }
627
628 void
629 gtk_list_store_prepend (GtkListStore *list_store,
630                         GtkTreeIter  *iter)
631 {
632   GtkTreePath *path;
633
634   g_return_if_fail (list_store != NULL);
635   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
636   g_return_if_fail (iter != NULL);
637
638   iter->stamp = list_store->stamp;
639   iter->tree_node = g_slist_alloc ();
640
641   G_SLIST (iter->tree_node)->next = G_SLIST (list_store->root);
642   list_store->root = iter->tree_node;
643
644   path = gtk_tree_path_new ();
645   gtk_tree_path_append_index (path, 0);
646   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
647                            "inserted",
648                            path, iter);
649   gtk_tree_path_free (path);
650 }
651
652 void
653 gtk_list_store_append (GtkListStore *list_store,
654                        GtkTreeIter  *iter)
655 {
656   GtkTreePath *path;
657   GSList *list, *prev;
658   gint i = 0;
659
660   g_return_if_fail (list_store != NULL);
661   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
662   g_return_if_fail (iter != NULL);
663
664   iter->stamp = list_store->stamp;
665   iter->tree_node = g_slist_alloc ();
666
667   prev = list = list_store->root;
668   while (list)
669     {
670       prev = list;
671       list = list->next;
672       i++;
673     }
674   
675   if (prev)
676     prev->next = iter->tree_node;
677   else
678     list_store->root = iter->tree_node;
679
680   path = gtk_tree_path_new ();
681   gtk_tree_path_append_index (path, i);
682   gtk_signal_emit_by_name (GTK_OBJECT (list_store),
683                            "inserted",
684                            path, iter);
685   gtk_tree_path_free (path);
686 }