glade-signal-model.c 28.7 KB
Newer Older
1
/*
2
 * glade-signal-model.c
3 4
 * Copyright (C) Johannes Schmid 2010 <jhs@gnome.org>
 * 
5
 * This library is free software; you can redistribute it and/or modify it
6 7 8 9 10 11 12 13 14 15 16 17
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public 
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 */
19 20 21
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
22 23

#include "glade-signal-model.h"
24
#include "glade-project.h"
25 26

#include <glib/gi18n-lib.h>
27 28
#include <string.h>

29
#define DETAIL_DEFAULT  _("<Type here>")
30
#define HANDLER_DEFAULT  _("<Type here>")
31
#define USERDATA_DEFAULT _("<Click here>")
32

33 34
struct _GladeSignalModelPrivate
{
35 36 37
  GladeWidget *widget;
  GList       *widgets; /* names of the widgets that this widgets derives from and that have signals */
  gint         stamp;
38

39 40
  GHashTable  *dummy_signals;
  GHashTable  *signals; /* signals of the widget */
41 42 43 44
};

enum
{
45 46 47
  PROP_0,
  PROP_WIDGET,
  PROP_SIGNALS
48 49
};

50 51 52 53 54 55 56 57 58
static void gtk_tree_model_iface_init (GtkTreeModelIface *iface);
static void gtk_tree_drag_source_iface_init (GtkTreeDragSourceIface *iface);
static void on_glade_signal_model_added (GladeWidget *widget, const GladeSignal *signal,
					 GladeSignalModel *model);
static void on_glade_signal_model_removed (GladeWidget *widget, const GladeSignal *signal,
					   GladeSignalModel *model);
static void on_glade_signal_model_changed (GladeWidget *widget, const GladeSignal *signal,
					   GladeSignalModel *model);	
static void on_glade_widget_support_changed (GladeWidget *widget, GladeSignalModel *model);
59

60
G_DEFINE_TYPE_WITH_CODE (GladeSignalModel, glade_signal_model, G_TYPE_OBJECT,
61
                         G_ADD_PRIVATE (GladeSignalModel)
62
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
63
                                                gtk_tree_model_iface_init);
64
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
65 66
                                                gtk_tree_drag_source_iface_init))

67 68 69
static void
glade_signal_model_init (GladeSignalModel *object)
{
70
  object->priv = glade_signal_model_get_instance_private (object);
71

72 73
  object->priv->dummy_signals = 
    g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_object_unref);
74 75 76
}

static void
77
glade_signal_model_create_widget_list (GladeSignalModel *sig_model)
78
{
79
  const GList *list;
80 81
  GladeWidget *widget = sig_model->priv->widget;
  GladeWidgetAdaptor *adaptor = glade_widget_get_adaptor (widget);
82

83 84 85 86
  for (list = glade_widget_adaptor_get_signals (adaptor);
       list != NULL; list = g_list_next (list))
    {
      GladeSignalClass *signal = (GladeSignalClass *) list->data;
87

88 89 90 91 92
      if (!g_list_find_custom (sig_model->priv->widgets, 
			       (gpointer) glade_signal_class_get_type (signal), (GCompareFunc) strcmp))
	{
	  sig_model->priv->widgets = 
	    g_list_prepend (sig_model->priv->widgets, (gpointer) glade_signal_class_get_type (signal));
93
	}
94 95
    }
  sig_model->priv->widgets = g_list_reverse (sig_model->priv->widgets);
96 97 98 99 100
}

static void
glade_signal_model_finalize (GObject *object)
{
101
  GladeSignalModel *sig_model = GLADE_SIGNAL_MODEL (object);
102

103 104 105
  g_list_free (sig_model->priv->widgets);
  g_hash_table_destroy (sig_model->priv->dummy_signals);
  G_OBJECT_CLASS (glade_signal_model_parent_class)->finalize (object);
106 107 108
}

static void
109 110 111 112
glade_signal_model_set_property (GObject *object,
                                 guint prop_id,
                                 const GValue *value,
                                 GParamSpec *pspec)
