gtktreestore.c 34.9 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
/* gtktreestore.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 "gtktreemodel.h"
#include "gtktreestore.h"
#include "gtktreedatalist.h"
23
#include "gtktreednd.h"
24
25
#include "gtksignal.h"
#include <string.h>
26
#include <gobject/gvaluecollector.h>
27
28
29

#define G_NODE(node) ((GNode *)node)

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

static guint tree_store_signals[LAST_SIGNAL] = { 0 };

40

41
42
43
static void         gtk_tree_store_init            (GtkTreeStore      *tree_store);
static void         gtk_tree_store_class_init      (GtkTreeStoreClass *tree_store_class);
static void         gtk_tree_store_tree_model_init (GtkTreeModelIface *iface);
44
45
static void         gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_tree_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
46
static guint        gtk_tree_store_get_flags       (GtkTreeModel      *tree_model);
47
static gint         gtk_tree_store_get_n_columns   (GtkTreeModel      *tree_model);
48
49
static GType        gtk_tree_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
50
51
static GtkTreePath *gtk_tree_store_get_path        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
52
static void         gtk_tree_store_get_value       (GtkTreeModel      *tree_model,
53
54
55
56
57
58
59
60
61
62
63
64
65
66
						    GtkTreeIter       *iter,
						    gint               column,
						    GValue            *value);
static gboolean     gtk_tree_store_iter_next       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_tree_store_iter_children   (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent);
static gboolean     gtk_tree_store_iter_has_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gint         gtk_tree_store_iter_n_children (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_tree_store_iter_nth_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
67
						    GtkTreeIter       *parent,
68
69
70
						    gint               n);
static gboolean     gtk_tree_store_iter_parent     (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
71
						    GtkTreeIter       *child);
72
73


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
static gboolean gtk_tree_store_drag_data_delete   (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
static gboolean gtk_tree_store_drag_data_get      (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path,
                                                   GtkSelectionData  *selection_data);
static gboolean gtk_tree_store_drag_data_received (GtkTreeDragDest   *drag_dest,
                                                   GtkTreePath       *dest,
                                                   GtkSelectionData  *selection_data);
static gboolean gtk_tree_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
                                                   GtkTreeModel      *src_model,
                                                   GtkTreePath       *src_path,
                                                   GtkTreePath       *dest_path);

static void     validate_gnode                    (GNode *node);

static inline void
validate_tree (GtkTreeStore *tree_store)
{
  if (gtk_debug_flags & GTK_DEBUG_TREE)
    {
      g_assert (G_NODE (tree_store->root)->parent == NULL);
      
      validate_gnode (G_NODE (tree_store->root));
    }
}

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
GtkType
gtk_tree_store_get_type (void)
{
  static GtkType tree_store_type = 0;

  if (!tree_store_type)
    {
      static const GTypeInfo tree_store_info =
      {
        sizeof (GtkTreeStoreClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_tree_store_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkTreeStore),
	0,              /* n_preallocs */
        (GInstanceInitFunc) gtk_tree_store_init
      };

120
121
122
123
124
125
126
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_tree_store_tree_model_init,
	NULL,
	NULL
      };

127
128
129
130
131
132
133
134
135
136
137
138
139
140
      static const GInterfaceInfo drag_source_info =
      {
	(GInterfaceInitFunc) gtk_tree_store_drag_source_init,
	NULL,
	NULL
      };

      static const GInterfaceInfo drag_dest_info =
      {
	(GInterfaceInitFunc) gtk_tree_store_drag_dest_init,
	NULL,
	NULL
      };
      
141
      tree_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeStore", &tree_store_info, 0);
142

143
144
145
      g_type_add_interface_static (tree_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
146
147
148
149
150
151
152
153
154

      g_type_add_interface_static (tree_store_type,
				   GTK_TYPE_TREE_DRAG_SOURCE,
				   &drag_source_info);
      g_type_add_interface_static (tree_store_type,
				   GTK_TYPE_TREE_DRAG_DEST,
				   &drag_dest_info);

      
155
156
157
158
159
160
    }

  return tree_store_type;
}

