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-grid-model.c

497 lines
14 KiB
C
Raw Normal View History

/*
* 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-grid-model.h"
typedef struct
{
gchar * detail;
gpointer callback;
}
GvnSignalInfo;
void _gvn_object_link (gpointer obj, gpointer * prop, gpointer prop_value, GvnSignalInfo * info)
{
gint i;
if (*prop)
{
for (i = 0; info[i].detail; i++)
g_signal_handlers_disconnect_by_func (*prop, info[i].callback, obj);
g_object_unref (*prop);
}
if (prop_value)
{
for (i = 0; info[i].detail; i++)
if (g_str_has_suffix (info[i].detail, ".after"))
{
gchar ** split = g_strsplit (info[i].detail, ".", 0);
g_signal_connect_after (prop_value, split[0], info[i].callback, obj);
g_strfreev (split);
}
else
g_signal_connect (prop_value, info[i].detail, info[i].callback, obj);
*prop = g_object_ref_sink (prop_value);
}
else
*prop = NULL;
}
#define gvn_object_link(obj, prop, prop_value, info) (_gvn_object_link (obj, (void**) prop, prop_value, info))
static void vn_grid_model_tree_model_init (GtkTreeModelIface * iface);
static void vn_grid_model_tree_sortable_init (GtkTreeSortableIface * iface);
G_DEFINE_TYPE_WITH_CODE (VnGridModel, vn_grid_model, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
vn_grid_model_tree_model_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE,
vn_grid_model_tree_sortable_init)
);
/**
* vn_grid_model_new:
* @model: a #DbModel
*
* Creates a new #VnGridModel with @model as the data model.
*
* Return value: (transfer full): a #VnGridModel.
**/
VnGridModel * vn_grid_model_new (DbModel * model)
{
return g_object_new (VN_TYPE_GRID_MODEL, "model", model, NULL);
}
/**
* vn_grid_model_get_model:
* @obj: a #VnGridModel
*
* Passes the #DbModel used internally by @model.
*
* Return value: (transfer none): a #DbModel.
**/
DbModel * vn_grid_model_get_model (VnGridModel * obj)
{
g_return_val_if_fail (VN_IS_GRID_MODEL (obj), NULL);
return obj->model;
}
/**
* vn_gtk_tree_iter_from_db_iter:
* @dest_iter: the #GtkTreeIter to set using the data on @src_iter
* @src_iter: a valid #DbIter
*
* Sets a #GtkTreeIter with the data of a #DbIter. This function is mostly used
* internally.
**/
void gtk_tree_iter_from_db_iter (GtkTreeIter * dest_iter, const DbIter * src_iter)
{
dest_iter->stamp = src_iter->stamp;
dest_iter->user_data = src_iter->data;
}
/**
* vn_gtk_tree_iter_to_db_iter:
* @src_iter: a valid #GtkTreeIter
* @dest_iter: the #DbIter to set using the data on @src_iter
*
* Sets a with #DbIter the data of a #GtkTreeIter. This function is mostly used
* internally.
**/
void gtk_tree_iter_to_db_iter (const GtkTreeIter * src_iter, DbIter * dest_iter)
{
dest_iter->stamp = src_iter->stamp;
dest_iter->data = src_iter->user_data;
}
/**
* vn_grid_model_iter_is_valid:
* @iter: a #GtkTreeIter
* @model: a #GtkTreeModel
*
* Checks if @iter is a valid #GtkTreeIter pointing inside #GtkTreeModel.
**/
gboolean vn_grid_model_iter_is_valid (GtkTreeIter * iter, GtkTreeModel * model)
{
DbIter dbiter;
g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
gtk_tree_iter_to_db_iter (iter, &dbiter);
return db_model_iter_is_valid (&dbiter, VN_GRID_MODEL (model)->model);
}
static gint vn_grid_model_get_nrows (GtkTreeModel * obj)
{
return db_model_get_nrows (VN_GRID_MODEL (obj)->model);
}
//++++ Broadcast of GtkTreeModel and GtkTreeSortable signals:
static void vn_grid_model_on_line_updated (DbModel * model, DbIter * dbiter, GtkTreeModel * obj)
{
GtkTreeIter iter;
gtk_tree_iter_from_db_iter (&iter, dbiter);
GtkTreePath * path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, db_model_get_path (model, dbiter));
gtk_tree_model_row_changed (obj, path, &iter);
gtk_tree_path_free (path);
}
static void vn_grid_model_on_line_inserted (DbModel * model, DbIter * dbiter, GtkTreeModel * obj)
{
GtkTreeIter iter;
gtk_tree_iter_from_db_iter (&iter, dbiter);
GtkTreePath * path = gtk_tree_path_new ();
gtk_tree_path_append_index (path,
db_model_get_path (model, dbiter));
gtk_tree_model_row_inserted (obj, path, &iter);
gtk_tree_path_free (path);
}
static void vn_grid_model_on_line_deleted (DbModel * model, gint position, GtkTreeModel * obj)
{
GtkTreePath * path = gtk_tree_path_new ();
gtk_tree_path_append_index (path, position);
if (gtk_tree_path_get_indices (path))
gtk_tree_model_row_deleted (obj, path);
gtk_tree_path_free (path);
}
static void vn_grid_model_on_lines_reordered (DbModel * model, guint col, gint * new_order, GtkTreeModel * obj)
{
GtkTreePath * path = gtk_tree_path_new ();
gtk_tree_model_rows_reordered (obj, path, NULL, new_order);
gtk_tree_path_free (path);
}
static void vn_grid_model_on_sort_changed (DbModel * model, GtkTreeSortable * obj)
{
g_signal_emit_by_name (obj, "sort-column-changed");
}
//++++ Implementation of GtkTreeModel methods (using DbModel methods)
static GtkTreeModelFlags vn_grid_model_get_flags (GtkTreeModel * obj)
{
return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
}
static gint vn_grid_model_get_ncols (GtkTreeModel * obj)
{
return db_model_get_ncols (VN_GRID_MODEL (obj)->model);
}
static GType vn_grid_model_get_column_type (GtkTreeModel * obj, gint index_)
{
return db_model_get_column_type (VN_GRID_MODEL (obj)->model, index_);
}
static gboolean vn_grid_model_get_iter (GtkTreeModel * obj, GtkTreeIter * iter,
GtkTreePath * path)
{
DbIter dbiter;
gint p = gtk_tree_path_get_indices (path)[0];
gboolean ret = db_model_get_iter (VN_GRID_MODEL (obj)->model, &dbiter, p);
if (ret)
gtk_tree_iter_from_db_iter (iter, &dbiter);
return ret;
}
static GtkTreePath * vn_grid_model_get_path (GtkTreeModel * obj, GtkTreeIter * iter)
{
GtkTreePath * path;
DbIter dbiter;
gtk_tree_iter_to_db_iter (iter, &dbiter);
path = gtk_tree_path_new ();
gtk_tree_path_append_index (path,
db_model_get_path (VN_GRID_MODEL (obj)->model, &dbiter));
return path;
}
static void vn_grid_model_get_value (GtkTreeModel * obj, GtkTreeIter * iter,
gint column, GValue * value)
{
const GValue * v;
DbIter dbiter;
gtk_tree_iter_to_db_iter (iter, &dbiter);
v = db_model_get_value (VN_GRID_MODEL (obj)->model, &dbiter, column, NULL);
if (v)
{
g_value_init (value, G_VALUE_TYPE (v));
g_value_copy (v, value);
}
else
g_value_init (value, GVN_TYPE_NULL);
}
static gboolean vn_grid_model_iter_next (GtkTreeModel * obj, GtkTreeIter * iter)
{
DbIter dbiter;
gtk_tree_iter_to_db_iter (iter, &dbiter);
gboolean ret_val = db_model_iter_next (VN_GRID_MODEL (obj)->model, &dbiter);
iter->user_data = dbiter.data;
return ret_val;
}
static gboolean vn_grid_model_iter_previous (GtkTreeModel * obj, GtkTreeIter * iter)
{
DbIter dbiter;
gtk_tree_iter_to_db_iter (iter, &dbiter);
gboolean ret_val = db_model_iter_prev (VN_GRID_MODEL (obj)->model, &dbiter);
iter->user_data = dbiter.data;
return ret_val;
}
static gboolean vn_grid_model_iter_children (GtkTreeModel * obj, GtkTreeIter * iter,
GtkTreeIter * parent)
{
if (parent == NULL)
{
DbIter dbiter;
gboolean ret_val = db_model_get_iter_first (VN_GRID_MODEL (obj)->model
,&dbiter);
if (ret_val)
gtk_tree_iter_from_db_iter (iter, &dbiter);
return ret_val;
}
return FALSE;
}
static gboolean vn_grid_model_iter_has_child (GtkTreeModel * obj, GtkTreeIter * iter)
{
return FALSE;
}
static gint vn_grid_model_iter_n_children (GtkTreeModel * obj, GtkTreeIter * iter)
{
if (iter == NULL)
return vn_grid_model_get_nrows (obj);
return 0;
}
static gboolean vn_grid_model_iter_nth_child (GtkTreeModel * obj, GtkTreeIter * iter
,GtkTreeIter * parent, gint n)
{
if (parent == NULL)
{
DbIter dbiter;
gboolean ret = db_model_get_iter (VN_GRID_MODEL (obj)->model, &dbiter, n);
if (ret)
gtk_tree_iter_from_db_iter (iter, &dbiter);
}
return FALSE;
}
static gboolean vn_grid_model_iter_parent (GtkTreeModel * obj, GtkTreeIter * iter,
GtkTreeIter * child)
{
return FALSE;
}
//++++ Implementation of GtkTreeSortable methods (using DbModel methods)
static gboolean vn_grid_model_get_sort_column_id (GtkTreeSortable * obj,
gint * sort_column_id,
GtkSortType * order)
{
return db_model_get_sort_column_id (VN_GRID_MODEL (obj)->model
,sort_column_id, (DbSortType *) order);
}
static void vn_grid_model_set_sort_column_id (GtkTreeSortable * obj, gint sort_column_id,
GtkSortType order)
{
DbSortType db_order;
if (order == GTK_SORT_ASCENDING)
db_order = DB_SORT_ASCENDING;
else
db_order = DB_SORT_DESCENDING;
db_model_set_sort_column_id (VN_GRID_MODEL (obj)->model, sort_column_id, db_order);
}
static void vn_grid_model_set_sort_func (GtkTreeSortable *sortable, gint sort_column_id,
GtkTreeIterCompareFunc sort_func, gpointer user_data, GDestroyNotify destroy)
{
g_log (g_quark_to_string (VN_GRID_MODEL_LOG_DOMAIN)
,G_LOG_LEVEL_WARNING, "Function vn_grid_model_set_sort_func not implemented");
}
static void vn_grid_model_set_default_sort_func (GtkTreeSortable *sortable,
GtkTreeIterCompareFunc sort_func, gpointer user_data, GDestroyNotify destroy)
{
g_log (g_quark_to_string (VN_GRID_MODEL_LOG_DOMAIN)
,G_LOG_LEVEL_WARNING, "Function vn_grid_model_set_default_sort_func not implemented");
}
static gboolean vn_grid_model_has_default_sort_func (GtkTreeSortable * obj)
{
return TRUE;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Properties
typedef enum
{
PROP_MODEL = 1
}
VnGridModelProp;
GvnSignalInfo signal_info[] =
{
{"line-updated.after", vn_grid_model_on_line_updated
},{"line-inserted", vn_grid_model_on_line_inserted
},{"line-deleted.after", vn_grid_model_on_line_deleted
},{"lines-reordered", vn_grid_model_on_lines_reordered
},{"sort-changed", vn_grid_model_on_sort_changed
},{NULL}
};
static void vn_grid_model_set_property (VnGridModel * obj, guint property_id,
const GValue * value, GParamSpec * pspec)
{
switch (property_id)
{
case PROP_MODEL:
gvn_object_link (obj, &obj->model, g_value_get_object (value), signal_info);
/*g_object_ref_sink (obj->model);
g_object_connect (obj->model
,"signal-after::line-updated", vn_grid_model_on_line_updated, obj
,"signal::line-inserted", vn_grid_model_on_line_inserted, obj
,"signal-after::line-deleted", vn_grid_model_on_line_deleted, obj
,"signal::lines-reordered", vn_grid_model_on_lines_reordered, obj
,"signal::sort-changed", vn_grid_model_on_sort_changed, obj, NULL);*/
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
}
}
static void vn_grid_model_get_property (VnGridModel * obj, guint property_id,
GValue * value, GParamSpec * pspec)
{
switch (property_id)
{
case PROP_MODEL:
g_value_set_object (value, obj->model);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Class
static void vn_grid_model_finalize (VnGridModel * obj)
{
gvn_object_link (obj, &obj->model, NULL, signal_info);
/*
g_object_disconnect (obj->model
,"any_signal", vn_grid_model_on_line_updated, obj
,"any_signal", vn_grid_model_on_line_inserted, obj
,"any_signal", vn_grid_model_on_line_deleted, obj
,"any_signal", vn_grid_model_on_lines_reordered, obj
,"any_signal", vn_grid_model_on_sort_changed, obj, NULL);
g_object_unref (obj->model);
*/
G_OBJECT_CLASS (vn_grid_model_parent_class)->finalize (G_OBJECT (obj));
}
static void vn_grid_model_class_init (VnGridModelClass * k)
{
GObjectClass * klass = G_OBJECT_CLASS (k);
klass->set_property = (GObjectSetPropertyFunc) vn_grid_model_set_property;
klass->get_property = (GObjectGetPropertyFunc) vn_grid_model_get_property;
klass->finalize = (GObjectFinalizeFunc) vn_grid_model_finalize;
g_object_class_install_property (klass, PROP_MODEL,
g_param_spec_object ("model"
,"Model"
,"The #DbModel with the data used by the #VnGridModel"
,DB_TYPE_MODEL
,G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE
));
}
static void vn_grid_model_tree_model_init (GtkTreeModelIface * iface)
{
iface->get_flags = vn_grid_model_get_flags;
iface->get_n_columns = vn_grid_model_get_ncols;
iface->get_column_type = vn_grid_model_get_column_type;
iface->get_iter = vn_grid_model_get_iter;
iface->get_path = vn_grid_model_get_path;
iface->get_value = vn_grid_model_get_value;
iface->iter_next = vn_grid_model_iter_next;
iface->iter_previous = vn_grid_model_iter_previous;
iface->iter_children = vn_grid_model_iter_children;
iface->iter_has_child = vn_grid_model_iter_has_child;
iface->iter_n_children = vn_grid_model_iter_n_children;
iface->iter_nth_child = vn_grid_model_iter_nth_child;
iface->iter_parent = vn_grid_model_iter_parent;
}
static void vn_grid_model_tree_sortable_init (GtkTreeSortableIface * iface)
{
iface->get_sort_column_id = vn_grid_model_get_sort_column_id;
iface->set_sort_column_id = vn_grid_model_set_sort_column_id;
iface->set_sort_func = vn_grid_model_set_sort_func;
iface->set_default_sort_func = vn_grid_model_set_default_sort_func;
iface->has_default_sort_func = vn_grid_model_has_default_sort_func;
}
static void vn_grid_model_init (VnGridModel * obj)
{
obj->model = NULL;
}