gtktreestore.c 92.7 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
 *
 * 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17
 */

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

30

31 32 33 34 35 36 37 38 39 40
/**
 * 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,
Sébastien Wilmet's avatar
Sébastien Wilmet committed
41
 * it also implements the tree
42
 * [drag and drop][gtk3-GtkTreeView-drag-and-drop]
Sébastien Wilmet's avatar
Sébastien Wilmet committed
43
 * interfaces.
44
 *
45
 * # GtkTreeStore as GtkBuildable
Matthias Clasen's avatar
Matthias Clasen committed
46
 *
47
 * The GtkTreeStore implementation of the #GtkBuildable interface allows
48 49 50
 * to specify the model columns with a <columns> element that may contain
 * multiple <column> elements, each specifying one model column. The “type”
 * attribute specifies the data type for the column.
Matthias Clasen's avatar
Matthias Clasen committed
51 52
 *
 * An example of a UI Definition fragment for a tree store:
53
 * |[
54 55 56 57 58 59 60
 * <object class="GtkTreeStore">
 *   <columns>
 *     <column type="gchararray"/>
 *     <column type="gchararray"/>
 *     <column type="gint"/>
 *   </columns>
 * </object>
61
 * ]|
62 63
 */

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

80

81
#define G_NODE(node) ((GNode *)node)
82 83
#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)
84

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


124 125 126 127 128 129
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);

130 131
static void gtk_tree_store_increment_stamp (GtkTreeStore  *tree_store);

132

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

/* Sortable Interfaces */

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

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

/* 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);

187 188
static void     validate_gnode                         (GNode *node);

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

194

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

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

Matthias Clasen's avatar
Matthias Clasen committed
206
G_DEFINE_TYPE_WITH_CODE (GtkTreeStore, gtk_tree_store, G_TYPE_OBJECT,
207
                         G_ADD_PRIVATE (GtkTreeStore)
Matthias Clasen's avatar
Matthias Clasen committed
208 209 210 211 212 213 214
			 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
215 216 217
						gtk_tree_store_sortable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_tree_store_buildable_init))
218 219

static void
220
gtk_tree_store_class_init (GtkTreeStoreClass *class)
221
{
222 223
  GObjectClass *object_class;

224
  object_class = (GObjectClass *) class;
225

226
  object_class->finalize = gtk_tree_store_finalize;
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
  iface->iter_next = gtk_tree_store_iter_next;
239
  iface->iter_previous = gtk_tree_store_iter_previous;
240 241 242 243 244
  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;
245 246
}

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

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

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

Johan Dahlin's avatar
Johan Dahlin committed
272 273 274 275 276 277 278
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;
}

279 280 281
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
282 283
  GtkTreeStorePrivate *priv;

284
  priv = gtk_tree_store_get_instance_private (tree_store);
285 286 287
  tree_store->priv = priv;
  priv->root = g_node_new (NULL);
  /* While the odds are against us getting 0...  */
288 289
  do
    {
290
      priv->stamp = g_random_int ();
291
    }
292
  while (priv->stamp == 0);
293

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

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

  g_return_val_if_fail (n_columns > 0, NULL);

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

  va_start (args, n_columns);
328

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

  return retval;
}
345
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
346
 * gtk_tree_store_newv: (rename-to gtk_tree_store_new)
347
 * @n_columns: number of columns in the tree store
348
 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
349 350 351
 *
 * Non vararg creation function.  Used primarily by language bindings.
 *
352
 * Returns: (transfer full): a new #GtkTreeStore
353 354 355 356 357 358 359 360 361 362
 **/
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
363
  retval = g_object_new (GTK_TYPE_TREE_STORE, NULL);
364 365 366 367 368 369
  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]))
	{
370
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
Manish Singh's avatar
Manish Singh committed
371
	  g_object_unref (retval);
372 373 374 375 376 377 378
	  return NULL;
	}
      gtk_tree_store_set_column_type (retval, i, types[i]);
    }

  return retval;
}
379

380 381 382 383 384

/**
 * gtk_tree_store_set_column_types:
 * @tree_store: A #GtkTreeStore
 * @n_columns: Number of columns for the tree store
385
 * @types: (array length=n_columns): An array of #GType types, one for each column
386
 * 
Matthias Clasen's avatar
Matthias Clasen committed
387 388 389 390
 * 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.
391 392 393 394 395 396 397 398 399
 **/
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));
400
  g_return_if_fail (tree_store->priv->columns_dirty == 0);
