gtkliststore.c 45.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* 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.
 */

#include <string.h>
#include "gtktreemodel.h"
#include "gtkliststore.h"
#include "gtktreedatalist.h"
24
#include "gtksignal.h"
Havoc Pennington's avatar
Havoc Pennington committed
25
#include "gtktreednd.h"
Havoc Pennington's avatar
Havoc Pennington committed
26
#include <gobject/gvaluecollector.h>
27 28

#define G_SLIST(x) ((GSList *) x)
29
#define GTK_LIST_STORE_IS_SORTED(list) (GTK_LIST_STORE (list)->sort_column_id != -1)
30 31 32 33

static void         gtk_list_store_init            (GtkListStore      *list_store);
static void         gtk_list_store_class_init      (GtkListStoreClass *class);
static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
Havoc Pennington's avatar
Havoc Pennington committed
34 35
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
36
static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
37
static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
38
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
39 40
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
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);
66

67 68

/* Drag and Drop */
Havoc Pennington's avatar
Havoc Pennington committed
69 70 71 72 73 74 75 76
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);
77 78 79 80
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
                                                   GtkTreeModel      *src_model,
                                                   GtkTreePath       *src_path,
                                                   GtkTreePath       *dest_path);
81

82

83
/* sortable */
84 85
static void     gtk_list_store_sort                    (GtkListStore           *list_store);
static void     gtk_list_store_sort_iter_changed       (GtkListStore           *list_store,
86 87
							GtkTreeIter            *iter,
							gint                    column);
88 89 90 91 92 93 94 95 96 97 98 99 100
static gboolean gtk_list_store_get_sort_column_id      (GtkTreeSortable        *sortable,
							gint                   *sort_column_id,
							GtkTreeSortOrder       *order);
static void     gtk_list_store_set_sort_column_id      (GtkTreeSortable        *sortable,
							gint                    sort_column_id,
							GtkTreeSortOrder        order);
static void     gtk_list_store_sort_column_id_set_func (GtkTreeSortable        *sortable,
							gint                    sort_column_id,
							GtkTreeIterCompareFunc  func,
							gpointer                data,
							GtkDestroyNotify        destroy);


101 102 103 104 105 106
static void
validate_list_store (GtkListStore *list_store)
{
  if (gtk_debug_flags & GTK_DEBUG_TREE)
    {
      g_assert (g_slist_length (list_store->root) == list_store->length);
107

108 109 110
      g_assert (g_slist_last (list_store->root) == list_store->tail);
    }
}
111 112 113 114

GtkType
gtk_list_store_get_type (void)
{
115
  static GType list_store_type = 0;
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131

  if (!list_store_type)
    {
      static const GTypeInfo list_store_info =
      {
	sizeof (GtkListStoreClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_list_store_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkListStore),
	0,
        (GInstanceInitFunc) gtk_list_store_init,
      };

132 133 134 135 136 137 138
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_list_store_tree_model_init,
	NULL,
	NULL
      };

Havoc Pennington's avatar
Havoc Pennington committed
139 140 141 142 143 144 145 146 147 148 149 150 151
      static const GInterfaceInfo drag_source_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_source_init,
	NULL,
	NULL
      };

      static const GInterfaceInfo drag_dest_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_dest_init,
	NULL,
	NULL
      };
152 153 154 155 156 157 158 159

      static const GInterfaceInfo sortable_info =
      {
	(GInterfaceInitFunc) gtk_list_store_sortable_init,
	NULL,
	NULL
      };

160
      list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
161 162 163
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
Havoc Pennington's avatar
Havoc Pennington committed
164 165 166 167 168 169
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_SOURCE,
				   &drag_source_info);
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_DEST,
				   &drag_dest_info);
170 171 172
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_SORTABLE,
				   &sortable_info);
173 174 175 176 177 178 179 180
    }

  return list_store_type;
}

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
181 182 183
  GObjectClass *object_class;

  object_class = (GObjectClass*) class;
184 185 186 187 188
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
189
  iface->get_flags = gtk_list_store_get_flags;
