gtktreestore.c 92.8 KB
Newer Older
1
/* gtktreestore.c
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"
25
#include "gtkbuildable.h"
26
#include "gtkbuilderprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
27
#include "gtkdebug.h"
28
#include "gtkintl.h"
29

30

31 32 33 34 35 36 37
/**
 * 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
Matthias Clasen's avatar
Matthias Clasen committed
38
 * widget.  It implements the #GtkTreeModel interface, and consequentially,
39 40
 * can use all of the methods available there.  It also implements the
 * #GtkTreeSortable interface so it can be sorted by the view.  Finally,
41
 * it also implements the tree
42
 * [drag and drop][gtk3-GtkTreeView-drag-and-drop]
43
 * interfaces.
44
 *
45
 * # GtkTreeStore as GtkBuildable
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.
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);
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

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
#ifdef G_ENABLE_DEBUG
196 197 198
static inline void
validate_tree (GtkTreeStore *tree_store)
{
199
  if (GTK_DEBUG_CHECK (TREE))
200
    {
201 202
      g_assert (G_NODE (tree_store->priv->root)->parent == NULL);
      validate_gnode (G_NODE (tree_store->priv->root));
203 204
    }
}
205 206 207
#else
#define validate_tree(store)
#endif
208

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

static void
223
gtk_tree_store_class_init (GtkTreeStoreClass *class)
224
{
225 226
  GObjectClass *object_class;

227
  object_class = (GObjectClass *) class;
228

229
  object_class->finalize = gtk_tree_store_finalize;
230 231 232 233 234
}

static void
gtk_tree_store_tree_model_init (GtkTreeModelIface *iface)
{
235
  iface->get_flags = gtk_tree_store_get_flags;
236
  iface->get_n_columns = gtk_tree_store_get_n_columns;
237
  iface->get_column_type = gtk_tree_store_get_column_type;
238
  iface->get_iter = gtk_tree_store_get_iter;
239
  iface->get_path = gtk_tree_store_get_path;
240
  iface->get_value = gtk_tree_store_get_value;
241
  iface->iter_next = gtk_tree_store_iter_next;
242
  iface->iter_previous = gtk_tree_store_iter_previous;
243 244 245 246 247
  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;
248 249
}

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

static void
259
gtk_tree_store_drag_dest_init (GtkTreeDragDestIface *iface)
260 261 262 263 264
{
  iface->drag_data_received = gtk_tree_store_drag_data_received;
  iface->row_drop_possible = gtk_tree_store_row_drop_possible;
}

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

275 276 277 278 279 280 281
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;
}

282 283 284
static void
gtk_tree_store_init (GtkTreeStore *tree_store)
{
285 286
  GtkTreeStorePrivate *priv;

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

297 298 299
  priv->sort_list = NULL;
  priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
  priv->columns_dirty = FALSE;
300 301
}

302 303 304
/**
 * gtk_tree_store_new:
 * @n_columns: number of columns in the tree store
Matthias Clasen's avatar
Matthias Clasen committed
305
 * @...: all #GType types for the columns, from first to last
306 307
 *
 * Creates a new tree store as with @n_columns columns each of the types passed
Matthias Clasen's avatar
Matthias Clasen committed
308 309
 * in.  Note that only types derived from standard GObject fundamental types
 * are supported.
310
 *
311 312
 * 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
313
 * #gint, #gchararray, and #GdkPixbuf respectively.
314
 *
315
 * Returns: a new #GtkTreeStore
316
 **/
317
GtkTreeStore *
318
gtk_tree_store_new (gint n_columns,
319
			       ...)
320
{
321
  GtkTreeStore *retval;
322 323 324 325 326
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

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

  va_start (args, n_columns);
331

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

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

  return retval;
}
382

383 384 385 386 387

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

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

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

424
  if (priv->n_columns == n_columns)
425 426
    return;

427 428 429 430
  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;
