[glade/gbinding] Move all binding source/target synchronization logic into the command system



commit 4540e5efb0b25f5a390e27fff865a14eea4bd2b3
Author: Denis Washington <denisw src gnome org>
Date:   Thu Aug 18 20:20:15 2011 +0200

    Move all binding source/target synchronization logic into the command system
    
    As to Tristan's request. This makes all the signal handling hackery I did
    in glade-property.c obsolete, which greatly simplifies the code! The only
    drawback is that changes of a binding source property's "enabled"/"sensitive"
    state are not recognized anymore as these are not registered as commands.
    How this will be fixed will still have to be discussed wih Pablo and Tristan
    (likely after GSoC).

 gladeui/glade-command.c  |  138 +++++++++++++++++++------
 gladeui/glade-property.c |  263 +++++-----------------------------------------
 gladeui/glade-property.h |    2 +
 3 files changed, 134 insertions(+), 269 deletions(-)
---
diff --git a/gladeui/glade-command.c b/gladeui/glade-command.c
index 8ab8cfc..3ca2667 100644
--- a/gladeui/glade-command.c
+++ b/gladeui/glade-command.c
@@ -705,31 +705,52 @@ glade_command_set_properties_list (GladeProject * project, GList * props)
 }
 
 
+static GList *
+glade_command_add_to_set_properties_list (GList * list,
+                                          GladeProperty * property,
+                                          const GValue * old_value,
+                                          const GValue * new_value)
+{
+  GCSetPropData *sdata;
+
+  sdata = g_new (GCSetPropData, 1);
+  sdata->property = property;
+  sdata->old_value = g_new0 (GValue, 1);
+  sdata->new_value = g_new0 (GValue, 1);
+  g_value_init (sdata->old_value, G_VALUE_TYPE (old_value));
+  g_value_init (sdata->new_value, G_VALUE_TYPE (new_value));
+  g_value_copy (old_value, sdata->old_value);
+  g_value_copy (new_value, sdata->new_value);
+
+  return g_list_prepend (list, sdata);
+}
+
 void
 glade_command_set_properties (GladeProperty * property,
                               const GValue * old_value,
                               const GValue * new_value, ...)
 {
-  GCSetPropData *sdata;
-  GladeProperty *prop;
+  GladeProperty *prop, *target;
   GladeWidget   *widget;
   GladeProject  *project;
   GValue *ovalue, *nvalue;
-  GList *list = NULL;
+  GList *list = NULL, *t;
   va_list vl;
 
   g_return_if_fail (GLADE_IS_PROPERTY (property));
 
   /* Add first set */
-  sdata = g_new (GCSetPropData, 1);
-  sdata->property = property;
-  sdata->old_value = g_new0 (GValue, 1);
-  sdata->new_value = g_new0 (GValue, 1);
-  g_value_init (sdata->old_value, G_VALUE_TYPE (old_value));
-  g_value_init (sdata->new_value, G_VALUE_TYPE (new_value));
-  g_value_copy (old_value, sdata->old_value);
-  g_value_copy (new_value, sdata->new_value);
-  list = g_list_prepend (list, sdata);
+  list = glade_command_add_to_set_properties_list (list, property,
+                                                   old_value, new_value);
+
+  /* Also set values of binding targets */
+  for (t = glade_property_get_binding_targets (property); t; t = t->next)
+    {
+      target = t->data;
+      if (!glade_property_get_binding_transform_func (target))
+          list = glade_command_add_to_set_properties_list (list, target,
+                                                           old_value, new_value);
+    }
 
   va_start (vl, new_value);
   while ((prop = va_arg (vl, GladeProperty *)) != NULL)
@@ -741,15 +762,18 @@ glade_command_set_properties (GladeProperty * property,
       g_assert (G_IS_VALUE (ovalue));
       g_assert (G_IS_VALUE (nvalue));
 
-      sdata = g_new (GCSetPropData, 1);
-      sdata->property = g_object_ref (G_OBJECT (prop));
-      sdata->old_value = g_new0 (GValue, 1);
-      sdata->new_value = g_new0 (GValue, 1);
-      g_value_init (sdata->old_value, G_VALUE_TYPE (ovalue));
-      g_value_init (sdata->new_value, G_VALUE_TYPE (nvalue));
-      g_value_copy (ovalue, sdata->old_value);
-      g_value_copy (nvalue, sdata->new_value);
-      list = g_list_prepend (list, sdata);
+      list = glade_command_add_to_set_properties_list (list, property,
+                                                       ovalue, nvalue);
+
+      for (t = glade_property_get_binding_targets (prop); t; t = t->next)
+        {
+          printf ("set target\n");
+          target = t->data;
+          if (!glade_property_get_binding_transform_func (target))
+            list = glade_command_add_to_set_properties_list (list, target,
+                                                             ovalue, nvalue);
+        }
+
     }
   va_end (vl);
 
@@ -841,9 +865,6 @@ glade_command_bind_property_execute (GladeCommand * cmd)
   glade_property_set_binding_source (target, source);
   glade_property_set_binding_transform_func (target, transform_func);
 
-  if (!source && G_IS_VALUE (&bcmd->old_value))
-      glade_property_set_value (target, &bcmd->old_value);
-
   bcmd->undo = !bcmd->undo;
   return TRUE;
 }
