[glade/gbinding] Big refactor: Move all GladeBinding functionality directly into GladeProperty



commit 710ea0d803f6df465ce1fdd03517934e8ba1e7b3
Author: Denis Washington <denisw src gnome org>
Date:   Sat Jun 25 00:23:44 2011 +0200

    Big refactor: Move all GladeBinding functionality directly into GladeProperty
    
    As discussed with Tristan van Berkom. This fixes races that formerly existed
    between creating a binding and attaching it to a GladeProperty (in this timeframe,
    two GladeBindings were active at once) and - surprisingly - makes the code quite a
    bit cleaner. This should be a much better base for implementing the next features
    on my TODO list than the former one was.
    
    As acherry on top, the new structure allowed me to fix a bug on the way: when
    undoing a property binding action, the binding target property was editable
    again, but the binding itself didn't actually disappear (meaning that editing
    the source property still overrode the value of the target). Now, everything
    works as intended. :)

 gladeui/Makefile.am             |    4 +-
 gladeui/glade-binding.c         |  442 ---------------------------------------
 gladeui/glade-binding.h         |   66 ------
 gladeui/glade-command.c         |   41 +---
 gladeui/glade-editor-property.c |   35 +++-
 gladeui/glade-project.c         |   26 ++-
 gladeui/glade-property.c        |  215 +++++++++++++++++--
 gladeui/glade-property.h        |   15 +-
 gladeui/glade-widget-adaptor.c  |   23 +--
 9 files changed, 276 insertions(+), 591 deletions(-)
---
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 29be1b8..5860d03 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -87,9 +87,7 @@ libgladeui_2_la_SOURCES = \
 	glade-displayable-values.c \
 	glade-signal-model.c \
 	glade-cell-renderer-icon.c \
-	glade-preview.c \
-	glade-binding.c \
-	glade-binding.h
+	glade-preview.c
 
 libgladeui_2_la_CPPFLAGS =  \
 	$(common_defines)   \
