gtktreestore.c 90.5 KB
Newer Older
1
/* gtktreestore.c
Manish Singh's avatar
Manish Singh committed
2
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * 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.
 */

20
#include "config.h"
Manish Singh's avatar
Manish Singh committed
21
22
#include <string.h>
#include <gobject/gvaluecollector.h>
23
24
25
#include "gtktreemodel.h"
#include "gtktreestore.h"
#include "gtktreedatalist.h"
26
#include "gtktreednd.h"
Johan Dahlin's avatar
Johan Dahlin committed
27
#include "gtkbuildable.h"
Matthias Clasen's avatar
Matthias Clasen committed
28
#include "gtkintl.h"
29

30

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * SECTION:gtktreestore
 * @Short_description: A tree-like data structure that can be used with the GtkTreeView
 * @Title: GtkTreeStore
 * @See_also: #GtkTreeModel
 *
 * The #GtkTreeStore object is a list model for use with a #GtkTreeView
 * widget.  It implements the #GtkTreeModel interface, and consequentialy,
 * can use all of the methods available there.  It also implements the
 * #GtkTreeSortable interface so it can be sorted by the view.  Finally,
 * it also implements the tree <link linkend="gtktreednd">drag and
 * drop</link> interfaces.
 *
 * <refsect2 id="GtkTreeStore-BUILDER-UI">
 * <title>GtkTreeStore as GtkBuildable</title>
 * The GtkTreeStore implementation of the #GtkBuildable interface allows
 * to specify the model columns with a &lt;columns&gt; element that may
 * contain multiple &lt;column&gt; elements, each specifying one model
 * column. The "type" attribute specifies the data type for the column.
 * <example>
 * <title>A UI Definition fragment for a tree store</title>
 * <programlisting><![CDATA[
 * <object class="GtkTreeStore">
 *   <columns>
 *     <column type="gchararray"/>
 *     <column type="gchararray"/>
 *     <column type="gint"/>
 *   </columns>
 * </object>
 * ]]></programlisting>
 * </example>
 * </refsect2>
 */

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
struct _GtkTreeStorePrivate
{
  gint stamp;
  gpointer root;
  gpointer last;
  gint n_columns;
  gint sort_column_id;
  GList *sort_list;
  GtkSortType order;
  GType *column_headers;
  GtkTreeIterCompareFunc default_sort_func;
  gpointer default_sort_data;
  GDestroyNotify default_sort_destroy;
  guint columns_dirty : 1;
};

81

82
#define G_NODE(node) ((GNode *)node)
83
84
#define GTK_TREE_STORE_IS_SORTED(tree) (((GtkTreeStore*)(tree))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
#define VALID_ITER(iter, tree_store) ((iter)!= NULL && (iter)->user_data != NULL && ((GtkTreeStore*)(tree_store))->priv->stamp == (iter)->stamp)
85

86
static void         gtk_tree_store_tree_model_init (GtkTreeModelIface *iface);
87
88
static void         gtk_tree_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_tree_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
89
static void         gtk_tree_store_sortable_init   (GtkTreeSortableIface   *iface);
Johan Dahlin's avatar
Johan Dahlin committed
90
static void         gtk_tree_store_buildable_init  (GtkBuildableIface      *iface);
91
static void         gtk_tree_store_finalize        (GObject           *object);
92
static GtkTreeModelFlags gtk_tree_store_get_flags  (GtkTreeModel      *tree_model);
93
static gint         gtk_tree_store_get_n_columns   (GtkTreeModel      *tree_model);
94
95
static GType        gtk_tree_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
96
97
98
static gboolean     gtk_tree_store_get_iter        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreePath       *path);
99
100
static GtkTreePath *gtk_tree_store_get_path        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
101
static void         gtk_tree_store_get_value       (GtkTreeModel      *tree_model,
102
103
104
105
106
107
108
109
110
111
112
113
114
115
						    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,
116
						    GtkTreeIter       *parent,
117
118
119
						    gint               n);
