505 lines
12 KiB
C
505 lines
12 KiB
C
|
/*
|
||
|
* 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#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
|
||
|
));
|
||
|
}
|