diff --git a/gladeui/glade-command.c b/gladeui/glade-command.c
index f67c86b..ebf263a 100644
--- a/gladeui/glade-command.c
+++ b/gladeui/glade-command.c
@@ -827,33 +827,17 @@ glade_command_bind_property_execute (GladeCommand * cmd)
 {
   GladeCommandBindProperty *bcmd; 
   GladeProperty *target, *source;
-  GladeBinding *binding;
 
   g_return_val_if_fail (GLADE_IS_COMMAND_BIND_PROPERTY (cmd), TRUE);
   
   bcmd = GLADE_COMMAND_BIND_PROPERTY (cmd);
   target = bcmd->target;
   source = bcmd->undo ? bcmd->old_source : bcmd->new_source;
-  binding = glade_property_get_binding (bcmd->target);
-  
-  if (!binding && source)
-    {
-      glade_property_set_binding (target,
-                                  glade_binding_new (source, target));
-      bcmd->old_source = NULL;
-    }
-  else if (binding)
-    {
-      bcmd->old_source = glade_binding_get_source (binding);
 
-      if (!source)
-        {
-          glade_property_set_binding (target, NULL);
-          glade_property_set_value (target, &bcmd->old_value);
-        }
-      else
-        glade_binding_set_source (binding, source);
-    }
+  glade_property_set_binding_source (target, source);
+
+  if (!source && G_IS_VALUE (&bcmd->old_value))
+      glade_property_set_value (target, &bcmd->old_value);
 
   bcmd->undo = !bcmd->undo;
   return TRUE;
@@ -898,24 +882,19 @@ void
 glade_command_bind_property (GladeProperty * target, GladeProperty * source)
 {
   GladeCommandBindProperty *me;
-  GladeBinding *binding;
   GladeCommand *cmd;
   
   g_return_if_fail (GLADE_IS_PROPERTY (target));
-  g_return_if_fail (GLADE_IS_PROPERTY (source));
+  g_return_if_fail (!source || GLADE_IS_PROPERTY (source));
 
   me = g_object_new (GLADE_COMMAND_BIND_PROPERTY_TYPE, NULL);
+  me->undo = FALSE;
   me->target = target;
+  me->old_source = glade_property_get_binding_source (target);
   me->new_source = source;
-  me->undo = FALSE;
-  
-  if ((binding = glade_property_get_binding (target)) != NULL)
-    me->old_source = glade_binding_get_source (binding);
-  else
-    {
-      me->old_source = NULL;
-      glade_property_get_value (target, &me->old_value);
-    }
+
+  if (!me->old_source)
+    glade_property_get_value (target, &me->old_value);
 
   cmd = GLADE_COMMAND (me);
   cmd->priv->project =
diff --git a/gladeui/glade-editor-property.c b/gladeui/glade-editor-property.c
index 8863d2a..792a2fc 100644
--- a/gladeui/glade-editor-property.c
+++ b/gladeui/glade-editor-property.c
@@ -266,14 +266,12 @@ glade_editor_property_tooltip_cb (GladeProperty * property,
 
   if (glade_property_get_sensitive (property))
     {
-      GladeBinding *binding;
+      GladeProperty *source;
       
-      if ((binding = glade_property_get_binding (property)) != NULL)
+      if ((source = glade_property_get_binding_source (property)) != NULL)
         {
-          GladeProperty *source;
           const gchar *source_obj, *source_prop;
 
-          source = glade_binding_get_source (binding);
           source_prop = glade_property_class_id (glade_property_get_class (source));
           source_obj = glade_widget_get_name (glade_property_get_widget (source));
           
@@ -308,7 +306,7 @@ glade_editor_property_sensitivity_cb (GladeProperty * property,
 
   gtk_widget_set_sensitive (eprop->priv->input, sensitive && support_sensitive &&
                             glade_property_get_enabled (property) &&
-                            !glade_property_get_binding (property));
+                            !glade_property_get_binding_source (property));
   if (eprop->priv->check)
     gtk_widget_set_sensitive (eprop->priv->check, sensitive && support_sensitive);
 }
@@ -332,7 +330,7 @@ glade_editor_property_fix_label (GladeEditorProperty * eprop)
     return;
 
   /* refresh label */
-  if (glade_property_get_binding (eprop->priv->property))
+  if (glade_property_get_binding_source (eprop->priv->property))
     text = g_strdup_printf ("<b><i>%s:</i></b>", glade_property_class_get_name (eprop->priv->klass));
   else if ((glade_property_get_state (eprop->priv->property) & GLADE_STATE_CHANGED) != 0)
     text = g_strdup_printf ("<b>%s:</b>", glade_property_class_get_name (eprop->priv->klass));
@@ -390,6 +388,27 @@ glade_editor_property_enabled_toggled_cb (GtkWidget * check,
                                                             (check)));
 }
 
+static void
+glade_editor_property_binding_source_cb (GladeProperty *property,
+                                         GParamSpec *pspec,
+                                         GladeEditorProperty *eprop)
+{
+  GladePropertyClass *pclass = glade_property_get_class (property);
+  
+  /* disable value input for bound properties */
+  if (glade_property_get_binding_source (property))
+    gtk_widget_set_sensitive (eprop->priv->input, FALSE);
+
+  /* refresh label formatting*/
+  glade_editor_property_fix_label (eprop);
+
+  /* update tooltip to describe the binding */
+  glade_editor_property_tooltip_cb
+    (property, glade_property_class_get_tooltip (pclass),
+     glade_propert_get_insensitive_tooltip (property),
+     glade_property_get_support_warning (property), eprop);
+}
+
 static gboolean
 glade_editor_property_button_pressed (GtkWidget * widget,
                                       GdkEventButton * event,
@@ -627,6 +646,10 @@ glade_editor_property_load_common (GladeEditorProperty * eprop,
           g_signal_connect (G_OBJECT (eprop->priv->property),
                             "notify::state",
                             G_CALLBACK (glade_editor_property_state_cb), eprop);
+      eprop->priv->state_id =
+          g_signal_connect (G_OBJECT (eprop->priv->property),
+                            "notify::binding-source",
+                            G_CALLBACK (glade_editor_property_binding_source_cb), eprop);
 
 
       /* In query dialogs when the user hits cancel, 
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index a2e9ed2..9f7d8be 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -1017,7 +1017,8 @@ glade_project_new (void)
   return project;
 }
 
-/* Called when finishing loading a glade file to resolve object type properties
+/* Called when finishing loading a glade file to resolve bound and object type
+ * properties
  */
 static void
 glade_project_fix_object_props (GladeProject *project)
@@ -1026,8 +1027,7 @@ glade_project_fix_object_props (GladeProject *project)
   GValue *value;
   GladeWidget *gwidget;
   GladeProperty *property;
-  gchar *txt;
-  GladeBinding *binding;
+  gchar *txt, *txt2;
   
   objects = g_list_copy (project->priv->objects);
   for (l = objects; l; l = l->next)
@@ -1059,8 +1059,24 @@ glade_project_fix_object_props (GladeProject *project)
                                  "glade-loaded-object", NULL);
             }
 
-          if ((binding = glade_property_get_binding (property)) != NULL)
-            glade_binding_complete (binding, project);
+          if ((txt = g_object_get_data (G_OBJECT (property),
+                                        "glade-source-object")) != NULL &&
+              (txt2 = g_object_get_data (G_OBJECT (property),
+                                         "glade-source-property")) != NULL)
+            {
+              GladeWidget *source_obj;
+              GladeProperty *source_prop;
+
+              source_obj = glade_project_get_widget_by_name (project, txt);
+              if (!source_obj)
+                continue;
+
+              source_prop = glade_widget_get_property (source_obj, txt2);
+              if (!source_prop)
+                continue;
+              
+              glade_property_set_binding_source (property, source_prop);
+            }
         }
     }
   g_list_free (objects);
diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c
index 63e905e..d03fb54 100644
--- a/gladeui/glade-property.c
+++ b/gladeui/glade-property.c
@@ -34,7 +34,7 @@
  * a #GladeProperty to interface with, #GladeProperty provides a means
  * to handle properties in the runtime environment.
  * 
- * A #GladeProperty can be seen as an instance of a #GladePropertyClass, 
+ * A #GladeProperty can be seen as an instance of a #GladePropertyClass,
  * the #GladePropertyClass describes how a #GladeProperty will function.
  */
 
@@ -104,8 +104,14 @@ struct _GladePropertyPrivate {
 					* or derived widget code).
 					*/
 
-  /* Non-NULL if the property is the target of a binding */
-  GladeBinding       *binding;
+  GladeProperty      *binding_source;  /* If non-NULL, the property that this
+                                        * GladeProperty's value is bound to
+                                        */
+
+  gulong              binding_handler; /* Signal handler to synchronize
+                                        * the GladeProperty with its binding
+                                        * source (if it is bound)
+                                        */
 
   /* Used only for translatable strings. */
   guint     i18n_translatable : 1;
@@ -129,6 +135,7 @@ enum
   PROP_CLASS,
   PROP_ENABLED,
   PROP_SENSITIVE,
+  PROP_BINDING_SOURCE,
   PROP_I18N_TRANSLATABLE,
   PROP_I18N_CONTEXT,
   PROP_I18N_COMMENT,