401 402 403 404 405 406

  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]))
	{
407
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
408 409 410 411 412 413
	  continue;
	}
      gtk_tree_store_set_column_type (tree_store, i, types[i]);
    }
}

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

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

424 425 426 427
  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;
428

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

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

435 436 437 438 439
/**
 * gtk_tree_store_set_column_type:
 * @tree_store: a #GtkTreeStore
 * @column: column number
 * @type: type of the data to be stored in @column
440
 *
441 442 443 444
 * 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.
445
 *
446
 **/
447
static void
448 449 450 451
gtk_tree_store_set_column_type (GtkTreeStore *tree_store,
				gint          column,
				GType         type)
{
452 453
  GtkTreeStorePrivate *priv = tree_store->priv;

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

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

469
  return FALSE;
470 471 472 473 474 475
}

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

478 479 480 481 482
  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);
483

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

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

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

497 498
/* fulfill the GtkTreeModel requirements */
/* NOTE: GtkTreeStore::root is a GNode, that acts as the parent node.  However,
William Jon McCann's avatar
William Jon McCann committed
499
 * it is not visible to the tree or to the user., and the path “0” refers to the
500 501
 * first child of GtkTreeStore::root.
 */
502 503


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

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

516
  priv->columns_dirty = TRUE;
517

518
  return priv->n_columns;
519 520
}

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

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

530
  priv->columns_dirty = TRUE;
531

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

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

546
  priv->columns_dirty = TRUE;
547

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

  g_return_val_if_fail (depth > 0, FALSE);

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

556
  if (!gtk_tree_store_iter_nth_child (tree_model, iter, &parent, indices[0]))
557 558 559 560
    {
      iter->stamp = 0;
      return FALSE;
    }
561 562 563 564

  for (i = 1; i < depth; i++)
    {
      parent = *iter;
565
      if (!gtk_tree_store_iter_nth_child (tree_model, iter, &parent, indices[i]))
566 567 568 569
        {
          iter->stamp = 0;
          return FALSE;
        }
570 571 572 573 574
    }

  return TRUE;
}

575 576
static GtkTreePath *
gtk_tree_store_get_path (GtkTreeModel *tree_model,
577
			 GtkTreeIter  *iter)
578
{
579
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
580
  GtkTreeStorePrivate *priv = tree_store->priv;
581 582 583
  GtkTreePath *retval;
  GNode *tmp_node;
  gint i = 0;
584

585
  g_return_val_if_fail (iter->user_data != NULL, NULL);
586
  g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
587

588
  validate_tree (tree_store);
589

590
  if (G_NODE (iter->user_data)->parent == NULL &&
591
      G_NODE (iter->user_data) == priv->root)
592
    return gtk_tree_path_new ();
593
  g_assert (G_NODE (iter->user_data)->parent != NULL);
594

595
  if (G_NODE (iter->user_data)->parent == G_NODE (priv->root))
596 597
    {
      retval = gtk_tree_path_new ();
598
      tmp_node = G_NODE (priv->root)->children;
599 600 601
    }
  else
    {
602
      GtkTreeIter tmp_iter = *iter;
603

604
      tmp_iter.user_data = G_NODE (iter->user_data)->parent;
605

606
      retval = gtk_tree_store_get_path (tree_model, &tmp_iter);
Havoc Pennington's avatar
Havoc Pennington committed
607
      tmp_node = G_NODE (iter->user_data)->parent->children;
608 609 610 611
    }

  if (retval == NULL)
    return NULL;
612

613 614 615 616 617 618 619 620
  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
621
      if (tmp_node == G_NODE (iter->user_data))
622 623 624
	break;
      i++;
    }
625

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

  gtk_tree_path_append_index (retval, i);

  return retval;
}