113
{
114
  GladeSignalModel *sig_model;
115 116 117 118 119 120 121

  g_return_if_fail (GLADE_IS_SIGNAL_MODEL (object));

  sig_model = GLADE_SIGNAL_MODEL (object);

  switch (prop_id)
    {
122 123 124 125 126 127 128 129 130 131 132
      case PROP_WIDGET:
        sig_model->priv->widget = g_value_get_object (value);
        glade_signal_model_create_widget_list (sig_model);
        g_signal_connect (sig_model->priv->widget, "add-signal-handler",
                          G_CALLBACK (on_glade_signal_model_added), sig_model);
        g_signal_connect (sig_model->priv->widget, "remove-signal-handler",
                          G_CALLBACK (on_glade_signal_model_removed), sig_model);
        g_signal_connect (sig_model->priv->widget, "change-signal-handler",
                          G_CALLBACK (on_glade_signal_model_changed), sig_model);
        g_signal_connect (sig_model->priv->widget, "support-changed",
                          G_CALLBACK (on_glade_widget_support_changed), sig_model);
133
      break;
134 135
      case PROP_SIGNALS:
        sig_model->priv->signals = g_value_get_pointer (value);
136
      break;
137 138
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
139 140
      break;
    }
141 142 143
}

static void
144 145 146 147
glade_signal_model_get_property (GObject *object,
                                 guint prop_id,
                                 GValue *value,
                                 GParamSpec *pspec)
148
{
149
  GladeSignalModel *sig_model;
150

151
  g_return_if_fail (GLADE_IS_SIGNAL_MODEL (object));
152

153
  sig_model = GLADE_SIGNAL_MODEL (object);
154

155 156
  switch (prop_id)
    {
157 158
      case PROP_WIDGET:
        g_value_set_object (value, sig_model->priv->widget);
159
      break;
160 161
      case PROP_SIGNALS:
        g_value_set_pointer (value, sig_model->priv->signals);
162
      break;
163 164
      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165 166
      break;
    }
167 168 169 170 171
}

