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

#include <string.h>
#include "gtktreemodel.h"
#include "gtkliststore.h"
#include "gtktreedatalist.h"
24
#include "gtksignal.h"
25
#include "gtktreednd.h"
Havoc Pennington's avatar
Havoc Pennington committed
26
#include <gobject/gvaluecollector.h>
27 28

#define G_SLIST(x) ((GSList *) x)
29 30 31 32

static void         gtk_list_store_init            (GtkListStore      *list_store);
static void         gtk_list_store_class_init      (GtkListStoreClass *class);
static void         gtk_list_store_tree_model_init (GtkTreeModelIface *iface);
33 34
static void         gtk_list_store_drag_source_init(GtkTreeDragSourceIface *iface);
static void         gtk_list_store_drag_dest_init  (GtkTreeDragDestIface   *iface);
35
static guint        gtk_list_store_get_flags       (GtkTreeModel      *tree_model);
36
static gint         gtk_list_store_get_n_columns   (GtkTreeModel      *tree_model);
37 38
static GType        gtk_list_store_get_column_type (GtkTreeModel      *tree_model,
						    gint               index);
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
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);
64

65 66 67 68 69 70 71 72
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);
73 74 75 76 77 78 79 80 81 82 83 84 85 86
static gboolean gtk_list_store_row_drop_possible  (GtkTreeDragDest   *drag_dest,
                                                   GtkTreeModel      *src_model,
                                                   GtkTreePath       *src_path,
                                                   GtkTreePath       *dest_path);
static void
validate_list_store (GtkListStore *list_store)
{
  if (gtk_debug_flags & GTK_DEBUG_TREE)
    {
      g_assert (g_slist_length (list_store->root) == list_store->length);
      
      g_assert (g_slist_last (list_store->root) == list_store->tail);
    }
}
87 88 89 90

GtkType
gtk_list_store_get_type (void)
{
91
  static GType list_store_type = 0;
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

  if (!list_store_type)
    {
      static const GTypeInfo list_store_info =
      {
	sizeof (GtkListStoreClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
        (GClassInitFunc) gtk_list_store_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
        sizeof (GtkListStore),
	0,
        (GInstanceInitFunc) gtk_list_store_init,
      };

108 109 110 111 112 113 114
      static const GInterfaceInfo tree_model_info =
      {
	(GInterfaceInitFunc) gtk_list_store_tree_model_init,
	NULL,
	NULL
      };

115 116 117 118 119 120 121 122 123 124 125 126 127 128
      static const GInterfaceInfo drag_source_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_source_init,
	NULL,
	NULL
      };

      static const GInterfaceInfo drag_dest_info =
      {
	(GInterfaceInitFunc) gtk_list_store_drag_dest_init,
	NULL,
	NULL
      };
      
129
      list_store_type = g_type_register_static (G_TYPE_OBJECT, "GtkListStore", &list_store_info, 0);
130 131 132
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_MODEL,
				   &tree_model_info);
133 134 135 136 137 138
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_SOURCE,
				   &drag_source_info);
      g_type_add_interface_static (list_store_type,
				   GTK_TYPE_TREE_DRAG_DEST,
				   &drag_dest_info);
139 140 141 142 143 144 145 146
    }

  return list_store_type;
}

static void
gtk_list_store_class_init (GtkListStoreClass *class)
{
147 148 149
  GObjectClass *object_class;

  object_class = (GObjectClass*) class;
150 151 152 153 154
}

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

169 170 171 172 173 174 175 176 177 178 179
static void
gtk_list_store_drag_source_init (GtkTreeDragSourceIface *iface)
{
  iface->drag_data_delete = gtk_list_store_drag_data_delete;
  iface->drag_data_get = gtk_list_store_drag_data_get;
}

static void
gtk_list_store_drag_dest_init   (GtkTreeDragDestIface   *iface)
{
  iface->drag_data_received = gtk_list_store_drag_data_received;
180
  iface->row_drop_possible = gtk_list_store_row_drop_possible;
181 182
}

