/* * 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-combo.h" #include "../vn-grid-model.h" #include /** * SECTION:vn-combo * @Short_description: a combo box widget * @Title: VnCombo * @See_also: #VnField * @Image: combo.png * * A combo box widget to select from a list of items, selected from a * database. */ static void vn_combo_model_holder_interface_init (DbModelHolderInterface * iface); G_DEFINE_TYPE_WITH_CODE (VnCombo, vn_combo, VN_TYPE_FIELD, G_IMPLEMENT_INTERFACE (DB_TYPE_MODEL_HOLDER, vn_combo_model_holder_interface_init) ); /** * vn_combo_new: * @model: the model used by combo box * * Creates a new #VnCombo * * Return value: a #VnCombo **/ VnField * vn_combo_new (DbModel * model) { return g_object_new (VN_TYPE_COMBO, "model", model, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private static void vn_combo_on_changed (GtkComboBox * combo, VnCombo * self) { GtkTreeIter iter; GValue value = G_VALUE_INIT; if (gtk_combo_box_get_active_iter (combo, &iter)) gtk_tree_model_get_value (self->tree, &iter, self->index_column, &value); else g_value_init (&value, GVN_TYPE_NULL); VN_FIELD_GET_CLASS (self)->value_changed (VN_FIELD (self), &value); g_value_unset (&value); } static void vn_combo_on_model_ready (VnCombo * self, const GValue * value) { DbIter iter; g_signal_handlers_block_by_func (self->combo, vn_combo_on_changed, self); if (!gvn_value_is_null (value) && db_model_search_value (self->model, self->index_column, &iter, value)) { GtkTreeIter tree_iter; vn_gtk_tree_iter_from_db_iter (&tree_iter, &iter); gtk_combo_box_set_active_iter (self->combo, &tree_iter); } else gtk_combo_box_set_active_iter (self->combo, NULL); g_signal_handlers_unblock_by_func (self->combo, vn_combo_on_changed, self); } static void vn_combo_set_value (VnCombo * self, const GValue * value) { if (self->model && db_model_get_status (self->model) == DB_MODEL_STATUS_READY) vn_combo_on_model_ready (self, value); } static void vn_combo_on_status_changed (DbModel * model, DbModelStatus status, VnCombo * self) { if (status == DB_MODEL_STATUS_READY) { gtk_combo_box_set_model (self->combo, self->tree); vn_combo_on_model_ready (self, gvn_param_get_value (GVN_PARAM (self))); db_model_use_null_row (model, vn_field_get_null (VN_FIELD (self))); } else gtk_combo_box_set_model (self->combo, NULL); } static DbModel * vn_combo_get_model (VnCombo * self) { return self->model; } static void vn_combo_set_model (VnCombo * self, DbModel * model) { g_return_if_fail (VN_IS_COMBO (self)); g_return_if_fail (DB_IS_MODEL (model) || !model); if (self->model) { g_signal_handlers_disconnect_by_func (self->model, vn_combo_on_status_changed, self); g_clear_object (&self->model); g_clear_object (&self->tree); } if (model) { self->tree = GTK_TREE_MODEL (vn_grid_model_new (model)); self->model = g_object_ref (model); g_signal_connect (model, "status-changed", G_CALLBACK (vn_combo_on_status_changed), self); vn_combo_on_status_changed (model, db_model_get_status (model), self); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * vn_combo_get_index_column: * @self: a #VnCombo * * Gets the combo column index. * * Return value: the column **/ guint vn_combo_get_index_column (VnCombo * self) { g_return_val_if_fail (VN_IS_COMBO (self), 0); return self->index_column; } /** * vn_combo_set_index_column: * @self: a #VnCombo * @column: the column * * Sets the column index used by combo. **/ void vn_combo_set_index_column (VnCombo * self, guint column) { g_return_if_fail (VN_IS_COMBO (self)); self->index_column = column; vn_combo_set_value (self, gvn_param_get_value (GVN_PARAM (self))); } /** * vn_combo_get_show_column: * @self: a #VnCombo * * Gets the column shown by combo. * * Return value: the column **/ guint vn_combo_get_show_column (VnCombo * self) { g_return_val_if_fail (VN_IS_COMBO (self), 0); return self->show_column; } /** * vn_combo_set_show_column: * @self: a #VnCombo * @column: the column * * Sets the column shown by combo. **/ void vn_combo_set_show_column (VnCombo * self, guint column) { g_return_if_fail (VN_IS_COMBO (self)); self->show_column = column; gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (self->combo), self->cell); gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self->combo), self->cell, "text", (gint) self->show_column); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_INDEX_COLUMN = 1 ,PROP_SHOW_COLUMN ,PROP_MODEL }; static void vn_combo_set_property (VnCombo * self, guint property_id, const GValue * value, GParamSpec * pspec) { switch (property_id) { case PROP_INDEX_COLUMN: vn_combo_set_index_column (self, g_value_get_uint (value)); break; case PROP_SHOW_COLUMN: vn_combo_set_show_column (self, g_value_get_uint (value)); break; case PROP_MODEL: vn_combo_set_model (self, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec); } } static void vn_combo_get_property (VnCombo * self, guint property_id, GValue * value, GParamSpec * pspec) { switch (property_id) { case PROP_INDEX_COLUMN: g_value_set_uint (value, self->index_column); break; case PROP_SHOW_COLUMN: g_value_set_uint (value, self->show_column); break; case PROP_MODEL: g_value_set_object (value, self->model); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (self, property_id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void vn_combo_init (VnCombo * self) { self->tree = NULL; self->model = NULL; self->combo = GTK_COMBO_BOX (gtk_combo_box_new ()); g_signal_connect (self->combo, "changed", G_CALLBACK (vn_combo_on_changed), self); gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->combo)); self->cell = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self->combo), self->cell, TRUE); VN_FIELD_GET_CLASS (self)->set_widget (VN_FIELD (self), GTK_WIDGET (self->combo)); } static void vn_combo_finalize (VnCombo * self) { vn_combo_set_model (self, NULL); G_OBJECT_CLASS (vn_combo_parent_class)->finalize (G_OBJECT (self)); } static void vn_combo_class_init (VnComboClass * klass) { GObjectClass * k = G_OBJECT_CLASS (klass); k->finalize = (GObjectFinalizeFunc) vn_combo_finalize; k->set_property = (GObjectSetPropertyFunc) vn_combo_set_property; k->get_property = (GObjectGetPropertyFunc) vn_combo_get_property; VN_FIELD_CLASS (klass)->set_value = (VnFieldSetValueFunc) vn_combo_set_value; g_object_class_override_property (k, PROP_MODEL, "model"); g_object_class_install_property (k, PROP_INDEX_COLUMN, g_param_spec_uint ("index-column" ,_("Index column") ,_("The column index of the model") ,0, 255, 0 ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_SHOW_COLUMN, g_param_spec_uint ("show-column" ,_("Show column") ,_("The column of the model shown by combo") ,0, 255, 1 ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); } static void vn_combo_model_holder_interface_init (DbModelHolderInterface * iface) { iface->get_model = (DbModelHolderGetModelFunc) vn_combo_get_model; iface->set_model = (DbModelHolderSetModelFunc) vn_combo_set_model; }