summaryrefslogtreecommitdiff
path: root/tag_model.c
diff options
context:
space:
mode:
authorJon Bergli Heier <snakebite@jvnv.net>2010-04-25 17:28:49 +0200
committerJon Bergli Heier <snakebite@jvnv.net>2010-04-25 17:28:49 +0200
commit0d4b1caee4135b6e0dcd2aa3bd6ce2387c1c3773 (patch)
tree5fc5c7dbed604437b34f21d90e8aaac5139c08e4 /tag_model.c
parente52bbb2a3d17cc12cab75deba113d3075b62337e (diff)
Added a tree model to display tags in tree structures.
Adding children to tags is not yet implemented.
Diffstat (limited to 'tag_model.c')
-rw-r--r--tag_model.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/tag_model.c b/tag_model.c
new file mode 100644
index 0000000..8144e4c
--- /dev/null
+++ b/tag_model.c
@@ -0,0 +1,489 @@
+#include "tag_model.h"
+
+static void tag_model_init(TagModel *tag_model);
+static void tag_model_class_init(TagModelClass *klass);
+static void tag_model_tree_model_init(GtkTreeModelIface *iface);
+static void tag_model_finalize(GObject *object);
+static GtkTreeModelFlags tag_model_get_flags(GtkTreeModel *tree_model);
+static gint tag_model_get_n_columns(GtkTreeModel *tree_model);
+static GType tag_model_get_column_type(GtkTreeModel *tree_model, gint index);
+static gboolean tag_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path);
+static GtkTreePath *tag_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static void tag_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value);
+static gboolean tag_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gboolean tag_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent);
+static gboolean tag_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gint tag_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter);
+static gboolean tag_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n);
+static gboolean tag_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child);
+
+static GObjectClass *parent_class = NULL;
+
+GType tag_model_get_type() {
+ static GType tag_model_type = 0;
+ if(tag_model_type == 0) {
+ static const GTypeInfo tag_model_info = {
+ sizeof(TagModelClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) tag_model_class_init,
+ NULL,
+ NULL,
+ sizeof(TagModel),
+ 0,
+ (GInstanceInitFunc) tag_model_init
+ };
+ static const GInterfaceInfo tree_model_info = {
+ (GInterfaceInitFunc) tag_model_tree_model_init,
+ NULL,
+ NULL
+ };
+ tag_model_type = g_type_register_static(G_TYPE_OBJECT, "TagModel", &tag_model_info, (GTypeFlags)0);
+ g_type_add_interface_static(tag_model_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
+ }
+ return tag_model_type;
+}
+
+static void tag_model_class_init(TagModelClass *klass) {
+ GObjectClass *object_class;
+
+ parent_class = (GObjectClass*)g_type_class_peek_parent(klass);
+ object_class = (GObjectClass*)klass;
+
+ object_class->finalize = tag_model_finalize;
+}
+
+static void tag_model_tree_model_init(GtkTreeModelIface *iface) {
+ iface->get_flags = tag_model_get_flags;
+ iface->get_n_columns = tag_model_get_n_columns;
+ iface->get_column_type = tag_model_get_column_type;
+ iface->get_iter = tag_model_get_iter;
+ iface->get_path = tag_model_get_path;
+ iface->get_value = tag_model_get_value;
+ iface->iter_next = tag_model_iter_next;
+ iface->iter_children = tag_model_iter_children;
+ iface->iter_has_child = tag_model_iter_has_child;
+ iface->iter_n_children = tag_model_iter_n_children;
+ iface->iter_nth_child = tag_model_iter_nth_child;
+ iface->iter_parent = tag_model_iter_parent;
+}
+
+static void tag_model_init_children(TagModelRecord *record) {
+ GArray *array;
+
+ record->children = g_array_new(FALSE, FALSE, sizeof(TagModelRecord));
+ if(db_get_tags(&array, record->tag.id)) {
+ for(int i = 0; i < array->len; i++) {
+ TagModelRecord temp;
+ struct tag_t *tag;
+
+ tag = &g_array_index(array, struct tag_t, i);
+ temp.tag.name = g_strdup(tag->name);
+ temp.tag.id = tag->id;
+ temp.tag.parent = tag->parent;
+ temp.checked = temp.inconsistent = FALSE;
+ temp.parent = record;
+ temp.children = NULL;
+ temp.pos = i;
+
+ g_array_append_val(record->children, temp);
+ tag_model_init_children(&g_array_index(record->children, TagModelRecord, temp.pos));
+
+ g_free(tag->name);
+ }
+ g_array_free(array, TRUE);
+ }
+}
+
+static void tag_model_init(TagModel *tag_model) {
+ TagModelRecord temp;
+ GArray *array;
+ tag_model->n_columns = TAG_MODEL_N_COLUMNS;
+
+ tag_model->column_types[0] = G_TYPE_BOOLEAN;
+ tag_model->column_types[1] = G_TYPE_BOOLEAN;
+ tag_model->column_types[2] = G_TYPE_STRING;
+
+ g_assert(TAG_MODEL_N_COLUMNS == 3);
+
+ tag_model->num_rows = 0;
+ tag_model->rows = g_array_new(FALSE, FALSE, sizeof(TagModelRecord));
+ tag_model->stamp = g_random_int();
+
+ if(db_get_top_level_tags(&array)) {
+ for(int i = 0; i < array->len; i++) {
+ struct tag_t *tag;
+
+ tag = &g_array_index(array, struct tag_t, i);
+
+ temp.tag.name = g_strdup(tag->name);
+ temp.tag.id = tag->id;
+ temp.tag.parent = tag->parent;
+ temp.checked = temp.inconsistent = FALSE;
+ temp.parent = NULL;
+ temp.children = NULL;
+ temp.pos = i;
+
+ g_free(tag->name);
+
+ g_array_append_val(tag_model->rows, temp);
+ tag_model_init_children(&g_array_index(tag_model->rows, TagModelRecord, tag_model->num_rows));
+ tag_model->num_rows++;
+ }
+ g_array_free(array, TRUE);
+ }
+}
+
+static void finalize_recursive(TagModelRecord *record) {
+ if(!record->children)
+ return;
+
+ for(int i = 0; i < record->children->len; i++) {
+ TagModelRecord *temp;
+ temp = &g_array_index(record->children, TagModelRecord, i);
+ g_free(temp->tag.name);
+ }
+}
+
+static void tag_model_finalize(GObject *object) {
+ TagModel *tag_model;
+
+ g_assert(MODEL_IS_TAG(object));
+
+ tag_model = TAG_MODEL(object);
+
+ for(int i = 0; i < tag_model->rows->len; i++) {
+ TagModelRecord *temp;
+ temp = &g_array_index(tag_model->rows, TagModelRecord, i);
+ g_free(temp->tag.name);
+ finalize_recursive(temp);
+ }
+
+ g_array_free(tag_model->rows, TRUE);
+}
+
+static GtkTreeModelFlags tag_model_get_flags(GtkTreeModel *tree_model) {
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), (GtkTreeModelFlags)0);
+
+ return GTK_TREE_MODEL_ITERS_PERSIST;
+}
+
+static gint tag_model_get_n_columns(GtkTreeModel *tree_model) {
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), 0);
+
+ return TAG_MODEL(tree_model)->n_columns;
+}
+
+static GType tag_model_get_column_type(GtkTreeModel *tree_model, gint index) {
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), G_TYPE_INVALID);
+ g_return_val_if_fail(index < TAG_MODEL(tree_model)->n_columns && index >= 0, G_TYPE_INVALID);
+
+ return TAG_MODEL(tree_model)->column_types[index];
+}
+
+inline static TagModelRecord *tag_model_get_record_recursive(TagModel *tag_model, gint *indices, gint depth) {
+ TagModelRecord *temp;
+ if(depth == 1) {
+ return &g_array_index(tag_model->rows, TagModelRecord, indices[depth-1]);
+ } else {
+ temp = tag_model_get_record_recursive(tag_model, indices, depth-1);
+ return &g_array_index(temp->children, TagModelRecord, indices[depth-1]);
+ }
+}
+
+static gboolean tag_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+ gint *indices, n, depth;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(path != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ indices = gtk_tree_path_get_indices(path);
+ depth = gtk_tree_path_get_depth(path);
+
+ n = indices[depth-1];
+ //if(n >= tag_model->num_rows || n < 0)
+ // return FALSE;
+
+ //record = &g_array_index(tag_model->rows, TagModelRecord, n);
+ record = tag_model_get_record_recursive(tag_model, indices, depth);
+
+ g_assert(record != NULL);
+ g_assert(record->pos == n);
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = record;
+ iter->user_data2 = NULL;
+ iter->user_data3 = NULL;
+
+ return TRUE;
+}
+
+static GtkTreePath *tag_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ GtkTreePath *path;
+ TagModelRecord *record;
+ TagModel *tag_model;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), NULL);
+ g_return_val_if_fail(iter != NULL, NULL);
+ g_return_val_if_fail(iter->user_data != NULL, NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ record = (TagModelRecord*)iter->user_data;
+
+ path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, record->pos);
+
+ return path;
+}
+
+static void tag_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) {
+ TagModelRecord *record;
+ TagModel *tag_model;
+
+ g_return_if_fail(MODEL_IS_TAG(tree_model));
+ g_return_if_fail(iter != NULL);
+ g_return_if_fail(column < TAG_MODEL(tree_model)->n_columns);
+
+ g_value_init(value, TAG_MODEL(tree_model)->column_types[column]);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ record = (TagModelRecord*)iter->user_data;
+
+ g_return_if_fail(record != NULL);
+
+ //if(record->pos >= tag_model->num_rows)
+ // g_return_if_reached();
+
+ switch(column) {
+ case TAG_MODEL_COL_CHECKED:
+ g_value_set_boolean(value, record->checked);
+ break;
+ case TAG_MODEL_COL_INCONSISTENT:
+ g_value_set_boolean(value, record->inconsistent);
+ break;
+ case TAG_MODEL_COL_NAME:
+ g_value_set_string_take_ownership(value, g_strdup(record->tag.name));
+ break;
+ }
+}
+
+static gboolean tag_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ TagModelRecord *record, *nextrecord;
+ TagModel *tag_model;
+ GArray *array;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), FALSE);
+
+ if(iter == NULL || iter->user_data == NULL)
+ return FALSE;
+
+ tag_model = TAG_MODEL(tree_model);
+
+ record = (TagModelRecord*)iter->user_data;
+
+ array = (record->parent ? record->parent->children : tag_model->rows);
+
+ if((record->pos + 1) >= array->len)
+ return FALSE;
+
+ nextrecord = &g_array_index(array, TagModelRecord, record->pos + 1);
+
+ g_assert(nextrecord != NULL);
+ g_assert(nextrecord->pos == (record->pos + 1));
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = nextrecord;
+
+ return TRUE;
+}
+
+static gboolean tag_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) {
+ TagModel *tag_model;
+ TagModelRecord *parent_record;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), FALSE);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ if(!parent) {
+ if(tag_model->num_rows == 0)
+ return FALSE;
+ iter->stamp = tag_model->stamp;
+ iter->user_data = &g_array_index(tag_model->rows, TagModelRecord, 0);
+ return TRUE;
+ }
+
+ //g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE);
+
+ parent_record = (TagModelRecord*)parent->user_data;
+
+ if(parent_record->children->len == 0)
+ return FALSE;
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = &g_array_index(parent_record->children, TagModelRecord, 0);
+
+ return TRUE;
+}
+
+static gboolean tag_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ TagModelRecord *record;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), FALSE);
+
+ record = (TagModelRecord*)iter->user_data;
+
+ return (record->parent == NULL && TAG_MODEL(tree_model)->num_rows == 0 ? FALSE : (record->children->len > 0 ? TRUE : FALSE));
+}
+
+static gint tag_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), -1);
+ g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ if(!iter) {
+ return tag_model->num_rows;
+ }
+
+ record = (TagModelRecord*)iter->user_data;
+
+ return record->children->len;
+}
+
+static gboolean tag_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) {
+ TagModelRecord *record, *parent_record;
+ TagModel *tag_model;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), FALSE);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ if(!parent) {
+ if(n >= tag_model->num_rows)
+ return FALSE;
+ record = &g_array_index(tag_model->rows, TagModelRecord, n);
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = record;
+
+ return TRUE;
+ }
+
+ //if(n >= tag_model->num_rows)
+ // return FALSE;
+
+ parent_record = parent->user_data;
+
+ if(n >= parent_record->children->len)
+ return FALSE;
+
+ record = &g_array_index(parent_record->children, TagModelRecord, n);
+
+ g_assert(record != NULL);
+ g_assert(record->pos == n);
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = record;
+
+ return TRUE;
+}
+
+static gboolean tag_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) {
+ TagModelRecord *childrecord;
+ TagModel *tag_model;
+
+ g_return_val_if_fail(MODEL_IS_TAG(tree_model), FALSE);
+
+ tag_model = TAG_MODEL(tree_model);
+
+ childrecord = (TagModelRecord*)child->user_data;
+
+ iter->stamp = tag_model->stamp;
+ iter->user_data = childrecord->parent;
+
+ return TRUE;
+}
+
+TagModel *tag_model_new() {
+ TagModel *new_tag_model;
+
+ new_tag_model = (TagModel*)g_object_new(MODEL_TYPE_TAG, NULL);
+
+ g_assert(new_tag_model != NULL);
+
+ return new_tag_model;
+}
+
+void tag_model_get_tag_record(GtkTreeModel *tree_model, GtkTreeIter *iter, struct tag_t **tag) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(iter != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+ record = (TagModelRecord*)iter->user_data;
+ *tag = &record->tag;
+}
+
+gboolean tag_model_get_checked(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(iter != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+ record = (TagModelRecord*)iter->user_data;
+
+ return record->checked;
+}
+
+void tag_model_set_checked(GtkTreeModel *tree_model, GtkTreeIter *iter, gboolean checked) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(iter != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+ record = (TagModelRecord*)iter->user_data;
+
+ record->checked = checked;
+}
+
+gboolean tag_model_get_inconsistent(GtkTreeModel *tree_model, GtkTreeIter *iter) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(iter != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+ record = (TagModelRecord*)iter->user_data;
+
+ return record->inconsistent;
+}
+
+void tag_model_set_inconsistent(GtkTreeModel *tree_model, GtkTreeIter *iter, gboolean inconsistent) {
+ TagModel *tag_model;
+ TagModelRecord *record;
+
+ g_assert(MODEL_IS_TAG(tree_model));
+ g_assert(iter != NULL);
+
+ tag_model = TAG_MODEL(tree_model);
+ record = (TagModelRecord*)iter->user_data;
+
+ record->inconsistent = inconsistent;
+}