Allow property actions to invert booleans

This can be handy when you want to change the sense of a toggle
in the UI without rewriting the underlying logic. Currently, this
is just exposed as a construct-only property. We may add a
convenience wrapper or a special !property syntax for this later.

https://bugzilla.gnome.org/show_bug.cgi?id=728489
This commit is contained in:
Matthias Clasen 2015-03-29 14:00:36 -04:00
parent fb1e5ff04b
commit 1102e6f9ca
2 changed files with 75 additions and 1 deletions

View File

@ -93,6 +93,7 @@ struct _GPropertyAction
gpointer object;
GParamSpec *pspec;
const GVariantType *state_type;
gboolean invert_boolean;
};
/**
@ -118,9 +119,18 @@ enum
PROP_STATE_TYPE,
PROP_STATE,
PROP_OBJECT,
PROP_PROPERTY_NAME
PROP_PROPERTY_NAME,
PROP_INVERT_BOOLEAN
};
static gboolean
g_property_action_get_invert_boolean (GAction *action)
{
GPropertyAction *paction = G_PROPERTY_ACTION (action);
return paction->invert_boolean;
}
static const gchar *
g_property_action_get_name (GAction *action)
{
@ -165,6 +175,10 @@ g_property_action_set_state (GPropertyAction *paction,
g_value_init (&value, paction->pspec->value_type);
g_settings_get_mapping (&value, variant, NULL);
if (paction->pspec->value_type == G_TYPE_BOOLEAN && paction->invert_boolean)
g_value_set_boolean (&value, !g_value_get_boolean (&value));
g_object_set_property (paction->object, paction->pspec->name, &value);
g_value_unset (&value);
}
@ -189,6 +203,10 @@ g_property_action_get_state (GAction *action)
g_value_init (&value, paction->pspec->value_type);
g_object_get_property (paction->object, paction->pspec->name, &value);
if (paction->pspec->value_type == G_TYPE_BOOLEAN && paction->invert_boolean)
g_value_set_boolean (&value, !g_value_get_boolean (&value));
result = g_settings_set_mapping (&value, paction->state_type, NULL);
g_value_unset (&value);
@ -316,6 +334,10 @@ g_property_action_set_property (GObject *object,
g_property_action_set_property_name (paction, g_value_get_string (value));
break;
case PROP_INVERT_BOOLEAN:
paction->invert_boolean = g_value_get_boolean (value);
break;
default:
g_assert_not_reached ();
}
@ -351,6 +373,10 @@ g_property_action_get_property (GObject *object,
g_value_take_variant (value, g_property_action_get_state (action));
break;
case PROP_INVERT_BOOLEAN:
g_value_set_boolean (value, g_property_action_get_invert_boolean (action));
break;
default:
g_assert_not_reached ();
}
@ -515,6 +541,23 @@ g_property_action_class_init (GPropertyActionClass *class)
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
/**
* GPropertyAction:invert-boolean:
*
* If %TRUE, the state of the action will be the negation of the
* property value, provided the property is boolean.
*
* Since: 2.46
*/
g_object_class_install_property (object_class, PROP_INVERT_BOOLEAN,
g_param_spec_boolean ("invert-boolean",
P_("Invert boolean"),
P_("Whether to invert the value of a boolean property"),
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
/**

View File

@ -1050,6 +1050,16 @@ test_property_actions (void)
g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
g_object_unref (action);
/* inverted */
action = g_object_new (G_TYPE_PROPERTY_ACTION,
"name", "disable-proxy",
"object", client,
"property-name", "enable-proxy",
"invert-boolean", TRUE,
NULL);
g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
g_object_unref (action);
/* enum... */
action = g_property_action_new ("type", client, "type");
g_action_map_add_action (G_ACTION_MAP (group), G_ACTION (action));
@ -1062,6 +1072,7 @@ test_property_actions (void)
ensure_state (group, "app-id", "'org.gtk.test'");
ensure_state (group, "keepalive", "uint32 0");
ensure_state (group, "tls", "false");
ensure_state (group, "disable-proxy", "false");
ensure_state (group, "type", "'stream'");
verify_changed (NULL);
@ -1102,6 +1113,11 @@ test_property_actions (void)
g_assert (g_socket_client_get_tls (client));
ensure_state (group, "tls", "true");
g_action_group_change_action_state (G_ACTION_GROUP (group), "disable-proxy", g_variant_new ("b", TRUE));
verify_changed ("disable-proxy:true");
ensure_state (group, "disable-proxy", "true");
g_assert (!g_socket_client_get_enable_proxy (client));
/* test toggle true->false */
g_action_group_activate_action (G_ACTION_GROUP (group), "tls", NULL);
verify_changed ("tls:false");
@ -1118,6 +1134,21 @@ test_property_actions (void)
verify_changed ("tls:false");
ensure_state (group, "tls", "false");
/* now do the same for the inverted action */
g_action_group_activate_action (G_ACTION_GROUP (group), "disable-proxy", NULL);
verify_changed ("disable-proxy:false");
g_assert (g_socket_client_get_enable_proxy (client));
ensure_state (group, "disable-proxy", "false");
g_action_group_activate_action (G_ACTION_GROUP (group), "disable-proxy", NULL);
verify_changed ("disable-proxy:true");
g_assert (!g_socket_client_get_enable_proxy (client));
ensure_state (group, "disable-proxy", "true");
g_socket_client_set_enable_proxy (client, TRUE);
verify_changed ("disable-proxy:false");
ensure_state (group, "disable-proxy", "false");
/* enum tests */
g_action_group_change_action_state (G_ACTION_GROUP (group), "type", g_variant_new ("s", "datagram"));
verify_changed ("type:'datagram'");