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

20
#include "config.h"
21 22
#include <errno.h>
#include <stdlib.h>
23
#include <string.h>
Manish Singh's avatar
Manish Singh committed
24
#include <gobject/gvaluecollector.h>
25 26 27
#include "gtktreemodel.h"
#include "gtkliststore.h"
#include "gtktreedatalist.h"
28
#include "gtktreednd.h"
29
#include "gtkintl.h"
30
#include "gtkbuildable.h"
31
#include "gtkbuilderprivate.h"
32

33

34
struct _GtkListStorePrivate
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
{
  GtkSortType order;
  GtkTreeIterCompareFunc default_sort_func;

  GDestroyNotify default_sort_destroy;
  GList *sort_list;
  GType *column_headers;

  gint stamp;
  gint n_columns;
  gint sort_column_id;
  gint length;

  guint columns_dirty : 1;

  gpointer default_sort_data;
  gpointer seq;         /* head of the list */
};

#define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
#define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->priv->stamp == (iter)->stamp && !g_sequence_iter_is_end ((iter)->user_data) && g_sequence_iter_get_sequence ((iter)->user_data) == list_store->priv->seq)
56 57

static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
58 59
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
60
static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
61
static void         gtk_list_store_buildable_init  (GtkBuildableIface      *iface);
62
static void         gtk_list_store_finalize        (GObject           *object);
63
static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
64
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
65 66
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreePath       *path);
static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    gint               column,
						    GValue            *value);
static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent);
static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent,
						    gint               n);
static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *child);
92

93

94 95 96 97 98 99
static void gtk_list_store_set_n_columns   (GtkListStore *list_store,
					    gint          n_columns);
static void gtk_list_store_set_column_type (GtkListStore *list_store,
					    gint          column,
					    GType         type);

100 101
static void gtk_list_store_increment_stamp (GtkListStore *list_store);

102

103
/* Drag and Drop */
Murray Cumming's avatar
Murray Cumming committed
104 105
static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
106 107 108 109 110 111 112 113
static gboolean gtk_list_store_drag_data_delete   (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
static gboolean gtk_list_store_drag_data_get      (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path,
                                                   GtkSelectionData  *selection_data);
static gboolean gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
                                                   GtkTreePath       *dest,
                                                   GtkSelectionData  *selection_data);
114
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
115 116
                                                   GtkTreePath       *dest_path,
						   GtkSelectionData  *selection_data);
117

118

119
/* sortable */
120 121 122 123 124 125 126 127 128 129 130 131 132 133
static void     gtk_list_store_sort                  (GtkListStore           *list_store);
static void     gtk_list_store_sort_iter_changed     (GtkListStore           *list_store,
						      GtkTreeIter            *iter,
						      gint                    column);
static gboolean gtk_list_store_get_sort_column_id    (GtkTreeSortable        *sortable,
						      gint                   *sort_column_id,
						      GtkSortType            *order);
static void     gtk_list_store_set_sort_column_id    (GtkTreeSortable        *sortable,
						      gint                    sort_column_id,
						      GtkSortType             order);
static void     gtk_list_store_set_sort_func         (GtkTreeSortable        *sortable,
						      gint                    sort_column_id,
						      GtkTreeIterCompareFunc  func,
						      gpointer                data,
134
						      GDestroyNotify          destroy);
135 136 137
static void     gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
						      GtkTreeIterCompareFunc  func,
						      gpointer                data,
138
						      GDestroyNotify          destroy);
139 140
static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable        *sortable);

141

142 143 144 145 146 147 148 149 150 151 152 153 154
/* buildable */
static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable  *buildable,
							   GtkBuilder    *builder,
							   GObject       *child,
							   const gchar   *tagname,
							   GMarkupParser *parser,
							   gpointer      *data);
static void     gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
							 GtkBuilder   *builder,
							 GObject      *child,
							 const gchar  *tagname,
							 gpointer     *data);

Matthias Clasen's avatar
Matthias Clasen committed
155 156 157 158 159 160 161 162
G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
						gtk_list_store_tree_model_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
						gtk_list_store_drag_source_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
						gtk_list_store_drag_dest_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