static void
161
gtk_tree_store_class_init (GtkTreeStoreClass *tree_store_class)
162
163
{
  GtkObjectClass *object_class;
164
165
166

  object_class = (GtkObjectClass *) tree_store_class;

167
168
  tree_store_signals[CHANGED] =
    gtk_signal_new ("changed",
169
170
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
171
                    GTK_SIGNAL_OFFSET (GtkTreeStoreClass, changed),
172
173
174
175
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
176
177
  tree_store_signals[INSERTED] =
    gtk_signal_new ("inserted",
178
179
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
180
                    GTK_SIGNAL_OFFSET (GtkTreeStoreClass, inserted),
181
182
183
184
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
185
186
  tree_store_signals[CHILD_TOGGLED] =
    gtk_signal_new ("child_toggled",
187
188
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
189
                    GTK_SIGNAL_OFFSET (GtkTreeStoreClass, child_toggled),
190
191
192
193
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
194
195
  tree_store_signals[DELETED] =
    gtk_signal_new ("deleted",
196
197
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
198
                    GTK_SIGNAL_OFFSET (GtkTreeStoreClass, deleted),
199
200
201
                    gtk_marshal_VOID__BOXED,
                    G_TYPE_NONE, 1,
		    GTK_TYPE_TREE_PATH);
202
203
204
205
206
}

static void
gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
{
207
  iface->get_flags = gtk_tree_store_get_flags;
208
  iface->get_n_columns = gtk_tree_store_get_n_columns;
209
  iface->get_column_type = gtk_tree_store_get_column_type;
210
  iface->get_path = gtk_tree_store_get_path;
211
  iface->get_value = gtk_tree_store_get_value;
212
213
214
215
216
217
  iface->iter_next = gtk_tree_store_iter_next;
  iface->iter_children = gtk_tree_store_iter_children;
  iface->iter_has_child = gtk_tree_store_iter_has_child;
  iface->iter_n_children = gtk_tree_store_iter_n_children;
  iface->iter_nth_child = gtk_tree_store_iter_nth_child;
  iface->iter_parent = gtk_tree_store_iter_parent;
218
219
}

220
221
222
223
224
225
226
227
228
229
230
231
232
233
static void
gtk_tree_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
  iface->drag_data_delete = gtk_tree_store_drag_data_delete;
  iface->drag_data_get = gtk_tree_store_drag_data_get;
}

static void
gtk_tree_store_drag_dest_init   (GtkTreeDragDestIface   *iface)
{
  iface->drag_data_received = gtk_tree_store_drag_data_received;
  iface->row_drop_possible = gtk_tree_store_row_drop_possible;
}

234
235
236
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
237
  tree_store->root = g_node_new (NULL);
238
  tree_store->stamp = g_random_int ();
239
240
}

241
GtkTreeStore *
242
243
gtk_tree_store_new (void)
{
244
  return GTK_TREE_STORE (gtk_type_new (gtk_tree_store_get_type ()));
245
246
}

247
GtkTreeStore *
248
249
gtk_tree_store_new_with_types (gint n_columns,
			       ...)
250
{
251
  GtkTreeStore *retval;
252
253
254
255
256
257
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_tree_store_new ();
258
  gtk_tree_store_set_n_columns (retval, n_columns);
259
260

  va_start (args, n_columns);
261

262
  for (i = 0; i < n_columns; i++)
263
    gtk_tree_store_set_column_type (retval, i, va_arg (args, GType));
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

  va_end (args);

  return retval;
}

void
gtk_tree_store_set_n_columns (GtkTreeStore *tree_store,
			      gint          n_columns)
{
  GType *new_columns;

  g_return_if_fail (tree_store != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));

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

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

      g_free (tree_store->column_headers);
    }

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

void
gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
				gint          column,
				GType         type)
{
  g_return_if_fail (tree_store != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
  g_return_if_fail (column >=0 && column < tree_store->n_columns);

  tree_store->column_headers[column] = type;
}

/* fulfill the GtkTreeModel requirements */
/* NOTE: GtkTreeStore::root is a GNode, that acts as the parent node.  However,
312
 * it is not visible to the tree or to the user., and the path "0" refers to the
313
314
 * first child of GtkTreeStore::root.
 */
315
316
317
318
319
320
321
322
323
324


static guint
gtk_tree_store_get_flags (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0);

  return GTK_TREE_MODEL_ITERS_PERSIST;
}

325
326
327
328
329
330
331
332
static gint
gtk_tree_store_get_n_columns (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0);

  return GTK_TREE_STORE (tree_model)->n_columns;
}

333
334
335
336
337
338
339
340
341
342
343
static GType
gtk_tree_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), G_TYPE_INVALID);
  g_return_val_if_fail (index < GTK_TREE_STORE (tree_model)->n_columns &&
			index >= 0, G_TYPE_INVALID);

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

344
345
static GtkTreePath *
gtk_tree_store_get_path (GtkTreeModel *tree_model,
346
			 GtkTreeIter  *iter)
