gtkliststore.c 35.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* gtkliststore.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <string.h>
#include "gtktreemodel.h"
#include "gtkliststore.h"
#include "gtktreedatalist.h"
24
#include "gtksignal.h"
Havoc Pennington's avatar
Havoc Pennington committed
25
#include "gtktreednd.h"
Havoc Pennington's avatar
Havoc Pennington committed
26
#include <gobject/gvaluecollector.h>
27
28

#define G_SLIST(x) ((GSList *) x)
29

30
enum {
31
32
33
34
  CHANGED,
  INSERTED,
  CHILD_TOGGLED,
  DELETED,
35
36
37
38
39
  LAST_SIGNAL
};

static guint list_store_signals[LAST_SIGNAL] = { 0 };

40
41
42
static void         gtk_list_store_init            (GtkListStore      *list_store);
static void         gtk_list_store_class_init      (GtkListStoreClass *class);
static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
Havoc Pennington's avatar
Havoc Pennington committed
43
44
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
45
static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
46
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
47
48
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreePath       *path);
static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    gint               column,
						    GValue            *value);
static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent);
static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent,
						    gint               n);
static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *child);
74

Havoc Pennington's avatar
Havoc Pennington committed
75
76
77
78
79
80
81
82
static gboolean gtk_list_store_drag_data_delete   (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
static gboolean gtk_list_store_drag_data_get      (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path,
                                                   GtkSelectionData  *selection_data);
static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
                                                   GtkTreePath       *dest,
                                                   GtkSelectionData  *selection_data);
83
84
85
86
87
88
89
90
91
92
93
94
95
96
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
                                                   GtkTreeModel      *src_model,
                                                   GtkTreePath       *src_path,
                                                   GtkTreePath       *dest_path);
static void
validate_list_store (GtkListStore *list_store)
{
  if (gtk_debug_flags & GTK_DEBUG_TREE)
    {
      g_assert (g_slist_length (list_store->root) == list_store->length);
      
      g_assert (g_slist_last (list_store->root) == list_store->tail);
    }
}
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

GtkType
gtk_list_store_get_type (void)
{
  static GtkType list_store_type = 0;

  if (!list_store_type)
    {
      static const GTypeInfo list_store_info =
      {
	sizeof (GtkListStoreClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_list_store_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkListStore),
	0,
        (GInstanceInitFunc) gtk_list_store_init,
      };

118
119
120
121
122
123
124
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_list_store_tree_model_init,
	NULL,
	NULL
      };

Havoc Pennington's avatar
Havoc Pennington committed
125
126
127
128
129
130
131
132
133
134
135
136
137
138
      static const GInterfaceInfo drag_source_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_source_init,
	NULL,
	NULL
      };

      static const GInterfaceInfo drag_dest_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_dest_init,
	NULL,
	NULL
      };
      
139
      list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
140
141
142
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
Havoc Pennington's avatar
Havoc Pennington committed
143
144
145
146
147
148
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_SOURCE,
				   &drag_source_info);
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_DEST,
				   &drag_dest_info);
149
150
151
152
153
154
155
156
157
158
159
    }

  return list_store_type;
}

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
  GtkObjectClass *object_class;

  object_class = (GtkObjectClass*) class;
160