static void
glade_signal_model_class_init (GladeSignalModelClass *klass)
{
172
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
173

174 175 176
  object_class->finalize = glade_signal_model_finalize;
  object_class->set_property = glade_signal_model_set_property;
  object_class->get_property = glade_signal_model_get_property;
177

178 179 180 181 182 183 184 185 186 187 188 189 190
  g_object_class_install_property (object_class,
				   PROP_WIDGET,
				   g_param_spec_object ("widget",
							"A GladeWidget",
							"The GladeWidget used to query the signals",
							GLADE_TYPE_WIDGET,
							G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
  g_object_class_install_property (object_class,
				   PROP_SIGNALS,
				   g_param_spec_pointer ("signals",
							 "A GHashTable containing the widget signals",
							 "Use to query signals",
							 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
191 192 193 194 195
}

/*
 * glade_signal_model_new:
 * @widget: The GladeWidget the signals belong to
196
 * @signals: The signals of the #GladeWidget
197 198 199 200 201
 *
 * Creates a new GladeSignalModel object to show and edit the
 * signals of a widgets in a GtkTreeView
 */

202
GtkTreeModel *
203
glade_signal_model_new (GladeWidget *widget, GHashTable *signals)
204
{
205
  GObject *object = g_object_new (GLADE_TYPE_SIGNAL_MODEL,
206 207 208
				  "widget", widget, 
				  "signals", signals, NULL);
  return GTK_TREE_MODEL (object);
209 210 211
}

static GtkTreeModelFlags
212
glade_signal_model_get_flags (GtkTreeModel *model)
213
{
214
  return 0;
215 216 217
}

static gint
218
glade_signal_model_get_n_columns (GtkTreeModel *model)
219
{
220
  return GLADE_SIGNAL_N_COLUMNS;
221 222 223
}

static GType
224
glade_signal_model_get_column_type (GtkTreeModel *model, gint column)
225
{
226 227
  switch (column)
    {
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
      case GLADE_SIGNAL_COLUMN_NAME:
        return G_TYPE_STRING;
      case GLADE_SIGNAL_COLUMN_SHOW_NAME:
        return G_TYPE_BOOLEAN;
      case GLADE_SIGNAL_COLUMN_HANDLER:
        return G_TYPE_STRING;
      case GLADE_SIGNAL_COLUMN_OBJECT:
        return G_TYPE_STRING;
      case GLADE_SIGNAL_COLUMN_SWAP:
        return G_TYPE_BOOLEAN;
      case GLADE_SIGNAL_COLUMN_AFTER:
        return G_TYPE_BOOLEAN;
      case GLADE_SIGNAL_COLUMN_TOOLTIP:
        return G_TYPE_STRING;
      case GLADE_SIGNAL_COLUMN_SIGNAL:
        return G_TYPE_OBJECT;
      case GLADE_SIGNAL_COLUMN_DETAIL:
        return G_TYPE_STRING;
      default:
        g_assert_not_reached();
        return G_TYPE_NONE;
249
    }
250 251 252 253
}

enum
{
254 255
  ITER_WIDGET = 0,
  ITER_SIGNAL = 1,
256 257
};

258
static inline gboolean
259 260
glade_signal_model_is_dummy_handler (GladeSignalModel *model,
                                     GladeSignal *signal)
261
{
262
  return glade_signal_get_handler (signal) == NULL;
263 264
}

265 266 267
static GladeSignal *
glade_signal_model_get_dummy_handler (GladeSignalModel *model, 
                                      const GladeSignalClass *sig_class)
268
{
269
  GladeSignal *signal;
270

271 272
  signal = g_hash_table_lookup (model->priv->dummy_signals, 
				glade_signal_class_get_name (sig_class));
273

274 275 276
  if (!signal)
    {
      signal = glade_signal_new (sig_class,
277 278
				 NULL,
				 NULL,
279 280 281 282 283
				 FALSE,
				 FALSE);
      g_hash_table_insert (model->priv->dummy_signals, 
			   (gpointer) glade_signal_class_get_name (sig_class), 
			   signal);
284 285

      glade_project_verify_signal (model->priv->widget, signal);
286 287
    }
  return signal;
288 289
}

290
static void
291 292 293
glade_signal_model_create_widget_iter (GladeSignalModel *sig_model,
                                       const gchar *widget,
                                       GtkTreeIter *iter)
294
{
295 296 297 298
  iter->stamp = sig_model->priv->stamp;
  iter->user_data = (gpointer) widget;
  iter->user_data2 = NULL;
  iter->user_data3 = NULL;
299 300 301
}

static void
302 303 304 305
glade_signal_model_create_signal_iter (GladeSignalModel *sig_model,
                                       const gchar *widget,
                                       const GladeSignal *signal,
                                       GtkTreeIter *iter)
306 307
{
	glade_signal_model_create_widget_iter (sig_model, widget, iter);
308
	iter->user_data2 = GLADE_SIGNAL (signal);
309 310
}

311
static GList *
312 313
glade_signal_model_create_signal_list (GladeSignalModel *sig_model,
				       const gchar *widget_type)
314
{
315 316
  GList *widget_signals = NULL;
  const GList *signals;
317 318
  GladeWidget *widget = sig_model->priv->widget;
  GladeWidgetAdaptor *adaptor = glade_widget_get_adaptor (widget);
319

320 321 322 323
  for (signals = glade_widget_adaptor_get_signals (adaptor);
       signals != NULL;
       signals = g_list_next (signals))
    {
324
      GladeSignalClass *sig_class = signals->data;
325
      if (g_str_equal (glade_signal_class_get_type (sig_class), widget_type))
326
	{
327
	  widget_signals = g_list_append (widget_signals, sig_class);
328
	}
329 330
    }
  return widget_signals;
331 332
}

333
static void
334 335
on_glade_signal_model_added (GladeWidget *widget,
                             const GladeSignal *signal,
336 337
                             GladeSignalModel* model)
{
338
  GtkTreeIter iter;	
339 340 341
  GtkTreePath *path;
  const GladeSignalClass *sig_class = glade_signal_get_class (signal);

342 343 344 345
  glade_signal_model_create_signal_iter (model,
					 glade_signal_class_get_type (sig_class),
					 signal, 
					 &iter);
346
  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
347

348
  gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
349 350
  gtk_tree_path_free (path);
  model->priv->stamp++;
351 352 353
}

static void
354 355
on_glade_signal_model_removed (GladeWidget *widget,
                               const GladeSignal *signal,
356
                               GladeSignalModel *model)
357
{
358
  GtkTreeIter iter;
359 360 361
  GtkTreePath *path;
  const GladeSignalClass *sig_class = glade_signal_get_class (signal);
  
362 363 364 365
  glade_signal_model_create_signal_iter (model,
					 glade_signal_class_get_type (sig_class),
					 signal, 
					 &iter);
366 367
  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
  gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
368 369
  gtk_tree_path_free (path);
  model->priv->stamp++;
370 371 372
}

static void
373 374
on_glade_signal_model_changed (GladeWidget *widget,
                               const GladeSignal *signal,
375
                               GladeSignalModel *model)
376
{
377
  GtkTreeIter iter;
378 379 380
  GtkTreePath *path;
  const GladeSignalClass *sig_class = glade_signal_get_class (signal);
  
381 382 383 384
  glade_signal_model_create_signal_iter (model,
					 glade_signal_class_get_type (sig_class),
					 signal, 
					 &iter);
385
  path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
386
  gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
387 388
  gtk_tree_path_free (path);
  model->priv->stamp++;
389 390
}

391
static void
392 393 394
verify_dummies (const gchar *signal_name,
                GladeSignal *signal,
                GladeSignalModel *model)
395 396 397 398 399 400 401
{
  glade_project_verify_signal (model->priv->widget, signal);

  on_glade_signal_model_changed (model->priv->widget, signal, model);
}

static void
402 403
emit_changed (const gchar *signal_name,
	      GPtrArray *signals,
404 405 406 407 408 409 410 411 412 413 414 415 416
	      GladeSignalModel *model)
{
  gint i;
  GladeSignal *signal;

  for (i = 0; i < signals->len; i++)
    {
      signal = (GladeSignal *)signals->pdata[i];
      on_glade_signal_model_changed (model->priv->widget, signal, model);
    }
}

static void
417
on_glade_widget_support_changed (GladeWidget *widget, GladeSignalModel *model)
418 419 420 421 422 423 424 425
{
  /* Update support warning on dummy signals */
  g_hash_table_foreach (model->priv->dummy_signals, (GHFunc)verify_dummies, model);

  /* row changed on every row */
  g_hash_table_foreach (model->priv->signals, (GHFunc)emit_changed, model);
}

426
static gboolean
427 428 429
glade_signal_model_get_iter (GtkTreeModel *model,
                             GtkTreeIter *iter,
                             GtkTreePath *path)
430
{
431
  gint *indices;
432
  gint depth;
433
  GladeSignalModel *sig_model;
434 435 436 437 438 439 440 441 442 443 444

  g_return_val_if_fail (path != NULL, FALSE);
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), FALSE);

  indices = gtk_tree_path_get_indices(path);
  depth = gtk_tree_path_get_depth (path);
  sig_model = GLADE_SIGNAL_MODEL (model);

  switch (depth)
    {
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
      case 1:
        /* Widget */
        {
          glade_signal_model_create_widget_iter (sig_model,
                                                 g_list_nth_data (sig_model->priv->widgets,
                                                                  indices[ITER_WIDGET]),
                                                 iter);
          return TRUE;
        }
      case 2:
        /* Signal */
        {
          gboolean retval;
          GtkTreePath *path =
            gtk_tree_path_new_from_indices (indices[ITER_WIDGET], -1);
          GtkTreeIter widget_iter;

          gtk_tree_model_get_iter (model, &widget_iter, path);
          retval = gtk_tree_model_iter_nth_child (model,
                                                  iter,
                                                  &widget_iter,
                                                  indices[ITER_SIGNAL]);
          gtk_tree_path_free (path);
          return retval;
        }
470 471
    }
  return FALSE;
472 473 474
}

static GtkTreePath*
475
glade_signal_model_get_path (GtkTreeModel *model, GtkTreeIter *iter)
476
{
477 478 479
  const gchar *widget;
  GladeSignal *handler;
  GladeSignalModel *sig_model;
480 481 482 483 484 485 486 487 488 489 490

  g_return_val_if_fail (iter != NULL, NULL);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), NULL);

  widget = iter->user_data;
  handler = iter->user_data2;
  sig_model = GLADE_SIGNAL_MODEL (model);

  if (handler)
    {
      /* Signal */
491
      const GladeSignalClass *sig_class = glade_signal_get_class (handler);
492
      gint index0, index1 = 0;
493 494
      GList *signal;
      GList *signals = glade_signal_model_create_signal_list (sig_model,
495 496 497 498 499 500 501
							      widget);

      index0 = g_list_index (sig_model->priv->widgets,
			     widget);

      for (signal = signals; signal != NULL; signal = g_list_next (signal))
	{		
502
	  GPtrArray *handlers = g_hash_table_lookup (sig_model->priv->signals,
503 504 505 506
						     glade_signal_class_get_name (signal->data));

	  if (signal->data != sig_class)
	    {
507 508
	      if (handlers) 
                index1 += handlers->len;
509 510 511 512 513 514
	      index1++; /* dummy_handler */
	    }
	  else
	    {
	      if (handlers)
		{
515 516
		  guint handler_index;
		  if (g_ptr_array_find (handlers, handler, &handler_index))
517
		    index1 += handler_index;
518 519
		  else
		    index1 += handlers->len;
520
		}
521 522
	      break;
	    }
523
	}
524 525 526 527 528 529 530 531 532
      return gtk_tree_path_new_from_indices (index0, index1, -1);
    }
  else if (widget)
    {
      /* Widget */
      return gtk_tree_path_new_from_indices (g_list_index (sig_model->priv->widgets,
							   widget), -1);
    }
  g_assert_not_reached();
533 534 535
}

