gtkliststore.c 74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 17
 */

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

31

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
/**
 * SECTION:gtkliststore
 * @Short_description: A list-like data structure that can be used with the GtkTreeView
 * @Title: GtkListStore
 * @See_also:#GtkTreeModel, #GtkTreeStore
 *
 * The #GtkListStore object is a list model for use with a #GtkTreeView
 * widget.  It implements the #GtkTreeModel interface, and consequentialy,
 * can use all of the methods available there.  It also implements the
 * #GtkTreeSortable interface so it can be sorted by the view.
 * Finally, it also implements the tree <link linkend="gtktreednd">drag and
 * drop</link> interfaces.
 *
 * The #GtkListStore can accept most GObject types as a column type, though
 * it can't accept all custom types.  Internally, it will keep a copy of
 * data passed in (such as a string or a boxed pointer).  Columns that
 * accept #GObject<!-- -->s are handled a little differently.  The
 * #GtkListStore will keep a reference to the object instead of copying the
 * value.  As a result, if the object is modified, it is up to the
 * application writer to call gtk_tree_model_row_changed() to emit the
 * #GtkTreeModel::row_changed signal.  This most commonly affects lists with
 * #GdkPixbuf<!-- -->s stored.
Benjamin Otte's avatar
Benjamin Otte committed
54
 *
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
 * <example>
 * <title>Creating a simple list store.</title>
 * <programlisting>
 * enum {
 *   COLUMN_STRING,
 *   COLUMN_INT,
 *   COLUMN_BOOLEAN,
 *   N_COLUMNS
 * };
 *
 * {
 *   GtkListStore *list_store;
 *   GtkTreePath *path;
 *   GtkTreeIter iter;
 *   gint i;
 *
 *   list_store = gtk_list_store_new (N_COLUMNS,
 *                                    G_TYPE_STRING,
 *                                    G_TYPE_INT,
 *                                    G_TYPE_BOOLEAN);
 *
 *   for (i = 0; i < 10; i++)
 *     {
 *       gchar *some_data;
 *
 *       some_data = get_some_data (i);
 *
 *       // Add a new row to the model
 *       gtk_list_store_append (list_store, &iter);
 *       gtk_list_store_set (list_store, &iter,
 *                           COLUMN_STRING, some_data,
 *                           COLUMN_INT, i,
 *                           COLUMN_BOOLEAN,  FALSE,
 *                           -1);
 *
 *       /<!---->* As the store will keep a copy of the string internally, we
 *        * free some_data.
 *        *<!---->/
 *       g_free (some_data);
 *     }
 *
 *   // Modify a particular row
 *   path = gtk_tree_path_new_from_string ("4");
 *   gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store),
 *                            &iter,
 *                            path);
 *   gtk_tree_path_free (path);
 *   gtk_list_store_set (list_store, &iter,
 *                       COLUMN_BOOLEAN, TRUE,
 *                       -1);
 * }
 * </programlisting>
 * </example>
Benjamin Otte's avatar
Benjamin Otte committed
108
 *
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
 * <refsect2>
 * <title>Performance Considerations</title>
 * Internally, the #GtkListStore was implemented with a linked list with a
 * tail pointer prior to GTK+ 2.6.  As a result, it was fast at data
 * insertion and deletion, and not fast at random data access.  The
 * #GtkListStore sets the #GTK_TREE_MODEL_ITERS_PERSIST flag, which means
 * that #GtkTreeIter<!-- -->s can be cached while the row exists.  Thus, if
 * access to a particular row is needed often and your code is expected to
 * run on older versions of GTK+, it is worth keeping the iter around.
 * </refsect2>
 * <refsect2>
 * <title>Atomic Operations</title>
 * It is important to note that only the methods
 * gtk_list_store_insert_with_values() and gtk_list_store_insert_with_valuesv()
 * are atomic, in the sense that the row is being appended to the store and the
 * values filled in in a single operation with regard to #GtkTreeModel signaling.
 * In contrast, using e.g. gtk_list_store_append() and then gtk_list_store_set()
 * will first create a row, which triggers the #GtkTreeModel::row-inserted signal
 * on #GtkListStore. The row, however, is still empty, and any signal handler
 * connecting to #GtkTreeModel::row-inserted on this particular store should be prepared
 * for the situation that the row might be empty. This is especially important
 * if you are wrapping the #GtkListStore inside a #GtkTreeModelFilter and are
 * using a #GtkTreeModelFilterVisibleFunc. Using any of the non-atomic operations
 * to append rows to the #GtkListStore will cause the
 * #GtkTreeModelFilterVisibleFunc to be visited with an empty row first; the
 * function must be prepared for that.
 * </refsect2>
 * <refsect2 id="GtkListStore-BUILDER-UI">
 * <title>GtkListStore as GtkBuildable</title>
 * <para>
 * The GtkListStore implementation of the GtkBuildable interface allows
 * to specify the model columns with a &lt;columns&gt; element that may
 * contain multiple &lt;column&gt; elements, each specifying one model
 * column. The "type" attribute specifies the data type for the column.
 *
 * Additionally, it is possible to specify content for the list store
 * in the UI definition, with the &lt;data&gt; element. It can contain
 * multiple &lt;row&gt; elements, each specifying to content for one
 * row of the list model. Inside a &lt;row&gt;, the &lt;col&gt; elements
 * specify the content for individual cells.
 *
 * Note that it is probably more common to define your models
 * in the code, and one might consider it a layering violation
 * to specify the content of a list store in a UI definition,
 * <emphasis>data</emphasis>, not <emphasis>presentation</emphasis>,
 * and common wisdom is to separate the two, as far as possible.
 * <!-- FIXME a bit inconclusive -->
 *
 * <example>
 * <title>A UI Definition fragment for a list store</title>
 * <programlisting><![CDATA[
 * <object class="GtkListStore">
 *   <columns>
 *     <column type="gchararray"/>
 *     <column type="gchararray"/>
 *     <column type="gint"/>
 *   </columns>
 *   <data>
 *     <row>
 *       <col id="0">John</col>
 *       <col id="1">Doe</col>
 *       <col id="2">25</col>
 *     </row>
 *     <row>
 *       <col id="0">Johan</col>
 *       <col id="1">Dahlin</col>
 *       <col id="2">50</col>
 *     </row>
 *   </data>
 * </object>
 * ]]></programlisting>
 * </example>
 * </para>
 * </refsect2>
 */