@@ -914,20 +935,44 @@ glade_command_bind_property (GladeProperty * target,
   cmd = GLADE_COMMAND (me);
   cmd->priv->project =
     glade_widget_get_project (glade_property_get_widget (me->target));
+  cmd->priv->description = g_strdup ("dummy");
 
-  cmd->priv->description =
-    g_strdup_printf ((source != NULL)
-                     ? _("Binding property \"%s\" of %s")
-                     : _("Unbinding property \"%s\" of %s"),
-                     glade_property_class_id (glade_property_get_class (target)),
-                     glade_widget_get_name (glade_property_get_widget (target)));
+  glade_command_push_group ((source != NULL)
+                            ? _("Binding property \"%s\" of %s")
+                            : _("Unbinding property \"%s\" of %s"),
+                            glade_property_class_id (glade_property_get_class (target)),
+                            glade_widget_get_name (glade_property_get_widget (target)));
+
+
+  /* Adjust the target's value to match the source (or reset it if a
+   * transformation function is involved, in which case we cannot know
+   * how the target value looks like)
+   */
+  if (source)
+    {
+      const GValue *value;
+
+      if (transform_func)
+        {
+          GladePropertyClass *pclass;
+
+          pclass = glade_property_get_class (source);
+          value = glade_property_class_get_default (pclass);
+        }
+      else
+        value = glade_property_inline_value (source);
+
+      glade_command_set_property_value (target, value);
+    }
 
   glade_command_check_group (GLADE_COMMAND (me));
 
   if (glade_command_bind_property_execute (GLADE_COMMAND (me)))
-      glade_project_push_undo (cmd->priv->project, cmd);
+    glade_project_push_undo (cmd->priv->project, cmd);
   else
     g_object_unref (G_OBJECT (me));
+
+  glade_command_pop_group ();
 }
 
 /**************************************************/
@@ -1297,6 +1342,32 @@ glade_command_delete_prop_refs (GladeWidget * widget)
   g_list_free (refs);
 }
 
+static void
+glade_command_delete_binding_refs (GladeWidget * widget)
+{
+  GList *props, *p;
+
+  props = glade_widget_get_properties (widget);
+  for (p = props; p; p = p->next)
+    {
+      GladeProperty *property = p->data;
+      GList *targets, *t;
+
+      /* We need to iterate over a copy of the binding target list
+       * because its items are removed during the loop
+       */
+      targets = g_list_copy (glade_property_get_binding_targets (property));
+
+      for (t = targets; t; t = t->next)
+        {
+          GladeProperty *target = t->data;
+          glade_command_bind_property (target, NULL, NULL);
+        }
+
+      g_list_free (targets);
+    }
+}
+
 static void glade_command_remove (GList * widgets);
 
 static void
@@ -1395,6 +1466,11 @@ glade_command_remove (GList * widgets)
       /* Undoably unset any object properties that may point to the removed object */
       glade_command_delete_prop_refs (widget);
 
+      /* Undoably delete any property bindings whose source property belongs to the
+       * removed widget
+       */
+      glade_command_delete_binding_refs (widget);
+
       /* Undoably unlock and remove any widgets locked by this widget */
       glade_command_remove_locked (widget, cdata->reffed);
 
diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c
index b7823e0..402a7d5 100644
--- a/gladeui/glade-property.c
+++ b/gladeui/glade-property.c
@@ -108,42 +108,13 @@ struct _GladePropertyPrivate {
                                         * GladeProperty's value is bound to
                                         */
 
-  /* Binding source validility flags */
-  gboolean            binding_source_valid; /* Indicates whether the binding source
-                                             * is belongs to a widget that is currently
-                                             * part of the project (becomes FALSE if
-                                             * the binding source widget is removed)
-                                             */
+  GList              *binding_targets; /* The properties that this property is the binding
+                                          source of */
 
   gchar              *binding_transform_func;  /* the transformation function for
                                                 * the property's binding
                                                 */
 
-  gulong              binding_value_handler;  /* Signal handler to synchronize
-                                               * the GladeProperty with its
-                                               * binding source (if it is bound)
-                                               */
-
-  gulong              binding_enabled_handler;  /* Signal handler to keeep
-                                                 * binding_source_enabled
-                                                 * updated
-                                                 */
-
-  gulong              binding_sensitive_handler;  /* Signal handler to keeep
-                                                   * binding_source_sensitive
-                                                   * updated
-                                                   */
-
-  gulong              binding_widget_remove_handler;  /* Signal handler to update
-                                                       * binding_source_valid when the
-                                                       * binding source widget is removed
-                                                       */
-
-  gulong              binding_widget_add_handler;     /* Signal handler to update
-                                                       * binding_source_valid when the
-                                                       * binding source widget is added back
-                                                       */
-
   /* Used only for translatable strings. */
   guint     i18n_translatable : 1;
   gchar    *i18n_context;
@@ -619,9 +590,6 @@ glade_property_get_real_property (GObject * object,
     }
 }
 
-/* Forward declare for glade_property_finalize() */
-static void glade_property_remove_binding_source (GladeProperty *property);
-
 static void
 glade_property_finalize (GObject * object)
 {
@@ -632,8 +600,8 @@ glade_property_finalize (GObject * object)
       g_value_unset (property->priv->value);
       g_free (property->priv->value);
     }
-  if (property->priv->binding_source)
-      glade_property_remove_binding_source (property);
+  if (property->priv->binding_targets)
+    g_list_free (property->priv->binding_targets);
   if (property->priv->binding_transform_func)
     g_free (property->priv->binding_transform_func);
   if (property->priv->i18n_comment)
@@ -658,12 +626,8 @@ glade_property_init (GladeProperty * property)
   property->priv->enabled = TRUE;
   property->priv->sensitive = TRUE;
   property->priv->binding_source = NULL;
+  property->priv->binding_targets = NULL;
   property->priv->binding_transform_func = NULL;
-  property->priv->binding_value_handler = 0;
-  property->priv->binding_enabled_handler = 0;
-  property->priv->binding_sensitive_handler = 0;
-  property->priv->binding_widget_remove_handler = 0;
-  property->priv->binding_widget_add_handler = 0;
   property->priv->i18n_translatable = TRUE;
   property->priv->i18n_comment = NULL;
   property->priv->sync_tolerance = 1;
@@ -1759,137 +1723,12 @@ glade_property_get_state (GladeProperty      *property)
   return property->priv->state;
 }
 