static gboolean     gtk_tree_store_iter_parent     (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
120
						    GtkTreeIter       *child);
121
122


123
124
125
126
127
128
static void gtk_tree_store_set_n_columns   (GtkTreeStore *tree_store,
					    gint          n_columns);
static void gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
					    gint          column,
					    GType         type);

129
130
static void gtk_tree_store_increment_stamp (GtkTreeStore  *tree_store);

131

132
/* DND interfaces */
Murray Cumming's avatar
Murray Cumming committed
133
134
static gboolean real_gtk_tree_store_row_draggable   (GtkTreeDragSource *drag_source,
						   GtkTreePath       *path);
135
static gboolean gtk_tree_store_drag_data_delete   (GtkTreeDragSource *drag_source,
136
						   GtkTreePath       *path);
137
static gboolean gtk_tree_store_drag_data_get      (GtkTreeDragSource *drag_source,
138
139
						   GtkTreePath       *path,
						   GtkSelectionData  *selection_data);
140
static gboolean gtk_tree_store_drag_data_received (GtkTreeDragDest   *drag_dest,
141
142
						   GtkTreePath       *dest,
						   GtkSelectionData  *selection_data);
143
static gboolean gtk_tree_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
144
145
						   GtkTreePath       *dest_path,
						   GtkSelectionData  *selection_data);
146
147
148

/* Sortable Interfaces */

149
150
151
static void     gtk_tree_store_sort                    (GtkTreeStore           *tree_store);
static void     gtk_tree_store_sort_iter_changed       (GtkTreeStore           *tree_store,
							GtkTreeIter            *iter,
152
153
							gint                    column,
							gboolean                emit_signal);
154
155
static gboolean gtk_tree_store_get_sort_column_id      (GtkTreeSortable        *sortable,
							gint                   *sort_column_id,
156
							GtkSortType            *order);
157
158
static void     gtk_tree_store_set_sort_column_id      (GtkTreeSortable        *sortable,
							gint                    sort_column_id,
159
							GtkSortType             order);
160
static void     gtk_tree_store_set_sort_func           (GtkTreeSortable        *sortable,
161
162
163
							gint                    sort_column_id,
							GtkTreeIterCompareFunc  func,
							gpointer                data,
Michael Natterer's avatar
Michael Natterer committed
164
							GDestroyNotify          destroy);
165
166
167
static void     gtk_tree_store_set_default_sort_func   (GtkTreeSortable        *sortable,
							GtkTreeIterCompareFunc  func,
							gpointer                data,
Michael Natterer's avatar
Michael Natterer committed
168
							GDestroyNotify          destroy);
169
static gboolean gtk_tree_store_has_default_sort_func   (GtkTreeSortable        *sortable);
170

Johan Dahlin's avatar
Johan Dahlin committed
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

/* buildable */

static gboolean gtk_tree_store_buildable_custom_tag_start (GtkBuildable  *buildable,
							   GtkBuilder    *builder,
							   GObject       *child,
							   const gchar   *tagname,
							   GMarkupParser *parser,
							   gpointer      *data);
static void     gtk_tree_store_buildable_custom_finished (GtkBuildable 	 *buildable,
							  GtkBuilder   	 *builder,
							  GObject      	 *child,
							  const gchar  	 *tagname,
							  gpointer     	  user_data);

186
187
static void     validate_gnode                         (GNode *node);

188
189
190
191
192
static void     gtk_tree_store_move                    (GtkTreeStore           *tree_store,
                                                        GtkTreeIter            *iter,
                                                        GtkTreeIter            *position,
                                                        gboolean                before);

193

