gtktreemodel.c 76.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* gtktreemodel.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 <stdlib.h>
#include <string.h>
21
#include <glib.h>
22
#include <glib/gprintf.h>
23
#include <gobject/gvaluecollector.h>
24
#include "gtktreemodel.h"
Jonathan Blandford's avatar
Jonathan Blandford committed
25 26
#include "gtktreeview.h"
#include "gtktreeprivate.h"
27
#include "gtkmarshalers.h"
Matthias Clasen's avatar
Matthias Clasen committed
28
#include "gtkintl.h"
Jonathan Blandford's avatar
Jonathan Blandford committed
29

30 31 32 33 34
/**
 * SECTION:gtktreemodel
 * @Title: GtkTreeModel
 * @Short_description: The tree interface used by GtkTreeView
 * @See_also: #GtkTreeView, #GtkTreeStore, #GtkListStore,
35
 *     <link linkend="gtk3-GtkTreeView-drag-and-drop">GtkTreeView drag-and-drop</link>
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 *     #GtkTreeSortable
 *
 * The #GtkTreeModel interface defines a generic tree interface for
 * use by the #GtkTreeView widget. It is an abstract interface, and
 * is designed to be usable with any appropriate data structure. The
 * programmer just has to implement this interface on their own data
 * type for it to be viewable by a #GtkTreeView widget.
 *
 * The model is represented as a hierarchical tree of strongly-typed,
 * columned data. In other words, the model can be seen as a tree where
 * every node has different values depending on which column is being
 * queried. The type of data found in a column is determined by using
 * the GType system (ie. #G_TYPE_INT, #GTK_TYPE_BUTTON, #G_TYPE_POINTER,
 * etc). The types are homogeneous per column across all nodes. It is
 * important to note that this interface only provides a way of examining
 * a model and observing changes. The implementation of each individual
 * model decides how and if changes are made.
 *
 * In order to make life simpler for programmers who do not need to
 * write their own specialized model, two generic models are provided
 * &mdash; the #GtkTreeStore and the #GtkListStore. To use these, the
 * developer simply pushes data into these models as necessary. These
 * models provide the data structure as well as all appropriate tree
 * interfaces. As a result, implementing drag and drop, sorting, and
 * storing data is trivial. For the vast majority of trees and lists,
 * these two models are sufficient.
 *
 * Models are accessed on a node/column level of granularity. One can
 * query for the value of a model at a certain node and a certain
 * column on that node. There are two structures used to reference
66
 * a particular node in a model. They are the #GtkTreePath-struct and the
William Jon McCann's avatar
William Jon McCann committed
67 68
 * #GtkTreeIter-struct (<abbrev>iter</abbrev> is short
 * for <quote>iterator</quote>). Most of the interface
69
 * consists of operations on a #GtkTreeIter-struct.
70 71 72
 *
 * A path is essentially a potential node. It is a location on a model
 * that may or may not actually correspond to a node on a specific
73
 * model. The #GtkTreePath-struct can be converted into either an
74 75 76 77 78 79
 * array of unsigned integers or a string. The string form is a list
 * of numbers separated by a colon. Each number refers to the offset
 * at that level. Thus, the path <quote>0</quote> refers to the root
 * node and the path <quote>2:4</quote> refers to the fifth child of
 * the third node.
 *
80
 * By contrast, a #GtkTreeIter-struct is a reference to a specific node on
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 108 109 110 111 112 113 114 115 116 117
 * a specific model. It is a generic struct with an integer and three
 * generic pointers. These are filled in by the model in a model-specific
 * way. One can convert a path to an iterator by calling
 * gtk_tree_model_get_iter(). These iterators are the primary way
 * of accessing a model and are similar to the iterators used by
 * #GtkTextBuffer. They are generally statically allocated on the
 * stack and only used for a short time. The model interface defines
 * a set of operations using them for navigating the model.
 *
 * It is expected that models fill in the iterator with private data.
 * For example, the #GtkListStore model, which is internally a simple
 * linked list, stores a list node in one of the pointers. The
 * #GtkTreeModelSort stores an array and an offset in two of the
 * pointers. Additionally, there is an integer field. This field is
 * generally filled with a unique stamp per model. This stamp is for
 * catching errors resulting from using invalid iterators with a model.
 *
 * The lifecycle of an iterator can be a little confusing at first.
 * Iterators are expected to always be valid for as long as the model
 * is unchanged (and doesn't emit a signal). The model is considered
 * to own all outstanding iterators and nothing needs to be done to
 * free them from the user's point of view. Additionally, some models
 * guarantee that an iterator is valid for as long as the node it refers
 * to is valid (most notably the #GtkTreeStore and #GtkListStore).
 * Although generally uninteresting, as one always has to allow for
 * the case where iterators do not persist beyond a signal, some very
 * important performance enhancements were made in the sort model.
 * As a result, the #GTK_TREE_MODEL_ITERS_PERSIST flag was added to
 * indicate this behavior.
 *
 * To help show some common operation of a model, some examples are
 * provided. The first example shows three ways of getting the iter at
 * the location <quote>3:2:5</quote>. While the first method shown is
 * easier, the second is much more common, as you often get paths from
 * callbacks.
 *
 * <example>
118
 * <title>Acquiring a #GtkTreeIter-struct</title>
119
 * |[<!-- language="C" -->
120 121 122 123 124 125
 *  /&ast; Three ways of getting the iter pointing to the location &ast;/
 * GtkTreePath *path;
 * GtkTreeIter iter;
 * GtkTreeIter parent_iter;
 *
 * /&ast; get the iterator from a string &ast;/
126
 * gtk_tree_model_get_iter_from_string (model, &iter, "3:2:5");
127 128 129
 *
 * /&ast; get the iterator from a path &ast;/
 * path = gtk_tree_path_new_from_string ("3:2:5");
130
 * gtk_tree_model_get_iter (model, &iter, path);
131 132 133
 * gtk_tree_path_free (path);
 *
 * /&ast; walk the tree to find the iterator &ast;/
134
 * gtk_tree_model_iter_nth_child (model, &iter, NULL, 3);
135
 * parent_iter = iter;
136
 * gtk_tree_model_iter_nth_child (model, &iter, &parent_iter, 2);
137
 * parent_iter = iter;
138
 * gtk_tree_model_iter_nth_child (model, &iter, &parent_iter, 5);
139
 * ]|
140 141 142 143
 * </example>
 *
 * This second example shows a quick way of iterating through a list
 * and getting a string and an integer from each row. The
144
 * populate_model() function used below is not
145 146 147 148
 * shown, as it is specific to the #GtkListStore. For information on
 * how to write such a function, see the #GtkListStore documentation.
 *
 * <example>
149
 * <title>Reading data from a #GtkTreeModel</title>
150
 * |[<!-- language="C" -->
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
 * enum
 * {
 *   STRING_COLUMN,
 *   INT_COLUMN,
 *   N_COLUMNS
 * };
 *
 * ...
 *
 * GtkTreeModel *list_store;
 * GtkTreeIter iter;
 * gboolean valid;
 * gint row_count = 0;
 *
 * /&ast; make a new list_store &ast;/
 * list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
 *
 * /&ast; Fill the list store with data &ast;/
 * populate_model (list_store);
 *
171 172
 * /&ast; Get the first iter in the list, check it is valid and walk
 *  &ast; through the list, reading each row. &ast;/
173
 * for (valid = gtk_tree_model_get_iter_first (list_store, &iter);
174
 *      valid;
175
 *      valid = gtk_tree_model_iter_next (list_store, &iter))
176 177 178 179 180 181 182
 *  {
 *    gchar *str_data;
 *    gint   int_data;
 *
 *    /&ast; Make sure you terminate calls to gtk_tree_model_get()
 *     &ast; with a '-1' value
 *     &ast;/
183 184 185
 *    gtk_tree_model_get (list_store, &iter,
 *                        STRING_COLUMN, &str_data,
 *                        INT_COLUMN, &int_data,
186 187 188 189 190 191 192 193
 *                        -1);
 *
 *    /&ast; Do something with the data &ast;/
 *    g_print ("Row &percnt;d: (&percnt;s,&percnt;d)\n", row_count, str_data, int_data);
 *    g_free (str_data);
 *
 *    row_count++;
 *  }
194
 * ]|
195 196
 * </example>
 *
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
 * The #GtkTreeModel interface contains two methods for reference
 * counting: gtk_tree_model_ref_node() and gtk_tree_model_unref_node().
 * These two methods are optional to implement. The reference counting
 * is meant as a way for views to let models know when nodes are being
 * displayed. #GtkTreeView will take a reference on a node when it is
 * visible, which means the node is either in the toplevel or expanded.
 * Being displayed does not mean that the node is currently directly
 * visible to the user in the viewport. Based on this reference counting
 * scheme a caching model, for example, can decide whether or not to cache
 * a node based on the reference count. A file-system based model would
 * not want to keep the entire file hierarchy in memory, but just the
 * folders that are currently expanded in every current view.
 *
 * When working with reference counting, the following rules must be taken
 * into account:
Matthias Clasen's avatar
Matthias Clasen committed
212 213 214 215 216 217 218 219 220 221 222 223 224 225
 *
 * - Never take a reference on a node without owning a reference on its parent.
 *   This means that all parent nodes of a referenced node must be referenced
 *   as well.
 *
 * - Outstanding references on a deleted node are not released. This is not
 *   possible because the node has already been deleted by the time the
 *   row-deleted signal is received.
 *
 * - Models are not obligated to emit a signal on rows of which none of its
 *   siblings are referenced. To phrase this differently, signals are only
 *   required for levels in which nodes are referenced. For the root level
 *   however, signals must be emitted at all times (however the root level
 *   is always referenced when any view is attached).
226
 */
