This repository has been archived on 2024-07-15. You can view files and clone it, but cannot push or open issues or pull requests.
hedera/vn/vn-field.c

573 lines
14 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 "vn-field.h"
G_DEFINE_ABSTRACT_TYPE (VnField, vn_field, GTK_TYPE_EVENT_BOX);
enum {
VALUE_CHANGED
,LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {0};
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Private
static void vn_field_spec_changed (VnField * obj)
{
gvn_param_spec_unset (obj->spec);
gvn_param_spec_merge (obj->spec, obj->user_spec);
if (obj->param)
gvn_param_spec_merge (obj->spec,
gvn_param_get_spec (obj->param));
}
static void vn_field_on_param_spec_changed (GvnParam * param, VnField * obj)
{
vn_field_spec_changed (obj);
}
static void vn_field_on_param_value_changed (GvnParam * param, const GValue * value, VnField * obj)
{
obj->update_param = FALSE;
vn_field_set_value (obj, value);
obj->update_param = TRUE;
}
static void vn_field_set_invalid (VnField * obj, const GError * err)
{
/* GdkRGBA color = {0.95, 0.8, 0.8, 1};
gtk_widget_override_background_color (GTK_WIDGET (obj->field),
GTK_STATE_FLAG_NORMAL, &color);
*/}
static void vn_field_on_param_status_changed (GvnParam * param, VnField * obj)
{
switch (gvn_param_get_status (param))
{
case GVN_PARAM_STATUS_OK:
gtk_widget_set_sensitive (obj->field, TRUE);
break;
case GVN_PARAM_STATUS_BUSY:
gtk_widget_set_sensitive (obj->field, FALSE);
break;
case GVN_PARAM_STATUS_ERROR:
vn_field_set_invalid (obj, gvn_param_get_error (param));
break;
}
}
static void vn_field_changed (VnField * obj)
{
if (obj->param && obj->update_param)
{
GError * err = NULL;
g_signal_handlers_block_by_func (obj->param,
vn_field_on_param_value_changed, obj);
if (!gvn_param_set_value (obj->param, obj->value, &err))
{
vn_field_set_invalid (obj, err);
g_error_free (err);
}
g_signal_handlers_unblock_by_func (obj->param,
vn_field_on_param_value_changed, obj);
}
g_signal_emit (obj, signals[VALUE_CHANGED], 0, obj->value);
}
static void vn_field_value_changed (VnField * obj, const GValue * value)
{
GType type;
gboolean changed;
if (obj->lock_changed_done)
return;
type = gvn_param_spec_get_gtype (obj->spec);
if (type != G_TYPE_NONE && !gvn_value_is_null (value))
{
if (G_VALUE_TYPE (obj->value) != type)
{
g_value_unset (obj->value);
g_value_init (obj->value, type);
}
g_value_transform (value, obj->value);
changed = TRUE;
}
else
changed = gvn_value_ccopy (value, obj->value);
if (changed)
vn_field_changed (obj);
}
static void vn_field_make_param (VnField * obj)
{
GvnParam * param;
if (!obj->iterator || !obj->column_name)
return;
param = db_iterator_get_param (obj->iterator, obj->column_name);
vn_field_set_param (obj, param);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Public
/**
* vn_field_get_value:
* @obj: the #VnField
*
* Gets the current field value.
*
* Return value: (transfer none): the #GValue
**/
const GValue * vn_field_get_value (VnField * obj)
{
return obj->value;
}
/**
* vn_field_set_value:
* @obj: the #VnField
* @value: a #GValue
*
* Sets the field value.
**/
void vn_field_set_value (VnField * obj, const GValue * value)
{
g_return_if_fail (VN_IS_FIELD (obj));
g_return_if_fail (G_IS_VALUE (value));
if (gvn_value_ccopy (value, obj->value))
{
obj->lock_changed_done = TRUE;
VN_FIELD_GET_CLASS (obj)->set_value (obj, obj->value);
obj->lock_changed_done = FALSE;
vn_field_changed (obj);
}
}
/**
* vn_field_get_param:
* @obj: the #VnField
*
* Return value: (transfer none):
**/
GvnParam * vn_field_get_param (VnField * obj)
{
g_return_val_if_fail (VN_IS_FIELD (obj), NULL);
return obj->param;
}
/**
* vn_field_set_param:
* @obj: the #VnField
* @param: a #GvnParam
*
* Binds the field with a #GvnParam.
**/
void vn_field_set_param (VnField * obj, GvnParam * param)
{
g_return_if_fail (VN_IS_FIELD (obj));
g_return_if_fail (GVN_IS_PARAM (param) || !param);
if (obj->param)
{
g_object_disconnect (obj->param
,"any_signal", vn_field_on_param_value_changed, obj
,"any_signal", vn_field_on_param_spec_changed, obj
,"any_signal", vn_field_on_param_status_changed, obj
,NULL
);
g_clear_object (&obj->param);
}
if (param)
{
obj->param = g_object_ref_sink (param);
g_object_connect (param
,"signal::value-changed", vn_field_on_param_value_changed, obj
,"signal::spec-changed", vn_field_on_param_spec_changed, obj
,"signal::status-changed", vn_field_on_param_status_changed, obj
,NULL
);
vn_field_on_param_spec_changed (param, obj);
vn_field_on_param_value_changed (param,
gvn_param_get_value (param), obj);
vn_field_on_param_status_changed (param, obj);
}
/* GFile * css = g_file_new_for_path ("vn/gui/style.css");
if (g_file_query_exists (css, NULL))
{
GError * err = NULL;
GtkCssProvider * provider = gtk_css_provider_get_default ();
if (gtk_css_provider_load_from_file (provider, css, &err))
{
GtkStyleContext * style;
style = gtk_widget_get_style_context (GTK_WIDGET (obj->field));
gtk_style_context_add_provider (style, GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_style_context_add_class (style, "invalid");
}
else
{
g_warning ("Vn: %s", err->message);
g_error_free (err);
}
}
else
g_warning ("Vn: Can't load CSS styles");
g_object_unref (css);
*/
}
/**
* vn_field_get_gtype:
* @obj: the #VnField
*
* Gets the field type.
*
* Return value: the field type or %G_TYPE_NONE if it havent.
**/
GType vn_field_get_gtype (VnField * obj)
{
g_return_val_if_fail (VN_IS_FIELD (obj), G_TYPE_INVALID);
return gvn_param_spec_get_gtype (obj->spec);
}
/**
* vn_field_set_gtype:
* @obj: the #VnField
* @type: a valid #GType
*
* Sets the type of the field. When you set a value, it will be converted to
* this type.
**/
void vn_field_set_gtype (VnField * obj, GType type)
{
g_return_if_fail (VN_IS_FIELD (obj));
gvn_param_spec_set_gtype (obj->user_spec, type);
vn_field_spec_changed (obj);
}
/**
* vn_field_get_null:
* @obj: the #VnField
*
* If field allows values with %GVN_TYPE_NULL type.
*
* Return value: %TRUE if it can, %FALSE otherwise.
**/
gboolean vn_field_get_null (VnField * obj)
{
g_return_val_if_fail (VN_IS_FIELD (obj), FALSE);
return gvn_param_spec_get_null (obj->spec);
}
/**
* vn_field_set_null:
* @obj: the #VnField
* @null: %TRUE if field should accept NULL values
*
* Sets if field allows values with %GVN_TYPE_NULL type. If param property of
* the field is set, this attribute will be merged with the same #GvnParam
* attribute, remaining the most restrictive.
**/
void vn_field_set_null (VnField * obj, gboolean null)
{
g_return_if_fail (VN_IS_FIELD (obj));
gvn_param_spec_set_null (obj->user_spec, null);
vn_field_spec_changed (obj);
}
/**
* vn_field_get_editable:
* @obj: the #VnField
*
* Gets whether the field value can be modified.
*
* Return value: %TRUE if field value can be edited, %FALSE otherwise.
**/
gboolean vn_field_get_editable (VnField * obj)
{
g_return_val_if_fail (VN_IS_FIELD (obj), FALSE);
return gvn_param_spec_get_editable (obj->spec);
}
/**
* vn_field_set_editable:
* @obj: the #VnField
* @editable: %TRUE if field can be editable
*
* Sets if field value can be modified. If param property of
* the field is set, this attribute will be merged with the same #GvnParam
* attribute, remaining the most restrictive.
**/
void vn_field_set_editable (VnField * obj, gboolean editable)
{
g_return_if_fail (VN_IS_FIELD (obj));
gvn_param_spec_set_editable (obj->user_spec, editable);
vn_field_spec_changed (obj);
}
/**
* vn_field_get_default:
* @obj: the #VnField
**/
const GValue * vn_field_get_default (VnField * obj)
{
g_return_val_if_fail (VN_IS_FIELD (obj), NULL);
return gvn_param_spec_get_default (obj->spec);
}
/**
* vn_field_set_default:
* @obj: the #VnField
* @def: the default #GValue
*
* Sets the default value of the field.
**/
void vn_field_set_default (VnField * obj, const GValue * def)
{
g_return_if_fail (VN_IS_FIELD (obj));
gvn_param_spec_set_default (obj->user_spec, def);
vn_field_spec_changed (obj);
}
/**
* vn_field_set_to_default:
* @obj: the #VnField
**/
void vn_field_set_to_default (VnField * obj)
{
g_return_if_fail (VN_IS_FIELD (obj));
vn_field_set_value (obj,
gvn_param_spec_get_default (obj->spec));
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties
enum
{
PROP_VALUE = 1
,PROP_PARAM
,PROP_ITERATOR
,PROP_COLUMN_NAME
,PROP_GTYPE
,PROP_EDITABLE
,PROP_NULL
,PROP_DEFAULT
};
static void vn_field_set_property (VnField * obj, guint id,
const GValue * value, GParamSpec * pspec)
{
switch (id)
{
case PROP_VALUE:
vn_field_set_value (obj, g_value_get_boxed (value));
break;
case PROP_PARAM:
vn_field_set_param (obj, g_value_get_object (value));
break;
case PROP_ITERATOR:
g_clear_object (&obj->iterator);
obj->iterator = g_value_dup_object (value);
vn_field_make_param (obj);
break;
case PROP_COLUMN_NAME:
g_free (obj->column_name);
obj->column_name = g_value_dup_string (value);
vn_field_make_param (obj);
break;
case PROP_GTYPE:
vn_field_set_gtype (obj, g_value_get_gtype (value));
break;
case PROP_EDITABLE:
vn_field_set_editable (obj, g_value_get_boolean (value));
break;
case PROP_NULL:
vn_field_set_null (obj, g_value_get_boolean (value));
break;
case PROP_DEFAULT:
vn_field_set_default (obj, g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
}
}
static void vn_field_get_property (VnField * obj, guint id,
GValue * value, GParamSpec * pspec)
{
switch (id)
{
case PROP_VALUE:
g_value_set_boxed (value, obj->value);
break;
case PROP_PARAM:
g_value_set_object (value, obj->param);
break;
case PROP_ITERATOR:
g_value_set_object (value, obj->iterator);
break;
case PROP_COLUMN_NAME:
g_value_set_string (value, obj->column_name);
break;
case PROP_GTYPE:
g_value_set_gtype (value, vn_field_get_gtype (obj));
break;
case PROP_EDITABLE:
g_value_set_boolean (value, vn_field_get_editable (obj));
break;
case PROP_NULL:
g_value_set_boolean (value, vn_field_get_null (obj));
break;
case PROP_DEFAULT:
g_value_set_boxed (value, vn_field_get_default (obj));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class
static void vn_field_init (VnField * obj)
{
GdkRGBA color = {0.0, 0.0, 0.0, 0.0};
obj->param = NULL;
obj->update_param = TRUE;
obj->lock_changed_done = FALSE;
obj->user_spec = gvn_param_spec_new ();
obj->spec = gvn_param_spec_new ();
obj->iterator = NULL;
obj->column_name = NULL;
obj->value = g_new0 (GValue, 1);
g_value_init (obj->value, GVN_TYPE_NULL);
gtk_widget_override_background_color (GTK_WIDGET (obj),
GTK_STATE_FLAG_NORMAL, &color);
}
static void vn_field_finalize (VnField * obj)
{
gvn_param_spec_free (obj->spec);
gvn_param_spec_free (obj->user_spec);
g_clear_object (&obj->iterator);
g_clear_object (&obj->param);
g_value_unset (obj->value);
g_free (obj->value);
g_free (obj->column_name);
G_OBJECT_CLASS (vn_field_parent_class)->finalize (G_OBJECT (obj));
}
static void vn_field_class_init (VnFieldClass * klass)
{
GObjectClass * k = G_OBJECT_CLASS (klass);
k->finalize = (GObjectFinalizeFunc) vn_field_finalize;
k->set_property = (GObjectSetPropertyFunc) vn_field_set_property;
k->get_property = (GObjectGetPropertyFunc) vn_field_get_property;
klass->value_changed = vn_field_value_changed;
signals[VALUE_CHANGED] = g_signal_new ("value-changed",
VN_TYPE_FIELD, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, G_TYPE_VALUE
);
g_object_class_install_property (k, PROP_VALUE,
g_param_spec_boxed ("value"
,_("Value")
,_("The current value of the field")
,G_TYPE_VALUE
,G_PARAM_READWRITE
));
g_object_class_install_property (k, PROP_PARAM,
g_param_spec_object ("param"
,_("Parameter")
,_("The param where the field can read/write its value")
,GVN_TYPE_PARAM
,G_PARAM_READWRITE
));
g_object_class_install_property (k, PROP_ITERATOR,
g_param_spec_object ("iterator"
,_("Iterator")
,_("The iterator used to get the field param")
,DB_TYPE_ITERATOR
,G_PARAM_READWRITE
));
g_object_class_install_property (k, PROP_COLUMN_NAME,
g_param_spec_string ("column-name"
,_("Column name")
,_("The column name on the iterator")
,NULL
,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 | G_PARAM_READWRITE
));
g_object_class_install_property (k, PROP_EDITABLE,
g_param_spec_boolean ("editable"
,_("Editable")
,_("Whether the field value is user editable")
,TRUE
,G_PARAM_CONSTRUCT | G_PARAM_READWRITE
));
g_object_class_install_property (k, PROP_NULL,
g_param_spec_boolean ("null"
,_("Null")
,_("Whether the field value can be of type GVN_TYPE_NULL")
,TRUE
,G_PARAM_CONSTRUCT | 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_READWRITE
));
}