183 184 185 186
static void
gtk_list_store_init (GtkListStore *list_store)
{
  list_store->root = NULL;
187
  list_store->tail = NULL;
188
  list_store->stamp = g_random_int ();
189
  list_store->length = 0;
190 191
}

192 193 194 195 196 197 198 199 200 201 202 203
/**
 * gtk_list_store_new:
 *
 * Creates a new #GtkListStore. A #GtkListStore implements the
 * #GtkTreeModel interface, and stores a linked list of
 * rows; each row can have any number of columns. Columns are of uniform type,
 * i.e. all cells in a column have the same type such as #G_TYPE_STRING or
 * #GDK_TYPE_PIXBUF. Use #GtkListStore to store data to be displayed in a
 * #GtkTreeView.
 * 
 * Return value: a new #GtkListStore
 **/
204
GtkListStore *
205 206
gtk_list_store_new (void)
{
207
  return GTK_LIST_STORE (g_object_new (gtk_list_store_get_type (), NULL));
208 209
}

210 211 212 213 214 215 216 217 218 219 220 221 222
/**
 * gtk_list_store_new_with_types:
 * @n_columns: number of columns in the list store
 * @Varargs: pairs of column number and #GType
 *
 * Creates a new list store as with gtk_list_store_new(),
 * simultaneously setting up the columns and column types as with
 * gtk_list_store_set_n_columns() and
 * gtk_list_store_set_column_type().
 * 
 * 
 * Return value: a new #GtkListStore
 **/
223
GtkListStore *
224 225 226
gtk_list_store_new_with_types (gint n_columns,
			       ...)
{
227
  GtkListStore *retval;
228 229 230 231 232 233
  va_list args;
  gint i;

  g_return_val_if_fail (n_columns > 0, NULL);

  retval = gtk_list_store_new ();
234
  gtk_list_store_set_n_columns (retval, n_columns);
235 236

  va_start (args, n_columns);
237

238
  for (i = 0; i < n_columns; i++)
239
    gtk_list_store_set_column_type (retval, i, va_arg (args, GType));
240 241 242 243 244 245

  va_end (args);

  return retval;
}

246 247 248 249 250 251 252 253
/**
 * gtk_list_store_set_n_columns:
 * @store: a #GtkListStore
 * @n_columns: number of columns
 *
 * Sets the number of columns in the #GtkListStore.
 * 
 **/
254 255 256 257 258 259 260 261
void
gtk_list_store_set_n_columns (GtkListStore *list_store,
			      gint          n_columns)
{
  GType *new_columns;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
262
  g_return_if_fail (n_columns > 0);
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282

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

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

      g_free (list_store->column_headers);
    }

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

283 284 285 286 287 288 289 290 291 292 293 294
/**
 * gtk_list_store_set_column_type:
 * @store: a #GtkListStore
 * @column: column number
 * @type: type of the data stored in @column
 *
 * Supported types include: %G_TYPE_UINT, %G_TYPE_INT, %G_TYPE_UCHAR,
 * %G_TYPE_CHAR, %G_TYPE_BOOLEAN, %G_TYPE_POINTER, %G_TYPE_FLOAT, %G_TYPE_STRING,
 * %G_TYPE_OBJECT, and %G_TYPE_BOXED, along with subclasses of those types such
 * as %GDK_TYPE_PIXBUF.
 * 
 **/
295 296 297 298 299 300 301 302 303 304 305 306 307
void
gtk_list_store_set_column_type (GtkListStore *list_store,
				gint          column,
				GType         type)
{
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (column >=0 && column < list_store->n_columns);

  list_store->column_headers[column] = type;
}

/* Fulfill the GtkTreeModel requirements */
308 309 310 311 312 313 314 315
static guint
gtk_list_store_get_flags (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_TREE_MODEL_ITERS_PERSIST;
}

316 317 318 319 320 321 322 323
static gint
gtk_list_store_get_n_columns (GtkTreeModel *tree_model)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), 0);

  return GTK_LIST_STORE (tree_model)->n_columns;
}