194
195
196
static inline void
validate_tree (GtkTreeStore *tree_store)
{
197
  if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
198
    {
199
      g_assert (G_NODE (tree_store->priv->root)->parent == NULL);
200

201
      validate_gnode (G_NODE (tree_store->priv->root));
202
203
204
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
205
206
207
208
209
210
211
212
G_DEFINE_TYPE_WITH_CODE (GtkTreeStore, gtk_tree_store, G_TYPE_OBJECT,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
						gtk_tree_store_tree_model_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
						gtk_tree_store_drag_source_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
						gtk_tree_store_drag_dest_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
Johan Dahlin's avatar
Johan Dahlin committed
213
214
215
						gtk_tree_store_sortable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_tree_store_buildable_init))
216
217

static void
218
gtk_tree_store_class_init (GtkTreeStoreClass *class)
219
{
220
221
  GObjectClass *object_class;

222
  object_class = (GObjectClass *) class;
223

224
  object_class->finalize = gtk_tree_store_finalize;
225
226

  g_type_class_add_private (class, sizeof (GtkTreeStorePrivate));
227
228
229
230
231
}

static void
gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
{
232
  iface->get_flags = gtk_tree_store_get_flags;
233
  iface->get_n_columns = gtk_tree_store_get_n_columns;
234
  iface->get_column_type = gtk_tree_store_get_column_type;
235
  iface->get_iter = gtk_tree_store_get_iter;
236
  iface->get_path = gtk_tree_store_get_path;
237
  iface->get_value = gtk_tree_store_get_value;
238
239
240
241
242
243
  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;
244
245
}

246
247
248
static void
gtk_tree_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
Murray Cumming's avatar
Murray Cumming committed
249
  iface->row_draggable = real_gtk_tree_store_row_draggable;
250
251
252
253
254
  iface->drag_data_delete = gtk_tree_store_drag_data_delete;
  iface->drag_data_get = gtk_tree_store_drag_data_get;
}

static void
255
gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface)
256
257
258
259
260
{
  iface->drag_data_received = gtk_tree_store_drag_data_received;
  iface->row_drop_possible = gtk_tree_store_row_drop_possible;
}

261
262
263
static void
gtk_tree_store_sortable_init (GtkTreeSortableIface *iface)
{
264
265
  iface->get_sort_column_id = gtk_tree_store_get_sort_column_id;
  iface->set_sort_column_id = gtk_tree_store_set_sort_column_id;
266
  iface->set_sort_func = gtk_tree_store_set_sort_func;
267
268
  iface->set_default_sort_func = gtk_tree_store_set_default_sort_func;
  iface->has_default_sort_func = gtk_tree_store_has_default_sort_func;
269
270
}

Johan Dahlin's avatar
Johan Dahlin committed
271
272
273
274
275
276
277
void
gtk_tree_store_buildable_init (GtkBuildableIface *iface)
{
  iface->custom_tag_start = gtk_tree_store_buildable_custom_tag_start;
  iface->custom_finished = gtk_tree_store_buildable_custom_finished;
}

278
279
280
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
281
282
283
284
285
286
287
288
  GtkTreeStorePrivate *priv;

  priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_store,
                                      GTK_TYPE_TREE_STORE,
                                      GtkTreeStorePrivate);
  tree_store->priv = priv;
  priv->root = g_node_new (NULL);
  /* While the odds are against us getting 0...  */
289
290
  do
    {
291
      priv->stamp = g_random_int ();
292
    }
293
  while (priv->stamp == 0);
294

295
296
297
  priv->sort_list = NULL;
  priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
  priv->columns_dirty = FALSE;
298
299
}

300
301
302
303
304
305
/**
 * gtk_tree_store_new:
 * @n_columns: number of columns in the tree store
 * @Varargs: all #GType types for the columns, from first to last
 *
 * Creates a new tree store as with @n_columns columns each of the types passed
306
307
308
309
 * in.  Note that only types derived from standard GObject fundamental types 
 * are supported. 
 *
 * As an example, <literal>gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
310
311
 * GDK_TYPE_PIXBUF);</literal> will create a new #GtkTreeStore with three columns, of type
 * <type>int</type>, <type>string</type> and #GdkPixbuf respectively.
312
313
314
 *
 * Return value: a new #GtkTreeStore
 **/