static void
536 537
glade_signal_model_get_value (GtkTreeModel *model,
                              GtkTreeIter *iter,
538
                              gint column,
539
                              GValue *value)
540
{	
541
  const gchar *widget;
542
  GladeSignal *signal;
543
  GladeSignalModel *sig_model;
544

545 546
  g_return_if_fail (iter != NULL);
  g_return_if_fail (GLADE_IS_SIGNAL_MODEL(model));
547

548
  widget = iter->user_data;
549
  signal = iter->user_data2;
550
  sig_model = GLADE_SIGNAL_MODEL (model);
551

552 553
  value = g_value_init (value, 
			glade_signal_model_get_column_type (model, column));
554

555 556
  switch (column)
    {
557
      case GLADE_SIGNAL_COLUMN_NAME:
558
        if (signal)
559
        {
560
          g_value_set_static_string (value, glade_signal_get_name (signal));
561 562 563 564
          break;
        }
        else
          g_value_set_static_string (value, widget);
565
      break;
566
      case GLADE_SIGNAL_COLUMN_SHOW_NAME:
567
        if (signal)
568 569
        {
          GPtrArray *handlers = g_hash_table_lookup (sig_model->priv->signals,
570
                                                     glade_signal_get_name (signal));
571 572
          guint index;
          if (!handlers || !handlers->len || (g_ptr_array_find (handlers, signal, &index) && index == 0))
573 574
            g_value_set_boolean (value, TRUE);
          else
575
            g_value_set_boolean (value, FALSE);
576 577 578 579
          break;
        }
        else if (widget)
          g_value_set_boolean (value, TRUE);
580
      break;	
581
      case GLADE_SIGNAL_COLUMN_HANDLER:
582 583 584 585 586
        if (signal)
          {
            const gchar *handler = glade_signal_get_handler (signal);
            g_value_set_static_string (value, handler ? handler : HANDLER_DEFAULT);
          }
587 588
        else 
          g_value_set_static_string (value, "");
589
      break;
590
      case GLADE_SIGNAL_COLUMN_OBJECT:
591
        if (signal)
592
        {
593
          const gchar *userdata = glade_signal_get_userdata (signal);
594 595 596 597 598 599 600 601
          if (userdata && strlen (userdata))
            g_value_set_static_string (value, userdata);
          else
            g_value_set_static_string (value, USERDATA_DEFAULT);
          break;
        }
        else 
          g_value_set_static_string (value, "");
602
      break;
603
      case GLADE_SIGNAL_COLUMN_SWAP:
604 605
        if (signal)
          g_value_set_boolean (value, glade_signal_get_swapped (signal));
606 607
        else 
          g_value_set_boolean (value, FALSE);
608
      break;
609
      case GLADE_SIGNAL_COLUMN_AFTER:
610 611
        if (signal)
          g_value_set_boolean (value, glade_signal_get_after (signal));
612 613 614 615
        else 
          g_value_set_boolean (value, FALSE);
        break;
      case GLADE_SIGNAL_COLUMN_TOOLTIP:
616 617
        if (signal)
          g_value_set_string (value, glade_signal_get_support_warning (signal));
618 619
        else
          g_value_set_static_string (value, NULL);
620
      break;
621
      case GLADE_SIGNAL_COLUMN_SIGNAL:
622
        g_value_set_object (value, signal);
623
      break;
624
      case GLADE_SIGNAL_COLUMN_DETAIL:
625 626 627 628 629
        if (signal)
          {
            const gchar *detail = glade_signal_get_detail (signal);
            g_value_set_static_string (value, detail ? detail : DETAIL_DEFAULT);
          }
630 631
        else 
          g_value_set_static_string (value, "");
632
      break;
633 634
      default:
        g_assert_not_reached();
635
    }
636 637
}