@@ -511,6 +518,10 @@ glade_property_set_real_property (GObject * object,
       case PROP_SENSITIVE:
         property->priv->sensitive = g_value_get_boolean (value);
         break;
+      case PROP_BINDING_SOURCE:
+        glade_property_set_binding_source (property,
+                                           g_value_get_pointer (value));
+        break;
       case PROP_I18N_TRANSLATABLE:
         glade_property_i18n_set_translatable (property,
                                               g_value_get_boolean (value));
@@ -545,6 +556,10 @@ glade_property_get_real_property (GObject * object,
       case PROP_SENSITIVE:
         g_value_set_boolean (value, glade_property_get_sensitive (property));
         break;
+      case PROP_BINDING_SOURCE:
+        g_value_set_pointer (value,
+                             glade_property_get_binding_source (property));
+        break;        
       case PROP_I18N_TRANSLATABLE:
         g_value_set_boolean (value,
                              glade_property_i18n_get_translatable (property));
@@ -574,8 +589,9 @@ glade_property_finalize (GObject * object)
       g_value_unset (property->priv->value);
       g_free (property->priv->value);
     }
-  if (property->priv->binding)
-    g_object_unref (property->priv->binding);
+  if (property->priv->binding_source)
+    g_signal_handler_disconnect (property->priv->binding_source,
+                                 property->priv->binding_handler);
   if (property->priv->i18n_comment)
     g_free (property->priv->i18n_comment);
   if (property->priv->i18n_context)
@@ -597,6 +613,8 @@ glade_property_init (GladeProperty * property)
 
   property->priv->enabled = TRUE;
   property->priv->sensitive = TRUE;
+  property->priv->binding_source = NULL;
+  property->priv->binding_handler = 0;
   property->priv->i18n_translatable = TRUE;
   property->priv->i18n_comment = NULL;
   property->priv->sync_tolerance = 1;
@@ -645,6 +663,13 @@ glade_property_klass_init (GladePropertyKlass * prop_class)
                           _("This gives backends control to set property sensitivity"),
                           TRUE, G_PARAM_READWRITE);
 