431

432 433
  if (priv->sort_list)
    _gtk_tree_data_list_header_free (priv->sort_list);
434

435
  priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
436 437
}

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

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

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

472
  return FALSE;
473 474 475 476 477 478
}

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

481 482 483 484 485
  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);
486

487
  if (priv->default_sort_destroy)
488
    {
489
      GDestroyNotify d = priv->default_sort_destroy;
490

491 492 493
      priv->default_sort_destroy = NULL;
      d (priv->default_sort_data);
      priv->default_sort_data = NULL;
494
    }
495

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

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


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

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

519
  priv->columns_dirty = TRUE;
520

521
  return priv->n_columns;
522 523
}

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

531
  g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
532

533
  priv->columns_dirty = TRUE;
534

535
  return priv->column_headers[index];
536 537
}

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

549
  priv->columns_dirty = TRUE;
550

551
  indices = gtk_tree_path_get_indices (path);
552 553 554 555
  depth = gtk_tree_path_get_depth (path);

  g_return_val_if_fail (depth > 0, FALSE);

556 557
  parent.stamp = priv->stamp;
  parent.user_data = priv->root;
558

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

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

  return TRUE;
}

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

588
  g_return_val_if_fail (iter->user_data != NULL, NULL);
589
  g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
590

591
  validate_tree (tree_store);
592

593
  if (G_NODE (iter->user_data)->parent == NULL &&
594
      G_NODE (iter->user_data) == priv->root)
595
    return gtk_tree_path_new ();
596
  g_assert (G_NODE (iter->user_data)->parent != NULL);
597

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

607
      tmp_iter.user_data = G_NODE (iter->user_data)->parent;
608

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

  if (retval == NULL)
    return NULL;
615

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

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

  gtk_tree_path_append_index (retval, i);

  return retval;
}


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

654
  g_return_if_fail (column < priv->n_columns);
655
  g_return_if_fail (VALID_ITER (iter, tree_store));
656

Havoc Pennington's avatar
Havoc Pennington committed
657
  list = G_NODE (iter->user_data)->data;
658 659 660 661

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

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

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

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

  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)
701 702 703 704
    {
      iter->stamp = 0;
      return FALSE;
    }
705 706 707 708

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

  return TRUE;
709 710
}

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

720 721
  if (parent)
    g_return_val_if_fail (VALID_ITER (parent, tree_store), FALSE);
722

723
  if (parent)
724
    children = G_NODE (parent->user_data)->children;
725
  else
726
    children = G_NODE (priv->root)->children;
727

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

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

Havoc Pennington's avatar
Havoc Pennington committed
748
  return G_NODE (iter->user_data)->children != NULL;
749 750 751
}

static gint
752 753
gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
				GtkTreeIter  *iter)
754
{
755
  GNode *node;
756 757
  gint i = 0;

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

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

765
  while (node)
766 767
    {
      i++;
768
      node = node->next;
769 770 771 772 773
    }

  return i;
}

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

785
  g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
786

787
  if (parent == NULL)
788
    parent_node = priv->root;
789
  else
Havoc Pennington's avatar
Havoc Pennington committed
790
    parent_node = parent->user_data;
791

792
  child = g_node_nth_child (parent_node, n);
793

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

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

816
  g_return_val_if_fail (iter != NULL, FALSE);
817
  g_return_val_if_fail (VALID_ITER (child, tree_store), FALSE);
818 819 820

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

821
  g_assert (parent != NULL);
822

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

836 837

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

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

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

Havoc Pennington's avatar
Havoc Pennington committed
877
  prev = list = G_NODE (iter->user_data)->data;
878 879 880 881 882

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

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

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

  while (column != 0)
    {
913
      list->next = _gtk_tree_data_list_alloc ();
914 915 916 917
      list = list->next;
      list->next = NULL;
      column --;
    }
918

919
  if (converted)
