gtkliststore.c 35.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 "gtktreednd.h"
Havoc Pennington's avatar
Havoc Pennington committed
26
#include <gobject/gvaluecollector.h>
27 28

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

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

static guint list_store_signals[LAST_SIGNAL] = { 0 };

40 41 42
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
43 44
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
45
static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
46
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
47 48
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
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);
74

Havoc Pennington's avatar
Havoc Pennington committed
75 76 77 78 79 80 81 82
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);
83 84 85 86 87 88 89 90 91 92 93 94 95 96
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
                                                   GtkTreeModel      *src_model,
                                                   GtkTreePath       *src_path,
                                                   GtkTreePath       *dest_path);
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);
      
      g_assert (g_slist_last (list_store->root) == list_store->tail);
    }
}
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

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

118 119 120 121 122 123 124
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_list_store_tree_model_init,
	NULL,
	NULL
      };

Havoc Pennington's avatar
Havoc Pennington committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138
      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
      };
      
139
      list_store_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
140 141 142
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
Havoc Pennington's avatar
Havoc Pennington committed
143 144 145 146 147 148
      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);
149 150 151 152 153 154 155 156 157 158 159
    }

  return list_store_type;
}

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

  object_class = (GtkObjectClass*) class;
160

161 162
  list_store_signals[CHANGED] =
    gtk_signal_new ("changed",
163 164
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
165
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, changed),
166 167 168 169
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
170 171
  list_store_signals[INSERTED] =
    gtk_signal_new ("inserted",
172 173
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
174
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, inserted),
175 176 177 178
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
179 180
  list_store_signals[CHILD_TOGGLED] =
    gtk_signal_new ("child_toggled",
181 182
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
183
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, child_toggled),
184 185 186 187
                    gtk_marshal_VOID__BOXED_BOXED,
                    G_TYPE_NONE, 2,
		    GTK_TYPE_TREE_PATH,
		    GTK_TYPE_TREE_ITER);
188 189
  list_store_signals[DELETED] =
    gtk_signal_new ("deleted",
190 191
                    GTK_RUN_FIRST,
                    GTK_CLASS_TYPE (object_class),
192
                    GTK_SIGNAL_OFFSET (GtkListStoreClass, deleted),
193 194 195
                    gtk_marshal_VOID__BOXED,
                    G_TYPE_NONE, 1,
		    GTK_TYPE_TREE_PATH);
196 197 198 199 200
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
201
  iface->get_flags = gtk_list_store_get_flags;
202
  iface->get_n_columns = gtk_list_store_get_n_columns;
203
  iface->get_column_type = gtk_list_store_get_column_type;
204
  iface->get_iter = gtk_list_store_get_iter;
205
  iface->get_path = gtk_list_store_get_path;
206
  iface->get_value = gtk_list_store_get_value;
207 208 209 210 211 212
  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;
213 214
}

Havoc Pennington's avatar
Havoc Pennington committed
215 216 217 218 219 220 221 222 223 224 225
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
gtk_list_store_drag_dest_init   (GtkTreeDragDestIface   *iface)
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
226
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
Havoc Pennington's avatar
Havoc Pennington committed
227 228
}

229 230 231 232
static void
gtk_list_store_init (GtkListStore *list_store)
{
  list_store->root = NULL;
233
  list_store->tail = NULL;
234
  list_store->stamp = g_random_int ();
235
  list_store->length = 0;
236 237
}

238 239 240 241 242 243 244 245 246 247 248 249
/**
 * 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.
 * 
 * Return value: a new #GtkListStore
 **/
250
GtkListStore *
251 252
gtk_list_store_new (void)
{
253
  return GTK_LIST_STORE (gtk_type_new (gtk_list_store_get_type ()));
254 255
}

256 257 258 259 260 261 262 263 264 265 266 267 268
/**
 * 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().
 * 
 * 
 * Return value: a new #GtkListStore
 **/
269
GtkListStore *
270 271 272
gtk_list_store_new_with_types (gint n_columns,
			       ...)
{
273
  GtkListStore *retval;
274 275 276 277 278 279
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_list_store_new ();
280
  gtk_list_store_set_n_columns (retval, n_columns);
281 282

  va_start (args, n_columns);
283

284
  for (i = 0; i < n_columns; i++)
285
    gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
286 287 288 289 290 291

  va_end (args);

  return retval;
}