315
GtkTreeStore *
316
gtk_tree_store_new (gint n_columns,
317
			       ...)
318
{
319
  GtkTreeStore *retval;
320
321
322
323
324
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
325
  retval = g_object_new (GTK_TYPE_TREE_STORE, NULL);
326
  gtk_tree_store_set_n_columns (retval, n_columns);
327
328

  va_start (args, n_columns);
329

330
  for (i = 0; i < n_columns; i++)
331
332
333
334
    {
      GType type = va_arg (args, GType);
      if (! _gtk_tree_data_list_check_type (type))
	{
335
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
Manish Singh's avatar
Manish Singh committed
336
	  g_object_unref (retval);
337
          va_end (args);
338
339
340
341
	  return NULL;
	}
      gtk_tree_store_set_column_type (retval, i, type);
    }
342
343
344
345
  va_end (args);

  return retval;
}
346
347
348
/**
 * gtk_tree_store_newv:
 * @n_columns: number of columns in the tree store
349
 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
350
351
352
 *
 * Non vararg creation function.  Used primarily by language bindings.
 *
353
 * Return value: (transfer full): a new #GtkTreeStore
354
355
356
357
358
359
360
361
362
363
 **/
GtkTreeStore *
gtk_tree_store_newv (gint   n_columns,
		     GType *types)
{
  GtkTreeStore *retval;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
364
  retval = g_object_new (GTK_TYPE_TREE_STORE, NULL);
365
366
367
368
369
370
  gtk_tree_store_set_n_columns (retval, n_columns);

   for (i = 0; i < n_columns; i++)
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
371
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
Manish Singh's avatar
Manish Singh committed
372
	  g_object_unref (retval);
373
374
375
376
377
378
379
	  return NULL;
	}
      gtk_tree_store_set_column_type (retval, i, types[i]);
    }

  return retval;
}
380

381
382
383
384
385

/**
 * gtk_tree_store_set_column_types:
 * @tree_store: A #GtkTreeStore
 * @n_columns: Number of columns for the tree store
386
 * @types: (array length=n_columns): An array of #GType types, one for each column
387
 * 
Matthias Clasen's avatar
Matthias Clasen committed
388
389
390
391
 * This function is meant primarily for #GObjects that inherit from 
 * #GtkTreeStore, and should only be used when constructing a new 
 * #GtkTreeStore.  It will not function after a row has been added, 
 * or a method on the #GtkTreeModel interface is called.
392
393
394
395
396
397
398
399
400
 **/
void
gtk_tree_store_set_column_types (GtkTreeStore *tree_store,
				 gint          n_columns,
				 GType        *types)
{
  gint i;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
401
  g_return_if_fail (tree_store->priv->columns_dirty == 0);
402
403
404
405
406
407

  gtk_tree_store_set_n_columns (tree_store, n_columns);
   for (i = 0; i < n_columns; i++)
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
408
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
409
410
411
412
413
414
	  continue;
	}
      gtk_tree_store_set_column_type (tree_store, i, types[i]);
    }
}

415
static void
416
417
418
gtk_tree_store_set_n_columns (GtkTreeStore *tree_store,
			      gint          n_columns)
{
419
  GtkTreeStorePrivate *priv = tree_store->priv;
420
  int i;
421

422
  if (priv->n_columns == n_columns)
423
424
    return;

425
426
427
428
  priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
  for (i = priv->n_columns; i < n_columns; i++)
    priv->column_headers[i] = G_TYPE_INVALID;
  priv->n_columns = n_columns;
429

430
431
  if (priv->sort_list)
    _gtk_tree_data_list_header_free (priv->sort_list);
432

433
  priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
434
435
}