347
348
349
350
{
  GtkTreePath *retval;
  GNode *tmp_node;
  gint i = 0;
351
  
352
  g_return_val_if_fail (tree_model != NULL, NULL);
353
354
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), NULL);
  g_return_val_if_fail (iter != NULL, NULL);
355
  g_return_val_if_fail (iter->user_data != NULL, NULL);
356

357
  validate_tree ((GtkTreeStore*)tree_model);
358

359
360
  g_assert (G_NODE (iter->user_data)->parent != NULL);
  
Havoc Pennington's avatar
Havoc Pennington committed
361
  if (G_NODE (iter->user_data)->parent == G_NODE (GTK_TREE_STORE (tree_model)->root))
362
363
364
365
366
367
    {
      retval = gtk_tree_path_new ();
      tmp_node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
    }
  else
    {
368
      GtkTreeIter tmp_iter = *iter;
369
370
      
      tmp_iter.user_data = G_NODE (iter->user_data)->parent;
371

372
      retval = gtk_tree_store_get_path (tree_model,
373
					&tmp_iter);
Havoc Pennington's avatar
Havoc Pennington committed
374
      tmp_node = G_NODE (iter->user_data)->parent->children;
375
376
377
378
    }

  if (retval == NULL)
    return NULL;
379

380
381
382
383
384
385
386
387
  if (tmp_node == NULL)
    {
      gtk_tree_path_free (retval);
      return NULL;
    }

  for (; tmp_node; tmp_node = tmp_node->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
388
      if (tmp_node == G_NODE (iter->user_data))
389
390
391
	break;
      i++;
    }
392

393
394
395
  if (tmp_node == NULL)
    {
      /* We couldn't find node, meaning it's prolly not ours */
396
      /* Perhaps I should do a g_return_if_fail here. */
397
398
399
400
401
402
403
404
405
406
407
      gtk_tree_path_free (retval);
      return NULL;
    }

  gtk_tree_path_append_index (retval, i);

  return retval;
}


static void
408
409
410
411
gtk_tree_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
412
413
414
415
416
417
{
  GtkTreeDataList *list;
  gint tmp_column = column;

  g_return_if_fail (tree_model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (tree_model));
418
  g_return_if_fail (iter != NULL);
419
420
  g_return_if_fail (column < GTK_TREE_STORE (tree_model)->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
421
  list = G_NODE (iter->user_data)->data;
422
423
424
425

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

426
427
  if (list)
    {
428
429
430
      _gtk_tree_data_list_node_to_value (list,
					 GTK_TREE_STORE (tree_model)->column_headers[column],
					 value);
431
432
433
434
435
436
    }
  else
    {
      /* We want to return an initialized but empty (default) value */
      g_value_init (value, GTK_TREE_STORE (tree_model)->column_headers[column]);
    }
437
438
439
}

static gboolean
440
441
gtk_tree_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
442
{
443
444
445
446
447
448
449
450
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
  
  if (G_NODE (iter->user_data)->next)
    {
      iter->user_data = G_NODE (iter->user_data)->next;
      return TRUE;
    }
  else
451
452
453
    return FALSE;
}

454
455
456
457
static gboolean
gtk_tree_store_iter_children (GtkTreeModel *tree_model,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
458
{
459
460
461
462
  GNode *children;

  g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
  
463
  if (parent)
464
    children = G_NODE (parent->user_data)->children;
465
  else
466
    children = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
467

468
469
470
471
472
473
474
475
  if (children)
    {
      iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
      iter->user_data = children;
      return TRUE;
    }
  else
    return FALSE;
476
477
478
}

static gboolean
479
480
gtk_tree_store_iter_has_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter)
481
{
482
483
484
  g_return_val_if_fail (tree_model != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
  g_return_val_if_fail (iter != NULL, FALSE);
485
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
486

Havoc Pennington's avatar
Havoc Pennington committed
487
  return G_NODE (iter->user_data)->children != NULL;
488
489
490
}

static gint
491
492
gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
				GtkTreeIter  *iter)
493
{
494
  GNode *node;
495
496
  gint i = 0;

497
498
  g_return_val_if_fail (tree_model != NULL, 0);
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), 0);
499
500
501
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
  
502
503
504
  if (iter == NULL)
    node = G_NODE (GTK_TREE_STORE (tree_model)->root)->children;
  else
Havoc Pennington's avatar
Havoc Pennington committed
505
    node = G_NODE (iter->user_data)->children;
506

507
  while (node)
508
509
    {
      i++;
510
      node = node->next;
511
512
513
514
515
    }

  return i;
}