292 293 294 295 296 297 298 299
/**
 * gtk_list_store_set_n_columns:
 * @store: a #GtkListStore
 * @n_columns: number of columns
 *
 * Sets the number of columns in the #GtkListStore.
 * 
 **/
300 301 302 303 304 305 306 307
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));
308
  g_return_if_fail (n_columns > 0);
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

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

329 330 331 332 333 334 335 336 337 338 339 340
/**
 * 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,
 * %G_TYPE_CHAR, %G_TYPE_BOOLEAN, %G_TYPE_POINTER, %G_TYPE_FLOAT, %G_TYPE_STRING,
 * %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with subclasses of those types such
 * as %GDK_TYPE_PIXBUF.
 * 
 **/
341 342 343 344 345 346 347 348 349 350 351 352 353
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 */
354 355 356 357 358 359 360 361
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;
}

362 363 364 365 366 367 368 369
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;
}

370 371 372 373 374 375 376 377 378 379 380
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];
}

381
static gboolean
382
gtk_list_store_get_iter (GtkTreeModel *tree_model,
383
			 GtkTreeIter  *iter,
384 385
			 GtkTreePath  *path)
{
386 387 388
  GSList *list;
  gint i;
  
389
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
390 391 392 393 394 395
  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);  

  i = gtk_tree_path_get_indices (path)[0];

  if (i >= GTK_LIST_STORE (tree_model)->length)
    return FALSE;
396
  
397 398
  list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
                      i);
399

400 401 402 403 404 405
  /* If this fails, list_store->length has gotten mangled. */
  g_assert (list);
  
  iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
  iter->user_data = list;
  return TRUE;
406 407 408 409
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
410
			 GtkTreeIter  *iter)
411 412 413 414 415 416
{
  GtkTreePath *retval;
  GSList *list;
  gint i = 0;

  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
417
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
418 419 420

  for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
421
      if (list == G_SLIST (iter->user_data))
422
	break;
423
      i++;
424 425 426 427 428 429 430 431 432 433
    }
  if (list == NULL)
    return NULL;

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

static void
434 435 436 437
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
438 439 440 441 442 443
{
  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);
444
  g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
445

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

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

451 452 453 454 455 456
  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);
457 458 459
}

static gboolean
460 461
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
462
{
463 464
  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);
465

466 467 468 469 470 471 472
  if (G_SLIST (iter->user_data)->next)
    {
      iter->user_data = G_SLIST (iter->user_data)->next;
      return TRUE;
    }
  else
    return FALSE;
473 474
}

475
static gboolean
476
gtk_list_store_iter_children (GtkTreeModel *tree_model,
477 478
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
479
{
480
  /* this is a list, nodes have no children */
481
  if (parent)
482 483 484 485 486 487 488
    return FALSE;

  /* but if parent == NULL we return the list itself as children of the
   * "root"
   */
  
  if (GTK_LIST_STORE (tree_model)->root)
489 490 491 492 493
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      iter->user_data = GTK_LIST_STORE (tree_model)->root;
      return TRUE;
    }
494 495
  else
    return FALSE;
496 497 498
}

static gboolean
499
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
500
			       GtkTreeIter  *iter)
501 502 503 504 505
{
  return FALSE;
}

static gint
506
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
507
				GtkTreeIter  *iter)
508
{
509
  if (iter == NULL)
510 511 512
    return GTK_LIST_STORE (tree_model)->length;
  else
    return 0;
513 514
}

515
static gboolean
516
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
517 518
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
519
			       gint          n)
520
{
521 522
  GSList *child;
  
523
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
524

525
  if (parent)
526
    return FALSE;
527

528
  child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
529

530 531 532 533 534 535
  if (child)
    {
      iter->user_data = child;
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      return TRUE;
    }
536
  else
537
    return FALSE;
538 539
}

540 541 542 543
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
544
{
545
  return FALSE;
546 547
}

548
/* Public accessors */
549 550 551
/* This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
552 553 554 555 556 557 558 559 560 561 562 563 564

/**
 * gtk_list_store_set_cell:
 * @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.
 * 
 **/
565
void
566 567 568 569
gtk_list_store_set_cell (GtkListStore *list_store,
			 GtkTreeIter  *iter,
			 gint          column,
			 GValue       *value)
570 571 572 573 574 575
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
576
  g_return_if_fail (iter != NULL);