163 164 165 166
						gtk_list_store_sortable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_list_store_buildable_init))

167 168 169 170

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
171 172 173
  GObjectClass *object_class;

  object_class = (GObjectClass*) class;
174 175

  object_class->finalize = gtk_list_store_finalize;
176

177
  g_type_class_add_private (class, sizeof (GtkListStorePrivate));
178 179 180 181 182
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
183
  iface->get_flags = gtk_list_store_get_flags;
184
  iface->get_n_columns = gtk_list_store_get_n_columns;
185
  iface->get_column_type = gtk_list_store_get_column_type;
186
  iface->get_iter = gtk_list_store_get_iter;
187
  iface->get_path = gtk_list_store_get_path;
188
  iface->get_value = gtk_list_store_get_value;
189 190 191 192 193 194
  iface->iter_next = gtk_list_store_iter_next;
  iface->iter_children = gtk_list_store_iter_children;
  iface->iter_has_child = gtk_list_store_iter_has_child;
  iface->iter_n_children = gtk_list_store_iter_n_children;
  iface->iter_nth_child = gtk_list_store_iter_nth_child;
  iface->iter_parent = gtk_list_store_iter_parent;
195 196
}

197 198 199
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
Murray Cumming's avatar
Murray Cumming committed
200
  iface->row_draggable = real_gtk_list_store_row_draggable;
201 202 203 204 205
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
206
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
207 208
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
209
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
210 211
}

212 213 214 215 216
static void
gtk_list_store_sortable_init (GtkTreeSortableIface *iface)
{
  iface->get_sort_column_id = gtk_list_store_get_sort_column_id;
  iface->set_sort_column_id = gtk_list_store_set_sort_column_id;
217
  iface->set_sort_func = gtk_list_store_set_sort_func;
218 219
  iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
  iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
220 221
}

222 223 224 225 226 227 228
void
gtk_list_store_buildable_init (GtkBuildableIface *iface)
{
  iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
}

229 230 231
static void
gtk_list_store_init (GtkListStore *list_store)
{
232
  GtkListStorePrivate *priv;
233 234 235

  list_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (list_store,
                                                  GTK_TYPE_LIST_STORE,
236
                                                  GtkListStorePrivate);
237 238 239 240 241 242 243 244
  priv = list_store->priv;

  priv->seq = g_sequence_new (NULL);
  priv->sort_list = NULL;
  priv->stamp = g_random_int ();
  priv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
  priv->columns_dirty = FALSE;
  priv->length = 0;
245 246
}

247 248 249
/**
 * gtk_list_store_new:
 * @n_columns: number of columns in the list store
250
 * @Varargs: all #GType types for the columns, from first to last
251
 *
252
 * Creates a new list store as with @n_columns columns each of the types passed
253 254 255 256
 * 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,
Matthias Clasen's avatar
Matthias Clasen committed
257 258
 * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
 * int, string and #GdkPixbuf respectively.
259
 *
260 261
 * Return value: a new #GtkListStore
 **/
262
GtkListStore *
263
gtk_list_store_new (gint n_columns,
Soeren Sandmann's avatar
Soeren Sandmann committed
264
		    ...)
265
{
266
  GtkListStore *retval;
267 268 269 270 271
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
272
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
273
  gtk_list_store_set_n_columns (retval, n_columns);
274 275

  va_start (args, n_columns);
276

277
  for (i = 0; i < n_columns; i++)
278 279 280 281
    {
      GType type = va_arg (args, GType);
      if (! _gtk_tree_data_list_check_type (type))
	{
282
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
Manish Singh's avatar
Manish Singh committed
283
	  g_object_unref (retval);
284 285 286 287 288
	  return NULL;
	}

      gtk_list_store_set_column_type (retval, i, type);
    }
289 290 291 292 293 294

  va_end (args);

  return retval;
}

295 296 297 298

