]> Pileus Git - ~andy/gtk/blob - gtk/gtkliststore.c
Got rid of GtkTreeNode, and changed it to GtkTreeIter. Added iterators
[~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 #if 0
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 gint           gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
42 static GtkTreeIter   *gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
43                                                       GtkTreePath       *path);
44 static GtkTreePath   *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
45                                                       GtkTreeIter       *iter);
46 static void           gtk_list_store_iter_get_value  (GtkTreeModel      *tree_model,
47                                                       GtkTreeIter       *iter,
48                                                       gint               column,
49                                                       GValue            *value);
50 static gboolean       gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
51                                                       GtkTreeIter       *iter);
52 static GtkTreeIter   *gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
53                                                       GtkTreeIter       *iter);
54 static gboolean       gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
55                                                       GtkTreeIter       *iter);
56 static gint           gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
57                                                       GtkTreeIter       *iter);
58 static GtkTreeIter   *gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
59                                                       GtkTreeIter       *iter,
60                                                       gint               n);
61 static GtkTreeIter   *gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
62                                                       GtkTreeIter       *iter);
63
64
65 GtkType
66 gtk_list_store_get_type (void)
67 {
68   static GtkType list_store_type = 0;
69
70   if (!list_store_type)
71     {
72       static const GTypeInfo list_store_info =
73       {
74         sizeof (GtkListStoreClass),
75         NULL,           /* base_init */
76         NULL,           /* base_finalize */
77         (GClassInitFunc) gtk_list_store_class_init,
78         NULL,           /* class_finalize */
79         NULL,           /* class_data */
80         sizeof (GtkListStore),
81         0,
82         (GInstanceInitFunc) gtk_list_store_init,
83       };
84
85       static const GInterfaceInfo tree_model_info =
86       {
87         (GInterfaceInitFunc) gtk_list_store_tree_model_init,
88         NULL,
89         NULL
90       };
91
92       list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
93       g_type_add_interface_static (list_store_type,
94                                    GTK_TYPE_TREE_MODEL,
95                                    &tree_model_info);
96     }
97
98   return list_store_type;
99 }
100
101 static void
102 gtk_list_store_class_init (GtkListStoreClass *class)
103 {
104   GtkObjectClass *object_class;
105
106   object_class = (GtkObjectClass*) class;
107
108   list_store_signals[CHANGED] =
109     gtk_signal_new ("changed",
110                     GTK_RUN_FIRST,
111                     GTK_CLASS_TYPE (object_class),
112                     GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
113                     gtk_marshal_VOID__POINTER_POINTER,
114                     GTK_TYPE_NONE, 2,
115                     GTK_TYPE_POINTER,
116                     GTK_TYPE_POINTER);
117   list_store_signals[INSERTED] =
118     gtk_signal_new ("inserted",
119                     GTK_RUN_FIRST,
120                     GTK_CLASS_TYPE (object_class),
121                     GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
122                     gtk_marshal_VOID__POINTER_POINTER,
123                     GTK_TYPE_NONE, 2,
124                     GTK_TYPE_POINTER,
125                     GTK_TYPE_POINTER);
126   list_store_signals[CHILD_TOGGLED] =
127     gtk_signal_new ("child_toggled",
128                     GTK_RUN_FIRST,
129                     GTK_CLASS_TYPE (object_class),
130                     GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
131                     gtk_marshal_VOID__POINTER_POINTER,
132                     GTK_TYPE_NONE, 2,
133                     GTK_TYPE_POINTER,
134                     GTK_TYPE_POINTER);
135   list_store_signals[DELETED] =
136     gtk_signal_new ("deleted",
137                     GTK_RUN_FIRST,
138                     GTK_CLASS_TYPE (object_class),
139                     GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
140                     gtk_marshal_VOID__POINTER,
141                     GTK_TYPE_NONE, 1,
142                     GTK_TYPE_POINTER);
143
144
145   gtk_object_class_add_signals (object_class, list_store_signals, LAST_SIGNAL);
146 }
147
148 static void
149 gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
150 {
151   iface->get_n_columns = gtk_list_store_get_n_columns;
152   iface->get_iter = gtk_list_store_get_iter;
153   iface->get_path = gtk_list_store_get_path;
154   iface->iter_get_value = gtk_list_store_iter_get_value;
155   iface->iter_next = gtk_list_store_iter_next;
156   iface->iter_children = gtk_list_store_iter_children;
157   iface->iter_has_child = gtk_list_store_iter_has_child;
158   iface->iter_n_children = gtk_list_store_iter_n_children;
159   iface->iter_nth_child = gtk_list_store_iter_nth_child;
160   iface->iter_parent = gtk_list_store_iter_parent;
161 }
162
163 static void
164 gtk_list_store_init (GtkListStore *list_store)
165 {
166   list_store->root = NULL;
167 }
168
169 GtkObject *
170 gtk_list_store_new (void)
171 {
172   return GTK_OBJECT (gtk_type_new (gtk_list_store_get_type ()));
173 }
174
175 GtkObject *
176 gtk_list_store_new_with_types (gint n_columns,
177                                ...)
178 {
179   GtkObject *retval;
180   va_list args;
181   gint i;
182
183   g_return_val_if_fail (n_columns > 0, NULL);
184
185   retval = gtk_list_store_new ();
186   gtk_list_store_set_n_columns (GTK_LIST_STORE (retval),
187                               n_columns);
188
189   va_start (args, n_columns);
190   for (i = 0; i < n_columns; i++)
191     gtk_list_store_set_column_type (GTK_LIST_STORE (retval),
192                                     i, va_arg (args, GType));
193
194   va_end (args);
195
196   return retval;
197 }
198
199 void
200 gtk_list_store_set_n_columns (GtkListStore *list_store,
201                               gint          n_columns)
202 {
203   GType *new_columns;
204
205   g_return_if_fail (list_store != NULL);
206   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
207
208   if (list_store->n_columns == n_columns)
209     return;
210
211   new_columns = g_new0 (GType, n_columns);
212   if (list_store->column_headers)
213     {
214       /* copy the old header orders over */
215       if (n_columns >= list_store->n_columns)
216         memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
217       else
218         memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));
219
220       g_free (list_store->column_headers);
221     }
222
223   list_store->column_headers = new_columns;
224   list_store->n_columns = n_columns;
225 }
226
227 void
228 gtk_list_store_set_column_type (GtkListStore *list_store,
229                                 gint          column,
230                                 GType         type)
231 {
232   g_return_if_fail (list_store != NULL);
233   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
234   g_return_if_fail (column >=0 && column < list_store->n_columns);
235
236   list_store->column_headers[column] = type;
237 }
238
239 /* Fulfill the GtkTreeModel requirements */
240 static gint
241 gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
242 {
243   g_return_val_if_fail (tree_model != NULL, 0);
244   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);
245
246   return GTK_LIST_STORE (tree_model)->n_columns;
247 }
248
249 static GtkTreeIter *
250 gtk_list_store_get_iter (GtkTreeModel *tree_model,
251                          GtkTreePath  *path)
252 {
253   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, NULL);
254
255   return (GtkTreeIter) g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
256                                     gtk_tree_path_get_indices (path)[0]);
257 }
258
259 static GtkTreePath *
260 gtk_list_store_get_path (GtkTreeModel *tree_model,
261                          GtkTreeIter   iter)
262 {
263   GtkTreePath *retval;
264   GSList *list;
265   gint i = 0;
266
267   g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
268
269   for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
270     {
271       i++;
272       if (list == G_SLIST (iter))
273         break;
274     }
275   if (list == NULL)
276     return NULL;
277
278   retval = gtk_tree_path_new ();
279   gtk_tree_path_append_index (retval, i);
280
281   return retval;
282 }
283
284 static void
285 gtk_list_store_iter_get_value (GtkTreeModel *tree_model,
286                                GtkTreeIter   iter,
287                                gint          column,
288                                GValue       *value)
289 {
290   GtkTreeDataList *list;
291   gint tmp_column = column;
292
293   g_return_if_fail (tree_model != NULL);
294   g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
295   g_return_if_fail (iter != NULL);
296   g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
297
298   list = G_SLIST (iter)->data;
299
300   while (tmp_column-- > 0 && list)
301     list = list->next;
302
303   g_return_if_fail (list != NULL);
304
305   gtk_tree_data_list_iter_to_value (list,
306                                     GTK_LIST_STORE (tree_model)->column_headers[column],
307                                     value);
308 }
309
310 static gboolean
311 gtk_list_store_iter_next (GtkTreeModel  *tree_model,
312                           GtkTreeIter   *iter)
313 {
314   if (iter == NULL || *iter == NULL)
315     return FALSE;
316
317   *iter = (GtkTreeIter) G_SLIST (*iter)->next;
318
319   return (*iter != NULL);
320 }
321
322 static GtkTreeIter
323 gtk_list_store_iter_children (GtkTreeModel *tree_model,
324                               GtkTreeIter   iter)
325 {
326   return NULL;
327 }
328
329 static gboolean
330 gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
331                                GtkTreeIter   iter)
332 {
333   return FALSE;
334 }
335
336 static gint
337 gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
338                                 GtkTreeIter   iter)
339 {
340   return 0;
341 }
342
343 static GtkTreeIter
344 gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
345                                GtkTreeIter   iter,
346                                gint          n)
347 {
348   return NULL;
349 }
350
351 static GtkTreeIter
352 gtk_list_store_iter_parent (GtkTreeModel *tree_model,
353                             GtkTreeIter   iter)
354 {
355   return NULL;
356 }
357
358 /* Public accessors */
359 GtkTreeIter
360 gtk_list_store_iter_new (void)
361 {
362   GtkTreeIter retval = (GtkTreeIter) g_slist_alloc ();
363
364   return retval;
365 }
366
367 /* This is a somewhat inelegant function that does a lot of list
368  * manipulations on it's own.
369  */
370 void
371 gtk_list_store_iter_set_cell (GtkListStore *list_store,
372                               GtkTreeIter   iter,
373                               gint          column,
374                               GValue       *value)
375 {
376   GtkTreeDataList *list;
377   GtkTreeDataList *prev;
378
379   g_return_if_fail (list_store != NULL);
380   g_return_if_fail (GTK_IS_LIST_STORE (list_store));
381   g_return_if_fail (iter != NULL);
382   g_return_if_fail (column >= 0 && column < list_store->n_columns);
383
384   prev = list = G_SLIST (iter)->data;
385
386   while (list != NULL)
387     {
388       if (column == 0)
389         {
390           gtk_tree_data_list_value_to_iter (list, value);
391           return;
392         }
393
394       column--;
395       prev = list;
396       list = list->next;
397     }
398
399   if (G_SLIST (iter)->data == NULL)
400     {
401       G_SLIST (iter)->data = list = gtk_tree_data_list_alloc ();
402       list->next = NULL;
403     }
404   else
405     {
406       list = prev->next = gtk_tree_data_list_alloc ();
407       list->next = NULL;
408     }
409
410   while (column != 0)
411     {
412       list->next = gtk_tree_data_list_alloc ();
413       list = list->next;
414       list->next = NULL;
415       column --;
416     }
417   gtk_tree_data_list_value_to_iter (list, value);
418 }
419
420 void
421 gtk_list_store_iter_remove (GtkListStore *list_store,
422                             GtkTreeIter   iter)
423 {
424   /* FIXME: implement */
425   g_warning ("Remember to implement this function\n");
426 }
427
428 GtkTreeIter
429 gtk_list_store_iter_insert (GtkListStore *list_store,
430                             gint          position,
431                             GtkTreeIter   iter)
432 {
433   GSList *list;
434
435   g_return_val_if_fail (list_store != NULL, iter);
436   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), iter);
437   g_return_val_if_fail (iter != NULL, iter);
438   g_return_val_if_fail (position < 0, iter);
439   g_return_val_if_fail (G_SLIST (iter)->next == NULL, iter);
440
441   if (position == 0)
442     {
443       gtk_list_store_iter_prepend (list_store, iter);
444       return iter;
445     }
446
447   list = g_slist_nth (G_SLIST (list_store->root), position);
448   if (list)
449     {
450       G_SLIST (iter)->next = list->next;
451       list->next = G_SLIST (iter)->next;
452     }
453
454   return iter;
455 }
456
457
458 GtkTreeIter
459 gtk_list_store_iter_insert_before (GtkListStore *list_store,
460                                    GtkTreeIter   sibling,
461                                    GtkTreeIter   iter)
462 {
463   g_return_val_if_fail (list_store != NULL, iter);
464   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), iter);
465   g_return_val_if_fail (iter != NULL, iter);
466
467   /* FIXME: This is all wrong.  This is actually insert_after */
468   if (sibling == NULL)
469     return gtk_list_store_iter_prepend (list_store, iter);
470
471   G_SLIST (iter)->next = G_SLIST (sibling)->next;
472   G_SLIST (sibling)->next = G_SLIST (iter);
473   return iter;
474 }
475
476 GtkTreeIter
477 gtk_list_store_iter_prepend (GtkListStore *list_store,
478                              GtkTreeIter   iter)
479 {
480   g_return_val_if_fail (list_store != NULL, iter);
481   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), iter);
482   g_return_val_if_fail (iter != NULL, iter);
483
484   G_SLIST (iter)->next = G_SLIST (list_store->root);
485   list_store->root = iter;
486
487   return iter;
488 }
489
490 GtkTreeIter
491 gtk_list_store_iter_append (GtkListStore *list_store,
492                             GtkTreeIter   iter)
493 {
494   GSList *list;
495
496   g_return_val_if_fail (list_store != NULL, iter);
497   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), iter);
498   g_return_val_if_fail (iter != NULL, iter);
499   g_return_val_if_fail (G_SLIST (iter)->next == NULL, iter);
500
501   list = g_slist_last (G_SLIST (list_store->root));
502   if (list == NULL)
503     list_store->root = iter;
504   else
505     list->next = G_SLIST (iter);
506
507   return iter;
508 }
509
510 GtkTreeIter
511 gtk_list_store_iter_get_root (GtkListStore *list_store)
512 {
513   g_return_val_if_fail (list_store != NULL, NULL);
514   g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), NULL);
515
516   return (GtkTreeIter *) list_store->root;
517 }
518 #endif