190
  iface->get_n_columns = gtk_list_store_get_n_columns;
191
  iface->get_column_type = gtk_list_store_get_column_type;
192
  iface->get_iter = gtk_list_store_get_iter;
193
  iface->get_path = gtk_list_store_get_path;
194
  iface->get_value = gtk_list_store_get_value;
195 196 197 198 199 200
  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;
201 202
}

Havoc Pennington's avatar
Havoc Pennington committed
203 204 205 206 207 208 209 210
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
211
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
Havoc Pennington's avatar
Havoc Pennington committed
212 213
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
214
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
Havoc Pennington's avatar
Havoc Pennington committed
215 216
}

217 218 219 220 221 222 223 224
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;
  iface->sort_column_id_set_func = gtk_list_store_sort_column_id_set_func;
}

225 226 227 228
static void
gtk_list_store_init (GtkListStore *list_store)
{
  list_store->root = NULL;
229
  list_store->tail = NULL;
230
  list_store->sort_list = NULL;
231
  list_store->stamp = g_random_int ();
232
  list_store->length = 0;
Jonathan Blandford's avatar
Jonathan Blandford committed
233
  list_store->sort_column_id = -1;
234 235
}

236 237 238 239 240 241 242 243 244
/**
 * gtk_list_store_new:
 *
 * Creates a new #GtkListStore. A #GtkListStore implements the
 * #GtkTreeModel interface, and stores a linked list of
 * rows; each row can have any number of columns. Columns are of uniform type,
 * i.e. all cells in a column have the same type such as #G_TYPE_STRING or
 * #GDK_TYPE_PIXBUF. Use #GtkListStore to store data to be displayed in a
 * #GtkTreeView.
245
 *
246 247
 * Return value: a new #GtkListStore
 **/
248
GtkListStore *
249 250
gtk_list_store_new (void)
{
251
  return GTK_LIST_STORE (g_object_new (gtk_list_store_get_type (), NULL));
252 253
}

254 255 256 257 258 259 260 261 262
/**
 * gtk_list_store_new_with_types:
 * @n_columns: number of columns in the list store
 * @Varargs: pairs of column number and #GType
 *
 * Creates a new list store as with gtk_list_store_new(),
 * simultaneously setting up the columns and column types as with
 * gtk_list_store_set_n_columns() and
 * gtk_list_store_set_column_type().
263 264
 *
 *
265 266
 * Return value: a new #GtkListStore
 **/
267
GtkListStore *
268 269 270
gtk_list_store_new_with_types (gint n_columns,
			       ...)
{
271
  GtkListStore *retval;
272 273 274 275 276 277
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_list_store_new ();
278
  gtk_list_store_set_n_columns (retval, n_columns);
279 280

  va_start (args, n_columns);
281

282
  for (i = 0; i < n_columns; i++)
283 284 285 286 287 288 289 290 291 292 293
    {
      GType type = va_arg (args, GType);
      if (! _gtk_tree_data_list_check_type (type))
	{
	  g_warning ("%s: Invalid type %s passed to gtk_list_store_new_with_types\n", G_STRLOC, g_type_name (type));
	  g_object_unref (G_OBJECT (retval));
	  return NULL;
	}

      gtk_list_store_set_column_type (retval, i, type);
    }
294 295 296 297 298 299

  va_end (args);

  return retval;
}

300 301 302 303 304 305
/**
 * gtk_list_store_set_n_columns:
 * @store: a #GtkListStore
 * @n_columns: number of columns
 *
 * Sets the number of columns in the #GtkListStore.
306
 *
307
 **/
308 309 310 311 312 313 314 315
void
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
  GType *new_columns;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
316
  g_return_if_fail (n_columns > 0);
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

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

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

      g_free (list_store->column_headers);
    }

333 334 335 336 337
  if (list_store->sort_list)
    _gtk_tree_data_list_header_free (list_store->sort_list);

  list_store->sort_list = _gtk_tree_data_list_header_new (n_columns, list_store->column_headers);