/**
 * gtk_list_store_newv:
 * @n_columns: number of columns in the list store
299
 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
300
 *
Matthias Clasen's avatar
Matthias Clasen committed
301
 * Non-vararg creation function.  Used primarily by language bindings.
302
 *
303
 * Return value: (transfer none): a new #GtkListStore
304 305 306 307 308 309 310 311 312 313
 **/
GtkListStore *
gtk_list_store_newv (gint   n_columns,
		     GType *types)
{
  GtkListStore *retval;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
314
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
315 316 317 318 319 320
  gtk_list_store_set_n_columns (retval, n_columns);

  for (i = 0; i < n_columns; i++)
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
321
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
Manish Singh's avatar
Manish Singh committed
322
	  g_object_unref (retval);
323 324 325 326 327 328 329 330 331
	  return NULL;
	}

      gtk_list_store_set_column_type (retval, i, types[i]);
    }

  return retval;
}

332 333 334 335
/**
 * gtk_list_store_set_column_types:
 * @list_store: A #GtkListStore
 * @n_columns: Number of columns for the list store
336 337
 * @types: (array length=n_columns): An array length n of #GTypes
 *
Matthias Clasen's avatar
Matthias Clasen committed
338 339 340
 * This function is meant primarily for #GObjects that inherit from #GtkListStore,
 * and should only be used when constructing a new #GtkListStore.  It will not
 * function after a row has been added, or a method on the #GtkTreeModel
341 342 343 344 345 346 347
 * interface is called.
 **/
void
gtk_list_store_set_column_types (GtkListStore *list_store,
				 gint          n_columns,
				 GType        *types)
{
348
  GtkListStorePrivate *priv;
349 350 351
  gint i;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
352 353 354 355

  priv = list_store->priv;

  g_return_if_fail (priv->columns_dirty == 0);
356 357

  gtk_list_store_set_n_columns (list_store, n_columns);
358
  for (i = 0; i < n_columns; i++)
359 360 361
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
362
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
363 364 365 366 367 368
	  continue;
	}
      gtk_list_store_set_column_type (list_store, i, types[i]);
    }
}

369
static void
370 371 372
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
373
  GtkListStorePrivate *priv = list_store->priv;
374
  int i;
375

376
  if (priv->n_columns == n_columns)
377 378
    return;

379 380 381 382
  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;
383

384 385 386
  if (priv->sort_list)
    _gtk_tree_data_list_header_free (priv->sort_list);
  priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
387 388
}

389
static void
390 391 392 393
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
394
  GtkListStorePrivate *priv = list_store->priv;
395

396 397
  if (!_gtk_tree_data_list_check_type (type))
    {
398
      g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
399 400
      return;
    }
401

402
  priv->column_headers[column] = type;
403 404
}

405 406 407 408
static void
gtk_list_store_finalize (GObject *object)
{
  GtkListStore *list_store = GTK_LIST_STORE (object);
409
  GtkListStorePrivate *priv = list_store->priv;
410

411 412
  g_sequence_foreach (priv->seq,
		      (GFunc) _gtk_tree_data_list_free, priv->column_headers);
Soeren Sandmann's avatar
Soeren Sandmann committed
413

414
  g_sequence_free (priv->seq);
415

416 417 418 419
  _gtk_tree_data_list_header_free (priv->sort_list);
  g_free (priv->column_headers);

  if (priv->default_sort_destroy)
420
    {
421
      GDestroyNotify d = priv->default_sort_destroy;
422

423 424 425
      priv->default_sort_destroy = NULL;
      d (priv->default_sort_data);
      priv->default_sort_data = NULL;
426
    }
427

428
  G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize (object);
429 430
}

431
/* Fulfill the GtkTreeModel requirements */
432
static GtkTreeModelFlags
433 434
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
435
  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
436 437
}

438 439 440
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
441
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
442
  GtkListStorePrivate *priv = list_store->priv;
443

444
  priv->columns_dirty = TRUE;
445

446
  return priv->n_columns;
447 448
}

449 450 451 452
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
453
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
454
  GtkListStorePrivate *priv = list_store->priv;
