gtkliststore.c 22.8 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 <gobject/gvaluecollector.h>
26 27

#define G_SLIST(x) ((GSList *) x)
28

29
enum {
30 31 32 33
  CHANGED,
  INSERTED,
  CHILD_TOGGLED,
  DELETED,
34 35 36 37 38
  LAST_SIGNAL
};

static guint list_store_signals[LAST_SIGNAL] = { 0 };

39 40 41
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);
42
static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
43
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
44 45
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
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);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92


GtkType
gtk_list_store_get_type (void)
{
  static GtkType list_store_type = 0;

  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,
      };

93 94 95 96 97 98 99
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_list_store_tree_model_init,
	NULL,
	NULL
      };

100
      list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
101 102 103
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
104 105 106 107 108 109 110 111 112 113 114
    }

  return list_store_type;
}

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
  GtkObjectClass *object_class;

  object_class = (GtkObjectClass*) class;
115

116 117
  list_store_signals[CHANGED] =
    gtk_signal_new ("changed",
118 119
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
120
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
121 122 123 124
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
125 126
  list_store_signals[INSERTED] =
    gtk_signal_new ("inserted",
127 128
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
129
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
130 131 132 133
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
134 135
  list_store_signals[CHILD_TOGGLED] =
    gtk_signal_new ("child_toggled",
136 137
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
138
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
139 140 141 142
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
143 144
  list_store_signals[DELETED] =
    gtk_signal_new ("deleted",
145 146
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
147
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
148 149 150
                    gtk_marshal_VOID__BOXED,
                    G_TYPE_NONE, 1,
		    GTK_TYPE_TREE_PATH);
151 152 153 154 155
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
156
  iface->get_flags = gtk_list_store_get_flags;
157
  iface->get_n_columns = gtk_list_store_get_n_columns;
158
  iface->get_column_type = gtk_list_store_get_column_type;
159
  iface->get_iter = gtk_list_store_get_iter;
160
  iface->get_path = gtk_list_store_get_path;
161
  iface->get_value = gtk_list_store_get_value;
162 163 164 165 166 167
  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;
168 169 170 171 172 173
}

static void
gtk_list_store_init (GtkListStore *list_store)
{
  list_store->root = NULL;
174
  list_store->tail = NULL;
175
  list_store->stamp = g_random_int ();
176 177
}

178
GtkListStore *
179 180
gtk_list_store_new (void)
{
181
  return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
182 183
}

184
GtkListStore *
185 186 187
gtk_list_store_new_with_types (gint n_columns,
			       ...)
{
188
  GtkListStore *retval;
189 190 191 192 193 194
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_list_store_new ();
195
  gtk_list_store_set_n_columns (retval, n_columns);
196 197

  va_start (args, n_columns);
198

199
  for (i = 0; i < n_columns; i++)
200
    gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
201 202 203 204 205 206 207 208 209 210 211 212 213 214

  va_end (args);

  return retval;
}

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));
215
  g_return_if_fail (n_columns > 0);
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248

  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);
    }

  list_store->column_headers = new_columns;
  list_store->n_columns = n_columns;
}

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

  list_store->column_headers[column] = type;
}

/* Fulfill the GtkTreeModel requirements */
249 250 251 252 253 254 255 256
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;
}

257 258 259 260 261 262 263 264
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;
}

265 266 267 268 269 270 271 272 273 274 275
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];
}

276
static gboolean
277
gtk_list_store_get_iter (GtkTreeModel *tree_model,
278
			 GtkTreeIter  *iter,
279 280
			 GtkTreePath  *path)
{
281 282 283 284
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
  
  iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
285
  iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
286 287
				 gtk_tree_path_get_indices (path)[0]);

Havoc Pennington's avatar
Havoc Pennington committed
288
  return iter->user_data != NULL;
289 290 291 292
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
293
			 GtkTreeIter  *iter)
294 295 296 297 298 299
{
  GtkTreePath *retval;
  GSList *list;
  gint i = 0;

  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
300
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
301 302 303

  for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
304
      if (list == G_SLIST (iter->user_data))
305
	break;
306
      i++;
307 308 309 310 311 312 313 314 315 316
    }
  if (list == NULL)
    return NULL;

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

static void
317 318 319 320
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
321 322 323 324 325 326
{
  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);
327
  g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
328

Havoc Pennington's avatar
Havoc Pennington committed
329
  list = G_SLIST (iter->user_data)->data;
330 331 332 333

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