338 339 340 341
  list_store->column_headers = new_columns;
  list_store->n_columns = n_columns;
}

342 343 344 345 346 347 348
/**
 * gtk_list_store_set_column_type:
 * @store: a #GtkListStore
 * @column: column number
 * @type: type of the data stored in @column
 *
 * Supported types include: %G_TYPE_UINT, %G_TYPE_INT, %G_TYPE_UCHAR,
349 350 351
 * %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.
352
 *
353
 **/
354 355 356 357 358 359 360 361
void
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (column >=0 && column < list_store->n_columns);
362 363 364 365 366
  if (!_gtk_tree_data_list_check_type (type))
    {
      g_warning ("%s: Invalid type %s passed to gtk_list_store_new_with_types\n", G_STRLOC, g_type_name (type));
      return;
    }
367 368 369 370 371

  list_store->column_headers[column] = type;
}

/* Fulfill the GtkTreeModel requirements */
372 373 374 375 376 377 378 379
static guint
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_TREE_MODEL_ITERS_PERSIST;
}

380 381 382 383 384 385 386 387
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_LIST_STORE (tree_model)->n_columns;
}

388 389 390 391 392 393 394 395 396 397 398
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
  g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
			index >= 0, G_TYPE_INVALID);

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

399
static gboolean
400
gtk_list_store_get_iter (GtkTreeModel *tree_model,
401
			 GtkTreeIter  *iter,
402 403
			 GtkTreePath  *path)
{
404 405
  GSList *list;
  gint i;
406

407
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
408
  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
409 410 411 412 413

  i = gtk_tree_path_get_indices (path)[0];

  if (i >= GTK_LIST_STORE (tree_model)->length)
    return FALSE;
414

415
  list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), i);
416

417 418
  /* If this fails, list_store->length has gotten mangled. */
  g_assert (list);
419

420 421 422
  iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
  iter->user_data = list;
  return TRUE;
423 424 425 426
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
427
			 GtkTreeIter  *iter)
428 429 430 431 432 433
{
  GtkTreePath *retval;
  GSList *list;
  gint i = 0;

  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
434
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
435 436 437

  for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
438
      if (list == G_SLIST (iter->user_data))
439
	break;
440
      i++;
441 442 443 444 445 446 447 448 449 450
    }
  if (list == NULL)
    return NULL;

  retval = gtk_tree_path_new ();
  gtk_tree_path_append_index (retval, i);
  return retval;
}

static void
451 452 453 454
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
455 456 457 458 459 460
{
  GtkTreeDataList *list;
  gint tmp_column = column;

  g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
  g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
461
  g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
462

Havoc Pennington's avatar
Havoc Pennington committed
463
  list = G_SLIST (iter->user_data)->data;
464 465 466 467

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

468 469 470 471 472 473
  if (list == NULL)
    g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
  else
    _gtk_tree_data_list_node_to_value (list,
				       GTK_LIST_STORE (tree_model)->column_headers[column],
				       value);
474 475 476
}

static gboolean
477 478
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
479
{
480 481
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
  g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
482

483 484 485 486 487 488 489
  if (G_SLIST (iter->user_data)->next)
    {
      iter->user_data = G_SLIST (iter->user_data)->next;
      return TRUE;
    }
  else
    return FALSE;
490 491
}

492
static gboolean
493
gtk_list_store_iter_children (GtkTreeModel *tree_model,
494 495
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
496
{
497
  /* this is a list, nodes have no children */
498
  if (parent)
499 500 501 502 503
    return FALSE;

  /* but if parent == NULL we return the list itself as children of the
   * "root"
   */
504

505
  if (GTK_LIST_STORE (tree_model)->root)
506 507 508 509 510
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      iter->user_data = GTK_LIST_STORE (tree_model)->root;
      return TRUE;
    }
511 512
  else
    return FALSE;
513 514 515
}

static gboolean
516
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
517
			       GtkTreeIter  *iter)
518 519 520 521 522
{
  return FALSE;
}

static gint
523
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
524
				GtkTreeIter  *iter)
