/* * Copyright (C) 2012 - Juan Ferrer Toribio * * 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 3 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, see . */ #include "gvn-misc.h" #include "gvn-param.h" #include "gvn-value.h" /** * SECTION: gvn-param * @Short_description: * @Title: GvnParam **/ G_DEFINE_TYPE (GvnParam, gvn_param, G_TYPE_INITIALLY_UNOWNED); enum { VALUE_CHANGED ,SPEC_CHANGED ,STATUS_CHANGED ,LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; /** * gvn_param_new: * * Creates a new #GvnParam. * * Return value: the new #GvnParam **/ GvnParam * gvn_param_new () { return g_object_new (GVN_TYPE_PARAM, NULL); } /** * gvn_param_new_with_spec: * @spec: the spec of param. * * Creates a new #GvnParam. * * Return value: the new #GvnParam **/ GvnParam * gvn_param_new_with_spec (const GvnParamSpec * spec) { return g_object_new (GVN_TYPE_PARAM, "spec", spec, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private static void gvn_param_set_status (GvnParam * obj, GvnParamStatus status) { obj->status = status; g_signal_emit (obj, signals[STATUS_CHANGED], 0, status); } static void gvn_param_set_error (GvnParam * obj, GError * error) { g_clear_error (&obj->error); obj->error = error; gvn_param_set_status (obj, GVN_PARAM_STATUS_ERROR); } static void gvn_param_set_spec (GvnParam * obj, const GvnParamSpec * spec) { GSList * n; if (obj->mode == GVN_PARAM_MASTER) for (n = obj->slaves; n; n = n->next) gvn_param_spec_merge (GVN_PARAM (n->data)->spec, spec); gvn_param_spec_unset (obj->spec); gvn_param_spec_merge (obj->spec, spec); g_signal_emit (obj, signals[SPEC_CHANGED], 0); } static void gvn_param_put_value (GvnParam * obj, const GValue * value) { if (gvn_param_spec_ccopy_value (obj->spec, value, obj->value)) { GError * tmp_err = NULL; if (obj->mode == GVN_PARAM_SLAVE) { if (!gvn_param_set_value (obj->master, obj->value, &tmp_err)) gvn_param_set_error (obj, tmp_err); } else if (obj->mode == GVN_PARAM_MASTER) { GSList * n; for (n = obj->slaves; n; n = n->next) if (!gvn_param_set_value (n->data, obj->value, &tmp_err)) gvn_param_set_error (n->data, tmp_err); } gvn_param_value_changed (obj); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * gvn_param_get_value: * @param: a #GvnParam where be took the value * * Gets the value of param. * * Return value: (transfer none): the #GValue **/ const GValue * gvn_param_get_value (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), NULL); return obj->value; } /** * gvn_param_set_value: * @param: #GvnParam object where @value wants to be validated. * @value: new value. * @err: (out) (allow-none): the return location for an allocated @GError, or * NULL to ignore errors. * * Sets @value into @param. * * Return value: %TRUE if assigment is valid, %FALSE otherwise. **/ gboolean gvn_param_set_value (GvnParam * obj, const GValue * value, GError ** err) { g_return_val_if_fail (GVN_IS_PARAM (obj), FALSE); g_return_val_if_fail (G_IS_VALUE (value), FALSE); if (gvn_param_spec_validate (obj->spec, value, err)) { gvn_param_put_value (obj, value); return TRUE; } return FALSE; } /** * gvn_param_get_spec: * @param: #GvnParam object * * Gets the #GvnParamSpec of @obj * * Return value: (transfer none): the #GvnParamSpec **/ const GvnParamSpec * gvn_param_get_spec (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), NULL); return obj->spec; } /** * gvn_param_get_master: * @sparam: a #GvnParam where be took the value * * Gets the master param of @obj * * Return value: (transfer none): the master #GvnParam or %NULL if it haven't. **/ GvnParam * gvn_param_get_master (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), NULL); return obj->master; } /** * gvn_param_bind: * @src: #GvnParam object * @dst: #GvnParam master * * Sets @dst as a master of @src **/ void gvn_param_set_master (GvnParam * obj, GvnParam * master) { g_return_if_fail (GVN_IS_PARAM (obj)); g_return_if_fail (GVN_IS_PARAM (master) || !master); g_return_if_fail (obj->mode != GVN_PARAM_MASTER); g_return_if_fail (obj->mode != GVN_PARAM_SLAVE || !master); g_return_if_fail (!master || master->mode != GVN_PARAM_SLAVE); if (master) { obj->master = g_object_ref_sink (master); obj->mode = GVN_PARAM_SLAVE; master->slaves = g_slist_prepend (master->slaves, obj); master->mode = GVN_PARAM_MASTER; } else { if (obj->mode == GVN_PARAM_SLAVE) { GSList ** slaves = &obj->master->slaves; if (!(*slaves = g_slist_remove (*slaves, obj))) master->mode = GVN_PARAM_FREE; } g_clear_object (&obj->master); obj->mode = GVN_PARAM_FREE; } } /** * gvn_param_get_status: * @obj: #GvnParam object * * Gets the status of @obj * * Return value: the current status of the param. **/ GvnParamStatus gvn_param_get_status (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), GVN_PARAM_STATUS_OK); return obj->status; } /** * gvn_param_get_error: * @obj: #GvnParam object * * Gets the error of @obj * * Return value: the current error of the param. **/ const GError * gvn_param_get_error (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), NULL); return obj->error; } /** * gvn_param_get_null: * @param: the #GvnParam **/ gboolean gvn_param_get_null (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), FALSE); return gvn_param_spec_get_null (obj->spec); } /** * gvn_param_get_editable: * @param: the #GvnParam **/ gboolean gvn_param_get_editable (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), FALSE); return gvn_param_spec_get_editable (obj->spec); } /** * gvn_param_get_default: * @obj: the #GvnParam **/ const GValue * gvn_param_get_default (GvnParam * obj) { g_return_val_if_fail (GVN_IS_PARAM (obj), NULL); return gvn_param_spec_get_default (obj->spec); } /** * gvn_param_set_to_default: * @obj: the #GvnParam **/ void gvn_param_set_to_default (GvnParam * obj) { g_return_if_fail (GVN_IS_PARAM (obj)); gvn_param_set_value (obj, gvn_param_spec_get_default (obj->spec), NULL); } /** * gvn_param_value_changed: * @obj: a #GvnParam * * Emits the "value-changed" signal for that param. **/ void gvn_param_value_changed (GvnParam * obj) { g_signal_emit (obj, signals[VALUE_CHANGED], 0, obj->value); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_VALUE = 1 ,PROP_MASTER ,PROP_MODE ,PROP_STATUS ,PROP_SPEC ,PROP_GTYPE ,PROP_EDITABLE ,PROP_NULL ,PROP_DEFAULT }; static void gvn_param_set_property (GvnParam * obj, guint property_id, const GValue * value, GParamSpec * pspec) { switch (property_id) { case PROP_VALUE: gvn_param_set_value (obj, g_value_get_boxed (value), NULL); break; case PROP_MASTER: gvn_param_set_master (obj, g_value_get_object (value)); break; case PROP_SPEC: gvn_param_spec_merge (obj->spec, g_value_get_boxed (value)); break; case PROP_GTYPE: gvn_param_spec_set_gtype (obj->spec, g_value_get_gtype (value)); break; case PROP_EDITABLE: gvn_param_spec_set_editable (obj->spec, g_value_get_boolean (value)); break; case PROP_NULL: gvn_param_spec_set_null (obj->spec, g_value_get_boolean (value)); break; case PROP_DEFAULT: gvn_param_spec_set_default (obj->spec, g_value_get_boxed (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); } } static void gvn_param_get_property (GvnParam * obj, guint property_id, GValue * value, GParamSpec * pspec) { switch (property_id) { case PROP_VALUE: g_value_set_boxed (value, obj->value); break; case PROP_MASTER: g_value_set_object (value, obj->master); break; case PROP_MODE: g_value_set_int (value, obj->mode); break; case PROP_STATUS: g_value_set_boolean (value, obj->status); break; case PROP_SPEC: g_value_set_boxed (value, obj->spec); break; case PROP_GTYPE: g_value_set_gtype (value, gvn_param_spec_get_gtype (obj->spec)); break; case PROP_EDITABLE: g_value_set_boolean (value, gvn_param_spec_get_editable (obj->spec)); break; case PROP_NULL: g_value_set_boolean (value, gvn_param_spec_get_null (obj->spec)); break; case PROP_DEFAULT: g_value_set_boxed (value, gvn_param_spec_get_default (obj->spec)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void gvn_param_init (GvnParam * obj) { obj->error = NULL; obj->master = NULL; obj->slaves = NULL; obj->mode = GVN_PARAM_FREE; obj->status = GVN_PARAM_STATUS_OK; obj->spec = gvn_param_spec_new (); obj->value = g_new0 (GValue, 1); g_value_init (obj->value, GVN_TYPE_NULL); } static void gvn_param_finalize (GvnParam * obj) { gvn_param_set_master (obj, NULL); gvn_param_spec_free (obj->spec); g_clear_error (&obj->error); g_value_unset (obj->value); g_free (obj->value); G_OBJECT_CLASS (gvn_param_parent_class)->finalize (G_OBJECT (obj)); } static void gvn_param_class_init (GvnParamClass * klass) { GObjectClass * k = G_OBJECT_CLASS (klass); k->finalize = (GObjectFinalizeFunc) gvn_param_finalize; k->set_property = (GObjectSetPropertyFunc) gvn_param_set_property; k->get_property = (GObjectGetPropertyFunc) gvn_param_get_property; klass->put_value = gvn_param_put_value; klass->set_spec = gvn_param_set_spec; klass->set_status = gvn_param_set_status; klass->set_error = gvn_param_set_error; signals[VALUE_CHANGED] = g_signal_new ("value-changed", GVN_TYPE_PARAM, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_VALUE ); signals[SPEC_CHANGED] = g_signal_new ("spec-changed", GVN_TYPE_PARAM, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); signals[STATUS_CHANGED] = g_signal_new ("status-changed", GVN_TYPE_PARAM, G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0 ); g_object_class_install_property (k, PROP_VALUE, g_param_spec_boxed ("value" ,_("Value") ,_("The value of the param") ,G_TYPE_VALUE ,G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_MASTER, g_param_spec_object ("master" ,_("Master") ,_("The master GvnParam of this parameter") ,GVN_TYPE_PARAM ,G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_MODE, g_param_spec_uint ("mode" ,_("Mode") ,_("The mode of the parameter") ,0 ,256 ,GVN_PARAM_FREE ,G_PARAM_READABLE )); g_object_class_install_property (k, PROP_STATUS, g_param_spec_uint ("status" ,_("Status") ,_("The current status of the parameter") ,0 ,256 ,GVN_PARAM_STATUS_OK ,G_PARAM_READABLE )); g_object_class_install_property (k, PROP_SPEC, g_param_spec_boxed ("spec" ,_("Spec") ,_("The spec of the parameter") ,GVN_TYPE_PARAM_SPEC ,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_GTYPE, g_param_spec_gtype ("gtype" ,_("Glib Type") ,_("The type of the value") ,G_TYPE_NONE ,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_EDITABLE, g_param_spec_boolean ("editable" ,_("Editable") ,_("Whether the param value can be modified") ,TRUE ,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_NULL, g_param_spec_boolean ("null" ,_("Null") ,_("Whether the param value can be of type GVN_TYPE_NULL") ,TRUE ,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_DEFAULT, g_param_spec_boxed ("default" ,_("Default Value") ,_("The default value") ,G_TYPE_VALUE ,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE )); }