638
static gboolean
639 640 641 642
glade_signal_model_iter_next_signal (GladeSignalModel *sig_model,
                                     const gchar *widget,
                                     GtkTreeIter *iter,
                                     GList *signal)
643
{
644 645 646
  if (signal->next)
    {
      signal = signal->next;
647 648
      GladeSignal *next_handler;
      GPtrArray *next_handlers = 
649 650 651
	g_hash_table_lookup (sig_model->priv->signals,
			     glade_signal_class_get_name (signal->data));
      if (next_handlers && next_handlers->len)
652
	{
653
	  next_handler = g_ptr_array_index (next_handlers, 0);
654
	}
655
      else
656
	{
657 658 659
	  next_handler = 
	    glade_signal_model_get_dummy_handler (sig_model,
						  signal->data);
660
	}
661 662 663 664 665 666 667 668 669 670 671
      glade_signal_model_create_signal_iter (sig_model, widget,
					     next_handler,
					     iter);
      g_list_free (signal);
      return TRUE;
    }
  else
    {
      g_list_free (signal);
      return FALSE;
    }
672 673 674
}


675
static gboolean
676
glade_signal_model_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
677
{
678 679
  const gchar *widget;
  GladeSignal *handler;
680
  GtkTreeIter parent;
681
  GladeSignalModel *sig_model;
682

683 684
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), FALSE);
685