920
    _gtk_tree_data_list_value_to_node (list, &real_value);
921 922
  else
    _gtk_tree_data_list_value_to_node (list, value);
923 924
  
  retval = TRUE;
925 926
  if (converted)
    g_value_unset (&real_value);
927

928
  if (sort && GTK_TREE_STORE_IS_SORTED (tree_store))
929
    gtk_tree_store_sort_iter_changed (tree_store, iter, old_column, TRUE);
930

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

957
  if (gtk_tree_store_real_set_value (tree_store, iter, column, value, TRUE))
958 959 960
    {
      GtkTreePath *path;

961
      path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
962 963 964
      gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
      gtk_tree_path_free (path);
    }
965 966
}

967 968
static GtkTreeIterCompareFunc
gtk_tree_store_get_compare_func (GtkTreeStore *tree_store)
969
{
970
  GtkTreeStorePrivate *priv = tree_store->priv;
971
  GtkTreeIterCompareFunc func = NULL;
972

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

990 991 992
  return func;
}

993 994 995 996 997 998 999 1000 1001
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)
{
1002
  GtkTreeStorePrivate *priv = tree_store->priv;
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
  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 &&
1017
	  columns[i] == priv->sort_column_id)
1018 1019 1020 1021
	*maybe_need_sort = TRUE;
    }
}

1022 1023 1024 1025 1026 1027 1028
static void
gtk_tree_store_set_valist_internal (GtkTreeStore *tree_store,
                                    GtkTreeIter  *iter,
                                    gboolean     *emit_signal,
                                    gboolean     *maybe_need_sort,
                                    va_list       var_args)
{
1029
  GtkTreeStorePrivate *priv = tree_store->priv;
1030 1031 1032 1033 1034 1035
  gint column;
  GtkTreeIterCompareFunc func = NULL;

  column = va_arg (var_args, gint);

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

Havoc Pennington's avatar
Havoc Pennington committed
1039
  while (column != -1)
1040
    {
Javier Jardón's avatar
Javier Jardón committed
1041
      GValue value = G_VALUE_INIT;
1042 1043
      gchar *error = NULL;

1044
      if (column < 0 || column >= priv->n_columns)
1045
	{
Havoc Pennington's avatar
Havoc Pennington committed
1046
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
1047 1048 1049
	  break;
	}

1050 1051
      G_VALUE_COLLECT_INIT (&value, priv->column_headers[column],
                            var_args, 0, &error);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
      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;
	}

1063 1064 1065 1066 1067
      *emit_signal = gtk_tree_store_real_set_value (tree_store,
						    iter,
						    column,
						    &value,
						    FALSE) || *emit_signal;
1068

1069
      if (func == _gtk_tree_data_list_compare_func &&
1070
	  column == priv->sort_column_id)
1071
	*maybe_need_sort = TRUE;
1072 1073 1074 1075 1076

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
1077 1078
}

1079
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1080
 * gtk_tree_store_set_valuesv: (rename-to gtk_tree_store_set)
1081 1082
 * @tree_store: A #GtkTreeStore
 * @iter: A valid #GtkTreeIter for the row being modified
1083 1084
 * @columns: (array length=n_values): an array of column numbers
 * @values: (array length=n_values): an array of GValues
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
 * @n_values: the length of the @columns and @values arrays
 *
 * A variant of gtk_tree_store_set_valist() which takes
 * the columns and values as two arrays, instead of varargs.  This
 * function is mainly intended for language bindings or in case
 * the number of columns to change is not known until run-time.
 *
 * Since: 2.12
 **/