455

456
  g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
457

458
  priv->columns_dirty = TRUE;
459

460
  return priv->column_headers[index];
461 462
}

463
static gboolean
464
gtk_list_store_get_iter (GtkTreeModel *tree_model,
465
			 GtkTreeIter  *iter,
466 467
			 GtkTreePath  *path)
{
468
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
469
  GtkListStorePrivate *priv = list_store->priv;
470
  GSequence *seq;
471
  gint i;
472

473 474 475
  priv->columns_dirty = TRUE;

  seq = priv->seq;
476

477
  i = gtk_tree_path_get_indices (path)[0];
478

479
  if (i >= g_sequence_get_length (seq))
480
    return FALSE;
481

482
  iter->stamp = priv->stamp;
483
  iter->user_data = g_sequence_get_iter_at_pos (seq, i);
484

485
  return TRUE;
486 487 488 489
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
490
			 GtkTreeIter  *iter)
491
{
492
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
493
  GtkListStorePrivate *priv = list_store->priv;
Soeren Sandmann's avatar
Soeren Sandmann committed
494
  GtkTreePath *path;
495

496
  g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
497

498
  if (g_sequence_iter_is_end (iter->user_data))
499
    return NULL;
Soeren Sandmann's avatar
Soeren Sandmann committed
500 501
	
  path = gtk_tree_path_new ();
502
  gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
Soeren Sandmann's avatar
Soeren Sandmann committed
503 504
  
  return path;
505 506 507
}

static void
508 509 510 511
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
512
{
513
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
514
  GtkListStorePrivate *priv = list_store->priv;
515 516 517
  GtkTreeDataList *list;
  gint tmp_column = column;

518
  g_return_if_fail (column < priv->n_columns);
519
  g_return_if_fail (VALID_ITER (iter, list_store));
Soeren Sandmann's avatar
Soeren Sandmann committed
520
		    
521
  list = g_sequence_get (iter->user_data);
522 523 524 525

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

526
  if (list == NULL)
527
    g_value_init (value, priv->column_headers[column]);
528 529
  else
    _gtk_tree_data_list_node_to_value (list,
530
				       priv->column_headers[column],
531
				       value);
532 533 534
}

static gboolean
535 536
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
537
{
538
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
539
  GtkListStorePrivate *priv = list_store->priv;
540 541
  gboolean retval;

542
  g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
543
  iter->user_data = g_sequence_iter_next (iter->user_data);
544

545 546 547 548 549
  retval = g_sequence_iter_is_end (iter->user_data);
  if (retval)
    iter->stamp = 0;

  return !retval;
550 551
}

552
static gboolean
553
gtk_list_store_iter_children (GtkTreeModel *tree_model,
554 555
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
556
{
557
  GtkListStore *list_store = (GtkListStore *) tree_model;
558
  GtkListStorePrivate *priv = list_store->priv;
559

560
  /* this is a list, nodes have no children */
561
  if (parent)
562 563 564 565
    {
      iter->stamp = 0;
      return FALSE;
    }
566

567
  if (g_sequence_get_length (priv->seq) > 0)
568
    {
569 570
      iter->stamp = priv->stamp;
      iter->user_data = g_sequence_get_begin_iter (priv->seq);
571 572
      return TRUE;
    }
573
  else
574 575 576 577
    {
      iter->stamp = 0;
      return FALSE;
    }
578 579 580
}

static gboolean
581
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
582
			       GtkTreeIter  *iter)
583 584 585 586 587
{
  return FALSE;
}

static gint
588
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
589
				GtkTreeIter  *iter)
590
{
591
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
592
  GtkListStorePrivate *priv = list_store->priv;
Soeren Sandmann's avatar
Soeren Sandmann committed
593

594
  if (iter == NULL)
595
    return g_sequence_get_length (priv->seq);
596

597
  g_return_val_if_fail (priv->stamp == iter->stamp, -1);
598 599

  return 0;
600 601
}

602
static gboolean
603
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
604 605
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
606
			       gint          n)