324 325 326 327 328 329 330 331 332 333 334
static GType
gtk_list_store_get_column_type (GtkTreeModel *tree_model,
				gint          index)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), G_TYPE_INVALID);
  g_return_val_if_fail (index < GTK_LIST_STORE (tree_model)->n_columns &&
			index >= 0, G_TYPE_INVALID);

  return GTK_LIST_STORE (tree_model)->column_headers[index];
}

335
static gboolean
336
gtk_list_store_get_iter (GtkTreeModel *tree_model,
337
			 GtkTreeIter  *iter,
338 339
			 GtkTreePath  *path)
{
340 341 342
  GSList *list;
  gint i;
  
343
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
344 345 346 347 348 349
  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);  

  i = gtk_tree_path_get_indices (path)[0];

  if (i >= GTK_LIST_STORE (tree_model)->length)
    return FALSE;
350
  
351 352
  list = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root),
                      i);
353

354 355 356 357 358 359
  /* If this fails, list_store->length has gotten mangled. */
  g_assert (list);
  
  iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
  iter->user_data = list;
  return TRUE;
360 361 362 363
}

static GtkTreePath *
gtk_list_store_get_path (GtkTreeModel *tree_model,
364
			 GtkTreeIter  *iter)
365 366 367 368 369 370
{
  GtkTreePath *retval;
  GSList *list;
  gint i = 0;

  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), NULL);
371
  g_return_val_if_fail (iter->stamp == GTK_LIST_STORE (tree_model)->stamp, NULL);
372 373 374

  for (list = G_SLIST (GTK_LIST_STORE (tree_model)->root); list; list = list->next)
    {
Havoc Pennington's avatar
Havoc Pennington committed
375
      if (list == G_SLIST (iter->user_data))
376
	break;
377
      i++;
378 379 380 381 382 383 384 385 386 387
    }
  if (list == NULL)
    return NULL;

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

static void
388 389 390 391
gtk_list_store_get_value (GtkTreeModel *tree_model,
			  GtkTreeIter  *iter,
			  gint          column,
			  GValue       *value)
392 393 394 395 396 397
{
  GtkTreeDataList *list;
  gint tmp_column = column;

  g_return_if_fail (GTK_IS_LIST_STORE (tree_model));
  g_return_if_fail (column < GTK_LIST_STORE (tree_model)->n_columns);
398
  g_return_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp);
399

Havoc Pennington's avatar
Havoc Pennington committed
400
  list = G_SLIST (iter->user_data)->data;
401 402 403 404

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

405 406 407 408 409 410
  if (list == NULL)
    g_value_init (value, GTK_LIST_STORE (tree_model)->column_headers[column]);
  else
    _gtk_tree_data_list_node_to_value (list,
				       GTK_LIST_STORE (tree_model)->column_headers[column],
				       value);
411 412 413
}

static gboolean
414 415
gtk_list_store_iter_next (GtkTreeModel  *tree_model,
			  GtkTreeIter   *iter)
416
{
417 418
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
  g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE);
419

420 421 422 423 424 425 426
  if (G_SLIST (iter->user_data)->next)
    {
      iter->user_data = G_SLIST (iter->user_data)->next;
      return TRUE;
    }
  else
    return FALSE;
427 428
}

429
static gboolean
430
gtk_list_store_iter_children (GtkTreeModel *tree_model,
431 432
			      GtkTreeIter  *iter,
			      GtkTreeIter  *parent)
433
{
434
  /* this is a list, nodes have no children */
435
  if (parent)
436 437 438 439 440 441 442
    return FALSE;

  /* but if parent == NULL we return the list itself as children of the
   * "root"
   */
  
  if (GTK_LIST_STORE (tree_model)->root)
443 444 445 446 447
    {
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      iter->user_data = GTK_LIST_STORE (tree_model)->root;
      return TRUE;
    }
448 449
  else
    return FALSE;
450 451 452
}