436
437
438
439
440
/**
 * gtk_tree_store_set_column_type:
 * @tree_store: a #GtkTreeStore
 * @column: column number
 * @type: type of the data to be stored in @column
441
 *
442
443
444
445
 * 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_DOUBLE, %G_TYPE_STRING, %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with
 * subclasses of those types such as %GDK_TYPE_PIXBUF.
446
 *
447
 **/
448
static void
449
450
451
452
gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
				gint          column,
				GType         type)
{
453
454
  GtkTreeStorePrivate *priv = tree_store->priv;

455
456
  if (!_gtk_tree_data_list_check_type (type))
    {
457
      g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
458
459
      return;
    }
460
  priv->column_headers[column] = type;
461
462
}

463
static gboolean
464
465
node_free (GNode *node, gpointer data)
{
466
467
468
469
  if (node->data)
    _gtk_tree_data_list_free (node->data, (GType*)data);
  node->data = NULL;

470
  return FALSE;
471
472
473
474
475
476
}

static void
gtk_tree_store_finalize (GObject *object)
{
  GtkTreeStore *tree_store = GTK_TREE_STORE (object);
477
  GtkTreeStorePrivate *priv = tree_store->priv;
478

479
480
481
482
483
  g_node_traverse (priv->root, G_POST_ORDER, G_TRAVERSE_ALL, -1,
		   node_free, priv->column_headers);
  g_node_destroy (priv->root);
  _gtk_tree_data_list_header_free (priv->sort_list);
  g_free (priv->column_headers);
484

485
  if (priv->default_sort_destroy)
486
    {
487
      GDestroyNotify d = priv->default_sort_destroy;
488

489
490
491
      priv->default_sort_destroy = NULL;
      d (priv->default_sort_data);
      priv->default_sort_data = NULL;
492
    }
493

494
  /* must chain up */
Matthias Clasen's avatar
Matthias Clasen committed
495
  G_OBJECT_CLASS (gtk_tree_store_parent_class)->finalize (object);
496
497
}

498
499
/* fulfill the GtkTreeModel requirements */
/* NOTE: GtkTreeStore::root is a GNode, that acts as the parent node.  However,
500
 * it is not visible to the tree or to the user., and the path "0" refers to the
501
502
 * first child of GtkTreeStore::root.
 */
503
504


505
static GtkTreeModelFlags
506
507
508
509
510
gtk_tree_store_get_flags (GtkTreeModel *tree_model)
{
  return GTK_TREE_MODEL_ITERS_PERSIST;
}

511
512
513
static gint
gtk_tree_store_get_n_columns (GtkTreeModel *tree_model)
{
514
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
515
  GtkTreeStorePrivate *priv = tree_store->priv;
516

517
  priv->columns_dirty = TRUE;
518

519
  return priv->n_columns;
520
521
}

522
523
524
525
static GType
gtk_tree_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
526
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
527
  GtkTreeStorePrivate *priv = tree_store->priv;
528

529
  g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
530

531
  priv->columns_dirty = TRUE;
532

533
  return priv->column_headers[index];
534
535
}

536
537
538
539
540
541
static gboolean
gtk_tree_store_get_iter (GtkTreeModel *tree_model,
			 GtkTreeIter  *iter,
			 GtkTreePath  *path)
{
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
542
  GtkTreeStorePrivate *priv = tree_store->priv;
543
544
545
546
  GtkTreeIter parent;
  gint *indices;
  gint depth, i;

547
  priv->columns_dirty = TRUE;
548

549
  indices = gtk_tree_path_get_indices (path);
550
551
552
553
  depth = gtk_tree_path_get_depth (path);

  g_return_val_if_fail (depth > 0, FALSE);

554
555
  parent.stamp = priv->stamp;
  parent.user_data = priv->root;
556

557
  if (!gtk_tree_store_iter_nth_child (tree_model, iter, &parent, indices[0]))
558
559
560
561
562
    return FALSE;

  for (i = 1; i < depth; i++)
    {
      parent = *iter;
563
      if (!gtk_tree_store_iter_nth_child (tree_model, iter, &parent, indices[i]))
564
565
566
567
568
569
	return FALSE;
    }

  return TRUE;
}