525
{
526 527 528
  g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, -1);

  if (iter->user_data == NULL)
529 530 531
    return GTK_LIST_STORE (tree_model)->length;
  else
    return 0;
532 533
}

534
static gboolean
535
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
536 537
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
538
			       gint          n)
539
{
540
  GSList *child;
541

542
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
543

544
  if (parent)
545
    return FALSE;
546

547
  child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
548

549 550 551
  if (child)
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
552
      iter->user_data = child;
553 554
      return TRUE;
    }
555
  else
556
    return FALSE;
557 558
}

559 560 561 562
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
563
{
564
  return FALSE;
565 566
}

567
/* Public accessors */
568 569 570
/* This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
571 572

/**
Jonathan Blandford's avatar
Jonathan Blandford committed
573
 * gtk_list_store_set_value:
574 575 576 577 578 579 580 581
 * @store: a #GtkListStore
 * @iter: iterator for the row you're modifying
 * @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.
582
 *
583
 **/
584
void
Jonathan Blandford's avatar
Jonathan Blandford committed
585 586 587 588
gtk_list_store_set_value (GtkListStore *list_store,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
589 590 591
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
592
  GtkTreePath *path;
593 594
  GValue real_value = {0, };
  gboolean converted = FALSE;
595 596 597

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
598
  g_return_if_fail (iter != NULL);
599
  g_return_if_fail (column >= 0 && column < list_store->n_columns);
Jonathan Blandford's avatar
Jonathan Blandford committed
600
  g_return_if_fail (G_IS_VALUE (value));
601

602
  if (! g_type_is_a (G_VALUE_TYPE (value), list_store->column_headers[column]))
603
    {
604 605
      if (! (g_value_type_compatible (G_VALUE_TYPE (value), list_store->column_headers[column]) &&
	     g_value_type_compatible (list_store->column_headers[column], G_VALUE_TYPE (value))))
606 607 608 609
	{
	  g_warning ("%s: Unable to convert from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
610
		     g_type_name (list_store->column_headers[column]));
611 612 613 614 615 616 617
	  return;
	}
      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)),
618
		     g_type_name (list_store->column_headers[column]));
619 620 621 622 623
	  g_value_unset (&real_value);
	  return;
	}
      converted = TRUE;
    }
624

Havoc Pennington's avatar
Havoc Pennington committed
625
  prev = list = G_SLIST (iter->user_data)->data;
626 627 628 629 630

  while (list != NULL)
    {
      if (column == 0)
	{
631
	  path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
632 633 634 635
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
636
	  gtk_tree_model_range_changed (GTK_TREE_MODEL (list_store), path, iter, path, iter);
637
	  gtk_tree_path_free (path);
638 639
	  if (converted)
	    g_value_unset (&real_value);
640 641 642 643 644 645 646 647
	  return;
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
648
  if (G_SLIST (iter->user_data)->data == NULL)
649
    {
Havoc Pennington's avatar
Havoc Pennington committed
650
      G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
651 652 653 654
      list->next = NULL;
    }
  else
    {
655
      list = prev->next = _gtk_tree_data_list_alloc ();
656 657 658 659 660
      list->next = NULL;
    }

  while (column != 0)
    {
661
      list->next = _gtk_tree_data_list_alloc ();
662 663 664 665
      list = list->next;
      list->next = NULL;
      column --;
    }
666 667

  path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
668
  if (converted)
669
    _gtk_tree_data_list_value_to_node (list, &real_value);
670 671
  else
    _gtk_tree_data_list_value_to_node (list, value);
672
  gtk_tree_model_range_changed (GTK_TREE_MODEL (list_store), path, iter, path, iter);
673
  gtk_tree_path_free (path);
674 675
  if (converted)
    g_value_unset (&real_value);
676 677

  if (GTK_LIST_STORE_IS_SORTED (list_store))
678
    gtk_list_store_sort_iter_changed (list_store, iter, column);
679 680
}

681 682 683 684 685 686 687 688
/**
 * gtk_list_store_set_valist:
 * @list_store: a #GtkListStore
 * @iter: row to set data for
 * @var_args: va_list of column/value pairs
 *
 * See gtk_list_store_set(); this version takes a va_list for
 * use by language bindings.
689
 *
690
 **/
Havoc Pennington's avatar
Havoc Pennington committed
691 692 693
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
694
                           va_list	 var_args)