static gboolean
453
gtk_list_store_iter_has_child (GtkTreeModel *tree_model,
454
			       GtkTreeIter  *iter)
455 456 457 458 459
{
  return FALSE;
}

static gint
460
gtk_list_store_iter_n_children (GtkTreeModel *tree_model,
461
				GtkTreeIter  *iter)
462
{
463
  if (iter == NULL)
464 465 466
    return GTK_LIST_STORE (tree_model)->length;
  else
    return 0;
467 468
}

469
static gboolean
470
gtk_list_store_iter_nth_child (GtkTreeModel *tree_model,
471 472
			       GtkTreeIter  *iter,
			       GtkTreeIter  *parent,
473
			       gint          n)
474
{
475 476
  GSList *child;
  
477
  g_return_val_if_fail (GTK_IS_LIST_STORE (tree_model), FALSE);
478

479
  if (parent)
480
    return FALSE;
481

482
  child = g_slist_nth (G_SLIST (GTK_LIST_STORE (tree_model)->root), n);
483

484 485 486 487 488 489
  if (child)
    {
      iter->user_data = child;
      iter->stamp = GTK_LIST_STORE (tree_model)->stamp;
      return TRUE;
    }
490
  else
491
    return FALSE;
492 493
}

494 495 496 497
static gboolean
gtk_list_store_iter_parent (GtkTreeModel *tree_model,
			    GtkTreeIter  *iter,
			    GtkTreeIter  *child)
498
{
499
  return FALSE;
500 501
}

502
/* Public accessors */
503 504 505
/* This is a somewhat inelegant function that does a lot of list
 * manipulations on it's own.
 */
506 507 508 509 510 511 512 513 514 515 516 517 518

/**
 * gtk_list_store_set_cell:
 * @store: a #GtkListStore
 * @iter: iterator for the row you're modifying
 * @column: column number to modify
 * @value: new value for the cell
 *
 * Sets the data in the cell specified by @iter and @column.
 * The type of @value must be convertible to the type of the
 * column.
 * 
 **/
519
void
520 521 522 523
gtk_list_store_set_cell (GtkListStore *list_store,
			 GtkTreeIter  *iter,
			 gint          column,
			 GValue       *value)