607
{
608
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
609
  GtkListStorePrivate *priv = list_store->priv;
610
  GSequenceIter *child;
611

612 613
  iter->stamp = 0;

614
  if (parent)
615
    return FALSE;
616

617
  child = g_sequence_get_iter_at_pos (priv->seq, n);
618

619
  if (g_sequence_iter_is_end (child))
620
    return FALSE;
Soeren Sandmann's avatar
Soeren Sandmann committed
621

622
  iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
623
  iter->user_data = child;
624

Soeren Sandmann's avatar
Soeren Sandmann committed
625
  return TRUE;
626 627
}

628 629 630 631
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
632
{
633
  iter->stamp = 0;
634
  return FALSE;
635 636
}

637
static gboolean
638 639 640
gtk_list_store_real_set_value (GtkListStore *list_store,
			       GtkTreeIter  *iter,
			       gint          column,
641 642
			       GValue       *value,
			       gboolean      sort)
643
{
644
  GtkListStorePrivate *priv = list_store->priv;
645 646
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
647
  gint old_column = column;
648 649
  GValue real_value = {0, };
  gboolean converted = FALSE;
650
  gboolean retval = FALSE;
651

652
  if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
653
    {
654 655
      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))))
656 657 658 659
	{
	  g_warning ("%s: Unable to convert from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
660
		     g_type_name (priv->column_headers[column]));
661
	  return retval;
662 663 664 665 666 667
	}
      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)),
668
		     g_type_name (priv->column_headers[column]));
669
	  g_value_unset (&real_value);
670
	  return retval;
671 672 673
	}
      converted = TRUE;
    }
674

675
  prev = list = g_sequence_get (iter->user_data);
676 677 678 679 680

  while (list != NULL)
    {
      if (column == 0)
	{
681 682 683 684
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
685
	  retval = TRUE;
686 687
	  if (converted)
	    g_value_unset (&real_value);
688 689
         if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
            gtk_list_store_sort_iter_changed (list_store, iter, old_column);
690
	  return retval;
691 692 693 694 695 696 697
	}

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

698
  if (g_sequence_get (iter->user_data) == NULL)
699
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
700
      list = _gtk_tree_data_list_alloc();
701
      g_sequence_set (iter->user_data, list);
702 703 704 705
      list->next = NULL;
    }
  else
    {
706
      list = prev->next = _gtk_tree_data_list_alloc ();
707 708 709 710 711
      list->next = NULL;
    }

  while (column != 0)
    {
712
      list->next = _gtk_tree_data_list_alloc ();
713 714 715 716
      list = list->next;
      list->next = NULL;
      column --;
    }
717

718
  if (converted)
719
    _gtk_tree_data_list_value_to_node (list, &real_value);
720 721
  else
    _gtk_tree_data_list_value_to_node (list, value);
722

723
  retval = TRUE;
724 725
  if (converted)
    g_value_unset (&real_value);
726

727
  if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
728
    gtk_list_store_sort_iter_changed (list_store, iter, old_column);
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751

  return retval;
}