227

Daniel Elstner's avatar
Daniel Elstner committed
228 229 230 231 232 233 234 235
#define INITIALIZE_TREE_ITER(Iter) \
    G_STMT_START{ \
      (Iter)->stamp = 0; \
      (Iter)->user_data  = NULL; \
      (Iter)->user_data2 = NULL; \
      (Iter)->user_data3 = NULL; \
    }G_STMT_END

236
#define ROW_REF_DATA_STRING "gtk-tree-row-refs"
Daniel Elstner's avatar
Daniel Elstner committed
237

238 239 240 241 242 243 244 245 246 247 248
enum {
  ROW_CHANGED,
  ROW_INSERTED,
  ROW_HAS_CHILD_TOGGLED,
  ROW_DELETED,
  ROWS_REORDERED,
  LAST_SIGNAL
};

static guint tree_model_signals[LAST_SIGNAL] = { 0 };

249 250
struct _GtkTreePath
{
251 252
  gint depth;    /* Number of elements */
  gint alloc;    /* Number of allocated elements */
253 254 255
  gint *indices;
};

256 257 258 259
typedef struct
{
  GSList *list;
} RowRefList;
260

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
static void      gtk_tree_model_base_init   (gpointer           g_class);

/* custom closures */
static void      row_inserted_marshal       (GClosure          *closure,
                                             GValue /* out */  *return_value,
                                             guint              n_param_value,
                                             const GValue      *param_values,
                                             gpointer           invocation_hint,
                                             gpointer           marshal_data);
static void      row_deleted_marshal        (GClosure          *closure,
                                             GValue /* out */  *return_value,
                                             guint              n_param_value,
                                             const GValue      *param_values,
                                             gpointer           invocation_hint,
                                             gpointer           marshal_data);