686 687
  widget = iter->user_data;
  handler = iter->user_data2;
688

689
  sig_model = GLADE_SIGNAL_MODEL (model);  
690

691
  gtk_tree_model_iter_parent (model, &parent, iter);		
692

693 694
  if (handler)
    {
695 696
      const GladeSignalClass *sig_class = glade_signal_get_class (handler);
      GList *signals = 
697 698 699 700 701 702
	glade_signal_model_create_signal_list (sig_model,
					       widget);
      GList* signal = g_list_find (signals, sig_class);
      GPtrArray* handlers = g_hash_table_lookup (sig_model->priv->signals,
						 glade_signal_class_get_name (sig_class));
      if (glade_signal_model_is_dummy_handler (sig_model, handler))
703
	{
704
	  return glade_signal_model_iter_next_signal (sig_model, widget, iter, signal);
705
	}
706
      else if (handlers)
707
	{
708 709 710 711
	  guint new_index = 0;
	  if (g_ptr_array_find (handlers, handler, &new_index))
	    new_index++;

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
	  if (new_index < handlers->len)
	    {
	      glade_signal_model_create_signal_iter (sig_model, widget,
						     g_ptr_array_index (handlers, new_index),
						     iter);
	      g_list_free (signals);
	      return TRUE;
	    }
	  else if (new_index == handlers->len)
	    {
	      glade_signal_model_create_signal_iter (sig_model, widget,
						     glade_signal_model_get_dummy_handler (sig_model,
											   sig_class),
						     iter);
	      g_list_free (signals);
	      return TRUE;
	    }
	  else
	    {
	      return glade_signal_model_iter_next_signal (sig_model, widget, iter, signal);
	    }
	}
      else
	{
	  g_list_free (signals);
	  return FALSE;
738
	}
739 740 741
    }
  else if (widget)
    {
742
      gint new_index = g_list_index (sig_model->priv->widgets, widget) + 1;
743 744 745 746 747 748 749 750
      
      return gtk_tree_model_iter_nth_child (model, iter, NULL, new_index);
    }
  iter->user_data = NULL;
  iter->user_data2 = NULL;
  iter->user_data3 = NULL;
  iter->stamp = 0;
  return FALSE;