+    properties[PROP_BINDING_SOURCE] =
+      g_param_spec_pointer ("binding-source",
+                          _("Binding Source Property"),
+                          _("If the property is the target of a property "
+                            "binding, this is the property it is bound to"),
+                          G_PARAM_READWRITE);
+
   properties[PROP_I18N_CONTEXT] =
     g_param_spec_string ("i18n-context",
                          _("Context"),
@@ -1237,6 +1262,103 @@ glade_property_write (GladeProperty * property,
 }
 
 /**
+ * glade_property_binding_read:
+ * @node: The #GladeXmlNode to read from
+ * @widget: The widget to which the target property belongs
+ *
+ * Read the binding information from @node and save it in
+ * the target #GladeProperty of @widget.
+ *
+ * Note that the actual binding source property will only be
+ * resolved after the project is completely loaded.
+ */
+void
+glade_property_binding_read (GladeXmlNode *node,
+                             GladeWidget  *widget)
+{
+  gchar *to, *from, *source;
+  GladeProperty *target;
+  
+  g_return_if_fail (node && glade_xml_node_verify (node, GLADE_XML_TAG_BINDING));
+  g_return_if_fail (GLADE_IS_WIDGET (widget));
+
+  to = glade_xml_get_property_string_required (node, GLADE_XML_TAG_TO, NULL);
+  if (!to)
+    return;
+
+  target = glade_widget_get_property (widget, to);
+  g_free (to);
+
+  if (!target)
+    return;
+
+  from = glade_xml_get_property_string_required (node, GLADE_XML_TAG_FROM, NULL);
+  source = glade_xml_get_property_string_required (node, GLADE_XML_TAG_SOURCE, NULL);
+
+  if (from && source)
+    {
+      g_object_set_data_full (G_OBJECT (target),
+                              "glade-source-property",
+                              g_strdup (from), g_free);
+      g_object_set_data_full (G_OBJECT (target),
+                              "glade-source-object",
+                              g_strdup (source), g_free);
+    }
+
+  g_free (from);
+  g_free (source);
+}
+
+/**
+ * glade_property_binding_write:
+ * @property: A #GladeProperty
+ * @context: A #GladeXmlContext
+ * @node: A #GladeXmlNode
+ *
+ * Write the binding information of @property to @node.
+ */
+void
+glade_property_binding_write (GladeProperty   *property,
+                              GladeXmlContext *context,
+                              GladeXmlNode    *node)
+{
+  GladeXmlNode *binding_node;
+  GladeProperty *source_prop;
+  const gchar *to, *from, *source;
+  GladeWidget *widget;
+
+  g_return_if_fail (GLADE_IS_PROPERTY (property));
+  g_return_if_fail (node != NULL);
+
+  if (!glade_property_get_binding_source (property))
+    return;
+  
+  if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET)))
+    return;
+
+  binding_node = glade_xml_node_new (context, GLADE_XML_TAG_BINDING);
+  glade_xml_node_append_child (node, binding_node);
+
+  to = glade_property_class_id (glade_property_get_class (property));
+
+  source_prop = glade_property_get_binding_source (property);  
+  from = glade_property_class_id (glade_property_get_class (source_prop));
+
+  widget = glade_property_get_widget (source_prop);
+  source = glade_widget_get_name (widget);
+  
+  glade_xml_node_set_property_string (binding_node,
+                                      GLADE_XML_TAG_TO,
+                                      to);
+  glade_xml_node_set_property_string (binding_node,
+                                      GLADE_XML_TAG_FROM,
+                                      from);
+  glade_xml_node_set_property_string (binding_node,
+                                      GLADE_XML_TAG_SOURCE,
+                                      source);
+}
+
+/**
  * glade_property_add_object:
  * @property: a #GladeProperty
  * @object: The #GObject to add
@@ -1563,29 +1685,82 @@ glade_property_get_state (GladeProperty      *property)
   return property->priv->state;
 }
 
-GladeBinding *
-glade_property_get_binding (GladeProperty    *property)
+GladeProperty *
+glade_property_get_binding_source (GladeProperty *property)
 {
   g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
   
-  return property->priv->binding;
+  return property->priv->binding_source;
 }
 
-void
-glade_property_set_binding (GladeProperty    *property,
-                            GladeBinding     *binding)
+static void
+glade_property_binding_source_weak_notify_cb (GladeProperty *property,
+                                              GObject       *binding_source)
 {
-  g_return_if_fail (GLADE_IS_PROPERTY (property));
-  g_return_if_fail ((GLADE_IS_BINDING (binding)
-                     && glade_binding_get_target (binding) == property)
-                    || !binding);
+  property->priv->binding_handler = 0;
+  g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_BINDING_SOURCE]);  
+}
+
+static void
+glade_property_binding_source_value_changed_cb (GladeProperty *prop,
+                                                GValue        *old_value,
+                                                GValue        *new_value,
+                                                GladeProperty *property)
+{
+  glade_property_set_value (property, new_value);
+}
 
-  if (property->priv->binding)
-    g_object_unref (property->priv->binding);
+static void
+glade_property_update_binding (GladeProperty *property,
+                               GladeProperty *old_source)
+{
+  GladeProperty *source;
+  GValue source_val = {0};
+
+  if (property->priv->binding_handler)
+    g_signal_handler_disconnect (old_source, property->priv->binding_handler);
+
+  source = glade_property_get_binding_source (property);
+
+  if (source)
+    {
+      property->priv->binding_handler =
+        g_signal_connect (source, "value-changed",
+                          G_CALLBACK (glade_property_binding_source_value_changed_cb),
+                          property);
+
+      /* Synchronize the source and target property values once */
+      glade_property_get_value (source, &source_val);
+      glade_property_set_value (property, &source_val);
+    }
+  else
+    property->priv->binding_handler = 0;
+
+}
+
+void
+glade_property_set_binding_source (GladeProperty *property,
+                                   GladeProperty *binding_source)
+{
+  GladeProperty *old_source;
   
-  property->priv->binding = binding;
-  if (binding)
-    g_object_ref (binding);
+  g_return_if_fail (GLADE_IS_PROPERTY (property));
+  g_return_if_fail (!binding_source || GLADE_IS_PROPERTY (binding_source));
+
+  old_source = property->priv->binding_source;
+  property->priv->binding_source = binding_source;
+
+  if (old_source)
+    g_object_weak_unref (G_OBJECT (old_source),
+                         (GWeakNotify) glade_property_binding_source_weak_notify_cb,
+                         property);
+  if (binding_source)
+    g_object_weak_ref (G_OBJECT (binding_source),
+                       (GWeakNotify) glade_property_binding_source_weak_notify_cb,
+                       property);
+
+  glade_property_update_binding (property, old_source);
+  g_object_notify_by_pspec (G_OBJECT (property), properties[PROP_BINDING_SOURCE]);
 }
 
 static gint glade_property_su_stack = 0;