/**
 * gtk_list_store_set_value:
 * @list_store: A #GtkListStore
 * @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_list_store_set_value (GtkListStore *list_store,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
{
752
  GtkListStorePrivate *priv = list_store->priv;
753

754 755 756
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));
  g_return_if_fail (G_IS_VALUE (value));
757 758
  priv = list_store->priv;
  g_return_if_fail (column >= 0 && column < priv->n_columns);
759

760
  if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
761 762 763
    {
      GtkTreePath *path;

764
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
765 766 767
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
768 769
}

770 771
static GtkTreeIterCompareFunc
gtk_list_store_get_compare_func (GtkListStore *list_store)
Havoc Pennington's avatar
Havoc Pennington committed
772
{
773
  GtkListStorePrivate *priv = list_store->priv;
774
  GtkTreeIterCompareFunc func = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
775

776
  if (GTK_LIST_STORE_IS_SORTED (list_store))
777
    {
778
      if (priv->sort_column_id != -1)
779 780
	{
	  GtkTreeDataSortHeader *header;
781 782
	  header = _gtk_tree_data_list_get_header (priv->sort_list,
						   priv->sort_column_id);
783 784
	  g_return_val_if_fail (header != NULL, NULL);
	  g_return_val_if_fail (header->func != NULL, NULL);
785 786 787 788
	  func = header->func;
	}
      else
	{
789
	  func = priv->default_sort_func;
790
	}
791 792
    }

793 794 795
  return func;
}

796 797 798 799 800 801 802 803 804
static void
gtk_list_store_set_vector_internal (GtkListStore *list_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    gint         *columns,
				    GValue       *values,
				    gint          n_values)
{
805
  GtkListStorePrivate *priv = list_store->priv;
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
  gint i;
  GtkTreeIterCompareFunc func = NULL;

  func = gtk_list_store_get_compare_func (list_store);
  if (func != _gtk_tree_data_list_compare_func)
    *maybe_need_sort = TRUE;

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

      if (func == _gtk_tree_data_list_compare_func &&
822
	  columns[i] == priv->sort_column_id)
823 824 825 826
	*maybe_need_sort = TRUE;
    }
}

827 828 829 830 831 832 833
static void
gtk_list_store_set_valist_internal (GtkListStore *list_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    va_list	  var_args)
{
834
  GtkListStorePrivate *priv = list_store->priv;
835 836 837 838 839 840
  gint column;
  GtkTreeIterCompareFunc func = NULL;

  column = va_arg (var_args, gint);

  func = gtk_list_store_get_compare_func (list_store);
841
  if (func != _gtk_tree_data_list_compare_func)
842
    *maybe_need_sort = TRUE;
843

Havoc Pennington's avatar
Havoc Pennington committed
844 845 846 847 848
  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

849
      if (column < 0 || column >= priv->n_columns)
Havoc Pennington's avatar
Havoc Pennington committed
850 851 852 853
	{
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}
854
      g_value_init (&value, priv->column_headers[column]);
Havoc Pennington's avatar
Havoc Pennington committed
855

856
      G_VALUE_COLLECT (&value, var_args, 0, &error);
Havoc Pennington's avatar
Havoc Pennington committed
857 858 859 860 861 862 863 864 865 866 867
      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;
	}

Jonathan Blandford's avatar
Jonathan Blandford committed
868
      /* FIXME: instead of calling this n times, refactor with above */
869 870 871 872 873 874
      *emit_signal = gtk_list_store_real_set_value (list_store,
						    iter,
						    column,
						    &value,
						    FALSE) || *emit_signal;
      
875
      if (func == _gtk_tree_data_list_compare_func &&
876
	  column == priv->sort_column_id)
877
	*maybe_need_sort = TRUE;
Havoc Pennington's avatar
Havoc Pennington committed
878 879 880 881 882

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
883 884
}

885 886 887 888
/**
 * gtk_list_store_set_valuesv:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
889 890
 * @columns: (array length=n_values): an array of column numbers
 * @values: (array length=n_values): an array of GValues
891
 * @n_values: the length of the @columns and @values arrays
892
 *
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
 * A variant of gtk_list_store_set_valist() which
 * takes the columns and values as two arrays, instead of
 * varargs. This function is mainly intended for 
 * language-bindings and in case the number of columns to
 * change is not known until run-time.
 *
 * Since: 2.12
 */
void
gtk_list_store_set_valuesv (GtkListStore *list_store,
			    GtkTreeIter  *iter,
			    gint         *columns,
			    GValue       *values,
			    gint          n_values)
{
908
  GtkListStorePrivate *priv;
909 910 911 912 913 914
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));

915 916
  priv = list_store->priv;

917 918 919 920 921 922
  gtk_list_store_set_vector_internal (list_store, iter,
				      &emit_signal,
				      &maybe_need_sort,
				      columns, values, n_values);

  if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
923
    gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
924 925 926 927 928 929 930 931 932 933 934

  if (emit_signal)
    {
      GtkTreePath *path;

      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
}