186
struct _GtkListStorePrivate
187 188 189 190 191 192 193 194 195 196 197 198
{
  GtkTreeIterCompareFunc default_sort_func;

  GDestroyNotify default_sort_destroy;
  GList *sort_list;
  GType *column_headers;

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

199 200
  GtkSortType order;

201 202 203 204 205 206 207
  guint columns_dirty : 1;

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

#define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->priv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
208
static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
209 210
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
211
static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
212
static void         gtk_list_store_buildable_init  (GtkBuildableIface      *iface);
213
static void         gtk_list_store_finalize        (GObject           *object);
214
static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
215
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
216 217
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
218 219 220 221 222 223 224 225 226 227 228
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);
229 230
static gboolean     gtk_list_store_iter_previous   (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
231 232 233 234 235 236 237 238 239 240 241 242 243 244
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);
245

246

247 248 249 250 251 252
static void gtk_list_store_set_n_columns   (GtkListStore *list_store,
					    gint          n_columns);
static void gtk_list_store_set_column_type (GtkListStore *list_store,
					    gint          column,
					    GType         type);

253 254
static void gtk_list_store_increment_stamp (GtkListStore *list_store);

255

256
/* Drag and Drop */
Murray Cumming's avatar
Murray Cumming committed
257 258
static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
259 260 261 262 263 264 265 266
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);
267
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
268 269
                                                   GtkTreePath       *dest_path,
						   GtkSelectionData  *selection_data);
270

271

272
/* sortable */
273 274 275 276 277 278 279 280 281 282 283 284 285 286
static void     gtk_list_store_sort                  (GtkListStore           *list_store);
static void     gtk_list_store_sort_iter_changed     (GtkListStore           *list_store,
						      GtkTreeIter            *iter,
						      gint                    column);
static gboolean gtk_list_store_get_sort_column_id    (GtkTreeSortable        *sortable,
						      gint                   *sort_column_id,
						      GtkSortType            *order);
static void     gtk_list_store_set_sort_column_id    (GtkTreeSortable        *sortable,
						      gint                    sort_column_id,
						      GtkSortType             order);
static void     gtk_list_store_set_sort_func         (GtkTreeSortable        *sortable,
						      gint                    sort_column_id,
						      GtkTreeIterCompareFunc  func,
						      gpointer                data,
287
						      GDestroyNotify          destroy);
288 289 290
static void     gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
						      GtkTreeIterCompareFunc  func,
						      gpointer                data,
291
						      GDestroyNotify          destroy);
292 293
static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable        *sortable);

294

295 296 297 298 299 300 301 302 303 304 305 306 307
/* buildable */
static gboolean gtk_list_store_buildable_custom_tag_start (GtkBuildable  *buildable,
							   GtkBuilder    *builder,
							   GObject       *child,
							   const gchar   *tagname,
							   GMarkupParser *parser,
							   gpointer      *data);