static void      rows_reordered_marshal     (GClosure          *closure,
                                             GValue /* out */  *return_value,
                                             guint              n_param_value,
                                             const GValue      *param_values,
                                             gpointer           invocation_hint,
                                             gpointer           marshal_data);

static void      gtk_tree_row_ref_inserted  (RowRefList        *refs,
                                             GtkTreePath       *path,
                                             GtkTreeIter       *iter);
static void      gtk_tree_row_ref_deleted   (RowRefList        *refs,
                                             GtkTreePath       *path);
static void      gtk_tree_row_ref_reordered (RowRefList        *refs,
                                             GtkTreePath       *path,
                                             GtkTreeIter       *iter,
                                             gint              *new_order);
292

Manish Singh's avatar
Manish Singh committed
293
GType
294 295
gtk_tree_model_get_type (void)
{
Manish Singh's avatar
Manish Singh committed
296
  static GType tree_model_type = 0;
297

298
  if (! tree_model_type)
299
    {
300
      const GTypeInfo tree_model_info =
301
      {
302
        sizeof (GtkTreeModelIface), /* class_size */
303 304 305 306 307 308 309 310
        gtk_tree_model_base_init,   /* base_init */
        NULL,           /* base_finalize */
        NULL,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        0,
        0,              /* n_preallocs */
        NULL
311 312
      };

Manish Singh's avatar
Manish Singh committed
313
      tree_model_type =
314 315
        g_type_register_static (G_TYPE_INTERFACE, I_("GtkTreeModel"),
                                &tree_model_info, 0);
Manish Singh's avatar
Manish Singh committed
316

317
      g_type_interface_add_prerequisite (tree_model_type, G_TYPE_OBJECT);
318 319 320 321 322
    }

  return tree_model_type;
}

323 324 325
static void
gtk_tree_model_base_init (gpointer g_class)
{
326
  static gboolean initialized = FALSE;
327
  GClosure *closure;
328

329
  if (! initialized)
330
    {
331 332 333 334
      GType row_inserted_params[2];
      GType row_deleted_params[1];
      GType rows_reordered_params[3];

335
      row_inserted_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
336 337
      row_inserted_params[1] = GTK_TYPE_TREE_ITER;

338
      row_deleted_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
339

340
      rows_reordered_params[0] = GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE;
341 342
      rows_reordered_params[1] = GTK_TYPE_TREE_ITER;
      rows_reordered_params[2] = G_TYPE_POINTER;
343

344 345 346
      /**
       * GtkTreeModel::row-changed:
       * @tree_model: the #GtkTreeModel on which the signal is emitted
347 348
       * @path: a #GtkTreePath-struct identifying the changed row
       * @iter: a valid #GtkTreeIter-struct pointing to the changed row
349
       *
350
       * This signal is emitted when a row in the model has changed.
351
       */
352
      tree_model_signals[ROW_CHANGED] =
353
        g_signal_new (I_("row-changed"),
354
                      GTK_TYPE_TREE_MODEL,
355
                      G_SIGNAL_RUN_LAST, 
356 357 358 359
                      G_STRUCT_OFFSET (GtkTreeModelIface, row_changed),
                      NULL, NULL,
                      _gtk_marshal_VOID__BOXED_BOXED,
                      G_TYPE_NONE, 2,
360
                      GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
361
                      GTK_TYPE_TREE_ITER);
362

363 364 365 366 367 368 369 370 371 372 373 374
      /* We need to get notification about structure changes
       * to update row references., so instead of using the
       * standard g_signal_new() with an offset into our interface
       * structure, we use a customs closures for the class
       * closures (default handlers) that first update row references
       * and then calls the function from the interface structure.
       *
       * The reason we don't simply update the row references from
       * the wrapper functions (gtk_tree_model_row_inserted(), etc.)
       * is to keep proper ordering with respect to signal handlers
       * connected normally and after.
       */
375 376 377 378

      /**
       * GtkTreeModel::row-inserted:
       * @tree_model: the #GtkTreeModel on which the signal is emitted
379 380
       * @path: a #GtkTreePath-struct identifying the new row
       * @iter: a valid #GtkTreeIter-struct pointing to the new row
381
       *
382 383
       * This signal is emitted when a new row has been inserted in
       * the model.
384 385
       *
       * Note that the row may still be empty at this point, since
386
       * it is a common pattern to first insert an empty row, and
387 388
       * then fill it with the desired values.
       */
389 390
      closure = g_closure_new_simple (sizeof (GClosure), NULL);
      g_closure_set_marshal (closure, row_inserted_marshal);
391
      tree_model_signals[ROW_INSERTED] =
392
        g_signal_newv (I_("row-inserted"),
393 394 395 396 397 398 399 400
                       GTK_TYPE_TREE_MODEL,
                       G_SIGNAL_RUN_FIRST,
                       closure,
                       NULL, NULL,
                       _gtk_marshal_VOID__BOXED_BOXED,
                       G_TYPE_NONE, 2,
                       row_inserted_params);

401 402 403
      /**
       * GtkTreeModel::row-has-child-toggled:
       * @tree_model: the #GtkTreeModel on which the signal is emitted
404 405
       * @path: a #GtkTreePath-struct identifying the row
       * @iter: a valid #GtkTreeIter-struct pointing to the row
406
       *
407 408
       * This signal is emitted when a row has gotten the first child
       * row or lost its last child row.
409
       */
410
      tree_model_signals[ROW_HAS_CHILD_TOGGLED] =
411
        g_signal_new (I_("row-has-child-toggled"),
412 413 414 415 416 417
                      GTK_TYPE_TREE_MODEL,
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (GtkTreeModelIface, row_has_child_toggled),
                      NULL, NULL,
                      _gtk_marshal_VOID__BOXED_BOXED,
                      G_TYPE_NONE, 2,
418
                      GTK_TYPE_TREE_PATH | G_SIGNAL_TYPE_STATIC_SCOPE,
419
                      GTK_TYPE_TREE_ITER);
420

421 422 423
      /**
       * GtkTreeModel::row-deleted:
       * @tree_model: the #GtkTreeModel on which the signal is emitted
424
       * @path: a #GtkTreePath-struct identifying the row
425
       *
426
       * This signal is emitted when a row has been deleted.
427 428 429
       *
       * Note that no iterator is passed to the signal handler,
       * since the row is already deleted.
430
       *
431 432 433
       * This should be called by models after a row has been removed.
       * The location pointed to by @path should be the location that
       * the row previously was at. It may not be a valid location anymore.
434
       */
435 436
      closure = g_closure_new_simple (sizeof (GClosure), NULL);
      g_closure_set_marshal (closure, row_deleted_marshal);
437
      tree_model_signals[ROW_DELETED] =
438
        g_signal_newv (I_("row-deleted"),
439 440 441 442 443 444 445 446
                       GTK_TYPE_TREE_MODEL,
                       G_SIGNAL_RUN_FIRST,
                       closure,
                       NULL, NULL,
                       _gtk_marshal_VOID__BOXED,
                       G_TYPE_NONE, 1,
                       row_deleted_params);

447
      /**
448
       * GtkTreeModel::rows-reordered: (skip)
449
       * @tree_model: the #GtkTreeModel on which the signal is emitted
450
       * @path: a #GtkTreePath-struct identifying the tree node whose children
451
       *     have been reordered
452
       * @iter: a valid #GtkTreeIter-struct pointing to the node whose children
453
       *     have been reordered, or %NULL if the depth of @path is 0
454 455 456
       * @new_order: an array of integers mapping the current position
       *     of each child to its old position before the re-ordering,
       *     i.e. @new_order<literal>[newpos] = oldpos</literal>
457
       *
458 459
       * This signal is emitted when the children of a node in the
       * #GtkTreeModel have been reordered.
460
       *
461
       * Note that this signal is not emitted
462 463 464
       * when rows are reordered by DND, since this is implemented
       * by removing and then reinserting the row.
       */
465 466
      closure = g_closure_new_simple (sizeof (GClosure), NULL);
      g_closure_set_marshal (closure, rows_reordered_marshal);
467
      tree_model_signals[ROWS_REORDERED] =
468
        g_signal_newv (I_("rows-reordered"),
469 470 471 472 473 474 475
                       GTK_TYPE_TREE_MODEL,
                       G_SIGNAL_RUN_FIRST,
                       closure,
                       NULL, NULL,
                       _gtk_marshal_VOID__BOXED_BOXED_POINTER,
                       G_TYPE_NONE, 3,
                       rows_reordered_params);
476
      initialized = TRUE;
477 478 479
    }
}

480 481 482 483 484 485 486 487 488
static void
row_inserted_marshal (GClosure          *closure,
                      GValue /* out */  *return_value,
                      guint              n_param_values,
                      const GValue      *param_values,
                      gpointer           invocation_hint,
                      gpointer           marshal_data)
{
  GtkTreeModelIface *iface;
489 490 491

  void (* row_inserted_callback) (GtkTreeModel *tree_model,
                                  GtkTreePath *path,
Matthias Clasen's avatar
Matthias Clasen committed
492
                                  GtkTreeIter *iter) = NULL;
493

494
  GObject *model = g_value_get_object (param_values + 0);
495 496
  GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (param_values + 1);
  GtkTreeIter *iter = (GtkTreeIter *)g_value_get_boxed (param_values + 2);
497 498 499

  /* first, we need to update internal row references */
  gtk_tree_row_ref_inserted ((RowRefList *)g_object_get_data (model, ROW_REF_DATA_STRING),
500
                             path, iter);
501

502 503
  /* fetch the interface ->row_inserted implementation */
  iface = GTK_TREE_MODEL_GET_IFACE (model);
504
  row_inserted_callback = G_STRUCT_MEMBER (gpointer, iface,
505 506
                              G_STRUCT_OFFSET (GtkTreeModelIface,
                                               row_inserted));
507

508
  /* Call that default signal handler, it if has been set */
509 510
  if (row_inserted_callback)
    row_inserted_callback (GTK_TREE_MODEL (model), path, iter);
511 512 513 514 515 516 517 518 519 520 521
}

static void
row_deleted_marshal (GClosure          *closure,
                     GValue /* out */  *return_value,
                     guint              n_param_values,
                     const GValue      *param_values,
                     gpointer           invocation_hint,
                     gpointer           marshal_data)
{
  GtkTreeModelIface *iface;
522
  void (* row_deleted_callback) (GtkTreeModel *tree_model,
523
                                 GtkTreePath  *path) = NULL;
524
  GObject *model = g_value_get_object (param_values + 0);
525
  GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (param_values + 1);
526 527 528

  /* first, we need to update internal row references */
  gtk_tree_row_ref_deleted ((RowRefList *)g_object_get_data (model, ROW_REF_DATA_STRING),
529
                            path);
530

531
  /* fetch the interface ->row_deleted implementation */
532
  iface = GTK_TREE_MODEL_GET_IFACE (model);
533
  row_deleted_callback = G_STRUCT_MEMBER (gpointer, iface,
534 535
                              G_STRUCT_OFFSET (GtkTreeModelIface,
                                               row_deleted));
536

537 538 539
  /* Call that default signal handler, it if has been set */
  if (row_deleted_callback)
    row_deleted_callback (GTK_TREE_MODEL (model), path);
540 541 542 543 544 545 546 547 548 549 550
}

static void
rows_reordered_marshal (GClosure          *closure,
                        GValue /* out */  *return_value,
                        guint              n_param_values,
                        const GValue      *param_values,
                        gpointer           invocation_hint,
                        gpointer           marshal_data)
{
  GtkTreeModelIface *iface;
551 552 553 554
  void (* rows_reordered_callback) (GtkTreeModel *tree_model,
                                    GtkTreePath  *path,
                                    GtkTreeIter  *iter,
                                    gint         *new_order);
555

556
  GObject *model = g_value_get_object (param_values + 0);
557 558 559
  GtkTreePath *path = (GtkTreePath *)g_value_get_boxed (param_values + 1);
  GtkTreeIter *iter = (GtkTreeIter *)g_value_get_boxed (param_values + 2);
  gint *new_order = (gint *)g_value_get_pointer (param_values + 3);
560

561 562
  /* first, we need to update internal row references */
  gtk_tree_row_ref_reordered ((RowRefList *)g_object_get_data (model, ROW_REF_DATA_STRING),
563
                              path, iter, new_order);
564

565
  /* fetch the interface ->rows_reordered implementation */
566
  iface = GTK_TREE_MODEL_GET_IFACE (model);
567
  rows_reordered_callback = G_STRUCT_MEMBER (gpointer, iface,
568 569
                              G_STRUCT_OFFSET (GtkTreeModelIface,
                                               rows_reordered));
570 571 572 573

  /* Call that default signal handler, it if has been set */
  if (rows_reordered_callback)
    rows_reordered_callback (GTK_TREE_MODEL (model), path, iter, new_order);
574 575
}

7's avatar
7 committed
576 577
/**
 * gtk_tree_path_new:
Jonathan Blandford's avatar
Jonathan Blandford committed
578
 *
579 580
 * Creates a new #GtkTreePath-struct.
 * This refers to a row.
Jonathan Blandford's avatar
Jonathan Blandford committed
581
 *
582
 * Return value: A newly created #GtkTreePath-struct.
583
 */
584 585 586 587
GtkTreePath *
gtk_tree_path_new (void)
{
  GtkTreePath *retval;
Philip Van Hoof's avatar
Philip Van Hoof committed
588
  retval = g_slice_new (GtkTreePath);
589
  retval->depth = 0;
590
  retval->alloc = 0;
591 592 593 594 595
  retval->indices = NULL;

  return retval;
}

7's avatar
7 committed
596 597
/**
 * gtk_tree_path_new_from_string:
598 599
 * @path: The string representation of a path
 *
600
 * Creates a new #GtkTreePath-struct initialized to @path.
Jonathan Blandford's avatar
Jonathan Blandford committed
601
 *
602 603 604 605 606
 * @path is expected to be a colon separated list of numbers.
 * For example, the string "10:4:0" would create a path of depth
 * 3 pointing to the 11th child of the root node, the 5th
 * child of that 11th child, and the 1st child of that 5th child.
 * If an invalid path string is passed in, %NULL is returned.
Jonathan Blandford's avatar
Jonathan Blandford committed
607
 *
608
 * Return value: A newly-created #GtkTreePath-struct, or %NULL
609
 */
610
GtkTreePath *
Tim Janik's avatar
Tim Janik committed
611
gtk_tree_path_new_from_string (const gchar *path)
612 613
{
  GtkTreePath *retval;
Tim Janik's avatar
Tim Janik committed
614
  const gchar *orig_path = path;
615 616 617
  gchar *ptr;
  gint i;

618 619
  g_return_val_if_fail (path != NULL, NULL);
  g_return_val_if_fail (*path != '\000', NULL);
620 621 622 623 624 625

  retval = gtk_tree_path_new ();

  while (1)
    {
      i = strtol (path, &ptr, 10);
626
      if (i < 0)
627 628 629 630 631
        {
          g_warning (G_STRLOC ": Negative numbers in path %s passed to gtk_tree_path_new_from_string", orig_path);
          gtk_tree_path_free (retval);
          return NULL;
        }
632 633 634

      gtk_tree_path_append_index (retval, i);

635
      if (*ptr == '\000')
636
        break;
637
      if (ptr == path || *ptr != ':')
638 639 640 641 642
        {
          g_warning (G_STRLOC ": Invalid path %s passed to gtk_tree_path_new_from_string", orig_path);
          gtk_tree_path_free (retval);
          return NULL;
        }
643 644 645 646 647 648
      path = ptr + 1;
    }

  return retval;
}

649 650
/**
 * gtk_tree_path_new_from_indices:
Matthias Clasen's avatar
Matthias Clasen committed
651
 * @first_index: first integer
Matthias Clasen's avatar
Matthias Clasen committed
652
 * @...: list of integers terminated by -1
653 654 655
 *
 * Creates a new path with @first_index and @varargs as indices.
 *
656
 * Return value: A newly created #GtkTreePath-struct
Matthias Clasen's avatar
Matthias Clasen committed
657 658
 *
 * Since: 2.2
659
 */
660 661
GtkTreePath *
gtk_tree_path_new_from_indices (gint first_index,
662
                                ...)
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
{
  int arg;
  va_list args;
  GtkTreePath *path;

  path = gtk_tree_path_new ();

  va_start (args, first_index);
  arg = first_index;

  while (arg != -1)
    {
      gtk_tree_path_append_index (path, arg);
      arg = va_arg (args, gint);
    }

  va_end (args);

  return path;
}

684 685 686 687 688 689 690
/**
 * gtk_tree_path_new_from_indicesv: (rename-to gtk_tree_path_new_from_indices)
 * @indices: (array length=length): array of indices
 * @length: length of @indices array
 *
 * Creates a new path with the given @indices array of @length.
 *
691
 * Return value: A newly created #GtkTreePath-struct
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
 *
 * Since: 3.12
 */
GtkTreePath *
gtk_tree_path_new_from_indicesv (gint *indices,
                                 gsize length)
{
  GtkTreePath *path;

  g_return_val_if_fail (indices != NULL && length != 0, NULL);

  path = gtk_tree_path_new ();
  path->alloc = length;
  path->depth = length;
  path->indices = g_new (gint, length);
  memcpy (path->indices, indices, length * sizeof (gint));

  return path;
}

7's avatar
7 committed
712 713
/**
 * gtk_tree_path_to_string:
714
 * @path: A #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
715
 *
716
 * Generates a string representation of the path.
Jonathan Blandford's avatar
Jonathan Blandford committed
717
 *
718 719 720 721 722 723 724
 * This string is a ':' separated list of numbers.
 * For example, "4:10:0:3" would be an acceptable
 * return value for this string.
 *
 * Return value: A newly-allocated string.
 *     Must be freed with g_free().
 */
725 726 727
gchar *
gtk_tree_path_to_string (GtkTreePath *path)
{
728 729
  gchar *retval, *ptr, *end;
  gint i, n;
730

731 732
  g_return_val_if_fail (path != NULL, NULL);

733 734 735
  if (path->depth == 0)
    return NULL;

736 737 738 739
  n = path->depth * 12;
  ptr = retval = g_new0 (gchar, n);
  end = ptr + n;
  g_snprintf (retval, end - ptr, "%d", path->indices[0]);
740
  while (*ptr != '\000')
741 742 743 744
    ptr++;

  for (i = 1; i < path->depth; i++)
    {
745
      g_snprintf (ptr, end - ptr, ":%d", path->indices[i]);
746
      while (*ptr != '\000')
747
        ptr++;
748 749 750 751 752
    }

  return retval;
}

7's avatar
7 committed
753
/**
754
 * gtk_tree_path_new_first:
Jonathan Blandford's avatar
Jonathan Blandford committed
755
 *
756
 * Creates a new #GtkTreePath-struct.
Jonathan Blandford's avatar
Jonathan Blandford committed
757
 *
758 759
 * The string representation of this path is "0".
 *
760
 * Return value: A new #GtkTreePath-struct
761
 */
762
GtkTreePath *
763
gtk_tree_path_new_first (void)
764 765 766 767 768 769 770 771 772
{
  GtkTreePath *retval;

  retval = gtk_tree_path_new ();
  gtk_tree_path_append_index (retval, 0);

  return retval;
}

7's avatar
7 committed
773 774
/**
 * gtk_tree_path_append_index:
775
 * @path: a #GtkTreePath-struct
776
 * @index_: the index
Jonathan Blandford's avatar
Jonathan Blandford committed
777
 *
778 779 780 781
 * Appends a new index to a path.
 *
 * As a result, the depth of the path is increased.
 */
782 783
void
gtk_tree_path_append_index (GtkTreePath *path,
784
                            gint         index_)
785
{
7's avatar
7 committed
786
  g_return_if_fail (path != NULL);
787 788 789 790 791 792 793 794 795 796 797
  g_return_if_fail (index_ >= 0);

  if (path->depth == path->alloc)
    {
      gint *indices;
      path->alloc = MAX (path->alloc * 2, 1);
      indices = g_new (gint, path->alloc);
      memcpy (indices, path->indices, path->depth * sizeof (gint));
      g_free (path->indices);
      path->indices = indices;
    }
7's avatar
7 committed
798

799
  path->depth += 1;
800
  path->indices[path->depth - 1] = index_;
801 802
}

7's avatar
7 committed
803 804
/**
 * gtk_tree_path_prepend_index:
805
 * @path: a #GtkTreePath-struct
806 807 808
 * @index_: the index
 *
 * Prepends a new index to a path.
Jonathan Blandford's avatar
Jonathan Blandford committed
809
 *
810 811
 * As a result, the depth of the path is increased.
 */
812 813
void
gtk_tree_path_prepend_index (GtkTreePath *path,
814
                             gint       index)
815
{
816
  if (path->depth == path->alloc)
817
    {
818 819 820 821 822 823
      gint *indices;
      path->alloc = MAX (path->alloc * 2, 1);
      indices = g_new (gint, path->alloc);
      memcpy (indices + 1, path->indices, path->depth * sizeof (gint));
      g_free (path->indices);
      path->indices = indices;
824
    }
825 826 827 828
  else if (path->depth > 0)
    memmove (path->indices + 1, path->indices, path->depth * sizeof (gint));

  path->depth += 1;
829 830 831
  path->indices[0] = index;
}

7's avatar
7 committed
832 833
/**
 * gtk_tree_path_get_depth:
834
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
835
 *
7's avatar
7 committed
836
 * Returns the current depth of @path.
Jonathan Blandford's avatar
Jonathan Blandford committed
837
 *
7's avatar
7 committed
838
 * Return value: The depth of @path
839
 */
840 841 842
gint
gtk_tree_path_get_depth (GtkTreePath *path)
{
7's avatar
7 committed
843 844
  g_return_val_if_fail (path != NULL, 0);

845 846 847
  return path->depth;
}

7's avatar
7 committed
848
/**
849
 * gtk_tree_path_get_indices: (skip)
850
 * @path: a #GtkTreePath-struct
851
 *
852
 * Returns the current indices of @path.
853
 *
854 855 856
 * This is an array of integers, each representing a node in a tree.
 * This value should not be freed.
 *
857 858
 * The length of the array can be obtained with gtk_tree_path_get_depth().
 *
859 860
 * Return value: The current indices, or %NULL
 */
861 862 863 864 865 866 867 868 869
gint *
gtk_tree_path_get_indices (GtkTreePath *path)
{
  g_return_val_if_fail (path != NULL, NULL);

  return path->indices;
}

/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
870
 * gtk_tree_path_get_indices_with_depth: (rename-to gtk_tree_path_get_indices)
871
 * @path: a #GtkTreePath-struct
872
 * @depth: (out) (allow-none): return location for number of elements
873
 *     returned in the integer array, or %NULL
874 875
 *
 * Returns the current indices of @path.
876
 *
877 878 879 880
 * This is an array of integers, each representing a node in a tree.
 * It also returns the number of elements in the array.
 * The array should not be freed.
 *
881 882
 * Return value: (array length=depth) (transfer none): The current
 *     indices, or %NULL
883 884
 *
 * Since: 3.0
885
 */
886
gint *
887 888
gtk_tree_path_get_indices_with_depth (GtkTreePath *path,
                                      gint        *depth)
889 890 891 892 893 894 895 896 897
{
  g_return_val_if_fail (path != NULL, NULL);

  if (depth)
    *depth = path->depth;

  return path->indices;
}

7's avatar
7 committed
898 899
/**
 * gtk_tree_path_free:
900
 * @path: (allow-none): a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
901
 *
902
 * Frees @path. If @path is %NULL, it simply returns.
903
 */
904 905 906
void
gtk_tree_path_free (GtkTreePath *path)
{
907 908
  if (!path)
    return;
909

910
  g_free (path->indices);
Philip Van Hoof's avatar
Philip Van Hoof committed
911
  g_slice_free (GtkTreePath, path);
912 913
}

7's avatar
7 committed
914 915
/**
 * gtk_tree_path_copy:
916
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
917
 *
918
 * Creates a new #GtkTreePath-struct as a copy of @path.
Jonathan Blandford's avatar
Jonathan Blandford committed
919
 *
920
 * Return value: a new #GtkTreePath-struct
921
 */
922
GtkTreePath *
923
gtk_tree_path_copy (const GtkTreePath *path)
924 925 926
{
  GtkTreePath *retval;

927 928
  g_return_val_if_fail (path != NULL, NULL);

Philip Van Hoof's avatar
Philip Van Hoof committed
929
  retval = g_slice_new (GtkTreePath);
930
  retval->depth = path->depth;
931 932
  retval->alloc = retval->depth;
  retval->indices = g_new (gint, path->alloc);
933 934 935 936
  memcpy (retval->indices, path->indices, path->depth * sizeof (gint));
  return retval;
}

Christian Persch's avatar
Christian Persch committed
937 938 939
G_DEFINE_BOXED_TYPE (GtkTreePath, gtk_tree_path,
                     gtk_tree_path_copy,
                     gtk_tree_path_free)
940

7's avatar
7 committed
941 942
/**
 * gtk_tree_path_compare:
943 944
 * @a: a #GtkTreePath-struct
 * @b: a #GtkTreePath-struct to compare with
945 946
 *
 * Compares two paths.
Jonathan Blandford's avatar
Jonathan Blandford committed
947
 *
948 949 950
 * If @a appears before @b in a tree, then -1 is returned.
 * If @b appears before @a, then 1 is returned.
 * If the two nodes are equal, then 0 is returned.
Jonathan Blandford's avatar
Jonathan Blandford committed
951
 *
952 953
 * Return value: the relative positions of @a and @b
 */
954
gint
7's avatar
7 committed
955
gtk_tree_path_compare (const GtkTreePath *a,
956
                       const GtkTreePath *b)
957 958 959 960 961 962 963 964 965 966 967
{
  gint p = 0, q = 0;

  g_return_val_if_fail (a != NULL, 0);
  g_return_val_if_fail (b != NULL, 0);
  g_return_val_if_fail (a->depth > 0, 0);
  g_return_val_if_fail (b->depth > 0, 0);

  do
    {
      if (a->indices[p] == b->indices[q])
968
        continue;
969
      return (a->indices[p] < b->indices[q]?-1:1);
970 971 972 973
    }
  while (++p < a->depth && ++q < b->depth);
  if (a->depth == b->depth)
    return 0;
974
  return (a->depth < b->depth?-1:1);
975 976
}

977 978
/**
 * gtk_tree_path_is_ancestor:
979 980
 * @path: a #GtkTreePath-struct
 * @descendant: another #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
981
 *
982
 * Returns %TRUE if @descendant is a descendant of @path.
Jonathan Blandford's avatar
Jonathan Blandford committed
983
 *
984
 * Return value: %TRUE if @descendant is contained inside @path
985
 */
986 987 988 989 990
gboolean
gtk_tree_path_is_ancestor (GtkTreePath *path,
                           GtkTreePath *descendant)
{
  gint i;
Jonathan Blandford's avatar
Jonathan Blandford committed
991

992 993 994 995 996 997
  g_return_val_if_fail (path != NULL, FALSE);
  g_return_val_if_fail (descendant != NULL, FALSE);

  /* can't be an ancestor if we're deeper */
  if (path->depth >= descendant->depth)
    return FALSE;
Jonathan Blandford's avatar
Jonathan Blandford committed
998

999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
  i = 0;
  while (i < path->depth)
    {
      if (path->indices[i] != descendant->indices[i])
        return FALSE;
      ++i;
    }

  return TRUE;
}

/**
 * gtk_tree_path_is_descendant:
1012 1013
 * @path: a #GtkTreePath-struct
 * @ancestor: another #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
1014
 *
Matthias Clasen's avatar
Matthias Clasen committed
1015
 * Returns %TRUE if @path is a descendant of @ancestor.
Jonathan Blandford's avatar
Jonathan Blandford committed
1016
 *
1017
 * Return value: %TRUE if @ancestor contains @path somewhere below it
1018
 */