161
162
  list_store_signals[CHANGED] =
    gtk_signal_new ("changed",
163
164
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
165
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
166
167
168
169
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
170
171
  list_store_signals[INSERTED] =
    gtk_signal_new ("inserted",
172
173
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
174
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
175
176
177
178
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
179
180
  list_store_signals[CHILD_TOGGLED] =
    gtk_signal_new ("child_toggled",
181
182
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
183
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
184
185
186
187
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
188
189
  list_store_signals[DELETED] =
    gtk_signal_new ("deleted",
190
191
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
192
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
193
194
195
                    gtk_marshal_VOID__BOXED,
                    G_TYPE_NONE, 1,
		    GTK_TYPE_TREE_PATH);
196
197
198
199
200
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
201
  iface->get_flags = gtk_list_store_get_flags;
202
  iface->get_n_columns = gtk_list_store_get_n_columns;
203
  iface->get_column_type = gtk_list_store_get_column_type;
204
  iface->get_iter = gtk_list_store_get_iter;
205
  iface->get_path = gtk_list_store_get_path;
206
  iface->get_value = gtk_list_store_get_value;
207
208
209
210
211
212
  iface->iter_next = gtk_list_store_iter_next;
  iface->iter_children = gtk_list_store_iter_children;
  iface->iter_has_child = gtk_list_store_iter_has_child;
  iface->iter_n_children = gtk_list_store_iter_n_children;
  iface->iter_nth_child = gtk_list_store_iter_nth_child;
  iface->iter_parent = gtk_list_store_iter_parent;
213
214
}

Havoc Pennington's avatar
Havoc Pennington committed
215
216
217
218
219
220
221
222
223
224
225
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
gtk_list_store_drag_dest_init   (GtkTreeDragDestIface   *iface)
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
226
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
Havoc Pennington's avatar
Havoc Pennington committed
227
228
}

229
230
231
232
static void
gtk_list_store_init (GtkListStore *list_store)
{
  list_store->root = NULL;
233
  list_store->tail = NULL;
234
  list_store->stamp = g_random_int ();
235
  list_store->length = 0;
236
237
}

238
239
240
241
242
243
244
245
246
247
248
249
/**
 * gtk_list_store_new:
 *
 * Creates a new #GtkListStore. A #GtkListStore implements the
 * #GtkTreeModel interface, and stores a linked list of
 * rows; each row can have any number of columns. Columns are of uniform type,
 * i.e. all cells in a column have the same type such as #G_TYPE_STRING or
 * #GDK_TYPE_PIXBUF. Use #GtkListStore to store data to be displayed in a
 * #GtkTreeView.
 * 
 * Return value: a new #GtkListStore
 **/
250
GtkListStore *
251
252
gtk_list_store_new (void)
{
253
  return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
254
255
}

256
257
258
259
260
261
262
263
264
265
266
267
268
/**
 * gtk_list_store_new_with_types:
 * @n_columns: number of columns in the list store
 * @Varargs: pairs of column number and #GType
 *
 * Creates a new list store as with gtk_list_store_new(),
 * simultaneously setting up the columns and column types as with
 * gtk_list_store_set_n_columns() and
 * gtk_list_store_set_column_type().
 * 
 * 
 * Return value: a new #GtkListStore
 **/
269
GtkListStore *
270
271
272
gtk_list_store_new_with_types (gint n_columns,
			       ...)
{
273
  GtkListStore *retval;
274
275
276
277
278
279
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_list_store_new ();
280
  gtk_list_store_set_n_columns (retval, n_columns);
281
282

  va_start (args, n_columns);
283

284
  for (i = 0; i < n_columns; i++)
285
    gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
286
287
288
289
290
291

  va_end (args);

  return retval;
}

292
293
294
295
296
297
298
299
/**
 * gtk_list_store_set_n_columns:
 * @store: a #GtkListStore
 * @n_columns: number of columns
 *
 * Sets the number of columns in the #GtkListStore.
 * 
 **/
300
301
302
303
304
305
306
307
void
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
  GType *new_columns;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
308
  g_return_if_fail (n_columns > 0);
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328

  if (list_store->n_columns == n_columns)
    return;

  new_columns = g_new0 (GType, n_columns);
  if (list_store->column_headers)
    {
      /* copy the old header orders over */
      if (n_columns >= list_store->n_columns)
	memcpy (new_columns, list_store->column_headers, list_store->n_columns * sizeof (gchar *));
      else
	memcpy (new_columns, list_store->column_headers, n_columns * sizeof (GType));

      g_free (list_store->column_headers);
    }

  list_store->column_headers = new_columns;
  list_store->n_columns = n_columns;
}

329
330
331
332
333
334
335
336
337
338
339
340
/**
 * gtk_list_store_set_column_type:
 * @store: a #GtkListStore
 * @column: column number
 * @type: type of the data stored in @column
 *
 * Supported types include: %G_TYPE_UINT, %G_TYPE_INT, %G_TYPE_UCHAR,
 * %G_TYPE_CHAR, %G_TYPE_BOOLEAN, %G_TYPE_POINTER, %G_TYPE_FLOAT, %G_TYPE_STRING,
 * %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with subclasses of those types such
 * as %GDK_TYPE_PIXBUF.
 * 
 **/
341
342
343
344
345
346
347
348
349
350
351
352
353
void
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (column >=0 && column < list_store->n_columns);

  list_store->column_headers[column] = type;
}

/* Fulfill the GtkTreeModel requirements */
354
355
356
357
358
359
360
361
static guint
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_TREE_MODEL_ITERS_PERSIST;
}

362
363
364
365
366
367
368
369
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_LIST_STORE (tree_model)->n_columns;
}