static void     gtk_list_store_buildable_custom_tag_end (GtkBuildable *buildable,
							 GtkBuilder   *builder,
							 GObject      *child,
							 const gchar  *tagname,
							 gpointer     *data);

Matthias Clasen's avatar
Matthias Clasen committed
308 309 310 311 312 313 314 315
G_DEFINE_TYPE_WITH_CODE (GtkListStore, gtk_list_store, G_TYPE_OBJECT,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
						gtk_list_store_tree_model_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
						gtk_list_store_drag_source_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST,
						gtk_list_store_drag_dest_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
316 317 318 319
						gtk_list_store_sortable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_list_store_buildable_init))

320 321 322 323

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
324 325 326
  GObjectClass *object_class;

  object_class = (GObjectClass*) class;
327 328

  object_class->finalize = gtk_list_store_finalize;
329

330
  g_type_class_add_private (class, sizeof (GtkListStorePrivate));
331 332 333 334 335
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
336
  iface->get_flags = gtk_list_store_get_flags;
337
  iface->get_n_columns = gtk_list_store_get_n_columns;
338
  iface->get_column_type = gtk_list_store_get_column_type;
339
  iface->get_iter = gtk_list_store_get_iter;
340
  iface->get_path = gtk_list_store_get_path;
341
  iface->get_value = gtk_list_store_get_value;
342
  iface->iter_next = gtk_list_store_iter_next;
343
  iface->iter_previous = gtk_list_store_iter_previous;
344 345 346 347 348
  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;
349 350
}

351 352 353
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
Murray Cumming's avatar
Murray Cumming committed
354
  iface->row_draggable = real_gtk_list_store_row_draggable;
355 356 357 358 359
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
360
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
361 362
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
363
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
364 365
}

366 367 368 369 370
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;
371
  iface->set_sort_func = gtk_list_store_set_sort_func;
372 373
  iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
  iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
374 375
}

376 377 378 379 380 381 382
void
gtk_list_store_buildable_init (GtkBuildableIface *iface)
{
  iface->custom_tag_start = gtk_list_store_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_list_store_buildable_custom_tag_end;
}

383 384 385
static void
gtk_list_store_init (GtkListStore *list_store)
{
386
  GtkListStorePrivate *priv;
387 388 389

  list_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (list_store,
                                                  GTK_TYPE_LIST_STORE,
390
                                                  GtkListStorePrivate);
391 392 393 394 395 396 397 398
  priv = list_store->priv;

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

401 402 403 404 405 406 407 408 409 410 411
static gboolean
iter_is_valid (GtkTreeIter  *iter,
               GtkListStore *list_store)
{
  return iter != NULL && 
         iter->user_data != NULL &&
         list_store->priv->stamp == iter->stamp &&
         !g_sequence_iter_is_end (iter->user_data) &&
         g_sequence_iter_get_sequence (iter->user_data) == list_store->priv->seq;
}

412 413 414
/**
 * gtk_list_store_new:
 * @n_columns: number of columns in the list store
Matthias Clasen's avatar
Matthias Clasen committed
415
 * @...: all #GType types for the columns, from first to last
416
 *
417
 * Creates a new list store as with @n_columns columns each of the types passed
Matthias Clasen's avatar
Matthias Clasen committed
418 419
 * in.  Note that only types derived from standard GObject fundamental types
 * are supported.
420
 *
421
 * As an example, <literal>gtk_list_store_new (3, G_TYPE_INT, G_TYPE_STRING,
Matthias Clasen's avatar
Matthias Clasen committed
422 423
 * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
 * int, string and #GdkPixbuf respectively.
424
 *
425
 * Return value: a new #GtkListStore
Matthias Clasen's avatar
Matthias Clasen committed
426
 */
427
GtkListStore *
428
gtk_list_store_new (gint n_columns,
Soeren Sandmann's avatar
Soeren Sandmann committed
429
		    ...)
430
{
431
  GtkListStore *retval;
432 433 434 435 436
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
437
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
438
  gtk_list_store_set_n_columns (retval, n_columns);
439 440

  va_start (args, n_columns);
441

442
  for (i = 0; i < n_columns; i++)
443 444 445
    {
      GType type = va_arg (args, GType);
      if (! _gtk_tree_data_list_check_type (type))
446 447 448 449 450 451 452
        {
          g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
          g_object_unref (retval);
          va_end (args);

          return NULL;
        }
453 454 455

      gtk_list_store_set_column_type (retval, i, type);
    }
456 457 458 459 460 461

  va_end (args);

  return retval;
}

462 463 464 465

/**
 * gtk_list_store_newv:
 * @n_columns: number of columns in the list store
466
 * @types: (array length=n_columns): an array of #GType types for the columns, from first to last
467
 *
Matthias Clasen's avatar
Matthias Clasen committed
468
 * Non-vararg creation function.  Used primarily by language bindings.
469
 *
470
 * Return value: (transfer full): a new #GtkListStore
471
 * Rename to: gtk_list_store_new
472 473 474 475 476 477 478 479 480 481
 **/
GtkListStore *
gtk_list_store_newv (gint   n_columns,
		     GType *types)
{
  GtkListStore *retval;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
482
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
483 484 485 486 487 488
  gtk_list_store_set_n_columns (retval, n_columns);

  for (i = 0; i < n_columns; i++)
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
489
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
Manish Singh's avatar
Manish Singh committed
490
	  g_object_unref (retval);
491 492 493 494 495 496 497 498 499
	  return NULL;
	}

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

  return retval;
}

