Wed, 21 Jan 2015 20:38:21 +0100
fixed memory allocation bug
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2014 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include "model.h" #define IS_UI_LIST_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type)) #define UI_LIST_MODEL(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel)) static void list_model_class_init(GObjectClass *cl, gpointer data); static void list_model_interface_init(GtkTreeModelIface *i, gpointer data); static void list_model_init(UiListModel *instance, GObjectClass *cl); static GObjectClass list_model_class; static const GTypeInfo list_model_info = { sizeof(GObjectClass), NULL, NULL, (GClassInitFunc)list_model_class_init, NULL, NULL, sizeof(UiListModel), 0, (GInstanceInitFunc)list_model_init }; static const GInterfaceInfo list_model_interface_info = { (GInterfaceInitFunc)list_model_interface_init, NULL, NULL }; static GType list_model_type; void ui_list_init() { list_model_type = g_type_register_static( G_TYPE_OBJECT, "UiListModel", &list_model_info, (GTypeFlags)0); g_type_add_interface_static( list_model_type, GTK_TYPE_TREE_MODEL, &list_model_interface_info); } static void list_model_class_init(GObjectClass *cl, gpointer data) { //cl->finalize = ...; // TODO } static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) { i->get_flags = ui_list_model_get_flags; i->get_n_columns = ui_list_model_get_n_columns; i->get_column_type = ui_list_model_get_column_type; i->get_iter = ui_list_model_get_iter; i->get_path = ui_list_model_get_path; i->get_value = ui_list_model_get_value; i->iter_next = ui_list_model_iter_next; i->iter_children = ui_list_model_iter_children; i->iter_has_child = ui_list_model_iter_has_child; i->iter_n_children = ui_list_model_iter_n_children; i->iter_nth_child = ui_list_model_iter_nth_child; i->iter_parent = ui_list_model_iter_parent; } static void list_model_init(UiListModel *instance, GObjectClass *cl) { instance->columntypes = NULL; instance->list = NULL; instance->numcolumns = 0; instance->stamp = g_random_int(); } static GType ui_gtk_type(UiModelType type) { switch(type) { case UI_STRING: return G_TYPE_STRING; case UI_INTEGER: return G_TYPE_INT; } return G_TYPE_INVALID; } static void ui_model_set_value(UiModelType type, void *data, GValue *value) { switch(type) { case UI_STRING: { value->g_type = G_TYPE_STRING; g_value_set_string(value, data); return; } case UI_INTEGER: { value->g_type = G_TYPE_INT; int *i = data; g_value_set_int(value, *i); return; } } value->g_type = G_TYPE_INVALID; } UiListModel* ui_list_model_new(UiListPtr *list, UiModelInfo *info) { UiListModel *model = g_object_new(list_model_type, NULL); model->info = info; model->list = list; model->columntypes = malloc(sizeof(GType)); model->numcolumns = info->columns; for(int i=0;i<info->columns;i++) { model->columntypes[i] = ui_gtk_type(info->types[i]); } return model; } GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) { return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); } gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), 0); UiListModel *model = UI_LIST_MODEL(tree_model); return model->numcolumns; } GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), G_TYPE_INVALID); UiListModel *model = UI_LIST_MODEL(tree_model); g_return_val_if_fail(index < model->numcolumns, G_TYPE_INVALID); return model->columntypes[index]; } gboolean ui_list_model_get_iter( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { g_assert(IS_UI_LIST_MODEL(tree_model)); UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; // check the depth of the path // a list must have a depth of 1 gint depth = gtk_tree_path_get_depth(path); g_assert(depth == 1); // get row gint *indices = gtk_tree_path_get_indices(path); gint row = indices[0]; // check row if(row == 0) { // we don't need to count if the first element is requested if(list->first(list) == NULL) { return FALSE; } } else if(row >= list->count(list)) { return FALSE; } // the UiList has an integrated iterator // we only get a value to adjust it void *val = NULL; if(row == 0) { val = list->first(list); } else { val = list->get(list, row); } iter->stamp = model->stamp; iter->user_data = list->iter; iter->user_data2 = (gpointer)(intptr_t)row; // list->index iter->user_data3 = val; return val ? TRUE : FALSE; } GtkTreePath* ui_list_model_get_path( GtkTreeModel *tree_model, GtkTreeIter *iter) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), NULL); g_return_val_if_fail(iter != NULL, NULL); g_return_val_if_fail(iter->user_data != NULL, NULL); UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; GtkTreePath *path = gtk_tree_path_new(); gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index return path; } void ui_list_model_get_value( GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { g_return_if_fail(IS_UI_LIST_MODEL(tree_model)); g_return_if_fail(iter != NULL); g_return_if_fail(iter->user_data != NULL); UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; g_return_if_fail(column < model->numcolumns); // TODO: return correct value from column //value->g_type = G_TYPE_STRING; list->iter = iter->user_data; //list->index = (int)(intptr_t)iter->user_data2; //list->current = iter->user_data3; if(model->info->getvalue) { void *data = model->info->getvalue(iter->user_data3, column); ui_model_set_value(model->info->types[column], data, value); } else { value->g_type = G_TYPE_INVALID; } } gboolean ui_list_model_iter_next( GtkTreeModel *tree_model, GtkTreeIter *iter) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); g_return_val_if_fail(iter != NULL, FALSE); g_return_val_if_fail(iter->user_data != NULL, FALSE); UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; list->iter = iter->user_data; //list->index = (int)(intptr_t)iter->user_data2; void *val = list->next(list); iter->user_data = list->iter; intptr_t index = (intptr_t)iter->user_data2; index++; //iter->user_data2 = (gpointer)(intptr_t)list->index; iter->user_data2 = (gpointer)index; iter->user_data3 = val; return val ? TRUE : FALSE; } gboolean ui_list_model_iter_children( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; if(parent) { return FALSE; } /* * a list element has no children * we set the iter to the first element */ void *val = list->first(list); iter->stamp = model->stamp; iter->user_data = list->iter; iter->user_data2 = (gpointer)0; iter->user_data3 = val; return val ? TRUE : FALSE; } gboolean ui_list_model_iter_has_child( GtkTreeModel *tree_model, GtkTreeIter *iter) { return FALSE; } gint ui_list_model_iter_n_children( GtkTreeModel *tree_model, GtkTreeIter *iter) { g_assert(IS_UI_LIST_MODEL(tree_model)); if(!iter) { // return number of rows UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; return list->count(list); } return 0; } gboolean ui_list_model_iter_nth_child( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); if(parent) { return FALSE; } UiListModel *model = UI_LIST_MODEL(tree_model); UiList *list = model->list->list; // check n if(n == 0) { // we don't need to count if the first element is requested if(list->first(list) == NULL) { return FALSE; } } else if(n >= list->count(list)) { return FALSE; } void *val = list->get(list, n); iter->stamp = model->stamp; iter->user_data = list->iter; iter->user_data2 = (gpointer)(intptr_t)n; // list->index iter->user_data3 = val; return val ? TRUE : FALSE; } gboolean ui_list_model_iter_parent( GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { return FALSE; }