370
371
372
373
374
375
376
377
378
379
380
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
  g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
			index >= 0, G_TYPE_INVALID);

  return GTK_LIST_STORE (tree_model)->column_headers[index];
}

381
static gboolean
382
gtk_list_store_get_iter (GtkTreeModel *tree_model,
383
			 GtkTreeIter  *iter,
384
385
			 GtkTreePath  *path)
{
386
387
388
  GSList *list;
  gint i;
  
389
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
390
391
392
393
394
395
  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);  

  i = gtk_tree_path_get_indices (path)[0];

  if (i >= GTK_LIST_STORE (tree_model)->length)
    return FALSE;
396
  
397
398
  list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
                      i);
399

400
401
402
403
404
405
  /* If this fails, list_store->length has gotten mangled. */
  g_assert (list);
  
  iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
  iter->user_data = list;
  return TRUE;
406
407
408
409
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
410
			 GtkTreeIter  *iter)
411
412
413
414
415
416
{
  GtkTreePath *retval;
  GSList *list;
  gint i = 0;

  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
417
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
418
419
420

  for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
421
      if (list == G_SLIST (iter->user_data))
422
	break;
423
      i++;
424
425
426
427
428
429
430
431
432
433
    }
  if (list == NULL)
    return NULL;

  retval = gtk_tree_path_new ();
  gtk_tree_path_append_index (retval, i);
  return retval;
}

static void
434
435
436
437
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
438
439
440
441
442
443
{
  GtkTreeDataList *list;
  gint tmp_column = column;

  g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
  g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
444
  g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
445

Havoc Pennington's avatar
Havoc Pennington committed
446
  list = G_SLIST (iter->user_data)->data;
447
448
449
450

  while (tmp_column-- > 0 && list)
    list = list->next;

451
452
453
454
455
456
  if (list == NULL)
    g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
  else
    _gtk_tree_data_list_node_to_value (list,
				       GTK_LIST_STORE (tree_model)->column_headers[column],
				       value);
457
458
459
}

static gboolean
460
461
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
462
{
463
464
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
  g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
465

466
467
468
469
470
471
472
  if (G_SLIST (iter->user_data)->next)
    {
      iter->user_data = G_SLIST (iter->user_data)->next;
      return TRUE;
    }
  else
    return FALSE;
473
474
}

475
static gboolean
476
gtk_list_store_iter_children (GtkTreeModel *tree_model,
477
478
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
479
{
480
  /* this is a list, nodes have no children */
481
  if (parent)
482
483
484
485
486
487
488
    return FALSE;

  /* but if parent == NULL we return the list itself as children of the
   * "root"
   */
  
  if (GTK_LIST_STORE (tree_model)->root)
489
490
491
492
493
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      iter->user_data = GTK_LIST_STORE (tree_model)->root;
      return TRUE;
    }
494
495
  else
    return FALSE;
496
497
498
}

static gboolean
499
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
500
			       GtkTreeIter  *iter)
501
502
503
504
505
{
  return FALSE;
}

static gint
506
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
507
				GtkTreeIter  *iter)
508
{
509
  if (iter == NULL)
510
511
512
    return GTK_LIST_STORE (tree_model)->length;
  else
    return 0;
513
514
}

515
static gboolean
516
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
517
518
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
519
			       gint          n)
520
{
521
522
  GSList *child;
  
523
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
524

525
  if (parent)
526
    return FALSE;
527

528
  child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
529

530
531
532
533
534
535
  if (child)
    {
      iter->user_data = child;
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      return TRUE;
    }
536
  else
537
    return FALSE;
538
539
}

540
541
542
543
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
544
{
545
  return FALSE;
546
547
}

548
/* Public accessors */
549
550
551
/* This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
552
553
554
555
556
557
558
559
560
561
562
563
564

/**
 * gtk_list_store_set_cell:
 * @store: a #GtkListStore
 * @iter: iterator for the row you're modifying
 * @column: column number to modify
 * @value: new value for the cell
 *
 * Sets the data in the cell specified by @iter and @column.
 * The type of @value must be convertible to the type of the
 * column.
 * 
 **/
565
void
566
567
568
569
gtk_list_store_set_cell (GtkListStore *list_store,
			 GtkTreeIter  *iter,
			 gint          column,
			 GValue       *value)
570
571
572
573
574
575
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
576
  g_return_if_fail (iter != NULL);