500 501 502 503
/**
 * gtk_list_store_set_column_types:
 * @list_store: A #GtkListStore
 * @n_columns: Number of columns for the list store
504 505
 * @types: (array length=n_columns): An array length n of #GTypes
 *
Matthias Clasen's avatar
Matthias Clasen committed
506 507 508
 * This function is meant primarily for #GObjects that inherit from #GtkListStore,
 * and should only be used when constructing a new #GtkListStore.  It will not
 * function after a row has been added, or a method on the #GtkTreeModel
509 510 511 512 513 514 515
 * interface is called.
 **/
void
gtk_list_store_set_column_types (GtkListStore *list_store,
				 gint          n_columns,
				 GType        *types)
{
516
  GtkListStorePrivate *priv;
517 518 519
  gint i;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
520 521 522 523

  priv = list_store->priv;

  g_return_if_fail (priv->columns_dirty == 0);
524 525

  gtk_list_store_set_n_columns (list_store, n_columns);
526
  for (i = 0; i < n_columns; i++)
527 528 529
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
530
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
531 532 533 534 535 536
	  continue;
	}
      gtk_list_store_set_column_type (list_store, i, types[i]);
    }
}

537
static void
538 539 540
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
541
  GtkListStorePrivate *priv = list_store->priv;
542
  int i;
543

544
  if (priv->n_columns == n_columns)
545 546
    return;

547 548 549 550
  priv->column_headers = g_renew (GType, priv->column_headers, n_columns);
  for (i = priv->n_columns; i < n_columns; i++)
    priv->column_headers[i] = G_TYPE_INVALID;
  priv->n_columns = n_columns;
551

552 553 554
  if (priv->sort_list)
    _gtk_tree_data_list_header_free (priv->sort_list);
  priv->sort_list = _gtk_tree_data_list_header_new (n_columns, priv->column_headers);
555 556
}

557
static void
558 559 560 561
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
562
  GtkListStorePrivate *priv = list_store->priv;
563

564 565
  if (!_gtk_tree_data_list_check_type (type))
    {
566
      g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
567 568
      return;
    }
569

570
  priv->column_headers[column] = type;
571 572
}

573 574 575 576
static void
gtk_list_store_finalize (GObject *object)
{
  GtkListStore *list_store = GTK_LIST_STORE (object);
577
  GtkListStorePrivate *priv = list_store->priv;
578

579 580
  g_sequence_foreach (priv->seq,
		      (GFunc) _gtk_tree_data_list_free, priv->column_headers);
Soeren Sandmann's avatar
Soeren Sandmann committed
581

582
  g_sequence_free (priv->seq);
583

584 585 586 587
  _gtk_tree_data_list_header_free (priv->sort_list);
  g_free (priv->column_headers);

  if (priv->default_sort_destroy)
588
    {
589
      GDestroyNotify d = priv->default_sort_destroy;
590

591 592 593
      priv->default_sort_destroy = NULL;
      d (priv->default_sort_data);
      priv->default_sort_data = NULL;
594
    }
595

596
  G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize (object);
597 598
}

599
/* Fulfill the GtkTreeModel requirements */
600
static GtkTreeModelFlags
601 602
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
603
  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
604 605
}

606 607 608
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
609
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
610
  GtkListStorePrivate *priv = list_store->priv;
611

612
  priv->columns_dirty = TRUE;
613

614
  return priv->n_columns;
615 616
}

617 618 619 620
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
621
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
622
  GtkListStorePrivate *priv = list_store->priv;
623

624
  g_return_val_if_fail (index < priv->n_columns, G_TYPE_INVALID);
