[epiphany/wip/property-bind: 1/3] Introduce ephy_action_bind_sensitivity and tests for it



commit 4a0b277ad08cbf0a066dd3d4c328e799f7a9f44f
Author: Xan Lopez <xan igalia com>
Date:   Sat Jan 28 21:30:10 2012 +0100

    Introduce ephy_action_bind_sensitivity and tests for it
    
    A method to control the sensitivity of a GtkAction through a list of
    GObject properties. We'll use this to automatically enable or disable
    the actions in the main EphyWindow.

 src/ephy-action-helper.c        |  115 +++++++++++++++++
 src/ephy-action-helper.h        |    3 +
 tests/Makefile.am               |    4 +
 tests/test-ephy-action-helper.c |  260 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 382 insertions(+), 0 deletions(-)
---
diff --git a/src/ephy-action-helper.c b/src/ephy-action-helper.c
index 4dbcdce..ab49c0f 100644
--- a/src/ephy-action-helper.c
+++ b/src/ephy-action-helper.c
@@ -66,3 +66,118 @@ ephy_action_change_sensitivity_flags (GtkAction *action,
 
 	gtk_action_set_sensitive (GTK_ACTION (action), value == 0);
 }
+
+typedef struct {
+    int index;
+    GBindingTransformFunc transform;
+} BindData;
+
+static void
+free_bind_data (BindData *data)
+{
+    g_slice_free (BindData, data);
+}
+
+#define BIND_KEY "EphyAction::Bind"
+
+static gboolean
+_ephy_action_sensitivity_transform (GBinding *binding,
+                                    const GValue *source_value,
+                                    GValue *target_value,
+                                    gpointer user_data)
+{
+    BindData *data = (BindData*)user_data;
+    static GQuark bind_quark = 0;
+    GObject *target;
+    guint value;
+    gboolean set = FALSE;
+
+    if (G_UNLIKELY (bind_quark == 0))
+        bind_quark = g_quark_from_static_string (BIND_KEY);
+
+    g_object_get (binding, "target", &target, NULL);
+
+    value = GPOINTER_TO_UINT (g_object_get_qdata (target, bind_quark));
+
+    if (data->transform)
+        set = data->transform (binding,
+                               source_value,
+                               target_value,
+                               user_data);
+    else
+        set = g_value_get_boolean (source_value);
+
+    if (set)
+        value |= data->index;
+    else
+        value &= ~data->index;
+
+    g_object_set_qdata (target, bind_quark, GUINT_TO_POINTER (value));
+    gtk_action_set_sensitive (GTK_ACTION (target), value == 0);
+
+    /* Do nothing else. */
+    return FALSE;
+}
+
+static void
+ephy_action_bind_sensitivity_valist (GtkAction *action,
+                                     va_list var_args)
+{
+    GObject *object;
+    int i = 1;
+
+    object = va_arg (var_args, GObject*);
+
+    while (object) {
+        const char *property;
+        GBindingTransformFunc transform;
+        GBindingFlags flags;
+        BindData *data;
+
+        property = va_arg (var_args, const char*);
+        transform = va_arg (var_args, GBindingTransformFunc);
+        flags = va_arg (var_args, GBindingFlags);
+
+        data = g_slice_new (BindData);
+        data->index = i;
+        data->transform = transform;
+
+        g_object_bind_property_full (object, property,
+                                     action, "sensitive",
+                                     flags,
+                                     _ephy_action_sensitivity_transform,
+                                     NULL,
+                                     data, (GDestroyNotify)free_bind_data);
+        i *= 2;
+
+        object = va_arg (var_args, GObject*);
+    }
+}
+
+/**
+ * ephy_action_bind_sensitivity:
+ * @action: a #GtkAction
+
+ * @...: a %NULL terminated list of properties that will control the
+ * sensitivity of the @action, as follows: the #GObject that holds the
+ * property, its name as C string, an optional #GBindingTransformFunc
+ * for the property and optional #GBindingFlags.
+ * 
+ * This method will set-up a series of property bindings so that
+ * @action is only sensitive if all the listed properties are %FALSE
+ * (or the defined #GBindingTransformFunc for a given property returns
+ * %FALSE).
+ *
+ **/
+void
+ephy_action_bind_sensitivity (GtkAction *action,
+                              ...)
+{
+    va_list var_args;
+
+    g_return_if_fail (GTK_IS_ACTION (action));
+
+    va_start (var_args, action);
+    ephy_action_bind_sensitivity_valist (action, var_args);
+    va_end (var_args);
+}
diff --git a/src/ephy-action-helper.h b/src/ephy-action-helper.h
index 71c0bbc..01d2ce5 100644
--- a/src/ephy-action-helper.h
+++ b/src/ephy-action-helper.h
@@ -37,6 +37,9 @@ void ephy_action_change_sensitivity_flags (GtkAction *action,
 					   guint flags,
 					   gboolean set);
 