516
517
518
519
static gboolean
gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
520
521
			       gint          n)
{
522
  GNode *parent_node;
523
  GNode *child;
524

525
526
  g_return_val_if_fail (tree_model != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TREE_STORE (tree_model), FALSE);
527
  g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
528

529
530
531
  if (parent == NULL)
    parent_node = GTK_TREE_STORE (tree_model)->root;
  else
Havoc Pennington's avatar
Havoc Pennington committed
532
    parent_node = parent->user_data;
533

534
  child = g_node_nth_child (parent_node, n);
535

536
537
538
539
540
541
  if (child)
    {
      iter->user_data = child;
      iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
      return TRUE;
    }
542
  else
543
    return FALSE;
544
545
}

546
547
548
549
static gboolean
gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
550
{
551
  GNode *parent;
552
  
553
554
555
556
557
558
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (iter->user_data != NULL, FALSE);

  parent = G_NODE (child->user_data)->parent;

  g_assert (parent != NULL);  
559

560
  if (parent != GTK_TREE_STORE (tree_model)->root)
561
    {
562
563
564
      iter->user_data = parent;
      iter->stamp = GTK_TREE_STORE (tree_model)->stamp;
      return TRUE;
565
    }
566
567
  else
    return FALSE;
568
569
570
571
572
573
574
}

/*
 * This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
void
575
576
577
578
gtk_tree_store_set_cell (GtkTreeStore *tree_store,
			 GtkTreeIter  *iter,
			 gint          column,
			 GValue       *value)
579
580
581
582
583
584
585
586
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;

  g_return_if_fail (tree_store != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
  g_return_if_fail (column >= 0 && column < tree_store->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
587
  prev = list = G_NODE (iter->user_data)->data;
588
589
590
591
592

  while (list != NULL)
    {
      if (column == 0)
	{
593
	  _gtk_tree_data_list_value_to_node (list, value);
594
595
596
	  gtk_signal_emit_by_name (GTK_OBJECT (tree_store),
				   "changed",
				   NULL, iter);
597
598
599
600
601
602
603
604
	  return;
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
605
  if (G_NODE (iter->user_data)->data == NULL)
606
    {
Havoc Pennington's avatar
Havoc Pennington committed
607
      G_NODE (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
608
609
610
611
      list->next = NULL;
    }
  else
    {
612
      list = prev->next = _gtk_tree_data_list_alloc ();
613
614
615
616
617
      list->next = NULL;
    }

  while (column != 0)
    {
618
      list->next = _gtk_tree_data_list_alloc ();
619
620
621
622
      list = list->next;
      list->next = NULL;
      column --;
    }
623
624
625
626
  _gtk_tree_data_list_value_to_node (list, value);
  gtk_signal_emit_by_name (GTK_OBJECT (tree_store),
			   "changed",
			   NULL, iter);
627
628
629
}

void
Havoc Pennington's avatar
Havoc Pennington committed
630
631
632
gtk_tree_store_set_valist (GtkTreeStore *tree_store,
                           GtkTreeIter  *iter,
                           va_list	var_args)
633
634
635
636
637
638
639
{
  gint column;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));

  column = va_arg (var_args, gint);

Havoc Pennington's avatar
Havoc Pennington committed
640
  while (column != -1)
641
642
643
644
645
646
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= tree_store->n_columns)
	{
Havoc Pennington's avatar
Havoc Pennington committed
647
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
	  break;
	}
      g_value_init (&value, tree_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;
	}

664
665
666
667
      gtk_tree_store_set_cell (tree_store,
			       iter,
			       column,
			       &value);
668
669
670
671
672
673
674

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

Havoc Pennington's avatar
Havoc Pennington committed
675
676
677
678
679
680
681
682
683
684
685
686
687
/**
 * gtk_tree_store_set:
 * @tree_store: a #GtkTreeStore
 * @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,
 * each column number followed by the value to be set. For example,
 * The list is terminated by a -1. For example, to set column 0 with type
 * %G_TYPE_STRING to "Foo", you would write gtk_tree_store_set (store, iter,
 * 0, "Foo", -1).
 **/
688
void
689
690
691
gtk_tree_store_set (GtkTreeStore *tree_store,
		    GtkTreeIter  *iter,
		    ...)
692
693
694
695
696
697
{
  va_list var_args;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));

  va_start (var_args, iter);
Havoc Pennington's avatar
Havoc Pennington committed
698
  gtk_tree_store_set_valist (tree_store, iter, var_args);
699
700
701
702
  va_end (var_args);
}