625

626
  priv->columns_dirty = TRUE;
627

628
  return priv->column_headers[index];
629 630
}

631
static gboolean
632
gtk_list_store_get_iter (GtkTreeModel *tree_model,
633
			 GtkTreeIter  *iter,
634 635
			 GtkTreePath  *path)
{
636
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
637
  GtkListStorePrivate *priv = list_store->priv;
638
  GSequence *seq;
639
  gint i;
640

641 642 643
  priv->columns_dirty = TRUE;

  seq = priv->seq;
644

645
  i = gtk_tree_path_get_indices (path)[0];
646

647
  if (i >= g_sequence_get_length (seq))
648 649 650 651
    {
      iter->stamp = 0;
      return FALSE;
    }
652

653
  iter->stamp = priv->stamp;
654
  iter->user_data = g_sequence_get_iter_at_pos (seq, i);
655

656
  return TRUE;
657 658 659 660
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
661
			 GtkTreeIter  *iter)
662
{
663
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
664
  GtkListStorePrivate *priv = list_store->priv;
Soeren Sandmann's avatar
Soeren Sandmann committed
665
  GtkTreePath *path;
666

667
  g_return_val_if_fail (iter->stamp == priv->stamp, NULL);
668

669
  if (g_sequence_iter_is_end (iter->user_data))
670
    return NULL;
Soeren Sandmann's avatar
Soeren Sandmann committed
671 672
	
  path = gtk_tree_path_new ();
673
  gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
Soeren Sandmann's avatar
Soeren Sandmann committed
674 675
  
  return path;
676 677 678
}

static void
679 680 681 682
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
683
{
684
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
685
  GtkListStorePrivate *priv = list_store->priv;
686 687 688
  GtkTreeDataList *list;
  gint tmp_column = column;

689
  g_return_if_fail (column < priv->n_columns);
690
  g_return_if_fail (iter_is_valid (iter, list_store));
Soeren Sandmann's avatar
Soeren Sandmann committed
691
		    
692
  list = g_sequence_get (iter->user_data);
693 694 695 696

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

697
  if (list == NULL)
698
    g_value_init (value, priv->column_headers[column]);
699 700
  else
    _gtk_tree_data_list_node_to_value (list,
701
				       priv->column_headers[column],
702
				       value);
703 704 705
}

static gboolean
706 707
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
708
{
709
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
710
  GtkListStorePrivate *priv = list_store->priv;
711 712
  gboolean retval;

713
  g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);
714
  iter->user_data = g_sequence_iter_next (iter->user_data);
715

716 717 718 719 720
  retval = g_sequence_iter_is_end (iter->user_data);
  if (retval)
    iter->stamp = 0;

  return !retval;
721 722
}

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
static gboolean
gtk_list_store_iter_previous (GtkTreeModel *tree_model,
                              GtkTreeIter  *iter)
{
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
  GtkListStorePrivate *priv = list_store->priv;

  g_return_val_if_fail (priv->stamp == iter->stamp, FALSE);

  if (g_sequence_iter_is_begin (iter->user_data))
    {
      iter->stamp = 0;
      return FALSE;
    }

  iter->user_data = g_sequence_iter_prev (iter->user_data);

  return TRUE;
}

743
static gboolean
744
gtk_list_store_iter_children (GtkTreeModel *tree_model,
745 746
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
747
{
748
  GtkListStore *list_store = (GtkListStore *) tree_model;
749
  GtkListStorePrivate *priv = list_store->priv;
750

751
  /* this is a list, nodes have no children */
752
  if (parent)
753 754 755 756
    {
      iter->stamp = 0;
      return FALSE;
    }
757

758
  if (g_sequence_get_length (priv->seq) > 0)
759
    {
760 761
      iter->stamp = priv->stamp;
      iter->user_data = g_sequence_get_begin_iter (priv->seq);
762 763
      return TRUE;
    }
764
  else
765 766 767 768
    {
      iter->stamp = 0;
      return FALSE;
    }
769 770 771
}

static gboolean
772
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
773
			       GtkTreeIter  *iter)
774 775 776 777 778
{
  return FALSE;
}

static gint
779
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
780
				GtkTreeIter  *iter)
781
{
782
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
783
  GtkListStorePrivate *priv = list_store->priv;
Soeren Sandmann's avatar
Soeren Sandmann committed
784

785
  if (iter == NULL)
786
    return g_sequence_get_length (priv->seq);
787

788
  g_return_val_if_fail (priv->stamp == iter->stamp, -1);
789 790

  return 0;
791 792
}

