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