[epiphany/wip/property-bind: 1/3] Introduce ephy_action_bind_sensitivity and tests for it
- From: Xan Lopez <xan src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/property-bind: 1/3] Introduce ephy_action_bind_sensitivity and tests for it
- Date: Mon, 30 Jan 2012 19:09:37 +0000 (UTC)
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]