935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
/**
 * gtk_list_store_set_valist:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
 * @var_args: va_list of column/value pairs
 *
 * See gtk_list_store_set(); this version takes a va_list for use by language
 * bindings.
 *
 **/
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
                           va_list	 var_args)
{
950
  GtkListStorePrivate *priv;
951 952 953 954 955 956
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));

957 958
  priv = list_store->priv;

959 960 961 962
  gtk_list_store_set_valist_internal (list_store, iter, 
				      &emit_signal, 
				      &maybe_need_sort,
				      var_args);
963

964
  if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
965
    gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
966

967 968 969 970
  if (emit_signal)
    {
      GtkTreePath *path;

971
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
972 973 974
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
Havoc Pennington's avatar
Havoc Pennington committed
975 976 977 978 979 980 981
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
 * @Varargs: pairs of column number and value, terminated with -1
982
 *
Havoc Pennington's avatar
Havoc Pennington committed
983 984
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
985
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
986
 * The list is terminated by a -1. For example, to set column 0 with type
Matthias Clasen's avatar
Matthias Clasen committed
987 988
 * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
 * 0, "Foo", -1)</literal>.
989 990 991
 *
 * 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
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
 **/
void
gtk_list_store_set (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

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

1005 1006
/**
 * gtk_list_store_remove:
1007 1008
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter
1009
 *
Matthias Clasen's avatar
Matthias Clasen committed
1010 1011 1012
 * Removes the given row from the list store.  After being removed, 
 * @iter is set to be the next valid row, or invalidated if it pointed 
 * to the last row in @list_store.
1013
 *
Kristian Rietveld's avatar
Kristian Rietveld committed
1014
 * Return value: %TRUE if @iter is valid, %FALSE if not.
1015
 **/
Kristian Rietveld's avatar
Kristian Rietveld committed
1016
gboolean
1017 1018 1019
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
1020
  GtkListStorePrivate *priv;
1021
  GtkTreePath *path;
1022
  GSequenceIter *ptr, *next;
1023

Kristian Rietveld's avatar
Kristian Rietveld committed
1024 1025
  g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
  g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
1026

1027 1028
  priv = list_store->priv;

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

Soeren Sandmann's avatar
Soeren Sandmann committed
1031
  ptr = iter->user_data;
1032
  next = g_sequence_iter_next (ptr);
Soeren Sandmann's avatar
Soeren Sandmann committed
1033
  
1034
  _gtk_tree_data_list_free (g_sequence_get (ptr), priv->column_headers);
1035
  g_sequence_remove (iter->user_data);
1036

1037
  priv->length--;
Soeren Sandmann's avatar
Soeren Sandmann committed
1038
  
1039
  gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
1040
  gtk_tree_path_free (path);
1041

1042
  if (g_sequence_iter_is_end (next))
1043
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
1044 1045
      iter->stamp = 0;
      return FALSE;
1046 1047 1048
    }
  else
    {
1049
      iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
1050 1051
      iter->user_data = next;
      return TRUE;
1052
    }
1053 1054
}

1055 1056
/**
 * gtk_list_store_insert:
1057
 * @list_store: A #GtkListStore
1058
 * @iter: (out): An unset #GtkTreeIter to set to the new row
1059 1060
 * @position: position to insert the new row
 *
1061 1062
 * Creates a new row at @position.  @iter will be changed to point to this new
 * row.  If @position is larger than the number of rows on the list, then the
1063 1064 1065
 * new row will be appended to the list. The row will be empty after this
 * function is called.  To fill in values, you need to call 
 * gtk_list_store_set() or gtk_list_store_set_value().
1066
 *
1067
 **/
