#include "walls_model.h" static void walls_model_init(WallsModel *walls_model); static void walls_model_class_init(WallsModelClass *klass); static void walls_model_tree_model_init(GtkTreeModelIface *iface); static void walls_model_finalize(GObject *object); static GtkTreeModelFlags walls_model_get_flags(GtkTreeModel *tree_model); static gint walls_model_get_n_columns(GtkTreeModel *tree_model); static GType walls_model_get_column_type(GtkTreeModel *tree_model, gint index); static gboolean walls_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path); static GtkTreePath *walls_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter); static void walls_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value); static gboolean walls_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter); static gboolean walls_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent); static gboolean walls_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter); static gint walls_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter); static gboolean walls_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n); static gboolean walls_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child); static GObjectClass *parent_class = NULL; GType walls_model_get_type() { static GType walls_model_type = 0; if(walls_model_type == 0) { static const GTypeInfo walls_model_info = { sizeof(WallsModelClass), NULL, NULL, (GClassInitFunc) walls_model_class_init, NULL, NULL, sizeof(WallsModel), 0, (GInstanceInitFunc) walls_model_init }; static const GInterfaceInfo tree_model_info = { (GInterfaceInitFunc) walls_model_tree_model_init, NULL, NULL }; walls_model_type = g_type_register_static(G_TYPE_OBJECT, "WallsModel", &walls_model_info, (GTypeFlags)0); g_type_add_interface_static(walls_model_type, GTK_TYPE_TREE_MODEL, &tree_model_info); } return walls_model_type; } static void walls_model_class_init(WallsModelClass *klass) { GObjectClass *object_class; parent_class = (GObjectClass*)g_type_class_peek_parent(klass); object_class = (GObjectClass*)klass; object_class->finalize = walls_model_finalize; } static void walls_model_tree_model_init(GtkTreeModelIface *iface) { iface->get_flags = walls_model_get_flags; iface->get_n_columns = walls_model_get_n_columns; iface->get_column_type = walls_model_get_column_type; iface->get_iter = walls_model_get_iter; iface->get_path = walls_model_get_path; iface->get_value = walls_model_get_value; iface->iter_next = walls_model_iter_next; iface->iter_children = walls_model_iter_children; iface->iter_has_child = walls_model_iter_has_child; iface->iter_n_children = walls_model_iter_n_children; iface->iter_nth_child = walls_model_iter_nth_child; iface->iter_parent = walls_model_iter_parent; } static void walls_model_init(WallsModel *walls_model) { WallsModelRecord temp; GArray *array; walls_model->n_columns = WALLS_MODEL_N_COLUMNS; walls_model->column_types[0] = G_TYPE_STRING; walls_model->column_types[1] = G_TYPE_STRING; walls_model->column_types[2] = G_TYPE_STRING; walls_model->column_types[3] = G_TYPE_STRING; g_assert(WALLS_MODEL_N_COLUMNS == 4); walls_model->num_rows = 0; walls_model->rows = g_array_new(TRUE, FALSE, sizeof(WallsModelRecord)); walls_model->stamp = g_random_int(); if(db_get_top_level_directories(&array)) { for(int i = 0; i < array->len; i++) { struct directory_t *dir; dir = &g_array_index(array, struct directory_t, i); temp.type = WALLS_MODEL_TYPE_DIR; temp.dir.name = g_strdup(dir->name); temp.dir.dirid = dir->dirid; temp.parent = NULL; temp.children = NULL; temp.pos = i; g_free(dir->name); g_array_append_val(walls_model->rows, temp); walls_model->num_rows++; } g_array_free(array, TRUE); } } static void walls_model_finalize(GObject *object) { printf("walls_model_finalize\n"); WallsModel *walls_model; g_assert(MODEL_IS_WALLS(object)); walls_model = WALLS_MODEL(object); for(int i = 0; i < walls_model->rows->len; i++) { WallsModelRecord *temp; temp = &g_array_index(walls_model->rows, WallsModelRecord, i); g_free(temp->dir.name); } g_array_free(walls_model->rows, TRUE); } static GtkTreeModelFlags walls_model_get_flags(GtkTreeModel *tree_model) { g_return_val_if_fail(MODEL_IS_WALLS(tree_model), (GtkTreeModelFlags)0); return GTK_TREE_MODEL_ITERS_PERSIST; } static gint walls_model_get_n_columns(GtkTreeModel *tree_model) { g_return_val_if_fail(MODEL_IS_WALLS(tree_model), 0); return WALLS_MODEL(tree_model)->n_columns; } static GType walls_model_get_column_type(GtkTreeModel *tree_model, gint index) { g_return_val_if_fail(MODEL_IS_WALLS(tree_model), G_TYPE_INVALID); g_return_val_if_fail(index < WALLS_MODEL(tree_model)->n_columns && index >= 0, G_TYPE_INVALID); return WALLS_MODEL(tree_model)->column_types[index]; } inline static void fill_dir(WallsModelRecord *record) { GArray *array; gint dircount = 0; record->children = g_array_new(FALSE, FALSE, sizeof(WallsModelRecord)); if(db_get_directories(record->dir.dirid, &array)) { for(int i = 0; i < array->len; i++) { WallsModelRecord temp; struct directory_t *dir; dir = &g_array_index(array, struct directory_t, i); temp.type = WALLS_MODEL_TYPE_DIR; temp.dir.name = g_strdup(dir->name); temp.dir.dirid = dir->dirid; temp.parent = record; temp.children = NULL; temp.pos = i; g_array_append_val(record->children, temp); g_free(dir->name); } dircount = array->len; g_array_free(array, TRUE); } if(db_get_wallpapers(record->dir.dirid, &array)) { for(int i = 0; i < array->len; i++) { WallsModelRecord temp; struct wallpaper_t *wall; wall = &g_array_index(array, struct wallpaper_t, i); temp.type = WALLS_MODEL_TYPE_WALL; temp.wall.filepath = g_strdup(wall->filepath); temp.wall.id = wall->id; temp.wall.size = wall->size; temp.wall.width = wall->width; temp.wall.height = wall->height; temp.parent = record; temp.children = NULL; temp.pos = dircount + i; g_array_append_val(record->children, temp); g_free(wall->filepath); } g_array_free(array, TRUE); } } #define WALLS_MODEL_ENSURE_CHILDREN(obj) if(!(obj)->children) fill_dir((obj)) inline static WallsModelRecord *walls_model_get_record_recursive(WallsModel *walls_model, gint *indices, gint depth) { WallsModelRecord *temp; if(depth == 1) { return &g_array_index(walls_model->rows, WallsModelRecord, indices[depth-1]); } else { temp = walls_model_get_record_recursive(walls_model, indices, depth-1); WALLS_MODEL_ENSURE_CHILDREN(temp); return &g_array_index(temp->children, WallsModelRecord, indices[depth-1]); } } static gboolean walls_model_get_iter(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreePath *path) { WallsModel *walls_model; WallsModelRecord *record; gint *indices, n, depth; g_assert(MODEL_IS_WALLS(tree_model)); g_assert(path != NULL); walls_model = WALLS_MODEL(tree_model); indices = gtk_tree_path_get_indices(path); depth = gtk_tree_path_get_depth(path); n = indices[depth-1]; //if(n >= walls_model->num_rows || n < 0) // return FALSE; //record = &g_array_index(walls_model->rows, WallsModelRecord, n); record = walls_model_get_record_recursive(walls_model, indices, depth); g_assert(record != NULL); g_assert(record->pos == n); iter->stamp = walls_model->stamp; iter->user_data = record; iter->user_data2 = NULL; iter->user_data3 = NULL; return TRUE; } static GtkTreePath *walls_model_get_path(GtkTreeModel *tree_model, GtkTreeIter *iter) { GtkTreePath *path; WallsModelRecord *record; WallsModel *walls_model; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), NULL); g_return_val_if_fail(iter != NULL, NULL); g_return_val_if_fail(iter->user_data != NULL, NULL); walls_model = WALLS_MODEL(tree_model); record = (WallsModelRecord*)iter->user_data; path = gtk_tree_path_new(); gtk_tree_path_append_index(path, record->pos); return path; } static void walls_model_get_value(GtkTreeModel *tree_model, GtkTreeIter *iter, gint column, GValue *value) { WallsModelRecord *record; WallsModel *walls_model; g_return_if_fail(MODEL_IS_WALLS(tree_model)); g_return_if_fail(iter != NULL); g_return_if_fail(column < WALLS_MODEL(tree_model)->n_columns); g_value_init(value, WALLS_MODEL(tree_model)->column_types[column]); walls_model = WALLS_MODEL(tree_model); record = (WallsModelRecord*)iter->user_data; g_return_if_fail(record != NULL); //if(record->pos >= walls_model->num_rows) // g_return_if_reached(); if(record->type == WALLS_MODEL_TYPE_DIR) { if(column == WALLS_MODEL_COL_NAME) { if(record->parent == NULL) g_value_set_string(value, record->dir.name); else g_value_set_string_take_ownership(value, g_path_get_basename(record->dir.name)); } else { g_value_set_string(value, ""); } return; } switch(column) { case WALLS_MODEL_COL_NAME: g_value_set_string_take_ownership(value, g_path_get_basename(record->wall.filepath)); break; case WALLS_MODEL_COL_SIZE: g_value_set_string_take_ownership(value, g_strdup_printf("%d", record->wall.size)); break; case WALLS_MODEL_COL_WIDTH: g_value_set_string_take_ownership(value, g_strdup_printf("%d", record->wall.width)); break; case WALLS_MODEL_COL_HEIGHT: g_value_set_string_take_ownership(value, g_strdup_printf("%d", record->wall.height)); break; } } static gboolean walls_model_iter_next(GtkTreeModel *tree_model, GtkTreeIter *iter) { WallsModelRecord *record, *nextrecord; WallsModel *walls_model; GArray *array; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); if(iter == NULL || iter->user_data == NULL) return FALSE; walls_model = WALLS_MODEL(tree_model); record = (WallsModelRecord*)iter->user_data; WALLS_MODEL_ENSURE_CHILDREN(record); array = (record->parent ? record->parent->children : walls_model->rows); if((record->pos + 1) >= array->len) return FALSE; nextrecord = &g_array_index(array, WallsModelRecord, record->pos + 1); g_assert(nextrecord != NULL); g_assert(nextrecord->pos == (record->pos + 1)); iter->stamp = walls_model->stamp; iter->user_data = nextrecord; return TRUE; } static gboolean walls_model_iter_children(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent) { WallsModel *walls_model; WallsModelRecord *parent_record; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); walls_model = WALLS_MODEL(tree_model); if(!parent) { if(walls_model->num_rows == 0) return FALSE; iter->stamp = walls_model->stamp; iter->user_data = &g_array_index(walls_model->rows, WallsModelRecord, 0); return TRUE; } //g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE); parent_record = (WallsModelRecord*)parent->user_data; if(parent_record->type == WALLS_MODEL_TYPE_WALL) return FALSE; WALLS_MODEL_ENSURE_CHILDREN(parent_record); if(parent_record->children->len == 0) return FALSE; iter->stamp = walls_model->stamp; iter->user_data = &g_array_index(parent_record->children, WallsModelRecord, 0); return TRUE; } static gboolean walls_model_iter_has_child(GtkTreeModel *tree_model, GtkTreeIter *iter) { WallsModelRecord *record; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); record = (WallsModelRecord*)iter->user_data; if(record->type == WALLS_MODEL_TYPE_DIR) { //return (record->children->len > 0 ? TRUE : FALSE); return (record->parent == NULL && WALLS_MODEL(tree_model)->num_rows == 0 ? FALSE : TRUE); } else return FALSE; } static gint walls_model_iter_n_children(GtkTreeModel *tree_model, GtkTreeIter *iter) { WallsModel *walls_model; WallsModelRecord *record; GArray *array; int n; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), -1); g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0); walls_model = WALLS_MODEL(tree_model); if(!iter) { return walls_model->num_rows; } record = (WallsModelRecord*)iter->user_data; if(record->type == WALLS_MODEL_TYPE_WALL) { return 0; } //array = NULL; //g_return_val_if_fail(db_get_wallpapers(record->dir.dirid, &array), -1); //for(n = 0; (&g_array_index(array, struct wallpaper_t, n))->filepath; n++); WALLS_MODEL_ENSURE_CHILDREN(record); return record->children->len; return n; } static gboolean walls_model_iter_nth_child(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *parent, gint n) { WallsModelRecord *record, *parent_record; WallsModel *walls_model; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); walls_model = WALLS_MODEL(tree_model); if(!parent) { if(n >= walls_model->num_rows) return FALSE; record = &g_array_index(walls_model->rows, WallsModelRecord, n); iter->stamp = walls_model->stamp; iter->user_data = record; return TRUE; } //if(n >= walls_model->num_rows) // return FALSE; parent_record = parent->user_data; WALLS_MODEL_ENSURE_CHILDREN(parent_record); if(n >= parent_record->children->len) return FALSE; record = &g_array_index(parent_record->children, WallsModelRecord, n); g_assert(record != NULL); g_assert(record->pos == n); iter->stamp = walls_model->stamp; iter->user_data = record; return TRUE; } static gboolean walls_model_iter_parent(GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { WallsModelRecord *record, *childrecord; WallsModel *walls_model; g_return_val_if_fail(MODEL_IS_WALLS(tree_model), FALSE); walls_model = WALLS_MODEL(tree_model); childrecord = (WallsModelRecord*)child->user_data; iter->stamp = walls_model->stamp; iter->user_data = childrecord->parent; return TRUE; } WallsModel *walls_model_new() { WallsModel *new_walls_model; new_walls_model = (WallsModel*)g_object_new(MODEL_TYPE_WALLS, NULL); g_assert(new_walls_model != NULL); return new_walls_model; } static void walls_model_get_record(GtkTreeModel *tree_model, GtkTreeIter *iter, void **data) { WallsModel *walls_model; WallsModelRecord *record; g_assert(MODEL_IS_WALLS(tree_model)); g_assert(iter != NULL); walls_model = WALLS_MODEL(tree_model); record = (WallsModelRecord*)iter->user_data; *data = (void*)(&record->dir); } void walls_model_get_dir_record(GtkTreeModel *tree_model, GtkTreeIter *iter, struct directory_t **dir) { walls_model_get_record(tree_model, iter, (void**)dir); } void walls_model_get_wall_record(GtkTreeModel *tree_model, GtkTreeIter *iter, struct wallpaper_t **wall) { walls_model_get_record(tree_model, iter, (void**)wall); } guint walls_model_get_record_type(GtkTreeModel *tree_model, GtkTreeIter *iter) { WallsModel *walls_model; WallsModelRecord *record; g_assert(MODEL_IS_WALLS(tree_model)); g_assert(iter != NULL); walls_model = WALLS_MODEL(tree_model); record = (WallsModelRecord*)iter->user_data; return record->type; }