-static gboolean
-glade_property_binding_source_valid (GladeProperty *binding_source)
-{
-  GladeWidget *source_widget;
-
-  if (!binding_source)
-    return FALSE;
-
-  source_widget = glade_property_get_widget (binding_source);
-
-  if (!glade_property_get_enabled (binding_source) ||
-      !glade_property_get_sensitive (binding_source) ||
-      !glade_widget_in_project (source_widget))
-    return FALSE;
-
-  return TRUE;
-}
-
 GladeProperty *
 glade_property_get_binding_source (GladeProperty *property)
 {
-  GladeProperty *source;
-
   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
 
-  source = property->priv->binding_source;
-  return (glade_property_binding_source_valid (source)) ? source : NULL;
-}
-
-static void
-glade_property_binding_source_weak_notify_cb (GladeProperty *property,
-                                              GObject       *binding_source)
-{
-  property->priv->binding_source = NULL;
-  property->priv->binding_value_handler = 0;
-  glade_property_remove_binding_source (property);
-}
-
-static void
-glade_property_remove_binding_source (GladeProperty *property)
-{
-  GladeProperty *old_source;
-  GladeWidget *widget;
-  GladeProject *project;
-
-  if ((old_source = property->priv->binding_source) != NULL)
-    {
-      g_object_weak_unref (G_OBJECT (old_source),
-                           (GWeakNotify) glade_property_binding_source_weak_notify_cb,
-                           property);
-
-      if (property->priv->binding_value_handler > 0)
-        g_signal_handler_disconnect (old_source, property->priv->binding_value_handler);
-      if (property->priv->binding_enabled_handler > 0)
-        g_signal_handler_disconnect (old_source, property->priv->binding_enabled_handler);
-      if (property->priv->binding_sensitive_handler > 0)
-        g_signal_handler_disconnect (old_source, property->priv->binding_sensitive_handler);
-    }
-
-  property->priv->binding_value_handler = 0;
-  property->priv->binding_enabled_handler = 0;
-  property->priv->binding_sensitive_handler = 0;
-
-  /* The property's widget might be currently finalized and have
-   * its project set to NULL, so prefer to query the binding source
-   * widget for it.
-   */
-  widget = old_source ?
-    glade_property_get_widget (old_source) :
-    glade_property_get_widget (property);
-  project = glade_widget_get_project (widget);
-
-  /* FIXME: If the property and binding source belong to the same widget
-   * and that widget is currently being finalized, we cannot get to the
-   * GladeProject as the widget has been removed from the project already.
-   * This means we can do nothing but to leak the "add-widget" and
-   * "remove-widget" signal handlers.  (However, as we guarded the
-   * handler closure with g_object_watch_closure() and the widget's
-   * finalization almost always means that the project is being
-   * finalized too, this isn't a big problem.)
-   */
-  if (project)
-    {
-      if (property->priv->binding_widget_remove_handler > 0)
-        g_signal_handler_disconnect (project,
-                                     property->priv->binding_widget_remove_handler);
-      if (property->priv->binding_widget_add_handler > 0)
-        g_signal_handler_disconnect (project,
-                                     property->priv->binding_widget_add_handler);
-    }
-
-  property->priv->binding_widget_remove_handler = 0;
-  property->priv->binding_widget_add_handler = 0;
-}
-
-static void
-glade_property_binding_source_value_changed_cb (GladeProperty *source,
-                                                GValue        *old_value,
-                                                GValue        *new_value,
-                                                GladeProperty *property)
-{
-  glade_property_set_value (property, new_value);
-}
-
-static void
-glade_property_binding_source_notify_enabled_sensitive_cb (GladeProperty *source,
-                                                           GParamSpec    *pspec,
-                                                           GladeProperty *property)
-{
-  if (glade_property_binding_source_valid (source))
-    {
-      GValue source_val = {0};
-
-      glade_property_get_value (source, &source_val);
-      glade_property_set_value (property, &source_val);
-    }
-  else
-    glade_property_reset (property);
-
-  g_object_notify_by_pspec (G_OBJECT (property),
-                            properties[PROP_BINDING_SOURCE]);
-}
-
-static void
-glade_property_binding_source_widget_cb (GladeProject  *project,
-                                         GladeWidget   *widget,
-                                         GladeProperty *property)
-{
-  if (widget == glade_property_get_widget (property->priv->binding_source))
-    g_object_notify_by_pspec (G_OBJECT (property),
-                              properties[PROP_BINDING_SOURCE]);
+  return property->priv->binding_source;
 }
 
 void
@@ -1907,82 +1746,37 @@ glade_property_set_binding_source (GladeProperty *property,
       GladePropertyClass *source_pclass = glade_property_get_class (binding_source);
       GParamSpec *prop_pspec = glade_property_class_get_pspec (prop_pclass);
       GParamSpec *source_pspec = glade_property_class_get_pspec (source_pclass);
+      GladeWidget *source_widget = glade_property_get_widget (binding_source);
 
       g_return_if_fail (source_pspec->flags | G_PARAM_READABLE);
       g_return_if_fail (prop_pspec->flags | G_PARAM_WRITABLE);
-      g_return_if_fail (glade_property_binding_source_valid (binding_source));
+      g_return_if_fail (glade_property_get_enabled (binding_source));
+      g_return_if_fail (glade_property_get_sensitive (binding_source));
+      g_return_if_fail (glade_widget_in_project (source_widget));
 
       if (property->priv->binding_transform_func)
         g_return_if_fail (g_type_is_a (G_PARAM_SPEC_TYPE (source_pspec),
                                        G_PARAM_SPEC_TYPE (prop_pspec)));
+
+      if (!g_list_find (binding_source->priv->binding_targets, property))
+        binding_source->priv->binding_targets =
+            g_list_prepend (binding_source->priv->binding_targets, property);
     }
 