static void
641 642 643 644
gtk_tree_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
645
{
646
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
647
  GtkTreeStorePrivate *priv = tree_store->priv;
648 649 650
  GtkTreeDataList *list;
  gint tmp_column = column;

651
  g_return_if_fail (column < priv->n_columns);
652
  g_return_if_fail (VALID_ITER (iter, tree_store));
653

Havoc Pennington's avatar
Havoc Pennington committed
654
  list = G_NODE (iter->user_data)->data;
655 656 657 658

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

659 660
  if (list)
    {
661
      _gtk_tree_data_list_node_to_value (list,
662
					 priv->column_headers[column],
663
					 value);
664 665 666 667
    }
  else
    {
      /* We want to return an initialized but empty (default) value */
668
      g_value_init (value, priv->column_headers[column]);
669
    }
670 671 672
}

static gboolean
673 674
gtk_tree_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
675
{
676
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
677
  g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->priv->stamp, FALSE);
678

679
  if (G_NODE (iter->user_data)->next == NULL)
680
    {
681 682
      iter->stamp = 0;
      return FALSE;
683
    }
684 685 686 687 688 689 690 691 692 693 694 695 696 697

  iter->user_data = G_NODE (iter->user_data)->next;

  return TRUE;
}

static gboolean
gtk_tree_store_iter_previous (GtkTreeModel *tree_model,
                              GtkTreeIter  *iter)
{
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
  g_return_val_if_fail (iter->stamp == GTK_TREE_STORE (tree_model)->priv->stamp, FALSE);

  if (G_NODE (iter->user_data)->prev == NULL)
698 699 700 701
    {
      iter->stamp = 0;
      return FALSE;
    }
702 703 704 705

  iter->user_data = G_NODE (iter->user_data)->prev;

  return TRUE;
706 707
}

708 709 710 711
static gboolean
gtk_tree_store_iter_children (GtkTreeModel *tree_model,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
712
{
713
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
714
  GtkTreeStorePrivate *priv = tree_store->priv;
715 716
  GNode *children;

717 718
  if (parent)
    g_return_val_if_fail (VALID_ITER (parent, tree_store), FALSE);
719

720
  if (parent)
721
    children = G_NODE (parent->user_data)->children;
722
  else
723
    children = G_NODE (priv->root)->children;
724

725 726
  if (children)
    {
727
      iter->stamp = priv->stamp;
728 729 730 731
      iter->user_data = children;
      return TRUE;
    }
  else
732 733 734 735
    {
      iter->stamp = 0;
      return FALSE;
    }
736 737 738
}

static gboolean
739 740
gtk_tree_store_iter_has_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter)
741
{
742
  g_return_val_if_fail (iter->user_data != NULL, FALSE);
743
  g_return_val_if_fail (VALID_ITER (iter, tree_model), FALSE);
744

Havoc Pennington's avatar
Havoc Pennington committed
745
  return G_NODE (iter->user_data)->children != NULL;
746 747 748
}

static gint
749 750
gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
				GtkTreeIter  *iter)
751
{
752
  GNode *node;
753 754
  gint i = 0;

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

757
  if (iter == NULL)
758
    node = G_NODE (GTK_TREE_STORE (tree_model)->priv->root)->children;
759
  else
Havoc Pennington's avatar
Havoc Pennington committed
760
    node = G_NODE (iter->user_data)->children;
761

762
  while (node)
763 764
    {
      i++;
765
      node = node->next;
766 767 768 769 770
    }

  return i;
}

771 772 773 774
static gboolean
gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model,
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
775 776
			       gint          n)
{
777
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
778
  GtkTreeStorePrivate *priv = tree_store->priv;
779
  GNode *parent_node;
780
  GNode *child;
781

782
  g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
783

784
  if (parent == NULL)
785
    parent_node = priv->root;
786
  else
Havoc Pennington's avatar
Havoc Pennington committed
787
    parent_node = parent->user_data;
788

789
  child = g_node_nth_child (parent_node, n);
790

791 792 793
  if (child)
    {
      iter->user_data = child;
794
      iter->stamp = priv->stamp;
795 796
      return TRUE;
    }
797
  else
798 799 800 801
    {
      iter->stamp = 0;
      return FALSE;
    }
802 803
}