577
578
  g_return_if_fail (column >= 0 && column < list_store->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
579
  prev = list = G_SLIST (iter->user_data)->data;
580
581
582
583
584

  while (list != NULL)
    {
      if (column == 0)
	{
585
	  _gtk_tree_data_list_value_to_node (list, value);
586
587
588
	  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
				   "changed",
				   NULL, iter);
589
590
591
592
593
594
595
596
	  return;
	}

      column--;
      prev = list;
      list = list->next;
    }

Havoc Pennington's avatar
Havoc Pennington committed
597
  if (G_SLIST (iter->user_data)->data == NULL)
598
    {
Havoc Pennington's avatar
Havoc Pennington committed
599
      G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
600
601
602
603
      list->next = NULL;
    }
  else
    {
604
      list = prev->next = _gtk_tree_data_list_alloc ();
605
606
607
608
609
      list->next = NULL;
    }

  while (column != 0)
    {
610
      list->next = _gtk_tree_data_list_alloc ();
611
612
613
614
      list = list->next;
      list->next = NULL;
      column --;
    }
615
616
617
618
  _gtk_tree_data_list_value_to_node (list, value);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "changed",
			   NULL, iter);
619
620
}

621
622
623
624
625
626
627
628
629
630
/**
 * gtk_list_store_set_valist:
 * @list_store: a #GtkListStore
 * @iter: row to set data for
 * @var_args: va_list of column/value pairs
 *
 * See gtk_list_store_set(); this version takes a va_list for
 * use by language bindings.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
631
632
633
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
634
                           va_list	 var_args)
Havoc Pennington's avatar
Havoc Pennington committed
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
{
  gint column;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  column = va_arg (var_args, gint);

  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= list_store->n_columns)
	{
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}
      g_value_init (&value, list_store->column_headers[column]);

      G_VALUE_COLLECT (&value, var_args, &error);
      if (error)
	{
	  g_warning ("%s: %s", G_STRLOC, error);
	  g_free (error);

 	  /* we purposely leak the value here, it might not be
	   * in a sane state if an error condition occoured
	   */
	  break;
	}

      gtk_list_store_set_cell (list_store,
			       iter,
			       column,
			       &value);

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
 * @Varargs: pairs of column number and value, terminated with -1
 * 
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
685
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
 * The list is terminated by a -1. For example, to set column 0 with type
 * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
 * 0, "Foo", -1).
 **/
void
gtk_list_store_set (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  va_start (var_args, iter);
  gtk_list_store_set_valist (list_store, iter, var_args);
  va_end (var_args);
}

