#include "window_tag.h" #include "tags_ui.h" #include "db.h" #include "text_input_dialog.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; 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); if(inconsistent) { gtk_list_store_set(GTK_LIST_STORE(model), &iter, 1, FALSE, -1); } else { gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, !active, -1); } } /* TODO: Find a better way to do this. */ inline static gboolean is_tag_inconsistent(struct tag_t *tag, GArray *walltags, gboolean *exists) { gint n_y, n_n; GArray *walltag_single; gboolean found; struct tag_t *wall_tag; n_y = n_n = 0; for(int i = 0; i < walltags->len; i++) { walltag_single = g_array_index(walltags, GArray*, i); found = FALSE; for(int j = 0; j < walltag_single->len; j++) { wall_tag = &g_array_index(walltag_single, struct tag_t, j); if(wall_tag->id == tag->id) { n_y++; found = TRUE; break; } } if(!found) n_n++; } if(n_y == 0) *exists = FALSE; else *exists = TRUE; 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; struct tag_t *tag; gboolean inconsistent, exists; struct tagdialog_data_t *data; data = user_data; wallarray = data->wallarray; walltags = g_array_new(FALSE, FALSE, sizeof(GArray*)); for(int i = 0; i < wallarray->len; i++) { if(db_get_wall_tags(g_array_index(wallarray, guint64, i), &walltag_single)) { g_array_append_val(walltags, walltag_single); } else { g_error("db_get_wall_tags failed\n"); return; } } model = gtk_list_store_new(4, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_UINT64); 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"); } 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) { GtkTreeViewColumn *col1, *col2; GtkCellRenderer *renderer; col1 = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col1, "Select"); gtk_tree_view_append_column(tagview, col1); col2 = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col2, "Name"); gtk_tree_view_append_column(tagview, col2); renderer = gtk_cell_renderer_toggle_new(); gtk_tree_view_column_pack_start(col1, renderer, FALSE); gtk_tree_view_column_add_attribute(col1, renderer, "active", 0); gtk_tree_view_column_add_attribute(col1, renderer, "inconsistent", 1); g_signal_connect(renderer, "toggled", G_CALLBACK(on_tagview_cell_toggled), user_data); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_end(col2, renderer, TRUE); gtk_tree_view_column_add_attribute(col2, renderer, "text", 2); tagview_create_model(tagview, user_data); } void on_tags_addbtn_clicked(GtkButton *button, gpointer user_data) { struct tagdialog_data_t *data; GtkDialog *dialog; gchar *s; data = user_data; dialog = text_input_dialog_new(data->dialog, "Enter the name of the new tag:"); if(gtk_dialog_run(dialog) == GTK_RESPONSE_OK) { s = text_input_dialog_get_text(GTK_WIDGET(dialog)); if(db_add_tag(s)) tagview_create_model(GTK_TREE_VIEW(data->tagview), user_data); else g_warning("Failed to add tag \"%s\"\n", s); g_free(s); } gtk_widget_destroy(GTK_WIDGET(dialog)); } void on_tags_rembtn_clicked(GtkButton *button, gpointer user_data) { GtkWidget *dialog; struct tagdialog_data_t *data; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; gchar *tagname; guint64 tagid; GValue value = {0}; data = user_data; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->tagview)); 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); 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); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_YES) { db_remove_tag(tagid); tagview_create_model(GTK_TREE_VIEW(data->tagview), user_data); } gtk_widget_destroy(dialog); } static void tags_select(gpointer user_data, gboolean select) { struct tagdialog_data_t *data; GtkTreeModel *model; GtkTreeIter iter; data = user_data; model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->tagview)); if(!gtk_tree_model_get_iter_first(model, &iter)) return; do { gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, select, -1); } while(gtk_tree_model_iter_next(model, &iter)); } void on_tags_selallbtn_clicked(GtkButton *button, gpointer user_data) { tags_select(user_data, TRUE); } void on_tags_selnonebtn_clicked(GtkButton *button, gpointer user_data) { tags_select(user_data, FALSE); } void on_tagsdialog_destroy(GtkObject *object, gpointer user_data) { g_free(user_data); } struct tagdialog_data_t *window_tagview_new(GtkWidget *parent, GArray* array) { GtkBuilder *builder; GtkDialog *dialog; GtkTreeView *tagview; GtkButton *selnonebtn; GtkImage *image; GError *error = NULL; struct tagdialog_data_t *data; builder = gtk_builder_new(); if(!gtk_builder_add_from_string(builder, tags_ui_string, -1, &error)) { g_warning("%s", error->message); g_error_free(error); return NULL; } dialog = GTK_DIALOG(gtk_builder_get_object(builder, "tagsdialog")); gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent)); gtk_window_set_default_size(GTK_WINDOW(dialog), 300, 300); tagview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "tagview")); selnonebtn = GTK_BUTTON(gtk_builder_get_object(builder, "selnonebtn")); gtk_button_set_label(selnonebtn, "Select None"); image = GTK_IMAGE(gtk_image_new_from_stock(GTK_STOCK_NEW, GTK_ICON_SIZE_BUTTON)); gtk_button_set_image(selnonebtn, GTK_WIDGET(image)); data = g_malloc(sizeof(struct tagdialog_data_t)); data->dialog = GTK_WIDGET(dialog); data->tagview = GTK_WIDGET(tagview); data->wallarray = array; tagview_init(tagview, data); gtk_builder_connect_signals(builder, data); return data; }