diff --git a/gladeui/glade-property.h b/gladeui/glade-property.h
index bbb103f..bf27416 100644
--- a/gladeui/glade-property.h
+++ b/gladeui/glade-property.h
@@ -2,7 +2,6 @@
 #define __GLADE_PROPERTY_H__
 
 #include <glib-object.h>
-#include "glade-binding.h"
 
 G_BEGIN_DECLS
 
@@ -122,6 +121,14 @@ void                    glade_property_write                 (GladeProperty
 							      GladeXmlContext    *context,
 							      GladeXmlNode       *node);
 
+void                    glade_property_binding_read          (GladeXmlNode       *node,
+                                                              GladeWidget        *widget);
+
+void                    glade_property_binding_write         (GladeProperty      *property,
+                                                              GladeXmlContext    *context,
+                                                              GladeXmlNode       *node);
+
+
 GladePropertyClass     *glade_property_get_class             (GladeProperty      *property);
 
 void                    glade_property_set_sensitive         (GladeProperty      *property,
@@ -159,10 +166,10 @@ GValue                 *glade_property_inline_value          (GladeProperty
 
 GladePropertyState      glade_property_get_state             (GladeProperty      *property);
 
-GladeBinding *          glade_property_get_binding           (GladeProperty      *property);
+GladeProperty          *glade_property_get_binding_source    (GladeProperty      *property);
 
-void                    glade_property_set_binding           (GladeProperty      *property,
-                                                              GladeBinding       *binding);
+void                    glade_property_set_binding_source    (GladeProperty      *property,
+                                                              GladeProperty      *binding_source);
 
 void                    glade_property_i18n_set_comment      (GladeProperty      *property, 
 							      const gchar        *str);
diff --git a/gladeui/glade-widget-adaptor.c b/gladeui/glade-widget-adaptor.c
index 4384c3b..66f2413 100644
--- a/gladeui/glade-widget-adaptor.c
+++ b/gladeui/glade-widget-adaptor.c
@@ -42,7 +42,6 @@
 #include "glade-displayable-values.h"
 #include "glade-editor-table.h"
 #include "glade-cursor.h"
-#include "glade-binding.h"
 
 /* For g_file_exists */
 #include <sys/types.h>
@@ -971,7 +970,6 @@ glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor * adaptor,
   GladeXmlNode *iter_node;
   GladeSignal *signal;
   GladeProperty *property;
-  GladeBinding *binding;
   gchar *name, *prop_name;
   GList *read_properties = NULL, *l;
 
@@ -1017,8 +1015,7 @@ glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor * adaptor,
       if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_BINDING))
         continue;
 
-      if (!(binding = glade_binding_read (iter_node, widget)))
-        continue;
+      glade_property_binding_read (iter_node, widget);
     }
 
   /* Read in the signals */
@@ -1056,28 +1053,26 @@ glade_widget_adaptor_object_write_widget (GladeWidgetAdaptor * adaptor,
                                           GladeXmlNode * node)
 {
   GList *props;
-  GSList *bindings = NULL, *b;
   
   /* Write the properties */
   for (props = glade_widget_get_properties (widget); props; props = props->next)
     {
       GladeProperty      *property = props->data;
       GladePropertyClass *klass = glade_property_get_class (property);
-      GladeBinding       *binding = glade_property_get_binding (property);
       
       if (glade_property_class_save (klass) && 
 	  glade_property_get_enabled (property))
         glade_property_write (GLADE_PROPERTY (props->data), context, node);
-
-      if (binding)
-        bindings = g_slist_prepend (bindings, binding);
     }
 
-  /* Write the bindings */
-  for (b = bindings; b; b = b->next)
-    glade_binding_write (b->data, context, node);
-
-  g_slist_free (bindings);
+  /* Write the properties' bindings */
+  for (props = glade_widget_get_properties (widget); props; props = props->next)
+    {
+      GladeProperty *property = props->data;
+      
+      if (glade_property_get_binding_source (property))
+        glade_property_binding_write (property, context, node);
+    }
 }
 
 static void



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