704
705
706
707
708
709
710
711
712
713
/**
 * gtk_list_store_get_valist:
 * @list_store: a #GtkListStore
 * @iter: a row in @list_store
 * @var_args: va_list of column/return location pairs
 *
 * See gtk_list_store_get(), this version takes a va_list for
 * language bindings to use.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
void
gtk_list_store_get_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
                           va_list	var_args)
{
  gint column;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  column = va_arg (var_args, gint);

  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= list_store->n_columns)
	{
	  g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}

      gtk_list_store_get_value (GTK_TREE_MODEL (list_store), iter, column, &value);

      G_VALUE_LCOPY (&value, var_args, &error);
      if (error)
	{
	  g_warning ("%s: %s", G_STRLOC, error);
	  g_free (error);

 	  /* we purposely leak the value here, it might not be
	   * in a sane state if an error condition occoured
	   */
	  break;
	}

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
/**
 * gtk_list_store_get:
 * @list_store: a #GtkListStore
 * @iter: a row in @list_store
 * @Varargs: pairs of column number and value return locations, terminated by -1
 *
 * Gets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
 * each column number followed by a place to store the value being
 * retrieved.  The list is terminated by a -1. For example, to get a
 * value from column 0 with type %G_TYPE_STRING, you would
 * write: gtk_list_store_set (store, iter, 0, &place_string_here, -1),
 * where place_string_here is a gchar* to be filled with the string.
 * If appropriate, the returned values have to be freed or unreferenced.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
772
773
774
775
776
777
778
779
780
781
782
783
784
785
void
gtk_list_store_get (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  va_start (var_args, iter);
  gtk_list_store_get_valist (list_store, iter, var_args);
  va_end (var_args);
}

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
static GSList*
remove_link_saving_prev (GSList  *list,
                         GSList  *link,
                         GSList **prevp)
{
  GSList *tmp;
  GSList *prev;

  prev = NULL;
  tmp = list;

  while (tmp)
    {
      if (tmp == link)
	{
	  if (prev)
802
803
804
	    prev->next = link->next;

	  if (list == link)
805
806
	    list = list->next;

807
	  link->next = NULL;
808
809
810
811
812
813
814
815
816
817
818
819
	  break;
	}

      prev = tmp;
      tmp = tmp->next;
    }

  *prevp = prev;
  
  return list;
}

Havoc Pennington's avatar
Havoc Pennington committed
820
821
822
823
static void
gtk_list_store_remove_silently (GtkListStore *list_store,
                                GtkTreeIter  *iter,
                                GtkTreePath  *path)
824
{
Havoc Pennington's avatar
Havoc Pennington committed
825
  if (G_SLIST (iter->user_data)->data)
Havoc Pennington's avatar
Havoc Pennington committed
826
827
828
829
830
    {
      _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
                                list_store->column_headers);
      G_SLIST (iter->user_data)->data = NULL;
    }
831
832
833
834
835
836
837

  {
    GSList *prev = NULL;
    
    list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
                                                G_SLIST (iter->user_data),
                                                &prev);
838
839

    list_store->length -= 1;
840
841
842
843
844
    
    if (iter->user_data == list_store->tail)
      list_store->tail = prev;
  }
  
845
  list_store->stamp ++;
Havoc Pennington's avatar
Havoc Pennington committed
846
847
}

848
849
850
851
852
853
854
855
856
/**
 * gtk_list_store_remove:
 * @store: a #GtkListStore
 * @iter: a row in @list_store
 *
 * Removes the given row from the list store, emitting the
 * "deleted" signal on #GtkTreeModel.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
857
858
859
860
861
862
863
864
void
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
  GtkTreePath *path;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
865
  g_return_if_fail (iter->user_data != NULL);  
Havoc Pennington's avatar
Havoc Pennington committed
866
867
868

  path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);

869
870
  validate_list_store (list_store);
  
Havoc Pennington's avatar
Havoc Pennington committed
871
872
  gtk_list_store_remove_silently (list_store, iter, path);

873
874
  validate_list_store (list_store);  
  
875
876
877
878
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "deleted",
			   path);
  gtk_tree_path_free (path);
879
880
}

881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
static void
insert_after (GtkListStore *list_store,
              GSList       *sibling,
              GSList       *new_list)
{
  g_return_if_fail (sibling != NULL);
  g_return_if_fail (new_list != NULL);
  
  /* insert new node after list */
  new_list->next = sibling->next;
  sibling->next = new_list;

  /* if list was the tail, the new node is the new tail */
  if (sibling == list_store->tail)
    list_store->tail = new_list;
896
897

  list_store->length += 1;
898
899
}

900
901
902
903
904
905
906
907
908
909
910
/**
 * gtk_list_store_insert:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @position: position to insert the new row
 *
 * Creates a new row at @position, initializing @iter to point to the
 * new row, and emitting the "inserted" signal from the #GtkTreeModel
 * interface.
 * 
 **/
911
912
913
914
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
915
916
{
  GSList *list;
917
  GtkTreePath *path;
918
919
  GSList *new_list;
  
920
921
922
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
923
  g_return_if_fail (position >= 0);
924
925
926

  if (position == 0)
    {
927
928
      gtk_list_store_prepend (list_store, iter);
      return;
929
930
    }

931
  new_list = g_slist_alloc ();
932
933

  list = g_slist_nth (G_SLIST (list_store->root), position - 1);
934
935

  if (list == NULL)
936
    {
937
938
      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
      return;
939
    }
940
941
942
943
944

  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
945
946

  validate_list_store (list_store);
947
  
948
949
950
951
952
953
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
954
955
}

956
957
958
959
960
961
962
963
964
965
966
/**
 * gtk_list_store_insert_before:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @sibling: an existing row
 *
 * Inserts a new row before @sibling, initializing @iter to point to
 * the new row, and emitting the "inserted" signal from the
 * #GtkTreeModel interface.
 * 
 **/
967
968
969
970
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
971
{
972
  GtkTreePath *path;
973
  GSList *list, *prev, *new_list;
974
975
976
977
978
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
979
980

  if (sibling == NULL)
981
982
983
984
    {
      gtk_list_store_append (list_store, iter);
      return;
    }
985
986
  
  new_list = g_slist_alloc ();
987

988
989
  prev = NULL;
  list = list_store->root;
Havoc Pennington's avatar
Havoc Pennington committed
990
  while (list && list != sibling->user_data)
991
992
993
994
995
    {
      prev = list;
      list = list->next;
      i++;
    }
996
997
998
999
1000

  if (list != sibling->user_data)
    {
      g_warning ("%s: sibling iterator invalid? not found in the list", G_STRLOC);
      return;