void
gtk_tree_store_set_valuesv (GtkTreeStore *tree_store,
			    GtkTreeIter  *iter,
			    gint         *columns,
			    GValue       *values,
			    gint          n_values)
{
1101
  GtkTreeStorePrivate *priv = tree_store->priv;
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
  g_return_if_fail (VALID_ITER (iter, tree_store));

  gtk_tree_store_set_vector_internal (tree_store, iter,
				      &emit_signal,
				      &maybe_need_sort,
				      columns, values, n_values);

  if (maybe_need_sort && GTK_TREE_STORE_IS_SORTED (tree_store))
1114
    gtk_tree_store_sort_iter_changed (tree_store, iter, priv->sort_column_id, TRUE);
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125

  if (emit_signal)
    {
      GtkTreePath *path;

      path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
      gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
      gtk_tree_path_free (path);
    }
}

1126 1127 1128 1129
/**
 * gtk_tree_store_set_valist:
 * @tree_store: A #GtkTreeStore
 * @iter: A valid #GtkTreeIter for the row being modified
1130
 * @var_args: va_list of column/value pairs
1131
 *
1132
 * See gtk_tree_store_set(); this version takes a va_list for
1133 1134 1135 1136 1137 1138 1139 1140
 * use by language bindings.
 *
 **/
void
gtk_tree_store_set_valist (GtkTreeStore *tree_store,
                           GtkTreeIter  *iter,
                           va_list       var_args)
{
1141
  GtkTreeStorePrivate *priv = tree_store->priv;
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_TREE_STORE (tree_store));
  g_return_if_fail (VALID_ITER (iter, tree_store));

  gtk_tree_store_set_valist_internal (tree_store, iter,
				      &emit_signal,
				      &maybe_need_sort,
				      var_args);
1152 1153

  if (maybe_need_sort && GTK_TREE_STORE_IS_SORTED (tree_store))
1154
    gtk_tree_store_sort_iter_changed (tree_store, iter, priv->sort_column_id, TRUE);
1155

1156 1157 1158 1159
  if (emit_signal)
    {
      GtkTreePath *path;

1160
      path = gtk_tree_store_get_path (GTK_TREE_MODEL (tree_store), iter);
1161 1162 1163
      gtk_tree_model_row_changed (GTK_TREE_MODEL (tree_store), path, iter);
      gtk_tree_path_free (path);
    }
1164 1165
}

Havoc Pennington's avatar
Havoc Pennington committed
1166 1167
/**
 * gtk_tree_store_set:
1168 1169
 * @tree_store: A #GtkTreeStore
 * @iter: A valid #GtkTreeIter for the row being modified
Matthias Clasen's avatar
Matthias Clasen committed
1170
 * @...: pairs of column number and value, terminated with -1
1171
 *
Havoc Pennington's avatar
Havoc Pennington committed
1172 1173
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
Matthias Clasen's avatar
Matthias Clasen committed
1174
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
1175
 * The list is terminated by a -1. For example, to set column 0 with type
1176
 * %G_TYPE_STRING to “Foo”, you would write
1177
 * `gtk_tree_store_set (store, iter, 0, "Foo", -1)`.
1178 1179 1180
 *
 * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
 * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
Havoc Pennington's avatar
Havoc Pennington committed
1181
 **/
1182
void
1183 1184 1185
gtk_tree_store_set (GtkTreeStore *tree_store,
		    GtkTreeIter  *iter,
		    ...)
1186 1187 1188 1189
{
  va_list var_args;

  va_start (var_args, iter);
Havoc Pennington's avatar
Havoc Pennington committed
1190
  gtk_tree_store_set_valist (tree_store, iter, var_args);
1191 1192 1193
  va_end (var_args);
}

1194 1195 1196 1197 1198 1199
/**
 * gtk_tree_store_remove:
 * @tree_store: A #GtkTreeStore
 * @iter: A valid #GtkTreeIter
 * 
 * Removes @iter from @tree_store.  After being removed, @iter is set to the
1200
 * next valid row at that level, or invalidated if it previously pointed to the
1201
 * last one.
Kristian Rietveld's avatar
Kristian Rietveld committed
1202
 *
1203
 * Returns: %TRUE if @iter is still valid, %FALSE if not.