-  old_source = glade_property_get_binding_source (property);
+  if ((old_source = property->priv->binding_source) != NULL)
+    old_source->priv->binding_targets =
+        g_list_remove (old_source->priv->binding_targets, property);
 
-  glade_property_remove_binding_source (property);
   property->priv->binding_source = binding_source;
+  g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_BINDING_SOURCE]);
+}
 
-  if (binding_source)
-    {
-      GladeWidget *widget = glade_property_get_widget (binding_source);
-      GladeProject *project = glade_widget_get_project (widget);
-      GClosure *closure;
-
-      g_object_weak_ref (G_OBJECT (binding_source),
-                         (GWeakNotify) glade_property_binding_source_weak_notify_cb,
-                         property);
-
-      /* Synchronize the source and target property values if there
-       * is no transformation function; if there is, the best thing we
-       * can do is to reset the target property to the default value
-       * (the source and target property types might not be compatible)
-       */
-      if (glade_property_get_binding_transform_func (property))
-        glade_property_reset (property);
-      else
-        {
-          GValue source_val = {0};
-
-          property->priv->binding_value_handler =
-            g_signal_connect (binding_source, "value-changed",
-                              G_CALLBACK (glade_property_binding_source_value_changed_cb),
-                              property);
-
-          glade_property_get_value (binding_source, &source_val);
-          glade_property_set_value (property, &source_val);
-        }
-
-      property->priv->binding_enabled_handler =
-        g_signal_connect (binding_source, "notify::enabled",
-                          G_CALLBACK (glade_property_binding_source_notify_enabled_sensitive_cb),
-                          property);
-
-      property->priv->binding_sensitive_handler =
-        g_signal_connect (binding_source, "notify::sensitive",
-                          G_CALLBACK (glade_property_binding_source_notify_enabled_sensitive_cb),
-                          property);
-
-      /* To be called when the binding source widget is deleted / re-added */
-      closure =
-        g_cclosure_new (G_CALLBACK (glade_property_binding_source_widget_cb),
-                        G_OBJECT (property), NULL);
-
-      /* Don't call after the binding source has been freed (see FIXME
-       * in glade_property_remove_binding_source() for why this is
-       * needed)
-       */
-      g_object_watch_closure (G_OBJECT (binding_source), closure);
-
-      property->priv->binding_widget_remove_handler =
-        g_signal_connect_closure (project, "remove-widget", closure, FALSE);
-
-      property->priv->binding_widget_add_handler =
-        g_signal_connect_closure (project, "add-widget", closure, FALSE);
-    }
+GList *
+glade_property_get_binding_targets (GladeProperty *property)
+{
+  g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
 
-  if (binding_source != old_source)
-    g_object_notify_by_pspec (G_OBJECT (property),
-                              properties[PROP_BINDING_SOURCE]);
+  return property->priv->binding_targets;
 }
 
 const gchar *
@@ -1990,10 +1784,7 @@ glade_property_get_binding_transform_func (GladeProperty *property)
 {
   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
 
-  if (glade_property_get_binding_source (property))
-    return property->priv->binding_transform_func;
-  else
-    return NULL;
+  return property->priv->binding_transform_func;
 }
 
 void
@@ -2007,10 +1798,6 @@ glade_property_set_binding_transform_func (GladeProperty *property,
     ? g_strdup (transform_func)
     : NULL;
 
-  /* Call glade_property_set_binding_source() to adjust to the new
-   * transformation function setting */
-  glade_property_set_binding_source (property, property->priv->binding_source);
-
   g_object_notify_by_pspec (G_OBJECT (property),
                             properties[PROP_BINDING_TRANSFORM_FUNC]);
 }
diff --git a/gladeui/glade-property.h b/gladeui/glade-property.h
index 9adce85..d07df44 100644
--- a/gladeui/glade-property.h
+++ b/gladeui/glade-property.h
@@ -171,6 +171,8 @@ GladeProperty          *glade_property_get_binding_source    (GladeProperty
 void                    glade_property_set_binding_source    (GladeProperty      *property,
                                                               GladeProperty      *binding_source);
 
+GList                  *glade_property_get_binding_targets   (GladeProperty      *property);
+
 const gchar            *glade_property_get_binding_transform_func (GladeProperty *property);
 
 void                    glade_property_set_binding_transform_func (GladeProperty *property,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]