From 0d4b1caee4135b6e0dcd2aa3bd6ce2387c1c3773 Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Sun, 25 Apr 2010 17:28:49 +0200 Subject: Added a tree model to display tags in tree structures. Adding children to tags is not yet implemented. --- db.c | 73 ++++++++- db.h | 3 + tag_model.c | 489 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tag_model.h | 58 +++++++ window_main.c | 59 +++---- window_tag.c | 72 ++++----- 6 files changed, 672 insertions(+), 82 deletions(-) create mode 100644 tag_model.c create mode 100644 tag_model.h diff --git a/db.c b/db.c index e6f0368..935e9c1 100644 --- a/db.c +++ b/db.c @@ -354,7 +354,7 @@ int db_get_wall_tags(sqlite_uint64 wallid, GArray **array) { sqlite3_stmt *stmt; int rc; - rc = sqlite3_prepare_v2(db, "SELECT t.id, t.name FROM tag t JOIN walltags w ON (w.tagid = t.id AND w.wallid = ?)", -1, &stmt, NULL); + rc = sqlite3_prepare_v2(db, "SELECT t.id, t.name, t.parent FROM tag t JOIN walltags w ON (w.tagid = t.id AND w.wallid = ?)", -1, &stmt, NULL); if(rc != SQLITE_OK) { return 0; @@ -369,6 +369,7 @@ int db_get_wall_tags(sqlite_uint64 wallid, GArray **array) { *array = g_array_new(FALSE, FALSE, sizeof(struct tag_t)); while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { temp.id = sqlite3_column_int64(stmt, 0); + temp.parent = sqlite3_column_int64(stmt, 2); temp.name = g_strdup((const gchar*)sqlite3_column_text(stmt, 1)); g_array_append_val(*array, temp); } @@ -630,6 +631,76 @@ int db_get_tags_all(GArray **array) { return 1; } +int db_get_top_level_tags(GArray **array) { + struct tag_t temp, *temp2; + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "SELECT id, name, parent FROM tag WHERE parent IS NULL ORDER BY name", -1, &stmt, NULL); + if(rc != SQLITE_OK) { + return 0; + } + + *array = g_array_new(FALSE, FALSE, sizeof(struct tag_t)); + while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + temp.name = g_strdup((const gchar*)sqlite3_column_text(stmt, 1)); + temp.id = sqlite3_column_int64(stmt, 0); + temp.parent = sqlite3_column_int64(stmt, 2); + g_array_append_val(*array, temp); + } + + sqlite3_finalize(stmt); + + if(rc != SQLITE_DONE) { + for(int i = 0; i < (*array)->len; i++) { + temp2 = &g_array_index(*array, struct tag_t, i); + g_free(temp2->name); + } + g_array_free(*array, TRUE); + return 0; + } + + return 1; +} + +int db_get_tags(GArray **array, sqlite3_uint64 parent) { + struct tag_t temp, *temp2; + sqlite3_stmt *stmt; + int rc; + + rc = sqlite3_prepare_v2(db, "SELECT id, name, parent FROM tag WHERE parent = ? ORDER BY name", -1, &stmt, NULL); + if(rc != SQLITE_OK) { + return 0; + } + + rc = sqlite3_bind_int64(stmt, 1, parent); + if(rc != SQLITE_OK) { + sqlite3_finalize(stmt); + return 0; + } + + *array = g_array_new(FALSE, FALSE, sizeof(struct tag_t)); + while((rc = sqlite3_step(stmt)) == SQLITE_ROW) { + temp.name = g_strdup((const gchar*)sqlite3_column_text(stmt, 1)); + temp.id = sqlite3_column_int64(stmt, 0); + temp.parent = sqlite3_column_int64(stmt, 2); + g_array_append_val(*array, temp); + } + + sqlite3_finalize(stmt); + + if(rc != SQLITE_DONE) { + for(int i = 0; i < (*array)->len; i++) { + temp2 = &g_array_index(*array, struct tag_t, i); + g_free(temp2->name); + } + g_array_free(*array, TRUE); + return 0; + } + + return 1; +} + int db_add_wall_tag(sqlite_uint64 wallid, sqlite_uint64 tagid) { sqlite3_stmt *stmt; int rc; diff --git a/db.h b/db.h index a2c19b1..969bace 100644 --- a/db.h +++ b/db.h @@ -22,6 +22,7 @@ struct wallpaper_t { struct tag_t { gchar *name; sqlite_uint64 id; + sqlite_uint64 parent; }; int db_open(); @@ -39,6 +40,8 @@ int db_get_wallpapers(sqlite_uint64, GArray**); int db_get_walls_by_tags(GArray*, GArray**); sqlite_uint64 db_add_tag(const char*, sqlite_uint64); int db_get_tags_all(GArray**); +int db_get_top_level_tags(GArray**); +int db_get_tags(GArray**, sqlite_uint64); int db_add_wall_tag(sqlite_uint64, sqlite_uint64); void db_remove_tag(sqlite_uint64); int db_remove_wall_tag(sqlite_uint64, sqlite_uint64); 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; +} diff --git a/tag_model.h b/tag_model.h new file mode 100644 index 0000000..43e59a1 --- /dev/null +++ b/tag_model.h @@ -0,0 +1,58 @@ +#ifndef _TAG_MODEL_H_ +#define _TAG_MODEL_H_ + +#include +#include + +#include "db.h" + +#define MODEL_TYPE_TAG (tag_model_get_type()) +#define TAG_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), MODEL_TYPE_TAG, TagModel)) +#define TAG_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), MODEL_TYPE_TAG, TagModelClass)) +#define MODEL_IS_TAG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), MODEL_TYPE_TAG)) +#define MODEL_IS_TAG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), MODEL_TYPE_TAG)) +#define TAG_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), MODEL_TYPE_TAG, TagModelClass)) + +enum { + TAG_MODEL_COL_CHECKED = 0, + TAG_MODEL_COL_INCONSISTENT, + TAG_MODEL_COL_NAME, + TAG_MODEL_N_COLUMNS, +}; + +typedef struct _TagModelRecord TagModelRecord; +typedef struct _TagModel TagModel; +typedef struct _TagModelClass TagModelClass; + +struct _TagModelRecord { + struct tag_t tag; + gboolean checked; + gboolean inconsistent; + TagModelRecord *parent; + GArray *children; + guint pos; +}; + +struct _TagModel { + GObject parent; + + guint num_rows; + GArray *rows; + gint n_columns; + GType column_types[TAG_MODEL_N_COLUMNS]; + gint stamp; +}; + +struct _TagModelClass { + GObjectClass parent_class; +}; + +GType tag_model_get_type(); +TagModel *tag_model_new(); +void tag_model_get_tag_record(GtkTreeModel*, GtkTreeIter*, struct tag_t**); +gboolean tag_model_get_checked(GtkTreeModel*, GtkTreeIter*); +void tag_model_set_checked(GtkTreeModel*, GtkTreeIter*, gboolean); +gboolean tag_model_get_inconsistent(GtkTreeModel*, GtkTreeIter*); +void tag_model_set_inconsistent(GtkTreeModel*, GtkTreeIter*, gboolean); + +#endif diff --git a/window_main.c b/window_main.c index e5cd3b7..d327177 100644 --- a/window_main.c +++ b/window_main.c @@ -11,6 +11,7 @@ #include "window_tag.h" #include "preload.h" #include "window_config.h" +#include "tag_model.h" enum zoom_mode_t { ZOOM_BESTFIT, @@ -80,6 +81,9 @@ inline static void tagview_create_model(GtkTreeView *tagview) { struct tag_t *tag; GtkTreeIter iter; + gtk_tree_view_set_model(tagview, GTK_TREE_MODEL(tag_model_new())); + return; + model = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_UINT64); if(db_get_tags_all(&array)) { @@ -114,7 +118,7 @@ inline static void tagview_init(GtkTreeView *tagview) { renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_end(col2, renderer, TRUE); - gtk_tree_view_column_add_attribute(col2, renderer, "text", 1); + gtk_tree_view_column_add_attribute(col2, renderer, "text", 2); tagview_create_model(tagview); } @@ -493,10 +497,8 @@ void display_from_tagview() { GtkTreeIter iter; GtkTreeModel *model, *old_model; GtkListStore *liststore; - GValue value = {0}; - gboolean active; GArray *tagarray, *wallarray; - guint64 id; + struct tag_t *tag; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tagview)); @@ -506,18 +508,12 @@ void display_from_tagview() { tagarray = g_array_new(FALSE, FALSE, sizeof(guint64)); do { - gtk_tree_model_get_value(model, &iter, 0, &value); - active = g_value_get_boolean(&value); - g_value_unset(&value); - - if(!active) + if(!tag_model_get_checked(model, &iter)) continue; - gtk_tree_model_get_value(model, &iter, 2, &value); - id = g_value_get_uint64(&value); - g_value_unset(&value); + tag_model_get_tag_record(GTK_TREE_MODEL(model), &iter, &tag); - g_array_append_val(tagarray, id); + g_array_append_val(tagarray, tag->id); } while(gtk_tree_model_iter_next(model, &iter)); if(!db_get_walls_by_tags(tagarray, &wallarray)) { @@ -542,17 +538,14 @@ void display_from_tagview() { void on_main_tagview_cell_toggled(GtkCellRendererToggle *cell_renderer, gchar *path_string, gpointer user_data) { GtkTreeIter iter; GtkTreeModel *model; - GValue value = {0}; gboolean active; model = gtk_tree_view_get_model(GTK_TREE_VIEW(tagview)); gtk_tree_model_get_iter_from_string(model, &iter, path_string); - gtk_tree_model_get_value(model, &iter, 0, &value); - active = g_value_get_boolean(&value); - g_value_unset(&value); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, !active, -1); + active = tag_model_get_checked(GTK_TREE_MODEL(model), &iter); + tag_model_set_checked(GTK_TREE_MODEL(model), &iter, !active); display_from_tagview(); } @@ -813,36 +806,26 @@ inline static void update_wall_tags(GArray *wallarray, guint64 tagid, gboolean a /** * Update tags for wallpapers. */ -static void update_tags(GArray *wallarray, GtkListStore *liststore) { +static void update_tags(GArray *wallarray, GtkTreeModel *model) { GtkTreeIter iter; - GValue value = {0}; - gboolean active, inconsistent; - guint64 tagid; + gboolean active; + struct tag_t *tag; /* No tags available. */ - if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter)) { + if(!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { return; } do { - gtk_tree_model_get_value(GTK_TREE_MODEL(liststore), &iter, 1, &value); - inconsistent = g_value_get_boolean(&value); - g_value_unset(&value); - /* Don't update inconsistent tags. */ - if(inconsistent) + if(tag_model_get_inconsistent(GTK_TREE_MODEL(model), &iter)) continue; - gtk_tree_model_get_value(GTK_TREE_MODEL(liststore), &iter, 0, &value); - active = g_value_get_boolean(&value); - g_value_unset(&value); - - gtk_tree_model_get_value(GTK_TREE_MODEL(liststore), &iter, 3, &value); - tagid = g_value_get_uint64(&value); - g_value_unset(&value); + active = tag_model_get_checked(GTK_TREE_MODEL(model), &iter); + tag_model_get_tag_record(GTK_TREE_MODEL(model), &iter, &tag); - update_wall_tags(wallarray, tagid, active); - } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter)); + update_wall_tags(wallarray, tag->id, active); + } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); } void on_tags_activate(GtkMenuItem *menuitem, gpointer user_data) { @@ -855,7 +838,7 @@ void on_tags_activate(GtkMenuItem *menuitem, gpointer user_data) { data = window_tagview_new(GTK_WIDGET(window), array); if(gtk_dialog_run(GTK_DIALOG(data->dialog)) == GTK_RESPONSE_APPLY) { - update_tags(array, GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->tagview)))); + update_tags(array, GTK_TREE_MODEL(gtk_tree_view_get_model(GTK_TREE_VIEW(data->tagview)))); } gtk_widget_destroy(GTK_WIDGET(data->dialog)); diff --git a/window_tag.c b/window_tag.c index ca6d6f4..da77cdc 100644 --- a/window_tag.c +++ b/window_tag.c @@ -2,12 +2,12 @@ #include "tags_ui.h" #include "db.h" #include "text_input_dialog.h" +#include "tag_model.h" void on_tagview_cell_toggled(GtkCellRendererToggle *cell_renderer, gchar *path_string, gpointer user_data) { GtkTreeIter iter; GtkTreeModel *model; struct tagdialog_data_t *data; - GValue value = {0}; gboolean active, inconsistent; data = user_data; @@ -15,18 +15,14 @@ void on_tagview_cell_toggled(GtkCellRendererToggle *cell_renderer, gchar *path_s model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->tagview)); gtk_tree_model_get_iter_from_string(model, &iter, path_string); - gtk_tree_model_get_value(model, &iter, 0, &value); - active = g_value_get_boolean(&value); - g_value_unset(&value); - gtk_tree_model_get_value(model, &iter, 1, &value); - inconsistent = g_value_get_boolean(&value); - g_value_unset(&value); + active = tag_model_get_checked(model, &iter); + inconsistent = tag_model_get_inconsistent(model, &iter); if(inconsistent) { - gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, FALSE, -1); + tag_model_set_inconsistent(GTK_TREE_MODEL(model), &iter, FALSE); } else { - gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, !active, -1); + tag_model_set_checked(GTK_TREE_MODEL(model), &iter, !active); } } @@ -60,12 +56,24 @@ inline static gboolean is_tag_inconsistent(struct tag_t *tag, GArray *walltags, return (n_n == 0 || n_y == 0 ? FALSE : TRUE); } -static void tagview_create_model(GtkTreeView *tagview, gpointer user_data) { - GtkListStore *model; - GArray *array, *walltags, *walltag_single, *wallarray; - GtkTreeIter iter; +/** + * foreach-callback for setting checked and inconsistent in the tag model. + */ +static gboolean tagview_model_foreach(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data) { struct tag_t *tag; gboolean inconsistent, exists; + + tag_model_get_tag_record(GTK_TREE_MODEL(model), iter, &tag); + inconsistent = is_tag_inconsistent(tag, (GArray*)user_data, &exists); + tag_model_set_checked(GTK_TREE_MODEL(model), iter, exists); + tag_model_set_inconsistent(GTK_TREE_MODEL(model), iter, inconsistent); + + return FALSE; +} + +static void tagview_create_model(GtkTreeView *tagview, gpointer user_data) { + GtkTreeModel *model; + GArray *walltags, *walltag_single, *wallarray; struct tagdialog_data_t *data; data = user_data; @@ -81,28 +89,16 @@ static void tagview_create_model(GtkTreeView *tagview, gpointer user_data) { } } - model = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_UINT64); + model = GTK_TREE_MODEL(tag_model_new()); + gtk_tree_view_set_model(tagview, GTK_TREE_MODEL(model)); - if(db_get_tags_all(&array)) { - for(int i = 0; i < array->len; i++) { - tag = &g_array_index(array, struct tag_t, i); - gtk_list_store_append(model, &iter); - inconsistent = is_tag_inconsistent(tag, walltags, &exists); - gtk_list_store_set(model, &iter, 0, exists, 1, inconsistent, 2, g_strdup(tag->name), 3, tag->id, -1); - g_free(tag->name); - } - g_array_free(array, TRUE); - } else { - g_warning("Could not fetch tags\n"); - } + gtk_tree_model_foreach(GTK_TREE_MODEL(model), tagview_model_foreach, walltags); for(int i = 0; i < walltags->len; i++) { walltag_single = g_array_index(walltags, GArray*, i); g_array_free(walltag_single, TRUE); } g_array_free(walltags, TRUE); - - gtk_tree_view_set_model(tagview, GTK_TREE_MODEL(model)); } static void tagview_init(GtkTreeView *tagview, gpointer user_data) { @@ -154,9 +150,7 @@ void on_tags_rembtn_clicked(GtkButton *button, gpointer user_data) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; - gchar *tagname; - guint64 tagid; - GValue value = {0}; + struct tag_t *tag; data = user_data; @@ -164,21 +158,13 @@ void on_tags_rembtn_clicked(GtkButton *button, gpointer user_data) { if(!gtk_tree_selection_get_selected(selection, &model, &iter)) return; - gtk_tree_model_get_value(model, &iter, 3, &value); - tagid = g_value_get_uint64(&value); - g_value_unset(&value); - - gtk_tree_model_get_value(model, &iter, 2, &value); - tagname = g_value_dup_string(&value); - g_value_unset(&value); + tag_model_get_tag_record(GTK_TREE_MODEL(model), &iter, &tag); dialog = gtk_message_dialog_new(GTK_WINDOW(data->dialog), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Are you sure you want to delete the tag \"%s\"?", tagname); - - g_free(tagname); + GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Are you sure you want to delete the tag \"%s\" and all its children?", tag->name); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) { - db_remove_tag(tagid); + db_remove_tag(tag->id); tagview_create_model(GTK_TREE_VIEW(data->tagview), user_data); } @@ -198,7 +184,7 @@ static void tags_select(gpointer user_data, gboolean select) { return; do { - gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, select, -1); + tag_model_set_checked(GTK_TREE_MODEL(model), &iter, select); } while(gtk_tree_model_iter_next(model, &iter)); } -- cgit v1.2.3