751 752 753
}

static gint
754
glade_signal_model_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
755
{
756 757 758
  GladeSignal *handler;
  GladeSignalModel *sig_model;
  const gchar *widget;
759 760 761

  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), 0);

762 763 764
  /* FIXME: return the number of toplevels, if it makes sense in this context */
  if (iter == NULL) return 0;
  
765 766 767 768 769 770 771 772 773 774
  handler = iter->user_data2;
  sig_model = GLADE_SIGNAL_MODEL (model);
  widget = iter->user_data;

  if (handler)
    {
      return 0;
    }
  else if (widget)
    {
775
      GList *signals = glade_signal_model_create_signal_list (sig_model,
776
							      widget);
777
      GList *signal;
778 779 780
      gint retval = 0;

      for (signal = signals; signal != NULL; signal = g_list_next (signal))
781
	{
782 783 784 785 786
	  GPtrArray* handlers = g_hash_table_lookup (sig_model->priv->signals,
						     glade_signal_class_get_name (signal->data));
	  if (handlers)
	    retval += handlers->len;
	  retval++; 
787
	}
788 789 790 791 792
      g_list_free (signals);
      
      return retval;
    }
  g_assert_not_reached ();	
793 794 795
}

static gboolean
796
glade_signal_model_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
797
{
798 799
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), FALSE);
800

801
  return (glade_signal_model_iter_n_children (model, iter) != 0);
802 803 804
}

static gboolean
805 806 807
glade_signal_model_iter_nth_child (GtkTreeModel *model,
                                   GtkTreeIter *iter,
                                   GtkTreeIter *parent,
808 809
                                   gint n)
{
810 811 812
  GladeSignal *handler;
  GladeSignalModel *sig_model;
  const gchar *widget;
813 814 815 816 817 818 819 820 821 822 823 824 825 826

  g_return_val_if_fail (iter != NULL, 0);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), 0);

  handler = parent ? parent->user_data2 : NULL;
  sig_model = GLADE_SIGNAL_MODEL (model);
  widget = parent ? parent->user_data : NULL;

  if (handler)
    {
      return FALSE;
    }
  else if (widget)
    {
827
      GList *signals = glade_signal_model_create_signal_list (sig_model,
828
							      widget);
829
      GList *signal;
830
      for (signal = signals; signal != NULL; signal = g_list_next (signal))
831
	{
832
	  GPtrArray *handlers = g_hash_table_lookup (sig_model->priv->signals,
833 834 835 836 837 838
						     glade_signal_class_get_name (signal->data));
	  if (handlers)
	    {
	      if (n >= handlers->len)
		n -= handlers->len;
	      else
839
		{
840 841 842 843 844 845
		  glade_signal_model_create_signal_iter (sig_model,
							 widget,
							 g_ptr_array_index (handlers, n),
							 iter);
		  g_list_free (signals);
		  return TRUE;
846
		}
847 848 849
	    }
	  if (n == 0)
	    {
850
	      GladeSignal *handler =
851 852 853 854 855 856 857 858 859 860
		glade_signal_model_get_dummy_handler (sig_model,
						      signal->data);
	      glade_signal_model_create_signal_iter (sig_model,
						     widget,
						     handler,
						     iter);
	      g_list_free (signals);
	      return TRUE;
	    }
	  n--;
861
	}
862 863 864 865 866
      return FALSE;
    }
  else
    {
      if (g_list_length (sig_model->priv->widgets) > n)
867
	{
868 869 870 871
	  glade_signal_model_create_widget_iter (sig_model,
						 g_list_nth_data (sig_model->priv->widgets, n),
						 iter);
	  return TRUE;
872
	}
873 874
    }
  return FALSE;
875 876 877
}

static gboolean
878 879 880
glade_signal_model_iter_children (GtkTreeModel *model,
                                  GtkTreeIter *iter,
                                  GtkTreeIter *parent)
881
{
882
  return glade_signal_model_iter_nth_child (model, iter, parent, 0);
883 884 885
}