570
571
static GtkTreePath *
gtk_tree_store_get_path (GtkTreeModel *tree_model,
572
			 GtkTreeIter  *iter)
573
{
574
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
575
  GtkTreeStorePrivate *priv = tree_store->priv;
576
577
578
  GtkTreePath *retval;
  GNode *tmp_node;
  gint i = 0;
579

580
  g_return_val_if_fail (iter->user_data != NULL, NULL);
581
  g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
582

583
  validate_tree (tree_store);
584

585
  if (G_NODE (iter->user_data)->parent == NULL &&
586
      G_NODE (iter->user_data) == priv->root)
587
    return gtk_tree_path_new ();
588
  g_assert (G_NODE (iter->user_data)->parent != NULL);
589

590
  if (G_NODE (iter->user_data)->parent == G_NODE (priv->root))
591
592
    {
      retval = gtk_tree_path_new ();
593
      tmp_node = G_NODE (priv->root)->children;
594
595
596
    }
  else
    {
597
      GtkTreeIter tmp_iter = *iter;
598

599
      tmp_iter.user_data = G_NODE (iter->user_data)->parent;
600

601
      retval = gtk_tree_store_get_path (tree_model, &tmp_iter);
Havoc Pennington's avatar
Havoc Pennington committed
602
      tmp_node = G_NODE (iter->user_data)->parent->children;
603
604
605
606
    }

  if (retval == NULL)
    return NULL;
607

608
609
610
611
612
613
614
615
  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
616
      if (tmp_node == G_NODE (iter->user_data))
617
618
619
	break;
      i++;
    }
620

621
622
623
  if (tmp_node == NULL)
    {
      /* We couldn't find node, meaning it's prolly not ours */
624
      /* Perhaps I should do a g_return_if_fail here. */
625
626
627
628
629
630
631
632
633
634
635
      gtk_tree_path_free (retval);
      return NULL;
    }

  gtk_tree_path_append_index (retval, i);

  return retval;
}


static void
636
637
638
639
gtk_tree_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
640
{
641
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
642
  GtkTreeStorePrivate *priv = tree_store->priv;
643
644
645
  GtkTreeDataList *list;
  gint tmp_column = column;

646
  g_return_if_fail (column < priv->n_columns);
647
  g_return_if_fail (VALID_ITER (iter, tree_store));
648

Havoc Pennington's avatar
Havoc Pennington committed
649
  list = G_NODE (iter->user_data)->data;
650
651
652
653

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

654
655
  if (list)
    {
656
      _gtk_tree_data_list_node_to_value (list,
657
					 priv->column_headers[column],
658
					 value);
659
660
661
662
    }
  else
    {
      /* We want to return an initialized but empty (default) value */
663
      g_value_init (value, priv->column_headers[column]);
664
    }
665
666
667
}

static gboolean
668
669
gtk_tree_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
670
{
671
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
672
  g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->priv->stamp, FALSE);
673

674
675
676
677
678
679
  if (G_NODE (iter->user_data)->next)
    {
      iter->user_data = G_NODE (iter->user_data)->next;
      return TRUE;
    }
  else
680
681
682
683
    {
      iter->stamp = 0;
      return FALSE;
    }
684
685
}

686
687
688
689
static gboolean
gtk_tree_store_iter_children (GtkTreeModel *tree_model,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
690
{
691
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
692
  GtkTreeStorePrivate *priv = tree_store->priv;
693
694
  GNode *children;

695
696
  if (parent)
    g_return_val_if_fail (VALID_ITER (parent, tree_store), FALSE);
697

698
  if (parent)
699
    children = G_NODE (parent->user_data)->children;
700
  else
701
    children = G_NODE (priv->root)->children;
702

703
704
  if (children)
    {
705
      iter->stamp = priv->stamp;
706
707
708
709
      iter->user_data = children;
      return TRUE;
    }
  else
710
711
712
713
    {
      iter->stamp = 0;
      return FALSE;
    }
714
715
716
}

static gboolean
717
718
gtk_tree_store_iter_has_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter)
719
{
720
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
721
  g_return_val_if_fail (VALID_ITER (iter, tree_model), FALSE);
722

Havoc Pennington's avatar
Havoc Pennington committed
723
  return G_NODE (iter->user_data)->children != NULL;
724
725
726
}