334 335 336 337 338 339
  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);
340 341 342
}

static gboolean
343 344
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
345
{
346 347
  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);
348

Havoc Pennington's avatar
Havoc Pennington committed
349
  iter->user_data = G_SLIST (iter->user_data)->next;
350

Havoc Pennington's avatar
Havoc Pennington committed
351
  return (iter->user_data != NULL);
352 353
}

354
static gboolean
355
gtk_list_store_iter_children (GtkTreeModel *tree_model,
356 357
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
358
{
359 360 361 362 363 364 365 366 367 368 369 370
  if (parent)
    {
      iter->stamp = 0;      
      iter->user_data = NULL;
      return FALSE;
    }
  else
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      iter->user_data = GTK_LIST_STORE (tree_model)->root;
      return TRUE;
    }
371 372 373
}

static gboolean
374
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
375
			       GtkTreeIter  *iter)
376 377 378 379 380
{
  return FALSE;
}

static gint
381
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
382
				GtkTreeIter  *iter)
383
{
384 385 386
  if (iter == NULL)
    return g_slist_length (G_SLIST (GTK_LIST_STORE (tree_model)->root));

387 388 389
  return 0;
}

390
static gboolean
391
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
392 393
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
394
			       gint          n)
395
{
396
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
397

398 399 400 401
  if (parent)
    {
      g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, FALSE);
      iter->stamp = 0;
Havoc Pennington's avatar
Havoc Pennington committed
402
      iter->user_data = NULL;
403 404 405 406

      return FALSE;
    }

Havoc Pennington's avatar
Havoc Pennington committed
407 408
  iter->user_data = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
  if (iter->user_data)
409 410 411 412
    iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
  else
    iter->stamp = 0;

Havoc Pennington's avatar
Havoc Pennington committed
413
  return (iter->user_data != NULL);
414 415
}

416 417 418 419
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
420
{
421
  iter->stamp = 0;
Havoc Pennington's avatar
Havoc Pennington committed
422
  iter->user_data = NULL;
423

424
  return FALSE;
425 426
}

427
/* Public accessors */
428 429 430 431
/* This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
void
432 433 434 435
gtk_list_store_set_cell (GtkListStore *list_store,
			 GtkTreeIter  *iter,
			 gint          column,
			 GValue       *value)
436 437 438 439 440 441
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
442
  g_return_if_fail (iter != NULL);
443 444
  g_return_if_fail (column >= 0 && column < list_store->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
445
  prev = list = G_SLIST (iter->user_data)->data;
446 447 448 449 450

  while (list != NULL)
    {
      if (column == 0)
	{
451
	  _gtk_tree_data_list_value_to_node (list, value);
452 453 454
	  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
				   "changed",
				   NULL, iter);
455 456 457 458 459 460 461 462
	  return;
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
463
  if (G_SLIST (iter->user_data)->data == NULL)
464
    {
Havoc Pennington's avatar
Havoc Pennington committed
465
      G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
466 467 468 469
      list->next = NULL;
    }
  else
    {
470
      list = prev->next = _gtk_tree_data_list_alloc ();
471 472 473 474 475
      list->next = NULL;
    }

  while (column != 0)
    {
476
      list->next = _gtk_tree_data_list_alloc ();
477 478 479 480
      list = list->next;
      list->next = NULL;
      column --;
    }
481 482 483 484
  _gtk_tree_data_list_value_to_node (list, value);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "changed",
			   NULL, iter);
485 486
}

Havoc Pennington's avatar
Havoc Pennington committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
                           va_list	var_args)
{
  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]);

      G_VALUE_COLLECT (&value, var_args, &error);
      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;
	}

      gtk_list_store_set_cell (list_store,
			       iter,
			       column,
			       &value);

      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
 * 
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
 * each column number followed by the value to be set. For example,
 * 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);
}

void
gtk_list_store_get_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
                           va_list	var_args)
{
  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 accessed (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}

      gtk_list_store_get_value (GTK_TREE_MODEL (list_store), iter, column, &value);

      G_VALUE_LCOPY (&value, var_args, &error);
      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;
	}

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

void
gtk_list_store_get (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_get_valist (list_store, iter, var_args);
  va_end (var_args);
}

616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
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)
	    prev->next = tmp->next;
	  if (list == tmp)
	    list = list->next;

	  tmp->next = NULL;
	  break;
	}

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

  *prevp = prev;
  
  return list;
}

649
void
650 651
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
652
{
653 654 655 656
  GtkTreePath *path;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
657 658
  g_return_if_fail (iter->user_data != NULL);
  
Havoc Pennington's avatar
Havoc Pennington committed
659 660
  if (G_SLIST (iter->user_data)->data)
    _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
661 662 663
			      list_store->column_headers);

  path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
664 665 666 667 668 669 670 671 672 673 674 675

  {
    GSList *prev = NULL;
    
    list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
                                                G_SLIST (iter->user_data),
                                                &prev);
    
    if (iter->user_data == list_store->tail)
      list_store->tail = prev;
  }
  
676 677 678 679 680
  list_store->stamp ++;
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "deleted",
			   path);
  gtk_tree_path_free (path);
681 682
}

683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
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);
  
  /* 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 */
  if (sibling == list_store->tail)
    list_store->tail = new_list;
}