793
static gboolean
794
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
795 796
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
797
			       gint          n)
798
{
799
  GtkListStore *list_store = GTK_LIST_STORE (tree_model);
800
  GtkListStorePrivate *priv = list_store->priv;
801
  GSequenceIter *child;
802

803 804
  iter->stamp = 0;

805
  if (parent)
806
    return FALSE;
807

808
  child = g_sequence_get_iter_at_pos (priv->seq, n);
809

810
  if (g_sequence_iter_is_end (child))
811
    return FALSE;
Soeren Sandmann's avatar
Soeren Sandmann committed
812

813
  iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
814
  iter->user_data = child;
815

Soeren Sandmann's avatar
Soeren Sandmann committed
816
  return TRUE;
817 818
}

819 820 821 822
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
823
{
824
  iter->stamp = 0;
825
  return FALSE;
826 827
}

828
static gboolean
829 830 831
gtk_list_store_real_set_value (GtkListStore *list_store,
			       GtkTreeIter  *iter,
			       gint          column,
832 833
			       GValue       *value,
			       gboolean      sort)
834
{
835
  GtkListStorePrivate *priv = list_store->priv;
836 837
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
838
  gint old_column = column;
Javier Jardón's avatar
Javier Jardón committed
839
  GValue real_value = G_VALUE_INIT;
840
  gboolean converted = FALSE;
841
  gboolean retval = FALSE;
842

843
  if (! g_type_is_a (G_VALUE_TYPE (value), priv->column_headers[column]))
844
    {
845
      if (! (g_value_type_transformable (G_VALUE_TYPE (value), priv->column_headers[column])))
846 847 848 849
	{
	  g_warning ("%s: Unable to convert from %s to %s\n",
		     G_STRLOC,
		     g_type_name (G_VALUE_TYPE (value)),
850
		     g_type_name (priv->column_headers[column]));
851
	  return retval;
852
	}
853 854

      g_value_init (&real_value, priv->column_headers[column]);
855 856 857 858 859
      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)),
860
		     g_type_name (priv->column_headers[column]));
861
	  g_value_unset (&real_value);
862
	  return retval;
863 864 865
	}
      converted = TRUE;
    }
866

867
  prev = list = g_sequence_get (iter->user_data);
868 869 870 871 872

  while (list != NULL)
    {
      if (column == 0)
	{
873 874 875 876
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
877
	  retval = TRUE;
878 879
	  if (converted)
	    g_value_unset (&real_value);
880 881
         if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
            gtk_list_store_sort_iter_changed (list_store, iter, old_column);
882
	  return retval;
883 884 885 886 887 888 889
	}

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

890
  if (g_sequence_get (iter->user_data) == NULL)
891
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
892
      list = _gtk_tree_data_list_alloc();
893
      g_sequence_set (iter->user_data, list);
894 895 896 897
      list->next = NULL;
    }
  else
    {
898
      list = prev->next = _gtk_tree_data_list_alloc ();
899 900 901 902 903
      list->next = NULL;
    }

  while (column != 0)
    {
904
      list->next = _gtk_tree_data_list_alloc ();
905 906 907 908
      list = list->next;
      list->next = NULL;
      column --;
    }
909

910
  if (converted)
911
    _gtk_tree_data_list_value_to_node (list, &real_value);
912 913
  else
    _gtk_tree_data_list_value_to_node (list, value);
914

915
  retval = TRUE;
916 917
  if (converted)
    g_value_unset (&real_value);
918

919
  if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
920
    gtk_list_store_sort_iter_changed (list_store, iter, old_column);
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943

  return retval;
}


/**
 * gtk_list_store_set_value:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
 * @column: column number to modify
 * @value: new value for the cell
 *
 * Sets the data in the cell specified by @iter and @column.
 * The type of @value must be convertible to the type of the
 * column.
 *
 **/