+void ephy_action_bind_sensitivity (GtkAction *action,
+                                   ...);
+
 G_END_DECLS
 
 #endif /* !EPHY_ACTION_HELPER_H */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 400b27c..612e389 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,4 +1,5 @@
 noinst_PROGRAMS = \
+	test-ephy-action-helper \
 	test-ephy-download \
 	test-ephy-embed-single \
 	test-ephy-location-entry \
@@ -103,6 +104,9 @@ LDADD += \
 	$(SEED_LIBS)
 endif
 
+test_ephy_action_helper_SOURCES = \
+	test-ephy-action-helper.c
+
 test_ephy_download_SOURCES = \
 	ephy-download.c
 
diff --git a/tests/test-ephy-action-helper.c b/tests/test-ephy-action-helper.c
new file mode 100644
index 0000000..690ecd2
--- /dev/null
+++ b/tests/test-ephy-action-helper.c
@@ -0,0 +1,260 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * test-ephy-action-helper.c
+ * This file is part of Epiphany
+ *
+ * Copyright  2012 - Igalia S.L.
+ *
+ * Epiphany 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.
+ *
+ * Epiphany 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 Epiphany; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+
+#include "ephy-action-helper.h"
+#include "ephy-debug.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-file-helpers.h"
+#include "ephy-shell.h"
+
+#include <gtk/gtk.h>
+
+/* Test source type. */
+typedef struct _EphySourcePrivate {
+  gboolean foo;
+  gboolean bar;
+} EphySourcePrivate;
+
+enum {
+  PROP_0,
+  PROP_FOO,
+  PROP_BAR
+};
+
+#define EPHY_TYPE_SOURCE (ephy_source_get_type ())
+#define EPHY_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_SOURCE, EphySource))
+
+typedef struct {
+  GObject parent;
+
+  EphySourcePrivate *priv;
+} EphySource;
+
+typedef struct {
+  GObjectClass parent_class;
+} EphySourceClass;
+
+GType ephy_source_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (EphySource, ephy_source, G_TYPE_OBJECT)
+
+static void
+ephy_source_get_property (GObject    *object,
+                          guint       property_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+  EphySource *source = EPHY_SOURCE (object);
+
+  switch (property_id)
+    {
+    case PROP_FOO:
+      g_value_set_boolean (value, source->priv->foo);
+      break;
+    case PROP_BAR:
+      g_value_set_boolean (value, source->priv->bar);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+ephy_source_set_property (GObject      *object,
+                          guint         property_id,
+                          const GValue *value,
+                          GParamSpec   *pspec)
+{
+  EphySource *source = EPHY_SOURCE (object);
+
+  switch (property_id)
+  {
+  case PROP_FOO:
+    source->priv->foo = g_value_get_boolean (value);
+    break;
+  case PROP_BAR:
+    source->priv->bar = g_value_get_boolean (value);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+ephy_source_class_init (EphySourceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = ephy_source_get_property;
+  object_class->set_property = ephy_source_set_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_FOO,
+                                   g_param_spec_boolean ("foo", NULL, NULL,
+                                                         FALSE,
+                                                         G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (object_class,
+                                   PROP_BAR,
+                                   g_param_spec_boolean ("bar", NULL, NULL,
+                                                         FALSE,
+                                                         G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_CONSTRUCT));
+
+  g_type_class_add_private (klass, sizeof (EphySourcePrivate));
+}
+
+static void
+ephy_source_init (EphySource *source)
+{
+  source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source, EPHY_TYPE_SOURCE, EphySourcePrivate);
+}
+
+/* End of test source type definition. */
+
+static gboolean
+transform (GBinding *binding,
+           const GValue *source_value,
+           GValue *target_value,
+           gpointer user_data)
+{
+  return g_value_get_boolean (source_value);
+}
+
+static void
+test_ephy_action_helper_single_bind ()
+{
+  GtkAction *action;
+  GObject *source;
+    
+  action = gtk_action_new ("TestAction", NULL, NULL, NULL);
+  source = g_object_new (EPHY_TYPE_SOURCE,
+                         "foo", TRUE,
+                         NULL);
+
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+  ephy_action_bind_sensitivity (action,
+                                source, "foo", NULL, G_BINDING_SYNC_CREATE,
+                                NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "foo", FALSE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+
+  g_object_set (source, "foo", TRUE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+}
+
+static void
+test_ephy_action_helper_double_bind ()
+{
+  GtkAction *action;
+  GObject *source;
+    
+  action = gtk_action_new ("TestAction", NULL, NULL, NULL);
+  source = g_object_new (EPHY_TYPE_SOURCE,
+                         "foo", FALSE,
+                         "bar", FALSE,
+                         NULL);
+
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+  ephy_action_bind_sensitivity (action,
+                                source, "foo", NULL, G_BINDING_SYNC_CREATE,
+                                source, "bar", NULL, G_BINDING_SYNC_CREATE,
+                                NULL);
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+
+  g_object_set (source, "foo", TRUE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "bar", TRUE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "foo", FALSE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "bar", FALSE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+}
+
+static void
+test_ephy_action_helper_double_bind_transform ()
+{
+  GtkAction *action;
+  GObject *source;
+    
+  action = gtk_action_new ("TestAction", NULL, NULL, NULL);
+  source = g_object_new (EPHY_TYPE_SOURCE,
+                         "foo", FALSE,
+                         "bar", FALSE,
+                         NULL);
+
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+  ephy_action_bind_sensitivity (action,
+                                source, "foo", transform, G_BINDING_SYNC_CREATE,
+                                source, "bar", transform, G_BINDING_SYNC_CREATE,
+                                NULL);
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+
+  g_object_set (source, "foo", TRUE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "bar", TRUE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "foo", FALSE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == FALSE);
+
+  g_object_set (source, "bar", FALSE, NULL);
+  g_assert (gtk_action_get_sensitive (action) == TRUE);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ret;
+
+  gtk_test_init (&argc, &argv);
+
+  ephy_debug_init ();
+  ephy_embed_prefs_init ();
+
+  if (!ephy_file_helpers_init (NULL, TRUE, FALSE, NULL)) {
+    g_debug ("Something wrong happened with ephy_file_helpers_init()");
+    return -1;
+  }
+
+  g_test_add_func ("/src/ephy-action-helper/single-bind",
+                   test_ephy_action_helper_single_bind);
+  g_test_add_func ("/src/ephy-action-helper/double-bind",
+                   test_ephy_action_helper_double_bind);
+  g_test_add_func ("/src/ephy-action-helper/double-bind-transform",
+                   test_ephy_action_helper_double_bind_transform);
+
+  ret = g_test_run ();
+
+  ephy_file_helpers_shutdown ();
+
+  return ret;
+}



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