void
Havoc Pennington's avatar
Havoc Pennington committed
703
704
705
gtk_tree_store_get_valist (GtkTreeStore *tree_store,
                           GtkTreeIter  *iter,
                           va_list	var_args)
706
707
708
709
710
711
712
{
  gint column;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));

  column = va_arg (var_args, gint);

Havoc Pennington's avatar
Havoc Pennington committed
713
  while (column != -1)
714
715
716
717
718
719
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= tree_store->n_columns)
	{
Havoc Pennington's avatar
Havoc Pennington committed
720
	  g_warning ("%s: Invalid column number %d accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
721
722
723
	  break;
	}

724
      gtk_tree_store_get_value (GTK_TREE_MODEL (tree_store), iter, column, &value);
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

      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);
    }
}

void
745
746
747
gtk_tree_store_get (GtkTreeStore *tree_store,
		    GtkTreeIter  *iter,
		    ...)
748
749
750
751
752
753
{
  va_list var_args;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));

  va_start (var_args, iter);
Havoc Pennington's avatar
Havoc Pennington committed
754
  gtk_tree_store_get_valist (tree_store, iter, var_args);
755
756
757
758
  va_end (var_args);
}

void
759
760
gtk_tree_store_remove (GtkTreeStore *model,
		       GtkTreeIter  *iter)
761
762
{
  GtkTreePath *path;
763

764
765
766
767
768
  GNode *parent;

  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));

Havoc Pennington's avatar
Havoc Pennington committed
769
  parent = G_NODE (iter->user_data)->parent;
770

771
772
  g_assert (parent != NULL);
  
Havoc Pennington's avatar
Havoc Pennington committed
773
774
  if (G_NODE (iter->user_data)->data)
    _gtk_tree_data_list_free ((GtkTreeDataList *) G_NODE (iter->user_data)->data,
775
776
			      model->column_headers);

777
  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
Havoc Pennington's avatar
Havoc Pennington committed
778
  g_node_destroy (G_NODE (iter->user_data));
779
780

  model->stamp++;
781
  gtk_signal_emit_by_name (GTK_OBJECT (model),
782
			   "deleted",
783
784
785
786
			   path);
  if (parent != G_NODE (model->root) && parent->children == NULL)
    {
      gtk_tree_path_up (path);
787
      
788
      gtk_signal_emit_by_name (GTK_OBJECT (model),
789
			       "child_toggled",
790
791
792
793
794
795
			       path,
			       parent);
    }
  gtk_tree_path_free (path);
}

796
void
797
798
799
800
gtk_tree_store_insert (GtkTreeStore *model,
		       GtkTreeIter  *iter,
		       GtkTreeIter  *parent,
		       gint          position)
801
802
{
  GtkTreePath *path;
803
  GNode *parent_node;
804
  
805
806
  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));
807

808
809
810
811
  if (parent)
    parent_node = parent->user_data;
  else
    parent_node = model->root;
812

813
  iter->stamp = model->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
814
  iter->user_data = g_node_new (NULL);
815
  g_node_insert (parent_node, position, G_NODE (iter->user_data));
816
817
  
  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
818
  gtk_signal_emit_by_name (GTK_OBJECT (model),
819
820
			   "inserted",
			   path, iter);
821
  gtk_tree_path_free (path);
822
823

  validate_tree ((GtkTreeStore*)model);
824
825
}

826
void
827
828
829
830
gtk_tree_store_insert_before (GtkTreeStore *model,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent,
			      GtkTreeIter  *sibling)
831
832
{
  GtkTreePath *path;
833
  GNode *parent_node = NULL;
834
835
  GNode *new_node;
  
836
837
838
  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));
  g_return_if_fail (iter != NULL);
839

840
  new_node = g_node_new (NULL);  
841

842
843
844
  if (parent == NULL && sibling == NULL)
    parent_node = model->root;
  else if (parent == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
845
    parent_node = G_NODE (sibling->user_data)->parent;
846
  else if (sibling == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
847
    parent_node = G_NODE (parent->user_data);
848
849
850
851
852
853
  else
    {
      g_return_if_fail (G_NODE (sibling->user_data)->parent ==
                        G_NODE (parent->user_data));
      parent_node = G_NODE (parent->user_data);
    }
854

855
  g_node_insert_before (parent_node,
Havoc Pennington's avatar
Havoc Pennington committed
856
			sibling ? G_NODE (sibling->user_data) : NULL,
857
                        new_node);
858

859
860
861
  iter->stamp = model->stamp;
  iter->user_data = new_node;
  
862
  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
863
  gtk_signal_emit_by_name (GTK_OBJECT (model),
864
865
			   "inserted",
			   path, iter);
866
  gtk_tree_path_free (path);
867
868

  validate_tree ((GtkTreeStore*)model);
869
870
}

871
void
872
873
874
875
gtk_tree_store_insert_after (GtkTreeStore *model,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *parent,
			     GtkTreeIter  *sibling)
876
877
{
  GtkTreePath *path;
878
  GNode *parent_node;
879
880
  GNode *new_node;
  
881
882
883
  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));
  g_return_if_fail (iter != NULL);