void
gtk_list_store_set_value (GtkListStore *list_store,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
{
944
  GtkListStorePrivate *priv;
945

946
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
947
  g_return_if_fail (iter_is_valid (iter, list_store));
948
  g_return_if_fail (G_IS_VALUE (value));
949 950
  priv = list_store->priv;
  g_return_if_fail (column >= 0 && column < priv->n_columns);
951

952
  if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
953 954 955
    {
      GtkTreePath *path;

956
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
957 958 959
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
960 961
}

962 963
static GtkTreeIterCompareFunc
gtk_list_store_get_compare_func (GtkListStore *list_store)
Havoc Pennington's avatar
Havoc Pennington committed
964
{
965
  GtkListStorePrivate *priv = list_store->priv;
966
  GtkTreeIterCompareFunc func = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
967

968
  if (GTK_LIST_STORE_IS_SORTED (list_store))
969
    {
970
      if (priv->sort_column_id != -1)
971 972
	{
	  GtkTreeDataSortHeader *header;
973 974
	  header = _gtk_tree_data_list_get_header (priv->sort_list,
						   priv->sort_column_id);
975 976
	  g_return_val_if_fail (header != NULL, NULL);
	  g_return_val_if_fail (header->func != NULL, NULL);
977 978 979 980
	  func = header->func;
	}
      else
	{
981
	  func = priv->default_sort_func;
982
	}
983 984
    }

985 986 987
  return func;
}

988 989 990 991 992 993 994 995 996
static void
gtk_list_store_set_vector_internal (GtkListStore *list_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    gint         *columns,
				    GValue       *values,
				    gint          n_values)
{
997
  GtkListStorePrivate *priv = list_store->priv;
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
  gint i;
  GtkTreeIterCompareFunc func = NULL;

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

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

      if (func == _gtk_tree_data_list_compare_func &&
1014
	  columns[i] == priv->sort_column_id)
1015 1016 1017 1018
	*maybe_need_sort = TRUE;
    }
}

1019 1020 1021 1022 1023 1024 1025
static void
gtk_list_store_set_valist_internal (GtkListStore *list_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    va_list	  var_args)
{
1026
  GtkListStorePrivate *priv = list_store->priv;
1027 1028 1029 1030 1031 1032
  gint column;
  GtkTreeIterCompareFunc func = NULL;

  column = va_arg (var_args, gint);

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

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

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

1047 1048
      G_VALUE_COLLECT_INIT (&value, priv->column_headers[column],
                            var_args, 0, &error);
Havoc Pennington's avatar
Havoc Pennington committed
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
      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
1060
      /* FIXME: instead of calling this n times, refactor with above */
1061 1062 1063 1064 1065 1066
      *emit_signal = gtk_list_store_real_set_value (list_store,
						    iter,
						    column,
						    &value,
						    FALSE) || *emit_signal;
      
1067
      if (func == _gtk_tree_data_list_compare_func &&
1068
	  column == priv->sort_column_id)
1069
	*maybe_need_sort = TRUE;
Havoc Pennington's avatar
Havoc Pennington committed
1070 1071 1072 1073 1074

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
1075 1076
}

1077 1078 1079 1080
/**
 * gtk_list_store_set_valuesv:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
1081 1082
 * @columns: (array length=n_values): an array of column numbers
 * @values: (array length=n_values): an array of GValues
1083
 * @n_values: the length of the @columns and @values arrays
1084
 *
1085 1086 1087 1088 1089 1090 1091
 * A variant of gtk_list_store_set_valist() which
 * takes the columns and values as two arrays, instead of
 * varargs. This function is mainly intended for 
 * language-bindings and in case the number of columns to
 * change is not known until run-time.
 *
 * Since: 2.12
1092
 * Rename to: gtk_list_store_set
1093 1094 1095 1096 1097 1098 1099 1100
 */
void
gtk_list_store_set_valuesv (GtkListStore *list_store,
			    GtkTreeIter  *iter,
			    gint         *columns,
			    GValue       *values,
			    gint          n_values)
{
1101
  GtkListStorePrivate *priv;
1102 1103 1104 1105
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1106
  g_return_if_fail (iter_is_valid (iter, list_store));
1107

1108 1109
  priv = list_store->priv;

1110 1111 1112 1113 1114 1115
  gtk_list_store_set_vector_internal (list_store, iter,
				      &emit_signal,
				      &maybe_need_sort,
				      columns, values, n_values);

  if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
1116
    gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127

  if (emit_signal)
    {
      GtkTreePath *path;

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

1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
/**
 * gtk_list_store_set_valist:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
 * @var_args: va_list of column/value pairs
 *
 * See gtk_list_store_set(); this version takes a va_list for use by language
 * bindings.
 *
 **/
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
                           va_list	 var_args)
{
1143
  GtkListStorePrivate *priv;
1144 1145 1146 1147
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1148
  g_return_if_fail (iter_is_valid (iter, list_store));
1149

1150 1151
  priv = list_store->priv;

1152 1153 1154 1155
  gtk_list_store_set_valist_internal (list_store, iter, 
				      &emit_signal, 
				      &maybe_need_sort,
				      var_args);
1156

1157
  if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
1158
    gtk_list_store_sort_iter_changed (list_store, iter, priv->sort_column_id);
1159

1160 1161 1162 1163
  if (emit_signal)
    {
      GtkTreePath *path;

1164
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
1165 1166 1167
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
Havoc Pennington's avatar
Havoc Pennington committed
1168 1169 1170 1171 1172 1173
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
Matthias Clasen's avatar
Matthias Clasen committed
1174
 * @...: pairs of column number and value, terminated with -1
1175
 *
Havoc Pennington's avatar
Havoc Pennington committed
1176 1177
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
1178
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
1179
 * The list is terminated by a -1. For example, to set column 0 with type
Matthias Clasen's avatar
Matthias Clasen committed
1180 1181
 * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
 * 0, "Foo", -1)</literal>.
1182 1183 1184
 *
 * The value will be referenced by the store if it is a %G_TYPE_OBJECT, and it
 * will be copied if it is a %G_TYPE_STRING or %G_TYPE_BOXED.
Matthias Clasen's avatar
Matthias Clasen committed
1185
 */
Havoc Pennington's avatar
Havoc Pennington committed
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
void
gtk_list_store_set (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

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

1198 1199
/**
 * gtk_list_store_remove:
1200 1201
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter
1202
 *
Matthias Clasen's avatar
Matthias Clasen committed
1203 1204 1205
 * Removes the given row from the list store.  After being removed, 
 * @iter is set to be the next valid row, or invalidated if it pointed 
 * to the last row in @list_store.
1206
 *
Kristian Rietveld's avatar
Kristian Rietveld committed
1207
 * Return value: %TRUE if @iter is valid, %FALSE if not.
1208
 **/
Kristian Rietveld's avatar
Kristian Rietveld committed
1209
gboolean
1210 1211 1212
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
1213
  GtkListStorePrivate *priv;
1214
  GtkTreePath *path;
1215
  GSequenceIter *ptr, *next;
1216

Kristian Rietveld's avatar
Kristian Rietveld committed
1217
  g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
1218
  g_return_val_if_fail (iter_is_valid (iter, list_store), FALSE);
1219

1220 1221
  priv = list_store->priv;

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

Soeren Sandmann's avatar
Soeren Sandmann committed
1224
  ptr = iter->user_data;
1225
  next = g_sequence_iter_next (ptr);
Soeren Sandmann's avatar
Soeren Sandmann committed
1226
  
1227
  _gtk_tree_data_list_free (g_sequence_get (ptr), priv->column_headers);
1228
  g_sequence_remove (iter->user_data);
1229

1230
  priv->length--;
Soeren Sandmann's avatar
Soeren Sandmann committed
1231
  
1232
  gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
1233
  gtk_tree_path_free (path);
1234

1235
  if (g_sequence_iter_is_end (next))
1236
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
1237 1238
      iter->stamp = 0;
      return FALSE;
1239 1240 1241
    }
  else
    {
1242
      iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
1243 1244
      iter->user_data = next;
      return TRUE;
1245
    }
1246 1247
}

1248 1249
/**
 * gtk_list_store_insert:
1250
 * @list_store: A #GtkListStore
1251
 * @iter: (out): An unset #GtkTreeIter to set to the new row
1252
 * @position: position to insert the new row, or -1 for last
1253
 *
1254
 * Creates a new row at @position.  @iter will be changed to point to this new
1255 1256 1257
 * row.  If @position is -1 or is larger than the number of rows on the list,
 * then the new row will be appended to the list. The row will be empty after
 * this function is called.  To fill in values, you need to call
1258
 * gtk_list_store_set() or gtk_list_store_set_value().
1259
 *
1260
 **/
1261 1262 1263 1264
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
1265
{
1266
  GtkListStorePrivate *priv;
1267
  GtkTreePath *path;
1268 1269
  GSequence *seq;
  GSequenceIter *ptr;
1270
  gint length;
1271

1272 1273
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1274

1275
  priv = list_store->priv;
1276

1277 1278 1279
  priv->columns_dirty = TRUE;

  seq = priv->seq;
1280

1281
  length = g_sequence_get_length (seq);
1282
  if (position > length || position < 0)
1283 1284
    position = length;

1285 1286
  ptr = g_sequence_get_iter_at_pos (seq, position);
  ptr = g_sequence_insert_before (ptr, NULL);
1287

1288
  iter->stamp = priv->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
1289
  iter->user_data = ptr;
1290

1291
  g_assert (iter_is_valid (iter, list_store));
1292

1293
  priv->length++;
1294
  
1295 1296
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
1297
  gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1298
  gtk_tree_path_free (path);
1299 1300
}

1301 1302
/**
 * gtk_list_store_insert_before:
1303
 * @list_store: A #GtkListStore
1304
 * @iter: (out): An unset #GtkTreeIter to set to the new row