700 701 702 703
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
704 705
{
  GSList *list;
706
  GtkTreePath *path;
707 708
  GSList *new_list;
  
709 710 711
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
712
  g_return_if_fail (position >= 0);
713 714 715

  if (position == 0)
    {
716 717
      gtk_list_store_prepend (list_store, iter);
      return;
718 719
    }

720
  new_list = g_slist_alloc ();
721 722

  list = g_slist_nth (G_SLIST (list_store->root), position - 1);
723 724

  if (list == NULL)
725
    {
726 727
      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
      return;
728
    }
729 730 731 732 733 734

  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
  
735 736 737 738 739 740
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
741 742
}

743 744 745 746
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
747
{
748
  GtkTreePath *path;
749
  GSList *list, *prev, *new_list;
750 751 752 753 754
  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);
755 756

  if (sibling == NULL)
757 758 759 760
    {
      gtk_list_store_append (list_store, iter);
      return;
    }
761 762
  
  new_list = g_slist_alloc ();
763 764

  prev = list = list_store->root;
Havoc Pennington's avatar
Havoc Pennington committed
765
  while (list && list != sibling->user_data)
766 767 768 769 770
    {
      prev = list;
      list = list->next;
      i++;
    }
771 772 773 774 775 776 777 778 779 780 781 782 783 784

  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;
785 786 787
  
  if (prev)
    {
788 789
      new_list->next = prev->next;
      prev->next = new_list;
790 791 792
    }
  else
    {
793 794
      new_list->next = list_store->root;
      list_store->root = new_list;
795 796
    }

797 798 799
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
  
800 801 802 803 804 805
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
806 807
}

808 809 810 811
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
812
{
813
  GtkTreePath *path;
814
  GSList *list, *new_list;
815 816 817 818
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
819
  g_return_if_fail (iter != NULL);
820 821
  if (sibling)
    g_return_if_fail (sibling->stamp == list_store->stamp);
822

823 824 825 826 827 828
  if (sibling == NULL)
    {
      gtk_list_store_prepend (list_store, iter);
      return;
    }

Havoc Pennington's avatar
Havoc Pennington committed
829
  for (list = list_store->root; list && list != sibling->user_data; list = list->next)
830 831
    i++;

832
  g_return_if_fail (list == sibling->user_data);
833

834
  new_list = g_slist_alloc ();
835

836 837 838 839 840
  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
  
841 842 843 844 845 846
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
847 848
}

849 850 851
void
gtk_list_store_prepend (GtkListStore *list_store,
			GtkTreeIter  *iter)
852
{
853 854 855 856 857
  GtkTreePath *path;

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

859
  iter->stamp = list_store->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
860
  iter->user_data = g_slist_alloc ();
861

862 863 864
  if (list_store->root == NULL)
    list_store->tail = iter->user_data;
  
Havoc Pennington's avatar
Havoc Pennington committed
865 866
  G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
  list_store->root = iter->user_data;
867

868 869 870 871 872 873
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, 0);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
874 875
}

876 877 878
void
gtk_list_store_append (GtkListStore *list_store,
		       GtkTreeIter  *iter)
879
{
880 881 882 883 884 885 886 887
  GtkTreePath *path;
  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);

  iter->stamp = list_store->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
888
  iter->user_data = g_slist_alloc ();
889

890 891
  if (list_store->tail)
    list_store->tail->next = iter->user_data;
892
  else
Havoc Pennington's avatar
Havoc Pennington committed
893
    list_store->root = iter->user_data;
894

895 896
  list_store->tail = iter->user_data;
  
897 898 899 900 901 902
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
903
}