884

885
  new_node = g_node_new (NULL);
886

887
888
889
  if (parent == NULL && sibling == NULL)
    parent_node = model->root;
  else if (parent == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
890
    parent_node = G_NODE (sibling->user_data)->parent;
891
  else if (sibling == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
892
    parent_node = G_NODE (parent->user_data);
893
894
895
896
897
898
  else
    {
      g_return_if_fail (G_NODE (sibling->user_data)->parent ==
                        G_NODE (parent->user_data));
      parent_node = G_NODE (parent->user_data);
    }
899

900
  
901
  g_node_insert_after (parent_node,
Havoc Pennington's avatar
Havoc Pennington committed
902
		       sibling ? G_NODE (sibling->user_data) : NULL,
903
904
905
906
907
                       new_node);
  
  iter->stamp = model->stamp;
  iter->user_data = new_node;
  
908
  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
909
  gtk_signal_emit_by_name (GTK_OBJECT (model),
910
911
			   "inserted",
			   path, iter);
912
  gtk_tree_path_free (path);
913
914

  validate_tree ((GtkTreeStore*)model);
915
916
}

917
void
918
919
920
gtk_tree_store_prepend (GtkTreeStore *model,
			GtkTreeIter  *iter,
			GtkTreeIter  *parent)
921
{
922
  GNode *parent_node;
923
  
924
925
926
  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));
  g_return_if_fail (iter != NULL);
927
928

  if (parent == NULL)
929
930
    parent_node = model->root;
  else
Havoc Pennington's avatar
Havoc Pennington committed
931
    parent_node = parent->user_data;
932
  
933
  if (parent_node->children == NULL)
934
935
    {
      GtkTreePath *path;
936
937
938
939
940
941
      
      iter->stamp = model->stamp;
      iter->user_data = g_node_new (NULL);
      
      g_node_prepend (parent_node, iter->user_data);
      
942
      if (parent_node != model->root)
943
944
945
	{
	  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), parent);
	  gtk_signal_emit_by_name (GTK_OBJECT (model),
946
				   "child_toggled",
947
948
				   path,
				   parent);
949
	  gtk_tree_path_append_index (path, 0);
950
951
952
	}
      else
	{
953
	  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
954
955
	}
      gtk_signal_emit_by_name (GTK_OBJECT (model),
956
			       "inserted",
957
			       path,
958
			       iter);
959
960
961
962
      gtk_tree_path_free (path);
    }
  else
    {
963
      gtk_tree_store_insert_after (model, iter, parent, NULL);
964
    }
965
966

  validate_tree ((GtkTreeStore*)model);
967
968
}

969
void
970
971
972
gtk_tree_store_append (GtkTreeStore *model,
		       GtkTreeIter  *iter,
		       GtkTreeIter  *parent)
973
{
974
975
976
977
978
  GNode *parent_node;

  g_return_if_fail (model != NULL);
  g_return_if_fail (GTK_IS_TREE_STORE (model));
  g_return_if_fail (iter != NULL);
979
  
980
  if (parent == NULL)
981
982
    parent_node = model->root;
  else
Havoc Pennington's avatar
Havoc Pennington committed
983
    parent_node = parent->user_data;
984

985
  if (parent_node->children == NULL)
986
987
    {
      GtkTreePath *path;
988

989
990
991
      iter->stamp = model->stamp;
      iter->user_data = g_node_new (NULL);
      
Havoc Pennington's avatar
Havoc Pennington committed
992
      g_node_append (parent_node, G_NODE (iter->user_data));
993
994

      if (parent_node != model->root)
995
996
997
	{
	  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), parent);
	  gtk_signal_emit_by_name (GTK_OBJECT (model),
998
				   "child_toggled",
999
1000
				   path,
				   parent);
1001
	  gtk_tree_path_append_index (path, 0);
1002
1003
1004
	}
      else
	{
1005
	  path = gtk_tree_store_get_path (GTK_TREE_MODEL (model), iter);
1006
	}
1007
      