1068 1069 1070 1071
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
1072
{
1073
  GtkListStorePrivate *priv;
1074
  GtkTreePath *path;
1075 1076
  GSequence *seq;
  GSequenceIter *ptr;
1077
  gint length;
1078

1079 1080
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1081
  g_return_if_fail (position >= 0);
1082

1083
  priv = list_store->priv;
1084

1085 1086 1087
  priv->columns_dirty = TRUE;

  seq = priv->seq;
1088

1089
  length = g_sequence_get_length (seq);
1090 1091 1092
  if (position > length)
    position = length;

1093 1094
  ptr = g_sequence_get_iter_at_pos (seq, position);
  ptr = g_sequence_insert_before (ptr, NULL);
1095

1096
  iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
1097
  iter->user_data = ptr;
1098

Soeren Sandmann's avatar
Soeren Sandmann committed
1099
  g_assert (VALID_ITER (iter, list_store));
1100

1101
  priv->length++;
1102
  
1103 1104
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
1105
  gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1106
  gtk_tree_path_free (path);
1107 1108
}

1109 1110
/**
 * gtk_list_store_insert_before:
1111
 * @list_store: A #GtkListStore
1112
 * @iter: (out): An unset #GtkTreeIter to set to the new row
1113
 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1114
 *
1115 1116 1117 1118
 * Inserts a new row before @sibling. If @sibling is %NULL, then the row will 
 * be appended to the end of the list. @iter will be changed to point to this 
 * new row. The row will be empty after this function is called. To fill in 
 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1119
 *
1120
 **/
1121 1122 1123 1124
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
1125
{
1126
  GtkListStorePrivate *priv;
1127
  GSequenceIter *after;
Soeren Sandmann's avatar
Soeren Sandmann committed
1128
  
1129 1130
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1131 1132 1133

  priv = list_store->priv;

1134 1135 1136
  if (sibling)
    g_return_if_fail (VALID_ITER (sibling, list_store));

Soeren Sandmann's avatar
Soeren Sandmann committed
1137
  if (!sibling)
1138
    after = g_sequence_get_end_iter (priv->seq);
1139
  else
Soeren Sandmann's avatar
Soeren Sandmann committed
1140
    after = sibling->user_data;
1141

1142
  gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1143 1144
}

1145 1146
/**
 * gtk_list_store_insert_after:
1147
 * @list_store: A #GtkListStore
1148
 * @iter: (out): An unset #GtkTreeIter to set to the new row
1149
 * @sibling: (allow-none): A valid #GtkTreeIter, or %NULL
1150
 *
Matthias Clasen's avatar
Matthias Clasen committed
1151 1152 1153 1154
 * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
 * prepended to the beginning of the list. @iter will be changed to point to
 * this new row. The row will be empty after this function is called. To fill
 * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1155
 *
1156
 **/
1157 1158 1159 1160
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
1161
{
1162
  GtkListStorePrivate *priv;
1163
  GSequenceIter *after;
1164 1165

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1166
  g_return_if_fail (iter != NULL);
1167 1168 1169

  priv = list_store->priv;

1170
  if (sibling)
1171
    g_return_if_fail (VALID_ITER (sibling, list_store));
1172

Soeren Sandmann's avatar
Soeren Sandmann committed
1173
  if (!sibling)
1174
    after = g_sequence_get_begin_iter (priv->seq);
Soeren Sandmann's avatar
Soeren Sandmann committed
1175
  else
1176
    after = g_sequence_iter_next (sibling->user_data);
1177

1178
  gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1179 1180
}

1181 1182
/**
 * gtk_list_store_prepend:
1183
 * @list_store: A #GtkListStore
1184
 * @iter: (out): An unset #GtkTreeIter to set to the prepend row
1185
 *
Matthias Clasen's avatar
Matthias Clasen committed
1186
 * Prepends a new row to @list_store. @iter will be changed to point to this new
Matthias Clasen's avatar
Matthias Clasen committed
1187 1188
 * row. The row will be empty after this function is called. To fill in
 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1189
 *
1190
 **/
1191 1192 1193
void
gtk_list_store_prepend (GtkListStore *list_store,
			GtkTreeIter  *iter)
1194
{
1195 1196
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1197

Soeren Sandmann's avatar
Soeren Sandmann committed
1198
  gtk_list_store_insert (list_store, iter, 0);
1199 1200
}

1201 1202
/**
 * gtk_list_store_append: