gtkliststore.c 64.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* gtkliststore.c
 * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

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

34
#define GTK_LIST_STORE_IS_SORTED(list) (((GtkListStore*)(list))->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID)
35
#define VALID_ITER(iter, list_store) ((iter)!= NULL && (iter)->user_data != NULL && list_store->stamp == (iter)->stamp && !g_sequence_iter_is_end ((iter)->user_data) && g_sequence_iter_get_sequence ((iter)->user_data) == list_store->seq)
36 37

static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
38 39
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
40
static void         gtk_list_store_sortable_init   (GtkTreeSortableIface   *iface);
41
static void         gtk_list_store_buildable_init  (GtkBuildableIface      *iface);
42
static void         gtk_list_store_finalize        (GObject           *object);
43
static GtkTreeModelFlags gtk_list_store_get_flags  (GtkTreeModel      *tree_model);
44
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
45 46
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
static gboolean     gtk_list_store_get_iter        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreePath       *path);
static GtkTreePath *gtk_list_store_get_path        (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static void         gtk_list_store_get_value       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    gint               column,
						    GValue            *value);
static gboolean     gtk_list_store_iter_next       (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_children   (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent);
static gboolean     gtk_list_store_iter_has_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gint         gtk_list_store_iter_n_children (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter);
static gboolean     gtk_list_store_iter_nth_child  (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *parent,
						    gint               n);
static gboolean     gtk_list_store_iter_parent     (GtkTreeModel      *tree_model,
						    GtkTreeIter       *iter,
						    GtkTreeIter       *child);
72

73

74 75 76 77 78 79
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);

80 81
static void gtk_list_store_increment_stamp (GtkListStore *list_store);

82

83
/* Drag and Drop */
Murray Cumming's avatar
Murray Cumming committed
84 85
static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path);
86 87 88 89 90 91 92 93
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);
94
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
95 96
                                                   GtkTreePath       *dest_path,
						   GtkSelectionData  *selection_data);
97

98

99
/* sortable */
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
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,
						      GtkDestroyNotify        destroy);
static void     gtk_list_store_set_default_sort_func (GtkTreeSortable        *sortable,
						      GtkTreeIterCompareFunc  func,
						      gpointer                data,
						      GtkDestroyNotify        destroy);
static gboolean gtk_list_store_has_default_sort_func (GtkTreeSortable        *sortable);

121

122 123 124 125 126 127 128 129 130 131 132 133 134
/* 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
135 136 137 138 139 140 141 142
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,
143 144 145 146
						gtk_list_store_sortable_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
						gtk_list_store_buildable_init))

147 148 149 150

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
151 152 153
  GObjectClass *object_class;

  object_class = (GObjectClass*) class;
154 155

  object_class->finalize = gtk_list_store_finalize;
156 157 158 159 160
}

static void
gtk_list_store_tree_model_init (GtkTreeModelIface *iface)
{
161
  iface->get_flags = gtk_list_store_get_flags;
162
  iface->get_n_columns = gtk_list_store_get_n_columns;
163
  iface->get_column_type = gtk_list_store_get_column_type;
164
  iface->get_iter = gtk_list_store_get_iter;
165
  iface->get_path = gtk_list_store_get_path;
166
  iface->get_value = gtk_list_store_get_value;
167 168 169 170 171 172
  iface->iter_next = gtk_list_store_iter_next;
  iface->iter_children = gtk_list_store_iter_children;
  iface->iter_has_child = gtk_list_store_iter_has_child;
  iface->iter_n_children = gtk_list_store_iter_n_children;
  iface->iter_nth_child = gtk_list_store_iter_nth_child;
  iface->iter_parent = gtk_list_store_iter_parent;
173 174
}

175 176 177
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
Murray Cumming's avatar
Murray Cumming committed
178
  iface->row_draggable = real_gtk_list_store_row_draggable;
179 180 181 182 183
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
184
gtk_list_store_drag_dest_init (GtkTreeDragDestIface *iface)
185 186
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
187
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
188 189
}

190 191 192 193 194
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;
195
  iface->set_sort_func = gtk_list_store_set_sort_func;
196 197
  iface->set_default_sort_func = gtk_list_store_set_default_sort_func;
  iface->has_default_sort_func = gtk_list_store_has_default_sort_func;
198 199
}

200 201 202 203 204 205 206
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;
}

207 208 209
static void
gtk_list_store_init (GtkListStore *list_store)
{
210
  list_store->seq = g_sequence_new (NULL);
211
  list_store->sort_list = NULL;
212
  list_store->stamp = g_random_int ();
213
  list_store->sort_column_id = -2;
214
  list_store->columns_dirty = FALSE;
215
  list_store->length = 0;
216 217
}

218 219 220
/**
 * gtk_list_store_new:
 * @n_columns: number of columns in the list store
221
 * @Varargs: all #GType types for the columns, from first to last
222
 *
223
 * Creates a new list store as with @n_columns columns each of the types passed
224 225 226 227
 * in.  Note that only types derived from standard GObject fundamental types 
 * are supported. 
 *
 * As an example, <literal>gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING,
Matthias Clasen's avatar
Matthias Clasen committed
228 229
 * GDK_TYPE_PIXBUF);</literal> will create a new #GtkListStore with three columns, of type
 * int, string and #GdkPixbuf respectively.
230
 *
231 232
 * Return value: a new #GtkListStore
 **/
233
GtkListStore *
234
gtk_list_store_new (gint n_columns,
Soeren Sandmann's avatar
Soeren Sandmann committed
235
		    ...)
236
{
237
  GtkListStore *retval;
238 239 240 241 242
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

Manish Singh's avatar
Manish Singh committed
243
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
244
  gtk_list_store_set_n_columns (retval, n_columns);
245 246

  va_start (args, n_columns);
247

248
  for (i = 0; i < n_columns; i++)
249 250 251 252
    {
      GType type = va_arg (args, GType);
      if (! _gtk_tree_data_list_check_type (type))
	{
253
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
Manish Singh's avatar
Manish Singh committed
254
	  g_object_unref (retval);
255 256 257 258 259
	  return NULL;
	}

      gtk_list_store_set_column_type (retval, i, type);
    }
260 261 262 263 264 265

  va_end (args);

  return retval;
}

266 267 268 269 270 271

/**
 * gtk_list_store_newv:
 * @n_columns: number of columns in the list store
 * @types: an array of #GType types for the columns, from first to last
 *
Matthias Clasen's avatar
Matthias Clasen committed
272
 * Non-vararg creation function.  Used primarily by language bindings.
273 274 275 276 277 278 279 280 281 282 283 284
 *
 * Return value: a new #GtkListStore
 **/
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
285
  retval = g_object_new (GTK_TYPE_LIST_STORE, NULL);
286 287 288 289 290 291
  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]))
	{
292
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
Manish Singh's avatar
Manish Singh committed
293
	  g_object_unref (retval);
294 295 296 297 298 299 300 301 302
	  return NULL;
	}

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

  return retval;
}

303 304 305 306
/**
 * gtk_list_store_set_column_types:
 * @list_store: A #GtkListStore
 * @n_columns: Number of columns for the list store
Matthias Clasen's avatar
Matthias Clasen committed
307
 * @types: An array length n of #GTypes
308
 * 
Matthias Clasen's avatar
Matthias Clasen committed
309 310 311
 * 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
312 313 314 315 316 317 318 319 320 321 322 323 324
 * interface is called.
 **/
void
gtk_list_store_set_column_types (GtkListStore *list_store,
				 gint          n_columns,
				 GType        *types)
{
  gint i;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (list_store->columns_dirty == 0);

  gtk_list_store_set_n_columns (list_store, n_columns);
325
  for (i = 0; i < n_columns; i++)
326 327 328
    {
      if (! _gtk_tree_data_list_check_type (types[i]))
	{
329
	  g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
330 331 332 333 334 335
	  continue;
	}
      gtk_list_store_set_column_type (list_store, i, types[i]);
    }
}

336
static void
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
  GType *new_columns;

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

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

      g_free (list_store->column_headers);
    }

357 358 359 360 361
  if (list_store->sort_list)
    _gtk_tree_data_list_header_free (list_store->sort_list);

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

362 363 364 365
  list_store->column_headers = new_columns;
  list_store->n_columns = n_columns;
}

366
static void
367 368 369 370
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
371 372
  if (!_gtk_tree_data_list_check_type (type))
    {
373
      g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type));
374 375
      return;
    }
376 377 378 379

  list_store->column_headers[column] = type;
}

380 381 382 383 384
static void
gtk_list_store_finalize (GObject *object)
{
  GtkListStore *list_store = GTK_LIST_STORE (object);

385 386
  g_sequence_foreach (list_store->seq,
		      (GFunc) _gtk_tree_data_list_free, list_store->column_headers);
Soeren Sandmann's avatar
Soeren Sandmann committed
387

388
  g_sequence_free (list_store->seq);
389

390 391 392 393 394
  _gtk_tree_data_list_header_free (list_store->sort_list);
  g_free (list_store->column_headers);
  
  if (list_store->default_sort_destroy)
    {
395 396
      GtkDestroyNotify d = list_store->default_sort_destroy;

397
      list_store->default_sort_destroy = NULL;
398
      d (list_store->default_sort_data);
399 400
      list_store->default_sort_data = NULL;
    }
401

402
  /* must chain up */
Matthias Clasen's avatar
Matthias Clasen committed
403
  (* G_OBJECT_CLASS (gtk_list_store_parent_class)->finalize) (object);
404 405
}

406
/* Fulfill the GtkTreeModel requirements */
407
static GtkTreeModelFlags
408 409
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
410
  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
411 412
}

413 414 415
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
416 417 418 419 420
  GtkListStore *list_store = (GtkListStore *) tree_model;

  list_store->columns_dirty = TRUE;

  return list_store->n_columns;
421 422
}

423 424 425 426
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
427 428
  GtkListStore *list_store = (GtkListStore *) tree_model;

429 430
  g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns, 
			G_TYPE_INVALID);
431

432 433 434
  list_store->columns_dirty = TRUE;

  return list_store->column_headers[index];
435 436
}

437
static gboolean
438
gtk_list_store_get_iter (GtkTreeModel *tree_model,
439
			 GtkTreeIter  *iter,
440 441
			 GtkTreePath  *path)
{
442
  GtkListStore *list_store = (GtkListStore *) tree_model;
443
  GSequence *seq;
444
  gint i;
445

446 447
  list_store->columns_dirty = TRUE;

Soeren Sandmann's avatar
Soeren Sandmann committed
448 449
  seq = list_store->seq;
  
450 451
  i = gtk_tree_path_get_indices (path)[0];

452
  if (i >= g_sequence_get_length (seq))
453
    return FALSE;
454

455
  iter->stamp = list_store->stamp;
456
  iter->user_data = g_sequence_get_iter_at_pos (seq, i);
457

458
  return TRUE;
459 460 461 462
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
463
			 GtkTreeIter  *iter)
464
{
Soeren Sandmann's avatar
Soeren Sandmann committed
465
  GtkTreePath *path;
466

467
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
468

469
  if (g_sequence_iter_is_end (iter->user_data))
470
    return NULL;
Soeren Sandmann's avatar
Soeren Sandmann committed
471 472
	
  path = gtk_tree_path_new ();
473
  gtk_tree_path_append_index (path, g_sequence_iter_get_position (iter->user_data));
Soeren Sandmann's avatar
Soeren Sandmann committed
474 475
  
  return path;
476 477 478
}

static void
479 480 481 482
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
483
{
484
  GtkListStore *list_store = (GtkListStore *) tree_model;
485 486 487
  GtkTreeDataList *list;
  gint tmp_column = column;

488 489
  g_return_if_fail (column < list_store->n_columns);
  g_return_if_fail (VALID_ITER (iter, list_store));
Soeren Sandmann's avatar
Soeren Sandmann committed
490
		    
491
  list = g_sequence_get (iter->user_data);
492 493 494 495

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

496
  if (list == NULL)
497
    g_value_init (value, list_store->column_headers[column]);
498 499
  else
    _gtk_tree_data_list_node_to_value (list,
500
				       list_store->column_headers[column],
501
				       value);
502 503 504
}

static gboolean
505 506
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
507
{
508
  g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
509
  iter->user_data = g_sequence_iter_next (iter->user_data);
510

511
  return !g_sequence_iter_is_end (iter->user_data);
512 513
}

514
static gboolean
515
gtk_list_store_iter_children (GtkTreeModel *tree_model,
516 517
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
518
{
519
  GtkListStore *list_store = (GtkListStore *) tree_model;
Soeren Sandmann's avatar
Soeren Sandmann committed
520
  
521
  /* this is a list, nodes have no children */
522
  if (parent)
523 524
    return FALSE;

525
  if (g_sequence_get_length (list_store->seq) > 0)
526
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
527
      iter->stamp = list_store->stamp;
528
      iter->user_data = g_sequence_get_begin_iter (list_store->seq);
529 530
      return TRUE;
    }
531 532
  else
    return FALSE;
533 534 535
}

static gboolean
536
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
537
			       GtkTreeIter  *iter)
538 539 540 541 542
{
  return FALSE;
}

static gint
543
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
544
				GtkTreeIter  *iter)
545
{
546
  GtkListStore *list_store = (GtkListStore *) tree_model;
Soeren Sandmann's avatar
Soeren Sandmann committed
547

548
  if (iter == NULL)
549
    return g_sequence_get_length (list_store->seq);
550 551

  g_return_val_if_fail (list_store->stamp == iter->stamp, -1);
552 553

  return 0;
554 555
}

556
static gboolean
557
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
558 559
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
560
			       gint          n)
561
{
562
  GtkListStore *list_store = (GtkListStore *) tree_model;
563
  GSequenceIter *child;
564

565
  if (parent)
566
    return FALSE;
567

568
  child = g_sequence_get_iter_at_pos (list_store->seq, n);
569

570
  if (g_sequence_iter_is_end (child))
571
    return FALSE;
Soeren Sandmann's avatar
Soeren Sandmann committed
572

573
  iter->stamp = list_store->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
574
  iter->user_data = child;
575

Soeren Sandmann's avatar
Soeren Sandmann committed
576
  return TRUE;
577 578
}

579 580 581 582
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
583
{
584
  return FALSE;
585 586
}

587
static gboolean
588 589 590
gtk_list_store_real_set_value (GtkListStore *list_store,
			       GtkTreeIter  *iter,
			       gint          column,
591 592
			       GValue       *value,
			       gboolean      sort)
593 594 595
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;
596
  gint old_column = column;
597 598
  GValue real_value = {0, };
  gboolean converted = FALSE;
599
  gboolean retval = FALSE;
600

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

624
  prev = list = g_sequence_get (iter->user_data);
625 626 627 628 629

  while (list != NULL)
    {
      if (column == 0)
	{
630 631 632 633
	  if (converted)
	    _gtk_tree_data_list_value_to_node (list, &real_value);
	  else
	    _gtk_tree_data_list_value_to_node (list, value);
634
	  retval = TRUE;
635 636
	  if (converted)
	    g_value_unset (&real_value);
637 638
         if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
            gtk_list_store_sort_iter_changed (list_store, iter, old_column);
639
	  return retval;
640 641 642 643 644 645 646
	}

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

647
  if (g_sequence_get (iter->user_data) == NULL)
648
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
649
      list = _gtk_tree_data_list_alloc();
650
      g_sequence_set (iter->user_data, list);
651 652 653 654
      list->next = NULL;
    }
  else
    {
655
      list = prev->next = _gtk_tree_data_list_alloc ();
656 657 658 659 660
      list->next = NULL;
    }

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

667
  if (converted)
668
    _gtk_tree_data_list_value_to_node (list, &real_value);
669 670
  else
    _gtk_tree_data_list_value_to_node (list, value);
671

672
  retval = TRUE;
673 674
  if (converted)
    g_value_unset (&real_value);
675

676
  if (sort && GTK_LIST_STORE_IS_SORTED (list_store))
677
    gtk_list_store_sort_iter_changed (list_store, iter, old_column);
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705

  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)
{
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));
  g_return_if_fail (column >= 0 && column < list_store->n_columns);
  g_return_if_fail (G_IS_VALUE (value));

706
  if (gtk_list_store_real_set_value (list_store, iter, column, value, TRUE))
707 708 709
    {
      GtkTreePath *path;

710
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
711 712 713
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
714 715
}

716 717
static GtkTreeIterCompareFunc
gtk_list_store_get_compare_func (GtkListStore *list_store)
Havoc Pennington's avatar
Havoc Pennington committed
718
{
719
  GtkTreeIterCompareFunc func = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
720

721
  if (GTK_LIST_STORE_IS_SORTED (list_store))
722
    {
723 724 725 726 727
      if (list_store->sort_column_id != -1)
	{
	  GtkTreeDataSortHeader *header;
	  header = _gtk_tree_data_list_get_header (list_store->sort_list,
						   list_store->sort_column_id);
728 729
	  g_return_val_if_fail (header != NULL, NULL);
	  g_return_val_if_fail (header->func != NULL, NULL);
730 731 732 733 734 735
	  func = header->func;
	}
      else
	{
	  func = list_store->default_sort_func;
	}
736 737
    }

738 739 740
  return func;
}

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
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)
{
  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 &&
	  columns[i] == list_store->sort_column_id)
	*maybe_need_sort = TRUE;
    }
}

771 772 773 774 775 776 777 778 779 780 781 782 783
static void
gtk_list_store_set_valist_internal (GtkListStore *list_store,
				    GtkTreeIter  *iter,
				    gboolean     *emit_signal,
				    gboolean     *maybe_need_sort,
				    va_list	  var_args)
{
  gint column;
  GtkTreeIterCompareFunc func = NULL;

  column = va_arg (var_args, gint);

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

Havoc Pennington's avatar
Havoc Pennington committed
787 788 789 790 791
  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

792
      if (column < 0 || column >= list_store->n_columns)
Havoc Pennington's avatar
Havoc Pennington committed
793 794 795 796 797 798
	{
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}
      g_value_init (&value, list_store->column_headers[column]);

799
      G_VALUE_COLLECT (&value, var_args, 0, &error);
Havoc Pennington's avatar
Havoc Pennington committed
800 801 802 803 804 805 806 807 808 809 810
      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
811
      /* FIXME: instead of calling this n times, refactor with above */
812 813 814 815 816 817
      *emit_signal = gtk_list_store_real_set_value (list_store,
						    iter,
						    column,
						    &value,
						    FALSE) || *emit_signal;
      
818
      if (func == _gtk_tree_data_list_compare_func &&
819
	  column == list_store->sort_column_id)
820
	*maybe_need_sort = TRUE;
Havoc Pennington's avatar
Havoc Pennington committed
821 822 823 824 825

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
826 827
}

828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
/**
 * gtk_list_store_set_valuesv:
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter for the row being modified
 * @columns: an array of column numbers
 * @values: an array of GValues 
 * @n_values: the length of the @columns and @values arrays
 * 
 * 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
 */
void
gtk_list_store_set_valuesv (GtkListStore *list_store,
			    GtkTreeIter  *iter,
			    gint         *columns,
			    GValue       *values,
			    gint          n_values)
{
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));

  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))
    gtk_list_store_sort_iter_changed (list_store, iter, list_store->sort_column_id);

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

875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
/**
 * 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)
{
  gboolean emit_signal = FALSE;
  gboolean maybe_need_sort = FALSE;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (VALID_ITER (iter, list_store));

  gtk_list_store_set_valist_internal (list_store, iter, 
				      &emit_signal, 
				      &maybe_need_sort,
				      var_args);
900

901 902 903
  if (maybe_need_sort && GTK_LIST_STORE_IS_SORTED (list_store))
    gtk_list_store_sort_iter_changed (list_store, iter, list_store->sort_column_id);

904 905 906 907
  if (emit_signal)
    {
      GtkTreePath *path;

908
      path = gtk_list_store_get_path (GTK_TREE_MODEL (list_store), iter);
909 910 911
      gtk_tree_model_row_changed (GTK_TREE_MODEL (list_store), path, iter);
      gtk_tree_path_free (path);
    }
Havoc Pennington's avatar
Havoc Pennington committed
912 913 914 915 916 917 918
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
 * @Varargs: pairs of column number and value, terminated with -1
919
 *
Havoc Pennington's avatar
Havoc Pennington committed
920 921
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
922
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
923
 * The list is terminated by a -1. For example, to set column 0 with type
Matthias Clasen's avatar
Matthias Clasen committed
924 925
 * %G_TYPE_STRING to "Foo", you would write <literal>gtk_list_store_set (store, iter,
 * 0, "Foo", -1)</literal>.
Havoc Pennington's avatar
Havoc Pennington committed
926 927 928 929 930 931 932 933 934 935 936 937 938
 **/
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);
}

939 940
/**
 * gtk_list_store_remove:
941 942
 * @list_store: A #GtkListStore
 * @iter: A valid #GtkTreeIter
943
 *
Matthias Clasen's avatar
Matthias Clasen committed
944 945 946
 * 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.
947
 *
Kristian Rietveld's avatar
Kristian Rietveld committed
948
 * Return value: %TRUE if @iter is valid, %FALSE if not.
949
 **/
Kristian Rietveld's avatar
Kristian Rietveld committed
950
gboolean
951 952 953 954
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
  GtkTreePath *path;
955
  GSequenceIter *ptr, *next;
956

Kristian Rietveld's avatar
Kristian Rietveld committed
957 958
  g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
  g_return_val_if_fail (VALID_ITER (iter, list_store), FALSE);
959 960 961

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

Soeren Sandmann's avatar
Soeren Sandmann committed
962
  ptr = iter->user_data;
963
  next = g_sequence_iter_next (ptr);
Soeren Sandmann's avatar
Soeren Sandmann committed
964
  
965 966
  _gtk_tree_data_list_free (g_sequence_get (ptr), list_store->column_headers);
  g_sequence_remove (iter->user_data);
967 968

  list_store->length--;
Soeren Sandmann's avatar
Soeren Sandmann committed
969
  
970
  gtk_tree_model_row_deleted (GTK_TREE_MODEL (list_store), path);
971
  gtk_tree_path_free (path);
972

973
  if (g_sequence_iter_is_end (next))
974
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
975 976
      iter->stamp = 0;
      return FALSE;
977 978 979
    }
  else
    {
Soeren Sandmann's avatar
Soeren Sandmann committed
980 981 982
      iter->stamp = list_store->stamp;
      iter->user_data = next;
      return TRUE;
983
    }
984 985
}

986 987
/**
 * gtk_list_store_insert:
988 989
 * @list_store: A #GtkListStore
 * @iter: An unset #GtkTreeIter to set to the new row
990 991
 * @position: position to insert the new row
 *
992 993
 * Creates a new row at @position.  @iter will be changed to point to this new
 * row.  If @position is larger than the number of rows on the list, then the
994 995 996
 * 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 
 * gtk_list_store_set() or gtk_list_store_set_value().
997
 *
998
 **/
999 1000 1001 1002
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
1003
{
1004
  GtkTreePath *path;
1005 1006
  GSequence *seq;
  GSequenceIter *ptr;
1007
  gint length;
1008

1009 1010
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1011
  g_return_if_fail (position >= 0);
1012

1013 1014
  list_store->columns_dirty = TRUE;

Soeren Sandmann's avatar
Soeren Sandmann committed
1015
  seq = list_store->seq;
1016

1017
  length = g_sequence_get_length (seq);
1018 1019 1020
  if (position > length)
    position = length;

1021 1022
  ptr = g_sequence_get_iter_at_pos (seq, position);
  ptr = g_sequence_insert_before (ptr, NULL);
1023

1024
  iter->stamp = list_store->stamp;
Soeren Sandmann's avatar
Soeren Sandmann committed
1025
  iter->user_data = ptr;
1026

Soeren Sandmann's avatar
Soeren Sandmann committed
1027
  g_assert (VALID_ITER (iter, list_store));
1028

1029 1030
  list_store->length++;
  
1031 1032
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
1033
  gtk_tree_model_row_inserted (GTK_TREE_MODEL (list_store), path, iter);
1034
  gtk_tree_path_free (path);
1035 1036
}

1037 1038
/**
 * gtk_list_store_insert_before:
1039 1040 1041
 * @list_store: A #GtkListStore
 * @iter: An unset #GtkTreeIter to set to the new row
 * @sibling: A valid #GtkTreeIter, or %NULL
1042
 *
1043 1044 1045 1046
 * Inserts a new row before @sibling. If @sibling is %NULL, then the row will 
 * be appended to the end of the list. @iter will be changed to point to this 
 * new row. The row will be empty after this function is called. To fill in 
 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1047
 *
1048
 **/
1049 1050 1051 1052
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
1053
{
1054
  GSequenceIter *after;
Soeren Sandmann's avatar
Soeren Sandmann committed
1055
  
1056 1057
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1058 1059 1060
  if (sibling)
    g_return_if_fail (VALID_ITER (sibling, list_store));

Soeren Sandmann's avatar
Soeren Sandmann committed
1061
  if (!sibling)
1062
    after = g_sequence_get_end_iter (list_store->seq);
1063
  else
Soeren Sandmann's avatar
Soeren Sandmann committed
1064
    after = sibling->user_data;
1065

1066
  gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1067 1068
}

1069 1070
/**
 * gtk_list_store_insert_after:
1071 1072 1073
 * @list_store: A #GtkListStore
 * @iter: An unset #GtkTreeIter to set to the new row
 * @sibling: A valid #GtkTreeIter, or %NULL
1074
 *
Matthias Clasen's avatar
Matthias Clasen committed
1075 1076 1077 1078
 * Inserts a new row after @sibling. If @sibling is %NULL, then the row will be
 * prepended to the beginning of the list. @iter will be changed to point to
 * this new row. The row will be empty after this function is called. To fill
 * in values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1079
 *
1080
 **/
1081 1082 1083 1084
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
1085
{
1086
  GSequenceIter *after;
1087 1088

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
1089
  g_return_if_fail (iter != NULL);
1090
  if (sibling)
1091
    g_return_if_fail (VALID_ITER (sibling, list_store));
1092

Soeren Sandmann's avatar
Soeren Sandmann committed
1093
  if (!sibling)
1094
    after = g_sequence_get_begin_iter (list_store->seq);
Soeren Sandmann's avatar
Soeren Sandmann committed
1095
  else
1096
    after = g_sequence_iter_next (sibling->user_data);
1097

1098
  gtk_list_store_insert (list_store, iter, g_sequence_iter_get_position (after));
1099 1100
}

1101 1102
/**
 * gtk_list_store_prepend:
1103 1104
 * @list_store: A #GtkListStore
 * @iter: An unset #GtkTreeIter to set to the prepend row
1105
 *
Matthias Clasen's avatar
Matthias Clasen committed
1106
 * Prepends a new row to @list_store. @iter will be changed to point to this new
Matthias Clasen's avatar
Matthias Clasen committed
1107 1108
 * row. The row will be empty after this function is called. To fill in
 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1109
 *
1110
 **/
1111 1112 1113
void
gtk_list_store_prepend (GtkListStore *list_store,
			GtkTreeIter  *iter)
1114
{
1115 1116
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
1117

Soeren Sandmann's avatar
Soeren Sandmann committed
1118
  gtk_list_store_insert (list_store, iter, 0);
1119 1120
}

1121 1122
/**
 * gtk_list_store_append:
1123 1124
 * @list_store: A #GtkListStore
 * @iter: An unset #GtkTreeIter to set to the appended row
1125
 *
1126 1127
 * Appends a new row to @list_store.  @iter will be changed to point to this new
 * row.  The row will be empty after this function is called.  To fill in
Matthias Clasen's avatar
Matthias Clasen committed
1128
 * values, you need to call gtk_list_store_set() or gtk_list_store_set_value().
1129
 *
1130
 **/
1131 1132 1133
void
gtk_list_store_append (GtkListStore *list_store,
		       GtkTreeIter  *iter)
1134
{
1135 1136 1137
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);

1138
  gtk_list_store_insert (list_store, iter, g_sequence_get_length (list_store->seq));
1139
}
1140

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
static void
gtk_list_store_increment_stamp (GtkListStore *list_store)
{
  do
    {
      list_store->stamp++;
    }
  while (list_store->stamp == 0);
}

Matthias Clasen's avatar
Matthias Clasen committed
1151 1152 1153 1154 1155 1156 1157
/**
 * gtk_list_store_clear:
 * @list_store: a #GtkListStore.
 *
 * Removes all rows from the list store.  
 *
 **/
1158 1159 1160 1161 1162 1163
void
gtk_list_store_clear (GtkListStore *list_store)
{
  GtkTreeIter iter;
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

1164
  while (g_sequence_get_length (list_store->seq) > 0)
1165 1166
    {
      iter.stamp = list_store->stamp;
1167
      iter.user_data = g_sequence_get_begin_iter (list_store->seq);
1168 1169
      gtk_list_store_remove (list_store, &iter);
    }
1170 1171

  gtk_list_store_increment_stamp (list_store);
1172 1173
}

Kristian Rietveld's avatar
Kristian Rietveld committed
1174 1175 1176 1177 1178
/**
 * gtk_list_store_iter_is_valid:
 * @list_store: A #GtkListStore.
 * @iter: A #GtkTreeIter.
 *
1179 1180
 * <warning>This function is slow. Only use it for debugging and/or testing
 * purposes.</warning>
Kristian Rietveld's avatar
Kristian Rietveld committed
1181 1182 1183 1184
 *
 * Checks if the given iter is a valid iter for this #GtkListStore.
 *
 * Return value: %TRUE if the iter is valid, %FALSE if the iter is invalid.
1185 1186
 *
 * Since: 2.2
Kristian Rietveld's avatar
Kristian Rietveld committed
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
 **/
gboolean
gtk_list_store_iter_is_valid (GtkListStore *list_store,
                              GtkTreeIter  *iter)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (list_store), FALSE);
  g_return_val_if_fail (iter != NULL, FALSE);

  if (!VALID_ITER (iter, list_store))
    return FALSE;

1198
  if (g_sequence_iter_get_sequence (iter->user_data) != list_store->seq)
Soeren Sandmann's avatar
Soeren Sandmann committed
1199
    return FALSE;
Kristian Rietveld's avatar
Kristian Rietveld committed
1200

Soeren Sandmann's avatar
Soeren Sandmann committed
1201
  return TRUE;
Kristian Rietveld's avatar
Kristian Rietveld committed
1202
}
1203

Murray Cumming's avatar
Murray Cumming committed
1204 1205 1206 1207 1208 1209
static gboolean real_gtk_list_store_row_draggable (GtkTreeDragSource *drag_source,
                                                   GtkTreePath       *path)
{
  return TRUE;
}
  
1210 1211 1212 1213 1214
static gboolean
gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
                                 GtkTreePath       *path)
{
  GtkTreeIter iter;
1215

1216
  if (gtk_list_store_get_iter (GTK_TREE_MODEL (drag_source),
1217 1218 1219
                               &iter,
                               path))
    {
1220
      gtk_list_store_remove (GTK_LIST_STORE (drag_source), &iter);
1221 1222
      return TRUE;
    }
1223
  return FALSE;
1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
}

static gboolean
gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
                              GtkTreePath       *path,
                              GtkSelectionData  *selection_data)
{
  /* Note that we don't need to handle the GTK_TREE_MODEL_ROW
   * target, because the default handler does it for us, but
   * we do anyway for the convenience of someone maybe overriding the
   * default handler.
   */

1237 1238 1239
  if (gtk_tree_set_row_drag_data (selection_data,
				  GTK_TREE_MODEL (drag_source),
				  path))
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260
    {
      return TRUE;
    }
  else
    {
      /* FIXME handle text targets at least. */
    }

  return FALSE;
}

static gboolean
gtk_list_store_drag_data_received (GtkTreeDragDest   *drag_dest,
                                   GtkTreePath       *dest,
                                   GtkSelectionData  *selection_data)
{
  GtkTreeModel *tree_model;
  GtkListStore *list_store;
  GtkTreeModel *src_model = NULL;
  GtkTreePath *src_path = NULL;
  gboolean retval = FALSE;
1261

1262 1263
  tree_model = GTK_TREE_MODEL (drag_dest);
  list_store = GTK_LIST_STORE (drag_dest);
1264

1265 1266 1267
  if (gtk_tree_get_row_drag_data (selection_data,
				  &src_model,
				  &src_path) &&
1268 1269 1270 1271 1272 1273
      src_model == tree_model)
    {
      /* Copy the given row to a new position */
      GtkTreeIter src_iter;
      GtkTreeIter dest_iter;
      GtkTreePath *prev;
1274

1275
      if (!gtk_list_store_get_iter (src_model,
1276 1277
                                    &src_iter,
                                    src_path))
1278 1279 1280
        {
          goto out;
        }
1281 1282 1283 1284 1285 1286 1287 1288 1289

      /* Get the path to insert _after_ (dest is the path to insert _before_) */
      prev = gtk_tree_path_copy (dest);

      if (!gtk_tree_path_prev (prev))
        {
          /* dest was the first spot in the list; which means we are supposed
           * to prepend.
           */
1290
          gtk_list_store_prepend (list_store, &dest_iter);
1291

1292 1293 1294 1295
          retval = TRUE;
        }
      else
        {
1296
          if (gtk_list_store_get_iter (tree_model, &dest_iter, prev))
1297 1298
            {
              GtkTreeIter tmp_iter = dest_iter;
Jonathan Blandford's avatar
Jonathan Blandford committed
1299

1300
              gtk_list_store_insert_after (list_store, &dest_iter, &tmp_iter);
Jonathan Blandford's avatar
Jonathan Blandford committed
1301

1302 1303 1304 1305 1306
              retval = TRUE;
            }
        }

      gtk_tree_path_free (prev);
1307

1308 1309 1310 1311
      /* If we succeeded in creating dest_iter, copy data from src
       */
      if (retval)
        {
1312
          GtkTreeDataList *dl = g_sequence_get (src_iter.user_data);
1313 1314 1315
          GtkTreeDataList *copy_head = NULL;
          GtkTreeDataList *copy_prev = NULL;
          GtkTreeDataList *copy_iter = NULL;
1316
	  GtkTreePath *path;
1317 1318 1319 1320 1321 1322 1323
          gint col;

          col = 0;
          while (dl)
            {
              copy_iter = _gtk_tree_data_list_node_copy (dl,
                                                         list_store->column_headers[col]);
1324

1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335
              if (copy_head == NULL)
                copy_head = copy_iter;

              if (copy_prev)
                copy_prev->next = copy_iter;

              copy_prev = copy_iter;

              dl = dl->next;
              ++col;
            }
1336

1337
	  dest_iter.stamp = list_store->stamp;
1338
          g_sequence_set (dest_iter.user_data, copy_head);