524 525 526 527 528 529
{
  GtkTreeDataList *list;
  GtkTreeDataList *prev;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
530
  g_return_if_fail (iter != NULL);
531 532
  g_return_if_fail (column >= 0 && column < list_store->n_columns);

Havoc Pennington's avatar
Havoc Pennington committed
533
  prev = list = G_SLIST (iter->user_data)->data;
534 535 536 537 538

  while (list != NULL)
    {
      if (column == 0)
	{
539
	  _gtk_tree_data_list_value_to_node (list, value);
540 541 542
	  g_signal_emit_by_name (G_OBJECT (list_store),
				 "changed",
				 NULL, iter);
543 544 545 546 547 548 549 550
	  return;
	}

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

Havoc Pennington's avatar
Havoc Pennington committed
551
  if (G_SLIST (iter->user_data)->data == NULL)
552
    {
Havoc Pennington's avatar
Havoc Pennington committed
553
      G_SLIST (iter->user_data)->data = list = _gtk_tree_data_list_alloc ();
554 555 556 557
      list->next = NULL;
    }
  else
    {
558
      list = prev->next = _gtk_tree_data_list_alloc ();
559 560 561 562 563
      list->next = NULL;
    }

  while (column != 0)
    {
564
      list->next = _gtk_tree_data_list_alloc ();
565 566 567 568
      list = list->next;
      list->next = NULL;
      column --;
    }
569
  _gtk_tree_data_list_value_to_node (list, value);
570
  g_signal_emit_by_name (G_OBJECT (list_store),
571 572
			   "changed",
			   NULL, iter);
573 574
}

575 576 577 578 579 580 581 582 583 584
/**
 * gtk_list_store_set_valist:
 * @list_store: a #GtkListStore
 * @iter: row to set data for
 * @var_args: va_list of column/value pairs
 *
 * See gtk_list_store_set(); this version takes a va_list for
 * use by language bindings.
 * 
 **/
Havoc Pennington's avatar
Havoc Pennington committed
585 586 587
void
gtk_list_store_set_valist (GtkListStore *list_store,
                           GtkTreeIter  *iter,
588
                           va_list	 var_args)
Havoc Pennington's avatar
Havoc Pennington committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
{
  gint column;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

  column = va_arg (var_args, gint);

  while (column != -1)
    {
      GValue value = { 0, };
      gchar *error = NULL;

      if (column >= list_store->n_columns)
	{
	  g_warning ("%s: Invalid column number %d added to iter (remember to end your list of columns with a -1)", G_STRLOC, column);
	  break;
	}
      g_value_init (&value, list_store->column_headers[column]);

608
      G_VALUE_COLLECT (&value, var_args, 0, &error);
Havoc Pennington's avatar
Havoc Pennington committed
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
      if (error)
	{
	  g_warning ("%s: %s", G_STRLOC, error);
	  g_free (error);

 	  /* we purposely leak the value here, it might not be
	   * in a sane state if an error condition occoured
	   */
	  break;
	}

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

      g_value_unset (&value);

      column = va_arg (var_args, gint);
    }
}

/**
 * gtk_list_store_set:
 * @list_store: a #GtkListStore
 * @iter: row iterator
 * @Varargs: pairs of column number and value, terminated with -1
 * 
 * Sets the value of one or more cells in the row referenced by @iter.
 * The variable argument list should contain integer column numbers,
639
 * each column number followed by the value to be set.
Havoc Pennington's avatar
Havoc Pennington committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
 * The list is terminated by a -1. For example, to set column 0 with type
 * %G_TYPE_STRING to "Foo", you would write gtk_list_store_set (store, iter,
 * 0, "Foo", -1).
 **/
void
gtk_list_store_set (GtkListStore *list_store,
		    GtkTreeIter  *iter,
		    ...)
{
  va_list var_args;

  g_return_if_fail (GTK_IS_LIST_STORE (list_store));

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

658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
static GSList*
remove_link_saving_prev (GSList  *list,
                         GSList  *link,
                         GSList **prevp)
{
  GSList *tmp;
  GSList *prev;

  prev = NULL;
  tmp = list;

  while (tmp)
    {
      if (tmp == link)
	{
	  if (prev)
674 675 676
	    prev->next = link->next;

	  if (list == link)
677 678
	    list = list->next;

679
	  link->next = NULL;
680 681 682 683 684 685 686 687 688 689 690 691
	  break;
	}

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

  *prevp = prev;
  
  return list;
}

692 693 694 695
static void
gtk_list_store_remove_silently (GtkListStore *list_store,
                                GtkTreeIter  *iter,
                                GtkTreePath  *path)
696
{
Havoc Pennington's avatar
Havoc Pennington committed
697
  if (G_SLIST (iter->user_data)->data)
698 699 700 701 702
    {
      _gtk_tree_data_list_free ((GtkTreeDataList *) G_SLIST (iter->user_data)->data,
                                list_store->column_headers);
      G_SLIST (iter->user_data)->data = NULL;
    }
703 704 705 706 707 708 709

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

    list_store->length -= 1;
712 713 714 715 716
    
    if (iter->user_data == list_store->tail)
      list_store->tail = prev;
  }
  
717
  list_store->stamp ++;
718 719
}

720 721 722 723 724 725 726 727 728
/**
 * gtk_list_store_remove:
 * @store: a #GtkListStore
 * @iter: a row in @list_store
 *
 * Removes the given row from the list store, emitting the
 * "deleted" signal on #GtkTreeModel.
 * 
 **/
729 730 731 732 733 734 735 736
void
gtk_list_store_remove (GtkListStore *list_store,
		       GtkTreeIter  *iter)
{
  GtkTreePath *path;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
737
  g_return_if_fail (iter->user_data != NULL);  
738 739 740

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

741 742
  validate_list_store (list_store);
  
743 744
  gtk_list_store_remove_silently (list_store, iter, path);

745 746
  validate_list_store (list_store);  
  
747
  g_signal_emit_by_name (G_OBJECT (list_store),
748 749 750
			   "deleted",
			   path);
  gtk_tree_path_free (path);
751 752
}

753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
static void
insert_after (GtkListStore *list_store,
              GSList       *sibling,
              GSList       *new_list)
{
  g_return_if_fail (sibling != NULL);
  g_return_if_fail (new_list != NULL);
  
  /* insert new node after list */
  new_list->next = sibling->next;
  sibling->next = new_list;

  /* if list was the tail, the new node is the new tail */
  if (sibling == list_store->tail)
    list_store->tail = new_list;
768 769

  list_store->length += 1;
770 771
}

772 773 774 775 776 777 778 779 780 781 782
/**
 * gtk_list_store_insert:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @position: position to insert the new row
 *
 * Creates a new row at @position, initializing @iter to point to the
 * new row, and emitting the "inserted" signal from the #GtkTreeModel
 * interface.
 * 
 **/
783 784 785 786
void
gtk_list_store_insert (GtkListStore *list_store,
		       GtkTreeIter  *iter,
		       gint          position)
787 788
{
  GSList *list;
789
  GtkTreePath *path;
790 791
  GSList *new_list;
  
792 793 794
  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
795
  g_return_if_fail (position >= 0);
796 797 798

  if (position == 0)
    {
799 800
      gtk_list_store_prepend (list_store, iter);
      return;
801 802
    }

803
  new_list = g_slist_alloc ();
804 805

  list = g_slist_nth (G_SLIST (list_store->root), position - 1);
806 807

  if (list == NULL)
808
    {
809 810
      g_warning ("%s: position %d is off the end of the list\n", G_STRLOC, position);
      return;
811
    }
812 813 814 815 816

  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
817 818

  validate_list_store (list_store);
819
  
820 821
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, position);
822
  g_signal_emit_by_name (G_OBJECT (list_store),
823 824 825
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
826 827
}

828 829 830 831 832 833 834 835 836 837 838
/**
 * gtk_list_store_insert_before:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @sibling: an existing row
 *
 * Inserts a new row before @sibling, initializing @iter to point to
 * the new row, and emitting the "inserted" signal from the
 * #GtkTreeModel interface.
 * 
 **/
839 840 841 842
void
gtk_list_store_insert_before (GtkListStore *list_store,
			      GtkTreeIter  *iter,
			      GtkTreeIter  *sibling)
843
{
844
  GtkTreePath *path;
845
  GSList *list, *prev, *new_list;
846 847 848 849 850
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
  g_return_if_fail (iter != NULL);
851 852

  if (sibling == NULL)
853 854 855 856
    {
      gtk_list_store_append (list_store, iter);
      return;
    }
857 858
  
  new_list = g_slist_alloc ();
859

860 861
  prev = NULL;
  list = list_store->root;
Havoc Pennington's avatar
Havoc Pennington committed
862
  while (list && list != sibling->user_data)
863 864 865 866 867
    {
      prev = list;
      list = list->next;
      i++;
    }
868 869 870 871 872 873 874 875 876 877 878 879 880 881

  if (list != sibling->user_data)
    {
      g_warning ("%s: sibling iterator invalid? not found in the list", G_STRLOC);
      return;
    }

  /* if there are no nodes, we become the list tail, otherwise we
   * are inserting before any existing nodes so we can't change
   * the tail
   */

  if (list_store->root == NULL)
    list_store->tail = new_list;
882 883 884
  
  if (prev)
    {
885 886
      new_list->next = prev->next;
      prev->next = new_list;
887 888 889
    }
  else
    {
890 891
      new_list->next = list_store->root;
      list_store->root = new_list;
892 893
    }

894 895
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
896 897 898 899

  list_store->length += 1;

  validate_list_store (list_store);
900
  
901 902
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
903
  g_signal_emit_by_name (G_OBJECT (list_store),
904 905 906
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
907 908
}

909 910 911 912 913 914 915 916 917 918 919
/**
 * gtk_list_store_insert_after:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 * @sibling: an existing row
 *
 * Inserts a new row after @sibling, initializing @iter to point to
 * the new row, and emitting the "inserted" signal from the
 * #GtkTreeModel interface.
 * 
 **/
920 921 922 923
void
gtk_list_store_insert_after (GtkListStore *list_store,
			     GtkTreeIter  *iter,
			     GtkTreeIter  *sibling)
924
{
925
  GtkTreePath *path;
926
  GSList *list, *new_list;
927 928 929 930
  gint i = 0;

  g_return_if_fail (list_store != NULL);
  g_return_if_fail (GTK_IS_LIST_STORE (list_store));
931
  g_return_if_fail (iter != NULL);
932 933
  if (sibling)
    g_return_if_fail (sibling->stamp == list_store->stamp);
934

935 936 937 938 939 940
  if (sibling == NULL)
    {
      gtk_list_store_prepend (list_store, iter);
      return;
    }

Havoc Pennington's avatar
Havoc Pennington committed
941
  for (list = list_store->root; list && list != sibling->user_data; list = list->next)
942 943
    i++;

944
  g_return_if_fail (list == sibling->user_data);
945

946
  new_list = g_slist_alloc ();
947

948 949 950 951
  insert_after (list_store, list, new_list);
  
  iter->stamp = list_store->stamp;
  iter->user_data = new_list;
952 953

  validate_list_store (list_store);
954
  
955 956
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
957
  g_signal_emit_by_name (G_OBJECT (list_store),
958 959 960
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
961 962
}

963 964 965 966 967 968 969 970 971 972
/**
 * gtk_list_store_prepend:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with new row
 *
 * Prepends a row to @store, initializing @iter to point to the
 * new row, and emitting the "inserted" signal on the #GtkTreeModel
 * interface for the @store.
 * 
 **/
973 974 975
void
gtk_list_store_prepend (GtkListStore *list_store,
			GtkTreeIter  *iter)
976
{
977 978 979 980 981
  GtkTreePath *path;

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

983
  iter->stamp = list_store->stamp;
Havoc Pennington's avatar
Havoc Pennington committed
984
  iter->user_data = g_slist_alloc ();
985

986 987 988
  if (list_store->root == NULL)
    list_store->tail = iter->user_data;
  
Havoc Pennington's avatar
Havoc Pennington committed
989 990
  G_SLIST (iter->user_data)->next = G_SLIST (list_store->root);
  list_store->root = iter->user_data;
991

992 993 994 995
  list_store->length += 1;

  validate_list_store (list_store);
  
996 997
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, 0);
998
  g_signal_emit_by_name (G_OBJECT (list_store),
999 1000 1001
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
1002 1003
}

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
/**
 * gtk_list_store_append:
 * @store: a #GtkListStore
 * @iter: iterator to initialize with the new row
 *
 * Appends a row to @store, initializing @iter to point to the
 * new row, and emitting the "inserted" signal on the #GtkTreeModel
 * interface for the @store.
 * 
 **/
1014 1015 1016
void
gtk_list_store_append (GtkListStore *list_store,
		       GtkTreeIter  *iter)
1017
{
1018 1019 1020 1021 1022 1023 1024 1025
  GtkTreePath *path;
  gint i = 0;

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

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

1028 1029
  if (list_store->tail)
    list_store->tail->next = iter->user_data;
1030
  else
Havoc Pennington's avatar
Havoc Pennington committed
1031
    list_store->root = iter->user_data;
1032

1033
  list_store->tail = iter->user_data;
1034 1035 1036 1037

  list_store->length += 1;

  validate_list_store (list_store);
1038
  
1039 1040
  path = gtk_tree_path_new ();
  gtk_tree_path_append_index (path, i);
1041
  g_signal_emit_by_name (G_OBJECT (list_store),
1042 1043 1044
			   "inserted",
			   path, iter);
  gtk_tree_path_free (path);
1045
}
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123

static gboolean
gtk_list_store_drag_data_delete (GtkTreeDragSource *drag_source,
                                 GtkTreePath       *path)
{
  GtkTreeIter iter;
  g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);
  
  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source),
                               &iter,
                               path))
    {
      gtk_list_store_remove (GTK_LIST_STORE (drag_source),
                             &iter);
      return TRUE;
    }
  else
    {
      return FALSE;
    }
}