1019 1020 1021 1022 1023
gboolean
gtk_tree_path_is_descendant (GtkTreePath *path,
                             GtkTreePath *ancestor)
{
  gint i;
Jonathan Blandford's avatar
Jonathan Blandford committed
1024

1025 1026
  g_return_val_if_fail (path != NULL, FALSE);
  g_return_val_if_fail (ancestor != NULL, FALSE);
Jonathan Blandford's avatar
Jonathan Blandford committed
1027

1028 1029 1030
  /* can't be a descendant if we're shallower in the tree */
  if (path->depth <= ancestor->depth)
    return FALSE;
Jonathan Blandford's avatar
Jonathan Blandford committed
1031

1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
  i = 0;
  while (i < ancestor->depth)
    {
      if (path->indices[i] != ancestor->indices[i])
        return FALSE;
      ++i;
    }

  return TRUE;
}


7's avatar
7 committed
1044 1045
/**
 * gtk_tree_path_next:
1046
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
1047
 *
7's avatar
7 committed
1048
 * Moves the @path to point to the next node at the current depth.
1049
 */
1050 1051 1052 1053
void
gtk_tree_path_next (GtkTreePath *path)
{
  g_return_if_fail (path != NULL);
7's avatar
7 committed
1054
  g_return_if_fail (path->depth > 0);
1055 1056 1057 1058

  path->indices[path->depth - 1] ++;
}

7's avatar
7 committed
1059 1060
/**
 * gtk_tree_path_prev:
1061
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
1062
 *
1063 1064
 * Moves the @path to point to the previous node at the
 * current depth, if it exists.
Jonathan Blandford's avatar
Jonathan Blandford committed
1065
 *
1066 1067 1068
 * Return value: %TRUE if @path has a previous node, and
 *     the move was made
 */
1069
gboolean
1070 1071 1072 1073
gtk_tree_path_prev (GtkTreePath *path)
{
  g_return_val_if_fail (path != NULL, FALSE);

Matthias Clasen's avatar
Matthias Clasen committed
1074 1075 1076
  if (path->depth == 0)
    return FALSE;

1077
  if (path->indices[path->depth - 1] == 0)
1078 1079
    return FALSE;

1080
  path->indices[path->depth - 1] -= 1;
1081 1082 1083 1084

  return TRUE;
}

7's avatar
7 committed
1085 1086
/**
 * gtk_tree_path_up:
1087
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
1088
 *
1089
 * Moves the @path to point to its parent node, if it has a parent.
Jonathan Blandford's avatar
Jonathan Blandford committed
1090
 *
1091 1092
 * Return value: %TRUE if @path has a parent, and the move was made
 */
1093
gboolean
1094 1095 1096 1097
gtk_tree_path_up (GtkTreePath *path)
{
  g_return_val_if_fail (path != NULL, FALSE);

1098
  if (path->depth == 0)
1099 1100 1101 1102 1103 1104 1105
    return FALSE;

  path->depth--;

  return TRUE;
}

7's avatar
7 committed
1106 1107
/**
 * gtk_tree_path_down:
1108
 * @path: a #GtkTreePath-struct
Jonathan Blandford's avatar
Jonathan Blandford committed
1109
 *
7's avatar
7 committed
1110
 * Moves @path to point to the first child of the current path.
1111
 */
1112 1113 1114 1115 1116 1117 1118 1119
void
gtk_tree_path_down (GtkTreePath *path)
{
  g_return_if_fail (path != NULL);

  gtk_tree_path_append_index (path, 0);
}

1120 1121
/**
 * gtk_tree_iter_copy:
1122
 * @iter: a #GtkTreeIter-struct
1123 1124
 *
 * Creates a dynamically allocated tree iterator as a copy of @iter.
Jonathan Blandford's avatar
Jonathan Blandford committed
1125
 *
1126 1127
 * This function is not intended for use in applications,
 * because you can just copy the structs by value
Matthias Clasen's avatar
Matthias Clasen committed
1128 1129
 * (<literal>GtkTreeIter new_iter = iter;</literal>).
 * You must free this iter with gtk_tree_iter_free().
Jonathan Blandford's avatar
Jonathan Blandford committed
1130
 *
1131 1132
 * Return value: a newly-allocated copy of @iter
 */
1133 1134 1135 1136 1137 1138 1139
GtkTreeIter *
gtk_tree_iter_copy (GtkTreeIter *iter)
{
  GtkTreeIter *retval;

  g_return_val_if_fail (iter != NULL, NULL);

1140
  retval = g_slice_new (GtkTreeIter);
1141 1142 1143 1144 1145 1146 1147
  *retval = *iter;

  return retval;
}

/**
 * gtk_tree_iter_free:
1148
 * @iter: a dynamically allocated tree iterator
Jonathan Blandford's avatar
Jonathan Blandford committed
1149
 *
Matthias Clasen's avatar
Matthias Clasen committed
1150
 * Frees an iterator that has been allocated by gtk_tree_iter_copy().
1151
 *
Matthias Clasen's avatar
Matthias Clasen committed
1152
 * This function is mainly used for language bindings.
1153
 */
1154 1155 1156 1157 1158
void
gtk_tree_iter_free (GtkTreeIter *iter)
{
  g_return_if_fail (iter != NULL);

1159
  g_slice_free (GtkTreeIter, iter);
1160 1161
}

Christian Persch's avatar
Christian Persch committed
1162 1163 1164
G_DEFINE_BOXED_TYPE (GtkTreeIter,  gtk_tree_iter,
                     gtk_tree_iter_copy,
                     gtk_tree_iter_free)
1165

1166 1167
/**
 * gtk_tree_model_get_flags:
1168 1169 1170
 * @tree_model: a #GtkTreeModel
 *
 * Returns a set of flags supported by this interface.