1008
      gtk_signal_emit_by_name (GTK_OBJECT (model),
1009
			       "inserted",
1010
			       path,
1011
			       iter);
1012
1013
1014
1015
      gtk_tree_path_free (path);
    }
  else
    {
1016
      gtk_tree_store_insert_before (model, iter, parent, NULL);
1017
    }
1018
1019

  validate_tree ((GtkTreeStore*)model);
1020
1021
1022
}

gboolean
1023
1024
1025
gtk_tree_store_is_ancestor (GtkTreeStore *model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *descendant)
1026
1027
1028
{
  g_return_val_if_fail (model != NULL, FALSE);
  g_return_val_if_fail (GTK_IS_TREE_STORE (model), FALSE);
1029
  g_return_val_if_fail (iter != NULL, FALSE);
1030
1031
  g_return_val_if_fail (descendant != NULL, FALSE);

Havoc Pennington's avatar
Havoc Pennington committed
1032
1033
  return g_node_is_ancestor (G_NODE (iter->user_data),
			     G_NODE (descendant->user_data));
1034
1035
1036
1037
}


gint
1038
1039
gtk_tree_store_iter_depth (GtkTreeStore *model,
			   GtkTreeIter  *iter)
1040
1041
1042
{
  g_return_val_if_fail (model != NULL, 0);
  g_return_val_if_fail (GTK_IS_TREE_STORE (model), 0);
1043
  g_return_val_if_fail (iter != NULL, 0);
1044

Havoc Pennington's avatar
Havoc Pennington committed
1045
  return g_node_depth (G_NODE (iter->user_data)) - 1;
1046
}
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271

/* DND */



static gboolean
gtk_tree_store_drag_data_delete (GtkTreeDragSource *drag_source,
                                 GtkTreePath       *path)
{
  GtkTreeIter iter;

  g_return_val_if_fail (GTK_IS_TREE_STORE (drag_source), FALSE);
  
  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
                               &iter,
                               path))
    {
      gtk_tree_store_remove (GTK_TREE_STORE (drag_source),
                             &iter);
      return TRUE;
    }
  else
    {
      return FALSE;
    }
}

static gboolean
gtk_tree_store_drag_data_get (GtkTreeDragSource *drag_source,
                              GtkTreePath       *path,
                              GtkSelectionData  *selection_data)
{
  g_return_val_if_fail (GTK_IS_TREE_STORE (drag_source), FALSE);

  /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
   * target, because the default handler does it for us, but
   * we do anyway for the convenience of someone maybe overriding the
   * default handler.
   */

  if (gtk_selection_data_set_tree_row (selection_data,
                                       GTK_TREE_MODEL (drag_source),
                                       path))
    {
      return TRUE;
    }
  else
    {
      /* FIXME handle text targets at least. */
    }

  return FALSE;
}

static void
copy_node_data (GtkTreeStore *tree_store,
                GtkTreeIter  *src_iter,
                GtkTreeIter  *dest_iter)
{
  GtkTreeDataList *dl = G_NODE (src_iter->user_data)->data;
  GtkTreeDataList *copy_head = NULL;
  GtkTreeDataList *copy_prev = NULL;
  GtkTreeDataList *copy_iter = NULL;
  gint col;
  
  col = 0;
  while (dl)
    {
      copy_iter = _gtk_tree_data_list_node_copy (dl,
                                                 tree_store->column_headers[col]);

      if (copy_head == NULL)
        copy_head = copy_iter;

      if (copy_prev)
        copy_prev->next = copy_iter;

      copy_prev = copy_iter;

      dl = dl->next;
      ++col;
    }
          
  G_NODE (dest_iter->user_data)->data = copy_head;

  gtk_signal_emit_by_name (GTK_OBJECT (tree_store),
                           "changed",
                           NULL, dest_iter);
}

static void
recursive_node_copy (GtkTreeStore *tree_store,
                     GtkTreeIter  *src_iter,
                     GtkTreeIter  *dest_iter)
{
  GtkTreeIter child;
  GtkTreeModel *model;

  model = GTK_TREE_MODEL (tree_store);
  
  copy_node_data (tree_store, src_iter, dest_iter);

  if (gtk_tree_model_iter_children (model,
                                    &child,
                                    src_iter))
    {
      /* Need to create children and recurse. Note our
       * dependence on persistent iterators here.
       */
      do
        {
          GtkTreeIter copy;

          /* Gee, a really slow algorithm... ;-) FIXME */
          gtk_tree_store_append (tree_store,
                                 &copy,
                                 dest_iter);
          
          recursive_node_copy (tree_store, &child, &copy);
        }
      while (gtk_tree_model_iter_next (model, &child));
    }
}