Havoc Pennington's avatar
Havoc Pennington committed
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
{
  gint column;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  column = va_arg (var_args, gint);

  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= list_store->n_columns)
	{
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}
      g_value_init (&value, list_store->column_headers[column]);

714
      G_VALUE_COLLECT (&value, var_args, 0, &error);
Havoc Pennington's avatar
Havoc Pennington committed
715 716 717 718 719 720 721 722 723 724 725
      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
726 727 728 729
      gtk_list_store_set_value (list_store,
				iter,
				column,
				&value);
Havoc Pennington's avatar
Havoc Pennington committed
730 731 732 733 734 735 736 737 738 739 740 741

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
 * @Varargs: pairs of column number and value, terminated with -1
742
 *
Havoc Pennington's avatar
Havoc Pennington committed
743 744
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
745
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
 * The list is terminated by a -1. For example, to set column 0 with type
 * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
 * 0, "Foo", -1).
 **/
void
gtk_list_store_set (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

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

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
static GSList*
remove_link_saving_prev (GSList  *list,
                         GSList  *link,
                         GSList **prevp)
{
  GSList *tmp;
  GSList *prev;

  prev = NULL;
  tmp = list;

  while (tmp)
    {
      if (tmp == link)
	{
	  if (prev)
780 781 782
	    prev->next = link->next;

	  if (list == link)
783 784
	    list = list->next;

785
	  link->next = NULL;
786 787 788 789 790 791 792 793
	  break;
	}

      prev = tmp;
      tmp = tmp->next;
    }

  *prevp = prev;
794

795 796 797
  return list;
}

Havoc Pennington's avatar
Havoc Pennington committed
798 799 800 801
static void
gtk_list_store_remove_silently (GtkListStore *list_store,
                                GtkTreeIter  *iter,
                                GtkTreePath  *path)
802
{
Havoc Pennington's avatar
Havoc Pennington committed
803
  if (G_SLIST (iter->user_data)->data)
Havoc Pennington's avatar
Havoc Pennington committed
804 805 806 807 808
    {
      _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
                                list_store->column_headers);
      G_SLIST (iter->user_data)->data = NULL;
    }
809 810 811

  {
    GSList *prev = NULL;
812

813 814 815
    list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
                                                G_SLIST (iter->user_data),
                                                &prev);
816 817

    list_store->length -= 1;
818

819 820 821
    if (iter->user_data == list_store->tail)
      list_store->tail = prev;
  }
822

823
  list_store->stamp ++;
Havoc Pennington's avatar
Havoc Pennington committed
824 825
}

826 827 828 829 830 831 832
/**
 * gtk_list_store_remove:
 * @store: a #GtkListStore
 * @iter: a row in @list_store
 *
 * Removes the given row from the list store, emitting the
 * "deleted" signal on #GtkTreeModel.
833
 *
834
 **/
Havoc Pennington's avatar
Havoc Pennington committed
835 836 837 838 839 840 841 842
void
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
  GtkTreePath *path;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
843
  g_return_if_fail (iter->user_data != NULL);
Havoc Pennington's avatar
Havoc Pennington committed
844 845 846

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

847
  validate_list_store (list_store);
848

Havoc Pennington's avatar
Havoc Pennington committed
849 850
  gtk_list_store_remove_silently (list_store, iter, path);

851
  validate_list_store (list_store);
852

853
  list_store->stamp ++;
854
  gtk_tree_model_deleted (GTK_TREE_MODEL (list_store), path);
855
  gtk_tree_path_free (path);
856 857
}