static gint
727
728
gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
				GtkTreeIter  *iter)
729
{
730
  GNode *node;
731
732
  gint i = 0;

Federico Mena Quintero's avatar
Federico Mena Quintero committed
733
  g_return_val_if_fail (iter == NULL || iter->user_data != NULL, 0);
734

735
  if (iter == NULL)
736
    node = G_NODE (GTK_TREE_STORE (tree_model)->priv->root)->children;
737
  else
Havoc Pennington's avatar
Havoc Pennington committed
738
    node = G_NODE (iter->user_data)->children;
739

740
  while (node)
741
742
    {
      i++;
743
      node = node->next;
744
745
746
747
748
    }

  return i;
}

749
750
751
752
static gboolean
gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
753
754
			       gint          n)
{
755
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
756
  GtkTreeStorePrivate *priv = tree_store->priv;
757
  GNode *parent_node;
758
  GNode *child;
759

760
  g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
761

762
  if (parent == NULL)
763
    parent_node = priv->root;
764
  else
Havoc Pennington's avatar
Havoc Pennington committed
765
    parent_node = parent->user_data;
766

767
  child = g_node_nth_child (parent_node, n);
768

769
770
771
  if (child)
    {
      iter->user_data = child;
772
      iter->stamp = priv->stamp;
773
774
      return TRUE;
    }
775
  else
776
777
778
779
    {
      iter->stamp = 0;
      return FALSE;
    }
780
781
}

782
783
784
785
static gboolean
gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
786
{
787
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
788
  GtkTreeStorePrivate *priv = tree_store->priv;
789
  GNode *parent;
790

791
  g_return_val_if_fail (iter != NULL, FALSE);
792
  g_return_val_if_fail (VALID_ITER (child, tree_store), FALSE);
793
794
795

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

796
  g_assert (parent != NULL);
797

798
  if (parent != priv->root)
799
    {
800
      iter->user_data = parent;
801
      iter->stamp = priv->stamp;
802
      return TRUE;
803
    }
804
  else
805
806
807
808
    {
      iter->stamp = 0;
      return FALSE;
    }
809
810
}

811
812

/* Does not emit a signal */
813
static gboolean
814
815
816
gtk_tree_store_real_set_value (GtkTreeStore *tree_store,
			       GtkTreeIter  *iter,
			       gint          column,
817
818
			       GValue       *value,
			       gboolean      sort)
819
{
820
  GtkTreeStorePrivate *priv = tree_store->priv;
821
822
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
823
  gint old_column = column;
824
  GValue real_value = { 0, };
825
  gboolean converted = FALSE;
826
  gboolean retval = FALSE;
827

828
  if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
829
    {
830
831
      if (! (g_value_type_compatible (G_VALUE_TYPE (value), priv->column_headers[column]) &&
	     g_value_type_compatible (priv->column_headers[column], G_VALUE_TYPE (value))))
832
833
834
835
	{
	  g_warning ("%s: Unable to convert from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
836
		     g_type_name (priv->column_headers[column]));
837
	  return retval;
838
839
840
841
842
843
	}
      if (!g_value_transform (value, &real_value))
	{
	  g_warning ("%s: Unable to make conversion from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
844
		     g_type_name (priv->column_headers[column]));
845
	  g_value_unset (&real_value);
846
	  return retval;
847
848
849
	}
      converted = TRUE;
    }
850

Havoc Pennington's avatar
Havoc Pennington committed
851
  prev = list = G_NODE (iter->user_data)->data;
852
853
854
855
856

  while (list != NULL)
    {
      if (column == 0)
	{
857
858
859
860
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
861
	  retval = TRUE;
862
863
	  if (converted)
	    g_value_unset (&real_value);
864
          if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
865
            gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
866
	  return retval;
867
868
869
870
871
872
873
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
874
  if (G_NODE (iter->user_data)->data == NULL)
875
    {
Havoc Pennington's avatar
Havoc Pennington committed
876
      G_NODE (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
877
878
879
880
      list->next = NULL;
    }
  else
    {
881
      list = prev->next = _gtk_tree_data_list_alloc ();
882
883
884
885
886
      list->next = NULL;
    }

  while (column != 0)
    {
887
      list->next = _gtk_tree_data_list_alloc ();
888
889
890
891
      list = list->next;
      list->next = NULL;
      column --;
    }
892

893
  if (converted)
894
    _gtk_tree_data_list_value_to_node (list, &real_value);
895
896
  else
    _gtk_tree_data_list_value_to_node (list, value);
897
898
  
  retval = TRUE;
899
900
  if (converted)
    g_value_unset (&real_value);
901

902
  if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
903
    gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
904

905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
  return retval;
}

/**
 * gtk_tree_store_set_value:
 * @tree_store: a #GtkTreeStore
 * @iter: A valid #GtkTreeIter for the row being modified
 * @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.
 *
 **/
void
gtk_tree_store_set_value (GtkTreeStore *tree_store,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
{
  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
  g_return_if_fail (VALID_ITER (iter, tree_store));
928
  g_return_if_fail (column >= 0 && column < tree_store->priv->n_columns);
929
930
  g_return_if_fail (G_IS_VALUE (value));

931
  if (gtk_tree_store_real_set_value (tree_store, iter, column, value, TRUE))
932
933
934
    {
      GtkTreePath *path;

935
      path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
936
937
938
      gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
      gtk_tree_path_free (path);
    }
939
940
}

941
942
static GtkTreeIterCompareFunc
gtk_tree_store_get_compare_func (GtkTreeStore *tree_store)
943
{
944
  GtkTreeStorePrivate *priv = tree_store->priv;
945
  GtkTreeIterCompareFunc func = NULL;
946

947
  if (GTK_TREE_STORE_IS_SORTED (tree_store))
948
    {
949
      if (priv->sort_column_id != -1)
950
951
	{
	  GtkTreeDataSortHeader *header;
952
953
	  header = _gtk_tree_data_list_get_header (priv->sort_list,
						   priv->sort_column_id);
954
955
	  g_return_val_if_fail (header != NULL, NULL);
	  g_return_val_if_fail (header->func != NULL, NULL);
956
957
958
959
	  func = header->func;
	}
      else
	{
960
	  func = priv->default_sort_func;
961
	}
962
963
    }

964
965
966
  return func;
}

967
968
969
970
971
972
973
974
975
static void
gtk_tree_store_set_vector_internal (GtkTreeStore *tree_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    gint         *columns,
				    GValue       *values,
				    gint          n_values)
{
976
  GtkTreeStorePrivate *priv = tree_store->priv;
977
978
979
980
981
982
983
984
985
986
987
988
989
990
  gint i;
  GtkTreeIterCompareFunc func = NULL;

  func = gtk_tree_store_get_compare_func (tree_store);
  if (func != _gtk_tree_data_list_compare_func)
    *maybe_need_sort = TRUE;

  for (i = 0; i < n_values; i++)
    {
      *emit_signal = gtk_tree_store_real_set_value (tree_store, iter,
						    columns[i], &values[i],
						    FALSE) || *emit_signal;

      if (func == _gtk_tree_data_list_compare_func &&
991
	  columns[i] == priv->sort_column_id)
992
993
994
995
	*maybe_need_sort = TRUE;
    }
}