/* * 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 "vn-column.h" #include "vn-grid.h" static void vn_column_buildable_init (GtkBuildableIface * iface); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (VnColumn, vn_column, GTK_TYPE_TREE_VIEW_COLUMN, G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, vn_column_buildable_init) ); static GdkRGBA vn_column_red; static GdkRGBA vn_column_green; /** * VnColumnStyleFunc: * @obj: a #VnColumn * @cell: the #GtkCellRenderer of the column * @iter: the #GtkTreeIter pointing the row * @value: (transfer none): the current value in the cell * * Function used to modify the cell depending on @value. This function is called * during the #GtkTreeCellDataFunc of #VnColumn, so the actions made here will * impact the speed of the user interface rendering, as this function is called * constantly to show the #VnGrid on the screen. **/ //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private static void vn_column_value_changed (VnColumn * obj, const gchar * path, const GValue * value) { DbIter iter; vn_column_get_iter (obj, path, &iter); db_model_set_value (vn_column_get_model (obj), &iter, obj->column_index, value, NULL); } static void vn_column_data_func (GtkTreeViewColumn * col, GtkCellRenderer * cell, GtkTreeModel * model, GtkTreeIter * iter, VnColumn * obj) { /* GdkRGBA * background; DbIter dbiter; DbModelRowOp ops; */ GValue value = G_VALUE_INIT; gtk_tree_model_get_value (model, iter, obj->column_index, &value); obj->set_value (obj, model, iter, cell, &value); /* vn_gtk_tree_iter_to_db_iter (iter, &dbiter); ops = db_model_get_row_operations ( vn_grid_model_get_model (VN_GRID_MODEL (model)) ,&dbiter ); if (ops & DB_MODEL_ROW_OP_DELETE) background = &vn_column_red; else if (ops & DB_MODEL_ROW_OP_INSERT || ops & DB_MODEL_ROW_OP_UPDATE) background = &vn_column_green; else background = NULL; g_object_set (cell, "cell-background-rgba", background, NULL); */ if (obj->style_func) obj->style_func (VN_COLUMN (col), cell, iter, &value); g_value_unset (&value); } static void vn_column_set_renderer (VnColumn * obj, GtkCellRenderer * cell) { GtkTreeViewColumn * column; obj->cell = cell; obj->set_value = VN_COLUMN_GET_CLASS (obj)->set_value; VN_COLUMN_GET_CLASS (obj)->set_editable (obj, obj->editable); column = GTK_TREE_VIEW_COLUMN (obj); gtk_tree_view_column_pack_start (column, cell, TRUE); gtk_tree_view_column_set_cell_data_func (column, cell, (GtkTreeCellDataFunc) vn_column_data_func, obj, NULL); } static void vn_column_update_column_index (VnColumn * obj) { if (obj->column_name) { DbModel * model = vn_column_get_model (obj); if (model && db_model_is_ready (model)) { obj->column_index = db_model_get_column_index (model, obj->column_name); if (obj->column_index >= 0) gtk_tree_view_column_set_sort_column_id ( GTK_TREE_VIEW_COLUMN (obj), obj->column_index); } } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * vn_column_get_column_name: * @obj: the #VnColumn * * Gets the column name. * * Return value: the column name **/ const gchar * vn_column_get_column_name (VnColumn * obj) { g_return_val_if_fail (VN_IS_COLUMN (obj), NULL); return obj->column_name; } /** * vn_column_set_column_name: * @obj: the #VnColumn * @name: the column name * * Sets the column name. **/ void vn_column_set_column_name (VnColumn * obj, const gchar * name) { g_return_if_fail (VN_IS_COLUMN (obj)); g_free (obj->column_name); obj->column_name = g_strdup (name); vn_column_update_column_index (obj); } /** * vn_column_get_column_index: * @obj: the #VnColumn * * Gets the column index. * * Return value: the column index **/ gint vn_column_get_column_index (VnColumn * obj) { g_return_val_if_fail (VN_IS_COLUMN (obj), -1); return obj->column_index; } /** * vn_column_set_column_index: * @obj: the #VnColumn * @index: the column index * * Sets the column index. **/ void vn_column_set_column_index (VnColumn * obj, gint index) { g_return_if_fail (VN_IS_COLUMN (obj)); g_return_if_fail (index >= -1); obj->column_index = index; vn_column_set_column_name (obj, NULL); if (index >= 0) gtk_tree_view_column_set_sort_column_id ( GTK_TREE_VIEW_COLUMN (obj), index); } /** * vn_column_get_editable: * @obj: the #VnColumn * * Gets if the column can be edited by the user. * * Return value: %TRUE if it's editable, %FALSE otherwhise **/ gboolean vn_column_get_editable (VnColumn * obj) { g_return_val_if_fail (VN_IS_COLUMN (obj), FALSE); return obj->editable; } /** * vn_column_set_editable: * @obj: the #VnColumn * @editable: a %gboolean indicating whether the column value is editable * * Sets if the column can be edited by the user. **/ void vn_column_set_editable (VnColumn * obj, gboolean editable) { g_return_if_fail (VN_IS_COLUMN (obj)); obj->editable = editable; VN_COLUMN_GET_CLASS (obj)->set_editable (obj, editable); } /** * vn_column_get_null: * @obj: the #VnColumn * * Gets if the column can be set to null by the user. * * Return value: %TRUE if it can be, %FALSE otherwhise **/ gboolean vn_column_get_null (VnColumn * obj) { g_return_val_if_fail (VN_IS_COLUMN (obj), FALSE); return obj->null; } /** * vn_column_set_null: * @obj: the #VnColumn * @null: a %gboolean indicating whether the column value can be null * * Sets if the column can be set to null by the user. **/ void vn_column_set_null (VnColumn * obj, gboolean null) { g_return_if_fail (VN_IS_COLUMN (obj)); obj->null = null; if (VN_COLUMN_GET_CLASS (obj)->set_null) VN_COLUMN_GET_CLASS (obj)->set_null (obj, null); } /** * vn_column_get_tab_index: * @obj: the #VnColumn * * Sets the order in which the column will be selected while pressing Tab across * the #VnGrid. * * Return value: the index of the column **/ int vn_column_get_tab_index (VnColumn * obj) { g_return_if_fail (VN_IS_COLUMN (obj)); return obj->tab_index; } /** * vn_column_set_tab_index: * @obj: the #VnColumn * @tab_index: the index of the column * * Sets the order in which the column will be selected while pressing Tab across * the #VnGrid. If the column is not editable, tab-index will be ignored bt the * #VnGrid, as the column can't be edited (i.e. not accessible through pressing * Tab). **/ void vn_column_set_tab_index (VnColumn * obj, gint tab_index) { g_return_if_fail (VN_IS_COLUMN (obj)); obj->tab_index = tab_index; } /** * vn_column_get_model: * @obj: the #VnColumn * * Gets the model used by the main #VnGrid. * * Return value: (transfer none): the #DbModel if has it, %NULL otherwise. **/ DbModel * vn_column_get_model (VnColumn * obj) { g_return_val_if_fail (VN_IS_COLUMN (obj), NULL); GtkWidget * grid = gtk_tree_view_column_get_tree_view ( GTK_TREE_VIEW_COLUMN (obj)); if (grid) return vn_grid_get_model (VN_GRID (grid)); return NULL; } /** * vn_column_get_iter: * @obj: the #VnColumn * @path: the path string * @iter: (out): the #DbIter to be set * * Gets a #DbIter from a #GtkTreePath string. * * Return value: %TRUE if the iter could be obtained, %FALSE otherwise. **/ gboolean vn_column_get_iter (VnColumn * obj, const gchar * path, DbIter * iter) { gboolean ret = FALSE; DbModel * model; GtkTreePath * tree_path; g_return_val_if_fail (VN_IS_COLUMN (obj), FALSE); g_return_val_if_fail (iter, FALSE); tree_path = gtk_tree_path_new_from_string (path); model = vn_column_get_model (obj); if (!tree_path) g_warning ("VnColumn: Invalid path."); else if (gtk_tree_path_get_depth (tree_path) < 1) g_warning ("VnColumn: Path has no indices."); else if (!model) g_warning ("VnColumn: Tree view has no model assigned."); else { db_model_get_iter (model, iter, gtk_tree_path_get_indices (tree_path)[0]); ret = TRUE; } gtk_tree_path_free (tree_path); return ret; } /** * vn_column_model_changed: * @obj: the #VnColumn * * This function is used primarily by the #VnGrid. Warns the column that the * model has changed. **/ void vn_column_model_changed (VnColumn * obj) { VnColumnClass * klass; g_return_if_fail (VN_IS_COLUMN (obj)); klass = VN_COLUMN_GET_CLASS (obj); vn_column_update_column_index (obj); if (klass->model_changed) klass->model_changed (obj); } /** * vn_column_get_cell_renderer: * @obj: a #VnColumn * * Retrieves the cell renderer used by the column. * * Return value: (transfer none): a #GtkCellRenderer **/ GtkCellRenderer * vn_column_get_cell_renderer (VnColumn * obj) { g_return_if_fail (VN_IS_COLUMN (obj)); return obj->cell; } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Buildable static GtkBuildableIface * parent_buildable_iface; static GObject * vn_column_buildable_get_internal_child (GtkBuildable * buildable, GtkBuilder * builder, const gchar * childname) { if (!g_strcmp0 (childname, "cell")) return G_OBJECT (vn_column_get_cell_renderer (VN_COLUMN (buildable))); return parent_buildable_iface->get_internal_child (buildable, builder, childname); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_COLUMN_INDEX = 1 ,PROP_COLUMN_NAME ,PROP_EDITABLE ,PROP_NULL ,PROP_TAB_INDEX ,PROP_STYLE_FUNC }; static void vn_column_set_property (VnColumn * obj, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_COLUMN_INDEX: vn_column_set_column_index (obj, g_value_get_int (value)); break; case PROP_COLUMN_NAME: vn_column_set_column_name (obj, g_value_get_string (value)); break; case PROP_EDITABLE: vn_column_set_editable (obj, g_value_get_boolean (value)); break; case PROP_NULL: vn_column_set_null (obj, g_value_get_boolean (value)); break; case PROP_TAB_INDEX: vn_column_set_tab_index (obj, g_value_get_int (value)); break; case PROP_STYLE_FUNC: obj->style_func = g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } static void vn_column_get_property (VnColumn * obj, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_COLUMN_INDEX: g_value_set_int (value, obj->column_index); break; case PROP_COLUMN_NAME: g_value_set_string (value, obj->column_name); break; case PROP_EDITABLE: g_value_set_boolean (value, obj->editable); break; case PROP_NULL: g_value_set_boolean (value, obj->null); break; case PROP_TAB_INDEX: g_value_set_int (value, obj->tab_index); break; case PROP_STYLE_FUNC: g_value_set_pointer (value, obj->style_func); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void vn_column_init (VnColumn * obj) { obj->column_index = -1; obj->column_name = NULL; obj->style_func = NULL; } static void vn_column_finalize (VnColumn * obj) { g_free (obj->column_name); G_OBJECT_CLASS (vn_column_parent_class)->finalize (G_OBJECT (obj)); } static void vn_column_buildable_init (GtkBuildableIface * iface) { parent_buildable_iface = g_type_interface_peek_parent (iface); iface->get_internal_child = vn_column_buildable_get_internal_child; } static void vn_column_class_init (VnColumnClass * klass) { GObjectClass * k = G_OBJECT_CLASS (klass); k->finalize = (GObjectFinalizeFunc) vn_column_finalize; k->set_property = (GObjectSetPropertyFunc) vn_column_set_property; k->get_property = (GObjectGetPropertyFunc) vn_column_get_property; klass->value_changed = vn_column_value_changed; klass->set_renderer = vn_column_set_renderer; klass->model_changed = NULL; gdk_rgba_parse (&vn_column_red, "#fcc"); gdk_rgba_parse (&vn_column_green, "#cfc"); g_object_class_install_property (k, PROP_COLUMN_INDEX, g_param_spec_int ("column-index" ,_("Column index") ,_("The column index in the model") ,-1, 255, -1 ,G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_COLUMN_NAME, g_param_spec_string ("column-name" ,_("Column name") ,_("The referenced column name") ,NULL ,G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_EDITABLE, g_param_spec_boolean ("editable" ,_("Editable") ,_("Whether the column values are editable") ,FALSE ,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") ,FALSE ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_TAB_INDEX, g_param_spec_int ("tab-index" ,_("Tab index") ,_("Order in which the tab selects the columns for edition") ,-1, 255, 0 ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_STYLE_FUNC, g_param_spec_pointer ("style-func" ,_("Style function") ,_("A VnColumnStyleFunc to set the properties of each cell " "depending on its value") ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); }