577 578
  g_return_if_fail (column >= 0 && column < list_store->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
579
  prev = list = G_SLIST (iter->user_data)->data;
580 581 582 583 584

  while (list != NULL)
    {
      if (column == 0)
	{
585
	  _gtk_tree_data_list_value_to_node (list, value);
586 587 588
	  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
				   "changed",
				   NULL, iter);
589 590 591 592 593 594 595 596
	  return;
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
597
  if (G_SLIST (iter->user_data)->data == NULL)
598
    {
Havoc Pennington's avatar
Havoc Pennington committed
599
      G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
600 601 602 603
      list->next = NULL;
    }
  else
    {
604
      list = prev->next = _gtk_tree_data_list_alloc ();
605 606 607 608 609
      list->next = NULL;
    }

  while (column != 0)
    {
610
      list->next = _gtk_tree_data_list_alloc ();
611 612 613 614
      list = list->next;
      list->next = NULL;
      column --;
    }
615 616 617 618
  _gtk_tree_data_list_value_to_node (list, value);
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "changed",
			   NULL, iter);
619 620
}

621 622 623 624 625 626 627 628 629 630
/**
 * 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.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
631 632 633
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
634
                           va_list	 var_args)
Havoc Pennington's avatar
Havoc Pennington committed
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
{
  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,
685
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
 * 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);
}

704 705 706 707 708 709 710 711 712 713
/**
 * gtk_list_store_get_valist:
 * @list_store: a #GtkListStore
 * @iter: a row in @list_store
 * @var_args: va_list of column/return location pairs
 *
 * See gtk_list_store_get(), this version takes a va_list for
 * language bindings to use.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
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);
    }
}

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
/**
 * gtk_list_store_get:
 * @list_store: a #GtkListStore
 * @iter: a row in @list_store
 * @Varargs: pairs of column number and value return locations, terminated by -1
 *
 * Gets 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 a place to store the value being
 * retrieved.  The list is terminated by a -1. For example, to get a
 * value from column 0 with type %G_TYPE_STRING, you would
 * write: gtk_list_store_set (store, iter, 0, &place_string_here, -1),
 * where place_string_here is a gchar* to be filled with the string.
 * If appropriate, the returned values have to be freed or unreferenced.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
772 773 774 775 776 777 778 779 780 781 782 783 784 785
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);
}

786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
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)
802 803 804
	    prev->next = link->next;

	  if (list == link)
805 806
	    list = list->next;

807
	  link->next = NULL;
808 809 810 811 812 813 814 815 816 817 818 819
	  break;
	}

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

  *prevp = prev;
  
  return list;
}

Havoc Pennington's avatar
Havoc Pennington committed
820 821 822 823
static void
gtk_list_store_remove_silently (GtkListStore *list_store,
                                GtkTreeIter  *iter,
                                GtkTreePath  *path)
824
{
Havoc Pennington's avatar
Havoc Pennington committed
825
  if (G_SLIST (iter->user_data)->data)
Havoc Pennington's avatar
Havoc Pennington committed
826 827 828 829 830
    {
      _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
                                list_store->column_headers);
      G_SLIST (iter->user_data)->data = NULL;
    }
831 832 833 834 835 836 837

  {
    GSList *prev = NULL;
    
    list_store->root = remove_link_saving_prev (G_SLIST (list_store->root),
                                                G_SLIST (iter->user_data),
                                                &prev);
838 839

    list_store->length -= 1;
840 841 842 843 844
    
    if (iter->user_data == list_store->tail)
      list_store->tail = prev;
  }
  
845
  list_store->stamp ++;
Havoc Pennington's avatar
Havoc Pennington committed
846 847
}

848 849 850 851 852 853 854 855 856
/**
 * 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.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
857 858 859 860 861 862 863 864
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));
865
  g_return_if_fail (iter->user_data != NULL);  
Havoc Pennington's avatar
Havoc Pennington committed
866 867 868

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

869 870
  validate_list_store (list_store);
  
Havoc Pennington's avatar
Havoc Pennington committed
871 872
  gtk_list_store_remove_silently (list_store, iter, path);

873 874
  validate_list_store (list_store);  
  
875 876 877 878
  gtk_signal_emit_by_name (GTK_OBJECT (list_store),
			   "deleted",
			   path);
  gtk_tree_path_free (path);
879 880
}

881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
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;
896 897

  list_store->length += 1;
898 899
}

900 901 902 903 904 905 906 907 908 909 910
/**
 * 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.
 * 
 **/
