ui/gtk/model.c

changeset 35
3e8b5c9b4033
child 40
caa0df8ed095
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ui/gtk/model.c	Sun May 11 10:41:29 2014 +0200
@@ -0,0 +1,331 @@
+/*
+ * 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();
+}
+
+UiListModel* ui_list_model_new(UiListPtr *list, ui_model_getvalue_f getvalue) {
+    UiListModel *model = g_object_new(list_model_type, NULL);
+    model->list = list;
+    model->getvalue = getvalue;
+    model->columntypes = malloc(sizeof(GType));
+    model->numcolumns = 1;
+    model->columntypes[0] = G_TYPE_STRING;
+    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->getvalue) {
+        char *str = model->getvalue(iter->user_data3, column);
+        g_value_set_string(value, str);
+    } else {
+        g_value_set_string(value, iter->user_data3);
+    }
+}
+
+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;
+}

mercurial