804 805 806 807
static gboolean
gtk_tree_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
808
{
809
  GtkTreeStore *tree_store = (GtkTreeStore *) tree_model;
810
  GtkTreeStorePrivate *priv = tree_store->priv;
811
  GNode *parent;
812

813
  g_return_val_if_fail (iter != NULL, FALSE);
814
  g_return_val_if_fail (VALID_ITER (child, tree_store), FALSE);
815 816 817

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

818
  g_assert (parent != NULL);
819

820
  if (parent != priv->root)
821
    {
822
      iter->user_data = parent;
823
      iter->stamp = priv->stamp;
824
      return TRUE;
825
    }
826
  else
827 828 829 830
    {
      iter->stamp = 0;
      return FALSE;
    }
831 832
}

833 834

/* Does not emit a signal */
835
static gboolean
836 837 838
gtk_tree_store_real_set_value (GtkTreeStore *tree_store,
			       GtkTreeIter  *iter,
			       gint          column,
839 840
			       GValue       *value,
			       gboolean      sort)
841
{
842
  GtkTreeStorePrivate *priv = tree_store->priv;
843 844
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
845
  gint old_column = column;
Javier Jardón's avatar
Javier Jardón committed
846
  GValue real_value = G_VALUE_INIT;
847
  gboolean converted = FALSE;
848
  gboolean retval = FALSE;
849

850
  if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
851
    {
852
      if (! (g_value_type_transformable (G_VALUE_TYPE (value), priv->column_headers[column])))
853 854 855 856
	{
	  g_warning ("%s: Unable to convert from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
857
		     g_type_name (priv->column_headers[column]));
858
	  return retval;
859
	}
860 861

      g_value_init (&real_value, priv->column_headers[column]);
862 863 864 865 866
      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)),
867
		     g_type_name (priv->column_headers[column]));
868
	  g_value_unset (&real_value);
869
	  return retval;
870 871 872
	}
      converted = TRUE;
    }
873

Havoc Pennington's avatar
Havoc Pennington committed
874
  prev = list = G_NODE (iter->user_data)->data;
875 876 877 878 879

  while (list != NULL)
    {
      if (column == 0)
	{
880 881 882 883
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
884
	  retval = TRUE;
885 886
	  if (converted)
	    g_value_unset (&real_value);
887
          if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
888
            gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
889
	  return retval;
890 891 892 893 894 895 896
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
897
  if (G_NODE (iter->user_data)->data == NULL)
898
    {
Havoc Pennington's avatar
Havoc Pennington committed
899
      G_NODE (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
900 901 902 903
      list->next = NULL;
    }
  else
    {
904
      list = prev->next = _gtk_tree_data_list_alloc ();
905 906 907 908 909
      list->next = NULL;
    }

  while (column != 0)
    {
910
      list->next = _gtk_tree_data_list_alloc ();
911 912 913 914
      list = list->next;
      list->next = NULL;
      column --;
    }
915

916
  if (converted)
917
    _gtk_tree_data_list_value_to_node (list, &real_value);
918 919
  else
    _gtk_tree_data_list_value_to_node (list, value);
920 921
  
  retval = TRUE;
922 923
  if (converted)
    g_value_unset (&real_value);
924

925
  if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
926
    gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
927

928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
  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));
951
  g_return_if_fail (column >= 0 && column < tree_store->priv->n_columns);
952 953
  g_return_if_fail (G_IS_VALUE (value));

954
  if (gtk_tree_store_real_set_value (tree_store, iter, column, value, TRUE))
955 956 957
    {
      GtkTreePath *path;

958
      path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
959 960 961
      gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
      gtk_tree_path_free (path);
    }
962 963
}

964 965
static GtkTreeIterCompareFunc
gtk_tree_store_get_compare_func (GtkTreeStore *tree_store)
966
{
967
  GtkTreeStorePrivate *priv = tree_store->priv;
968
  GtkTreeIterCompareFunc func = NULL;
969

970
  if (GTK_TREE_STORE_IS_SORTED (tree_store))
971
    {
972
      if (priv->sort_column_id != -1)
973 974
	{
	  GtkTreeDataSortHeader *header;
975 976
	  header = _gtk_tree_data_list_get_header (priv->sort_list,
						   priv->sort_column_id);
977 978
	  g_return_val_if_fail (header != NULL, NULL);
	  g_return_val_if_fail (header->func != NULL, NULL);
979 980 981 982
	  func = header->func;
	}
      else
	{
983
	  func = priv->default_sort_func;
984
	}
985 986
    }

987 988 989
  return func;
}

Kristian Rietveld's avatar