911 912 913 914
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
915 916
{
  GSList *list;
917
  GtkTreePath *path;
918 919
  GSList *new_list;
  
920 921 922
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
923
  g_return_if_fail (position >= 0);
924 925 926

  if (position == 0)
    {
927 928
      gtk_list_store_prepend (list_store, iter);
      return;
929 930
    }

931
  new_list = g_slist_alloc ();
932 933

  list = g_slist_nth (G_SLIST (list_store->root), position - 1);
934 935

  if (list == NULL)
936
    {
937 938
      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
      return;
939
    }
940 941 942 943 944

  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
945 946

  validate_list_store (list_store);
947
  
948 949 950 951 952 953
  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);
954 955
}

956 957 958 959 960 961 962 963 964 965 966
/**
 * 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.
 * 
 **/
967 968 969 970
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
971
{
972
  GtkTreePath *path;
973
  GSList *list, *prev, *new_list;
974 975 976 977 978
  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);
979 980

  if (sibling == NULL)
981 982 983 984
    {
      gtk_list_store_append (list_store, iter);
      return;
    }
985 986
  
  new_list = g_slist_alloc ();
987

988 989
  prev = NULL;
  list = list_store->root;
Havoc Pennington's avatar
Havoc Pennington committed
990
  while (list && list != sibling->user_data)
991 992 993 994 995
    {
      prev = list;
      list = list->next;
      i++;
    }
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009

  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;
1010 1011 1012
  
  if (prev)
    {
1013 1014
      new_list->next = prev->next;
      prev->next = new_list;
1015 1016 1017
    }
  else
    {
1018 1019
      new_list->next = list_store->root;
      list_store->root = new_list;
1020 1021
    }

1022 1023
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
1024 1025 1026 1027

  list_store->length += 1;

  validate_list_store (list_store);
1028
  
1029 1030 1031 1032 1033 1034
  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);
1035 1036
}

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
/**
 * 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.
 * 
 **/
1048 1049 1050 1051
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
1052
{
1053
  GtkTreePath *path;
1054
  GSList *list, *new_list;
1055 1056 1057 1058
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1059
  g_return_if_fail (iter != NULL);
1060 1061
  if (sibling)
    g_return_if_fail (sibling->stamp == list_store->stamp);
1062

1063 1064 1065 1066 1067 1068
  if (sibling == NULL)
    {
      gtk_list_store_prepend (list_store, iter);
      return;
    }

Havoc Pennington's avatar
Havoc Pennington committed
1069
  for (list = list_store->root; list && list != sibling->user_data; list = list->next)
1070 1071
    i++;

1072
  g_return_if_fail (list == sibling->user_data);
1073

1074
  new_list = g_slist_alloc ();
1075

1076 1077 1078 1079
  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
1080 1081

  validate_list_store (list_store);
1082
  
1083 1084 1085 1086 1087 1088
  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);
1089 1090
}

1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
/**
 * gtk_list_store_prepend:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with new row
 *
 * Prepends a row to @store, initializing @iter to point to the
 * new row, and emitting the "inserted" signal on the #GtkTreeModel
 * interface for the @store.
 * 
 **/
1101 1102 1103
void
gtk_list_store_prepend (GtkListStore *list_store,
			GtkTreeIter  *iter)
1104
{
1105 1106 1107 1108 1109
  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);
1110

1111
  iter->stamp = list_store->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
1112
  iter->user_data = g_slist_alloc ();
1113

1114 1115 1116
  if (list_store->root == NULL)
    list_store->tail = iter->user_data;
  
Havoc Pennington's avatar
Havoc Pennington committed
1117 1118
  G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
  list_store->root = iter->user_data;
1119

1120 1121 1122 1123
  list_store->length += 1;

  validate_list_store (list_store);
  
1124 1125 1126 1127 1128 1129
  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);
1130 1131
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
/**
 * gtk_list_store_append:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 *
 * Appends a row to @store, initializing @iter to point to the
 * new row, and emitting the "inserted" signal on the #GtkTreeModel
 * interface for the @store.
 * 
 **/
1142 1143 1144
void
gtk_list_store_append (GtkListStore *list_store,
		       GtkTreeIter  *iter)
1145
{
1146 1147 1148 1149 1150 1151 1152 1153
  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
1154
  iter->user_data = g_slist_alloc ();
1155

1156 1157
  if (list_store->tail)
    list_store->tail->next = iter->user_data;
1158
  else
Havoc Pennington's avatar
Havoc Pennington committed
1159
    list_store->root = iter->user_data;
1160

1161
  list_store->tail = iter->user_data;
1162 1163 1164 1165

  list_store->length += 1;

  validate_list_store (list_store);
1166