858 859 860 861 862 863 864
static void
insert_after (GtkListStore *list_store,
              GSList       *sibling,
              GSList       *new_list)
{
  g_return_if_fail (sibling != NULL);
  g_return_if_fail (new_list != NULL);
865

866 867 868 869 870
  /* insert new node after list */
  new_list->next = sibling->next;
  sibling->next = new_list;

  /* if list was the tail, the new node is the new tail */
871
  if (sibling == ((GSList *) list_store->tail))
872
    list_store->tail = new_list;
873 874

  list_store->length += 1;
875 876
}

877 878 879 880 881 882 883 884 885
/**
 * gtk_list_store_insert:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @position: position to insert the new row
 *
 * Creates a new row at @position, initializing @iter to point to the
 * new row, and emitting the "inserted" signal from the #GtkTreeModel
 * interface.
886
 *
887
 **/
888 889 890 891
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
892 893
{
  GSList *list;
894
  GtkTreePath *path;
895
  GSList *new_list;
896

897 898 899
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
900
  g_return_if_fail (position >= 0);
901

902 903
  if (position == 0 ||
      GTK_LIST_STORE_IS_SORTED (list_store))
904
    {
905 906
      gtk_list_store_prepend (list_store, iter);
      return;
907 908
    }

909
  new_list = g_slist_alloc ();
910 911

  list = g_slist_nth (G_SLIST (list_store->root), position - 1);
912 913

  if (list == NULL)
914
    {
915 916
      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
      return;
917
    }
918 919

  insert_after (list_store, list, new_list);
920

921 922
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
923 924

  validate_list_store (list_store);
925

926 927
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
928
  gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
929
  gtk_tree_path_free (path);
930 931
}

932 933 934 935 936 937 938 939 940
/**
 * gtk_list_store_insert_before:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @sibling: an existing row
 *
 * Inserts a new row before @sibling, initializing @iter to point to
 * the new row, and emitting the "inserted" signal from the
 * #GtkTreeModel interface.
941
 *
942
 **/
943 944 945 946
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
947
{
948
  GtkTreePath *path;
949
  GSList *list, *prev, *new_list;
950 951 952 953 954
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
955

956 957 958 959 960 961
  if (GTK_LIST_STORE_IS_SORTED (list_store))
    {
      gtk_list_store_prepend (list_store, iter);
      return;
    }

962
  if (sibling == NULL)
963 964 965 966
    {
      gtk_list_store_append (list_store, iter);
      return;
    }
967

968
  new_list = g_slist_alloc ();
969

970 971
  prev = NULL;
  list = list_store->root;
Havoc Pennington's avatar
Havoc Pennington committed
972
  while (list && list != sibling->user_data)
973 974 975 976 977
    {
      prev = list;
      list = list->next;
      i++;
    }
978 979 980 981 982 983 984 985 986 987 988 989 990 991

  if (list != sibling->user_data)
    {
      g_warning ("%s: sibling iterator invalid? not found in the list", G_STRLOC);
      return;
    }

  /* if there are no nodes, we become the list tail, otherwise we
   * are inserting before any existing nodes so we can't change
   * the tail
   */

  if (list_store->root == NULL)
    list_store->tail = new_list;
992

993 994
  if (prev)
    {
995 996
      new_list->next = prev->next;
      prev->next = new_list;
997 998 999
    }
  else
    {
1000 1001
      new_list->next = list_store->root;
      list_store->root = new_list;
1002 1003
    }

1004 1005
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
1006 1007 1008 1009

  list_store->length += 1;

  validate_list_store (list_store);
1010

1011 1012
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
1013
  gtk_tree_model_inserted (GTK_TREE_MODEL (list_store), path, iter);
1014
  gtk_tree_path_free (path);
1015 1016
}

1017 1018 1019 1020 1021 1022 1023 1024 1025
/**
 * gtk_list_store_insert_after:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @sibling: an existing row
 *
 * Inserts a new row after @sibling, initializing @iter to point to
 * the new row, and emitting the "inserted" signal from the
 * #GtkTreeModel interface.
1026
 *
1027
 **/
1028 1029 1030 1031
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
1032
{