static gboolean
gtk_tree_store_drag_data_received (GtkTreeDragDest   *drag_dest,
                                   GtkTreePath       *dest,
                                   GtkSelectionData  *selection_data)
{
  GtkTreeModel *tree_model;
  GtkTreeStore *tree_store;
  GtkTreeModel *src_model = NULL;
  GtkTreePath *src_path = NULL;
  gboolean retval = FALSE;
  
  g_return_val_if_fail (GTK_IS_TREE_STORE (drag_dest), FALSE);

  tree_model = GTK_TREE_MODEL (drag_dest);
  tree_store = GTK_TREE_STORE (drag_dest);

  validate_tree (tree_store);
  
  if (gtk_selection_data_get_tree_row (selection_data,
                                       &src_model,
                                       &src_path) &&
      src_model == tree_model)
    {
      /* Copy the given row to a new position */
      GtkTreeIter src_iter;
      GtkTreeIter dest_iter;
      GtkTreePath *prev;
      
      if (!gtk_tree_model_get_iter (src_model,
                                    &src_iter,
                                    src_path))
        {
          goto out;
        }

      /* Get the path to insert _after_ (dest is the path to insert _before_) */
      prev = gtk_tree_path_copy (dest);
      
      if (!gtk_tree_path_prev (prev))
        {
          GtkTreeIter dest_parent;
          GtkTreePath *parent;
          GtkTreeIter *dest_parent_p;
          
          /* dest was the first spot at the current depth; which means
           * we are supposed to prepend.
           */
          
          /* Get the parent, NULL if parent is the root */
          dest_parent_p = NULL;
          parent = gtk_tree_path_copy (dest);
          if (gtk_tree_path_up (parent))
            {
              gtk_tree_model_get_iter (tree_model,
                                       &dest_parent,
                                       parent);
              dest_parent_p = &dest_parent;
            }
          gtk_tree_path_free (parent);
          parent = NULL;
          
          gtk_tree_store_prepend (GTK_TREE_STORE (tree_model),
                                  &dest_iter,
                                  dest_parent_p);
          
          retval = TRUE;
        }
      else
        {
          if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
                                       &dest_iter,
                                       prev))
            {
              GtkTreeIter tmp_iter = dest_iter;
              gtk_tree_store_insert_after (GTK_TREE_STORE (tree_model),
                                           &dest_iter,
                                           NULL,
                                           &tmp_iter);
              retval = TRUE;

            }
        }

      gtk_tree_path_free (prev);
      
      /* If we succeeded in creating dest_iter, walk src_iter tree branch,
       * duplicating it below dest_iter.
       */
      
      if (retval)
        {
          recursive_node_copy (tree_store,
                               &src_iter,
                               &dest_iter);
        }
    }
  else
    {
      /* FIXME maybe add some data targets eventually, or handle text
       * targets in the simple case.
       */
Havoc Pennington's avatar
Havoc Pennington committed
1272

1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
    }

 out:
  
  if (src_path)
    gtk_tree_path_free (src_path);
  
  return retval;  
}

static gboolean
gtk_tree_store_row_drop_possible (GtkTreeDragDest *drag_dest,
                                  GtkTreeModel    *src_model,
                                  GtkTreePath     *src_path,
                                  GtkTreePath     *dest_path)
{
  /* can only drag to ourselves */
  if (src_model != GTK_TREE_MODEL (drag_dest))
    return FALSE;
  
  /* Can't drop into ourself. */
  if (gtk_tree_path_is_ancestor (src_path,
                                 dest_path))
    return FALSE;

  /* Can't drop if dest_path's parent doesn't exist */
  {
    GtkTreeIter iter;
    GtkTreePath *tmp = gtk_tree_path_copy (dest_path);

    /* if we can't go up, we know the parent exists, the root
     * always exists.
     */
    if (gtk_tree_path_up (tmp))
      {
        if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest),
                                      &iter, tmp))
          {
            if (tmp)
              gtk_tree_path_free (tmp);
            return FALSE;
          }
      }
    
    if (tmp)
      gtk_tree_path_free (tmp);
  }
  
  /* Can otherwise drop anywhere. */
  return TRUE;
}
     
static void
validate_gnode (GNode* node)
{
  GNode *iter;
  
  iter = node->children;
  while (iter != NULL)
    {
      g_assert (iter->parent == node);
      if (iter->prev)
        g_assert (iter->prev->next == iter);
      validate_gnode (iter);
      iter = iter->next;
    }
}