static gboolean
gtk_list_store_drag_data_get (GtkTreeDragSource *drag_source,
                              GtkTreePath       *path,
                              GtkSelectionData  *selection_data)
{
  g_return_val_if_fail (GTK_IS_LIST_STORE (drag_source), FALSE);

  /* 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.
   */

  if (gtk_selection_data_set_tree_row (selection_data,
                                       GTK_TREE_MODEL (drag_source),
                                       path))
    {
      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;
  
  g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);

  tree_model = GTK_TREE_MODEL (drag_dest);
  list_store = GTK_LIST_STORE (drag_dest);
  
  if (gtk_selection_data_get_tree_row (selection_data,
                                       &src_model,
                                       &src_path) &&
      src_model == tree_model)
    {
      /* Copy the given row to a new position */
      GtkTreeIter src_iter;
      GtkTreeIter dest_iter;
      GtkTreePath *prev;
      
      if (!gtk_tree_model_get_iter (src_model,
                                    &src_iter,
                                    src_path))
1124 1125 1126
        {
          goto out;
        }
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186

      /* 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.
           */
          gtk_list_store_prepend (GTK_LIST_STORE (tree_model),
                                  &dest_iter);
          
          retval = TRUE;
        }
      else
        {
          if (gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_model),
                                       &dest_iter,
                                       prev))
            {
              GtkTreeIter tmp_iter = dest_iter;
              gtk_list_store_insert_after (GTK_LIST_STORE (tree_model),
                                           &dest_iter,
                                           &tmp_iter);
              retval = TRUE;
            }
        }

      gtk_tree_path_free (prev);
      
      /* If we succeeded in creating dest_iter, copy data from src
       */
      if (retval)
        {
          GtkTreeDataList *dl = G_SLIST (src_iter.user_data)->data;
          GtkTreeDataList *copy_head = NULL;
          GtkTreeDataList *copy_prev = NULL;
          GtkTreeDataList *copy_iter = NULL;
          gint col;

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

              if (copy_prev)
                copy_prev->next = copy_iter;

              copy_prev = copy_iter;

              dl = dl->next;
              ++col;
            }
          
          G_SLIST (dest_iter.user_data)->data = copy_head;
          
1187
          g_signal_emit_by_name (G_OBJECT (tree_model),
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
                                   "changed",
                                   NULL, &dest_iter);
        }
    }
  else
    {
      /* FIXME maybe add some data targets eventually, or handle text
       * targets in the simple case.
       */
    }

 out:
  
  if (src_path)
    gtk_tree_path_free (src_path);
  
  return retval;  
}
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231

static gboolean
gtk_list_store_row_drop_possible (GtkTreeDragDest *drag_dest,
                                  GtkTreeModel    *src_model,
                                  GtkTreePath     *src_path,
                                  GtkTreePath     *dest_path)
{
  gint *indices;
  
  g_return_val_if_fail (GTK_IS_LIST_STORE (drag_dest), FALSE);

  if (src_model != GTK_TREE_MODEL (drag_dest))
    return FALSE;
  
  if (gtk_tree_path_get_depth (dest_path) != 1)
    return FALSE;

  /* can drop before any existing node, or before one past any existing. */

  indices = gtk_tree_path_get_indices (dest_path);

  if (indices[0] <= GTK_LIST_STORE (drag_dest)->length)
    return TRUE;
  else
    return FALSE;
}