static gboolean
886 887 888
glade_signal_model_iter_parent (GtkTreeModel *model,
                                GtkTreeIter *iter,
                                GtkTreeIter *child)
889
{
890 891 892
  GladeSignalModel *sig_model;
  GladeSignal *handler;
  const gchar *widget;
893

894 895 896
  g_return_val_if_fail (iter != NULL, FALSE);
  g_return_val_if_fail (child != NULL, FALSE);
  g_return_val_if_fail (GLADE_IS_SIGNAL_MODEL(model), FALSE);  
897

898 899 900
  sig_model = GLADE_SIGNAL_MODEL (model);
  handler = child->user_data2;
  widget = child->user_data;
901

902 903 904 905 906 907
  if (handler)
    {
      glade_signal_model_create_widget_iter (sig_model, widget, iter);
      return TRUE;
    }
  return FALSE;
908 909 910 911 912
}

static void
gtk_tree_model_iface_init (GtkTreeModelIface *iface)
{
913 914 915 916 917 918 919 920 921 922 923 924
  iface->get_flags = glade_signal_model_get_flags;
  iface->get_column_type = glade_signal_model_get_column_type;
  iface->get_n_columns = glade_signal_model_get_n_columns;
  iface->get_iter = glade_signal_model_get_iter;
  iface->get_path = glade_signal_model_get_path;
  iface->get_value = glade_signal_model_get_value;	
  iface->iter_next = glade_signal_model_iter_next;
  iface->iter_children = glade_signal_model_iter_children;
  iface->iter_has_child = glade_signal_model_iter_has_child;
  iface->iter_n_children = glade_signal_model_iter_n_children;
  iface->iter_nth_child = glade_signal_model_iter_nth_child;
  iface->iter_parent = glade_signal_model_iter_parent;
925 926 927
}

static gboolean
928
glade_signal_model_row_draggable (GtkTreeDragSource *model, GtkTreePath *path)
929
{
930
  GtkTreeIter iter;
931
  GladeSignal *signal;
932 933
  gboolean retval;
  gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
934

935 936 937
  gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
		      GLADE_SIGNAL_COLUMN_SIGNAL, &signal,
		      -1);
938

939 940
  retval = signal && !glade_signal_model_is_dummy_handler (GLADE_SIGNAL_MODEL (model),
							   signal);
941

942 943
  g_object_unref (signal);
  return retval;
944 945 946
}

static gboolean
947 948 949
glade_signal_model_drag_data_get (GtkTreeDragSource *model, 
                                  GtkTreePath *path,
                                  GtkSelectionData *data)
950
{
951
  GtkTreeIter iter;
952

953 954
  if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
    {
955 956 957 958
      GladeSignal *signal;
      const gchar *widget = iter.user_data;
      gchar *dnd_text;
      const gchar *user_data;
959 960 961 962

      gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
			  GLADE_SIGNAL_COLUMN_SIGNAL, &signal, -1);

963 964 965 966 967 968 969 970
      user_data = glade_signal_get_userdata (signal);
      
      dnd_text = g_strdup_printf ("%s:%s:%s:%s:%d:%d", widget, 
                                  glade_signal_get_name (signal),
                                  glade_signal_get_handler (signal),
                                  user_data && strlen (user_data) ? user_data : "(none)",
                                  glade_signal_get_swapped (signal),
                                  glade_signal_get_after (signal));
971 972 973 974 975 976 977 978 979 980 981 982 983
      gtk_selection_data_set (data,
			      gdk_atom_intern_static_string ("application/x-glade-signal"),
			      8,
			      (guchar*) dnd_text,
			      strlen (dnd_text));

      g_free (dnd_text);
      return TRUE;
    }
  else
    {
      return FALSE;
    }
984 985 986
}

static gboolean
987 988
glade_signal_model_drag_data_delete (GtkTreeDragSource *model, 
                                     GtkTreePath *path)
989
{
990 991
  /* We don't move rows... */
  return FALSE;
992 993 994
}

static void
995
gtk_tree_drag_source_iface_init (GtkTreeDragSourceIface *iface)
996
{
997 998 999
  iface->row_draggable = glade_signal_model_row_draggable;
  iface->drag_data_get = glade_signal_model_drag_data_get;
  iface->drag_data_delete = glade_signal_model_drag_data_delete;
1000
}