[glade/gbinding: 1/60] Implement reading/writing of <binding> tags
- From: Denis Washington <denisw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glade/gbinding: 1/60] Implement reading/writing of <binding> tags
- Date: Tue, 13 Dec 2011 06:59:33 +0000 (UTC)
commit bdb21809eac0ac2f84f9a3c485f780b33bc90c6f
Author: Denis Washington <denisw src gnome org>
Date: Fri Jun 3 22:26:28 2011 +0200
Implement reading/writing of <binding> tags
This is the first in a (hopefully) long line of commits to implement
support for GObject property binding in Glade. It extends Glade's
GtkBuilder parsing/writing code to recognize property binding definitions
(which are codified as <binding> tags), create objects of the new
GladeBinding class to represent them, and write them back to the GtkBuilder
file when saving.
What this means is that if you now open a file with <binding> tags and
save them again later, the binding information is not lost.
gladeui/Makefile.am | 4 +-
gladeui/glade-binding.c | 348 ++++++++++++++++++++++++++++++++++++++++
gladeui/glade-binding.h | 63 +++++++
gladeui/glade-project.c | 6 +-
gladeui/glade-property.c | 29 ++++-
gladeui/glade-property.h | 7 +
gladeui/glade-widget-adaptor.c | 19 ++-
gladeui/glade-xml-utils.h | 3 +
8 files changed, 475 insertions(+), 4 deletions(-)
---
diff --git a/gladeui/Makefile.am b/gladeui/Makefile.am
index 7563f99..ee868db 100644
--- a/gladeui/Makefile.am
+++ b/gladeui/Makefile.am
@@ -88,7 +88,9 @@ libgladeui_2_la_SOURCES = \
glade-displayable-values.c \
glade-signal-model.c \
glade-cell-renderer-icon.c \
- glade-preview.c
+ glade-preview.c \
+ glade-binding.c \
+ glade-binding.h
libgladeui_2_la_CPPFLAGS = \
$(common_defines) \
diff --git a/gladeui/glade-binding.c b/gladeui/glade-binding.c
new file mode 100644
index 0000000..29a6673
--- /dev/null
+++ b/gladeui/glade-binding.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2011 Denis Washington
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Authors:
+ * Denis Washington <denisw online de>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "glade-binding.h"
+#include "glade-property.h"
+#include "glade-project.h"
+
+struct _GladeBindingPrivate {
+
+ GladeProperty *target; /* A pointer to the the binding's target
+ * GladeProperty
+ */
+
+ GladeProperty *source; /* A pointer to the the binding's source
+ * GladeProperty
+ */
+
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE,
+ PROP_TARGET,
+ N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES];
+
+static void glade_binding_class_init (GladeBindingClass * klass);
+static void glade_binding_init (GladeBinding * binding);
+static void glade_binding_finalize (GObject * object);
+
+G_DEFINE_TYPE (GladeBinding, glade_binding, G_TYPE_OBJECT)
+
+/*******************************************************************************
+ GObjectClass & Object Construction
+ *******************************************************************************/
+static void
+glade_binding_init (GladeBinding * binding)
+{
+ binding->priv = G_TYPE_INSTANCE_GET_PRIVATE (binding,
+ GLADE_TYPE_BINDING,
+ GladeBindingPrivate);
+
+ binding->priv->source = NULL;
+ binding->priv->target = NULL;
+}
+
+static void
+glade_binding_finalize (GObject * object)
+{
+}
+
+static void
+glade_binding_get_property (GObject * object,
+ guint prop_id,
+ GValue * value,
+ GParamSpec * pspec)
+{
+ GladeBinding *binding = GLADE_BINDING (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ g_value_set_object (value, binding->priv->source);
+ break;
+ case PROP_TARGET:
+ g_value_set_object (value, binding->priv->target);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+glade_binding_set_property (GObject * object,
+ guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec)
+{
+ GladeBinding *binding = GLADE_BINDING (object);
+
+ switch (prop_id)
+ {
+ case PROP_SOURCE:
+ binding->priv->source = g_value_get_object (value);
+ break;
+ case PROP_TARGET:
+ binding->priv->target = g_value_get_object (value);
+ if (binding->priv->target)
+ glade_property_set_binding (binding->priv->target, binding);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+glade_binding_class_init (GladeBindingClass * klass)
+{
+ GObjectClass *object_class;
+ g_return_if_fail (klass != NULL);
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ /* GObjectClass */
+ object_class->get_property = glade_binding_get_property;
+ object_class->set_property = glade_binding_set_property;
+ object_class->finalize = glade_binding_finalize;
+
+ /* Properties */
+ properties[PROP_TARGET] =
+ g_param_spec_object ("target",
+ _("Target"),
+ _("The GladeBinding's target property"),
+ GLADE_TYPE_PROPERTY,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+
+ properties[PROP_SOURCE] =
+ g_param_spec_object ("source",
+ _("Source"),
+ _("The GladeBinding's source property"),
+ GLADE_TYPE_PROPERTY,
+ G_PARAM_READWRITE);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ /* Private */
+ g_type_class_add_private (klass, sizeof (GladeBindingPrivate));
+}
+
+/*******************************************************************************
+ API
+ *******************************************************************************/
+/**
+ * glade_binding_new:
+ * @source: The binding source property
+ * @target: The binding target property
+ *
+ * Create a new GladeBinding with the specified @source and
+ * @target property.
+ *
+ * Returns: The newly created #GladeBinding
+ */
+GladeBinding *
+glade_binding_new (GladeProperty * source,
+ GladeProperty * target)
+{
+ return g_object_new (GLADE_TYPE_BINDING,
+ "source", source,
+ "target", target,
+ NULL);
+}
+
+/**
+ * glade_binding_get_target:
+ * @binding: The #GladeBinding
+ *
+ * Returns: The binding's target property
+ */
+GladeProperty *
+glade_binding_get_target (GladeBinding * binding)
+{
+ g_return_val_if_fail (GLADE_IS_BINDING (binding), NULL);
+
+ return binding->priv->target;
+}
+
+/**
+ * glade_binding_get_target:
+ * @binding: The #GladeBinding
+ *
+ * Returns: The binding's source property
+ */
+GladeProperty *
+glade_binding_get_source (GladeBinding * binding)
+{
+ g_return_val_if_fail (GLADE_IS_BINDING (binding), NULL);
+
+ return binding->priv->source;
+}
+
+/**
+ * glade_binding_read:
+ * @node: The #GladeXmlNode to read from
+ * @widget: The widget to which the target property belongs
+ *
+ * Read the binding information from @node and create a new
+ * #GladeBinding from it, which is returned.
+ *
+ * Note that binding's source property will only be resolved
+ * after the project is completely loaded by calling
+ * glade_binding_complete().
+ *
+ * Returns: The read #GladeBinding
+ */
+GladeBinding *
+glade_binding_read (GladeXmlNode * node,
+ GladeWidget * widget)
+{
+ gchar *to, *from, *source;
+ GladeProperty *target;
+ GladeBinding *binding;
+
+ g_return_val_if_fail (node != NULL, NULL);
+ g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
+
+ if (!glade_xml_node_verify (node, GLADE_XML_TAG_BINDING))
+ return NULL;
+
+ if (!(to = glade_xml_get_property_string_required (node, "to", NULL))
+ || !(from = glade_xml_get_property_string_required (node, "from", NULL))
+ || !(source = glade_xml_get_property_string_required (node, "source", NULL)))
+ return NULL;
+
+ target = glade_widget_get_property (widget, to);
+ binding = glade_binding_new (NULL, target);
+
+ /* We need to wait with resolving the source property until the complete
+ * project is loaded, as the object referred to might not have been read
+ * in yet.
+ */
+ g_object_set_data_full (G_OBJECT (binding),
+ "glade-source-property-name", from,
+ g_free);
+ g_object_set_data_full (G_OBJECT (binding),
+ "glade-source-object-name", source,
+ g_free);
+
+ return binding;
+}
+
+/**
+ * glade_binding_complete:
+ * @binding: The #GladeBinding
+ * @project: The containing #GladeProject
+ *
+ * Resolves the source property of a #GladeBinding read from
+ * a file with glade_binding_read() by looking it up in the
+ * passed #GladeProject (which must be completely loaded).
+ */
+void
+glade_binding_complete (GladeBinding * binding,
+ GladeProject * project)
+{
+ gchar *source_obj, *source_prop;
+ GladeWidget *widget;
+
+ g_return_if_fail (GLADE_IS_BINDING (binding));
+ g_return_if_fail (GLADE_IS_PROJECT (project));
+
+ source_obj = g_object_get_data (G_OBJECT (binding),
+ "glade-source-object-name");
+ source_prop = g_object_get_data (G_OBJECT (binding),
+ "glade-source-property-name");
+
+ /* If the binding has no attached source property data,
+ * there is nothing to do
+ */
+ if (!source_obj)
+ {
+ g_assert (source_prop != NULL);
+ return;
+ }
+
+ widget = glade_project_get_widget_by_name (project, source_obj);
+ if (widget)
+ {
+ GladeProperty *source = glade_widget_get_property (widget, source_prop);
+ if (source)
+ binding->priv->source = source;
+ }
+}
+
+/**
+ * glade_binding_write:
+ * @binding: a #GladeBinding
+ * @context: A #GladeXmlContext
+ * @node: A #GladeXmlNode
+ *
+ * Write @binding to @node.
+ */
+void
+glade_binding_write (GladeBinding * binding,
+ GladeXmlContext * context,
+ GladeXmlNode * node)
+{
+ GladeXmlNode *binding_node;
+ GladeProperty *target_prop, *source_prop;
+ const gchar *to, *from, *source;
+ GladeWidget *widget;
+
+ g_return_if_fail (GLADE_IS_BINDING (binding));
+ g_return_if_fail (glade_binding_get_target (binding) != NULL);
+ g_return_if_fail (glade_binding_get_source (binding) != NULL);
+ g_return_if_fail (node != NULL);
+
+ 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);
+
+ target_prop = glade_binding_get_target (binding);
+ source_prop = glade_binding_get_source (binding);
+ to = glade_property_class_id (glade_property_get_class (target_prop));
+ from = glade_property_class_id (glade_property_get_class (source_prop));
+
+ widget = glade_property_get_widget (glade_binding_get_source (binding));
+ 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);
+}
diff --git a/gladeui/glade-binding.h b/gladeui/glade-binding.h
new file mode 100644
index 0000000..d992bd6
--- /dev/null
+++ b/gladeui/glade-binding.h
@@ -0,0 +1,63 @@
+#ifndef __GLADE_BINDING_H__
+#define __GLADE_BINDING_H__
+
+#include <glib-object.h>
+#include "glade-xml-utils.h"
+
+G_BEGIN_DECLS
+
+#define GLADE_TYPE_BINDING (glade_binding_get_type())
+#define GLADE_BINDING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_BINDING, GladeBinding))
+#define GLADE_BINDING_KLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_BINDING, GladeBindingClass))
+#define GLADE_IS_BINDING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_BINDING))
+#define GLADE_IS_BINDING_KLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_BINDING))
+#define GLADE_BINDING_GET_KLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_BINDING, GladePropertyKlass))
+
+typedef struct _GladeBinding GladeBinding;
+typedef struct _GladeBindingClass GladeBindingClass;
+typedef struct _GladeBindingPrivate GladeBindingPrivate;
+
+/* Forward-declare GladeProperty so that
+ * we don't have to include "glade-property.h",
+ * which depends on this header file
+ */
+typedef struct _GladeProperty GladeProperty;
+
+struct _GladeBinding
+{
+ GObject parent_instance;
+
+ GladeBindingPrivate *priv;
+};
+
+
+struct _GladeBindingClass
+{
+ GObjectClass parent_class;
+};
+
+
+GType glade_binding_get_type (void) G_GNUC_CONST;
+
+GladeBinding *glade_binding_new (GladeProperty * source,
+ GladeProperty * widget);
+
+GladeProperty *glade_binding_get_target (GladeBinding * binding);
+
+GladeProperty *glade_binding_get_source (GladeBinding * binding);
+
+GladeBinding *glade_binding_read (GladeXmlNode * node,
+ GladeWidget * widget);
+
+void glade_binding_complete (GladeBinding * binding,
+ GladeProject * project);
+
+void glade_binding_write (GladeBinding * binding,
+ GladeXmlContext * context,
+ GladeXmlNode * node);
+
+void glade_binding_free (GladeBinding * binding);
+
+G_END_DECLS
+
+#endif /* __GLADE_BINDING_H__ */
diff --git a/gladeui/glade-project.c b/gladeui/glade-project.c
index 9dea0a7..267b9fb 100644
--- a/gladeui/glade-project.c
+++ b/gladeui/glade-project.c
@@ -1048,7 +1048,8 @@ glade_project_fix_object_props (GladeProject *project)
GladeWidget *gwidget;
GladeProperty *property;
gchar *txt;
-
+ GladeBinding *binding;
+
objects = g_list_copy (project->priv->objects);
for (l = objects; l; l = l->next)
{
@@ -1078,6 +1079,9 @@ glade_project_fix_object_props (GladeProject *project)
g_object_set_data (G_OBJECT (property),
"glade-loaded-object", NULL);
}
+
+ if ((binding = glade_property_get_binding (property)) != NULL)
+ glade_binding_complete (binding, project);
}
}
g_list_free (objects);
diff --git a/gladeui/glade-property.c b/gladeui/glade-property.c
index 5abbe51..877e26d 100644
--- a/gladeui/glade-property.c
+++ b/gladeui/glade-property.c
@@ -104,11 +104,14 @@ struct _GladePropertyPrivate {
* or derived widget code).
*/
+ /* Non-NULL if the property is the target of a binding */
+ GladeBinding *binding;
+
/* Used only for translatable strings. */
guint i18n_translatable : 1;
gchar *i18n_context;
gchar *i18n_comment;
-
+
gint syncing; /* Avoid recursion while synchronizing object with value */
gint sync_tolerance;
};
@@ -1170,6 +1173,7 @@ glade_property_write (GladeProperty * property,
{
GladeXmlNode *prop_node;
gchar *name, *value;
+ GladeBinding *binding;
g_return_if_fail (GLADE_IS_PROPERTY (property));
g_return_if_fail (node != NULL);
@@ -1225,6 +1229,11 @@ glade_property_write (GladeProperty * property,
GLADE_TAG_COMMENT,
property->priv->i18n_comment);
}
+
+ /* Write property's binding if existent */
+ if ((binding = glade_property_get_binding (property)) != NULL)
+ glade_binding_write (binding, context, node);
+
g_free (name);
g_free (value);
}
@@ -1556,6 +1565,24 @@ glade_property_get_state (GladeProperty *property)
return property->priv->state;
}
+GladeBinding *
+glade_property_get_binding (GladeProperty *property)
+{
+ g_return_val_if_fail (GLADE_IS_PROPERTY (property), NULL);
+
+ return property->priv->binding;
+}
+
+void
+glade_property_set_binding (GladeProperty *property,
+ GladeBinding *binding)
+{
+ g_return_if_fail (GLADE_IS_PROPERTY (property));
+ g_return_if_fail (GLADE_IS_BINDING (binding));
+ g_return_if_fail (glade_binding_get_target (binding) == property);
+
+ property->priv->binding = binding;
+}
static gint glade_property_su_stack = 0;
diff --git a/gladeui/glade-property.h b/gladeui/glade-property.h
index b69c248..9f4aeb6 100644
--- a/gladeui/glade-property.h
+++ b/gladeui/glade-property.h
@@ -2,6 +2,8 @@
#define __GLADE_PROPERTY_H__
#include <glib-object.h>
+#include "glade-binding.h"
+#include "glade-property-class.h"
G_BEGIN_DECLS
@@ -158,6 +160,11 @@ GValue *glade_property_inline_value (GladeProperty
GladePropertyState glade_property_get_state (GladeProperty *property);
+GladeBinding * glade_property_get_binding (GladeProperty *property);
+
+void glade_property_set_binding (GladeProperty *property,
+ GladeBinding *binding);
+
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 55ab934..27070a9 100644
--- a/gladeui/glade-widget-adaptor.c
+++ b/gladeui/glade-widget-adaptor.c
@@ -42,6 +42,7 @@
#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>
@@ -996,6 +997,7 @@ 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;
@@ -1034,6 +1036,17 @@ glade_widget_adaptor_object_read_widget (GladeWidgetAdaptor * adaptor,
}
g_list_free (read_properties);
+ /* Read in property bindings */
+ for (iter_node = glade_xml_node_get_children (node);
+ iter_node; iter_node = glade_xml_node_next (iter_node))
+ {
+ if (!glade_xml_node_verify_silent (iter_node, GLADE_XML_TAG_BINDING))
+ continue;
+
+ if (!(binding = glade_binding_read (iter_node, widget)))
+ continue;
+ }
+
/* Read in the signals */
for (iter_node = glade_xml_node_get_children (node);
iter_node; iter_node = glade_xml_node_next (iter_node))
@@ -1075,10 +1088,14 @@ glade_widget_adaptor_object_write_widget (GladeWidgetAdaptor * adaptor,
{
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)
+ glade_binding_write (binding, context, node);
}
}
diff --git a/gladeui/glade-xml-utils.h b/gladeui/glade-xml-utils.h
index 20e7fc2..a5eace2 100644
--- a/gladeui/glade-xml-utils.h
+++ b/gladeui/glade-xml-utils.h
@@ -43,6 +43,9 @@ typedef struct _GladeProject GladeProject;
#define GLADE_XML_TAG_PROPERTY "property"
#define GLADE_XML_TAG_CLASS "class"
#define GLADE_XML_TAG_ID "id"
+#define GLADE_XML_TAG_BINDING "binding"
+#define GLADE_XML_TAG_TO "to"
+#define GLADE_XML_TAG_FROM "from"
#define GLADE_XML_TAG_SIGNAL "signal"
#define GLADE_XML_TAG_HANDLER "handler"
#define GLADE_XML_TAG_AFTER "after"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]