- configuration is shared with the events, so changes in events are reflected in workflow and vice versa --- src/gtk-helpers/config_dialog.c | 262 ++++++++++++++++++++++++------- src/gtk-helpers/event_config_dialog.c | 158 +++++++------------ src/gtk-helpers/internal_libreport_gtk.h | 39 +++-- src/gtk-helpers/workflow_config_dialog.c | 83 +++++----- src/gui-wizard-gtk/main.c | 2 +- src/gui-wizard-gtk/wizard.c | 8 +- src/include/event_config.h | 4 +- src/include/internal_libreport.h | 2 +- src/lib/event_config.c | 13 +- src/lib/workflow.c | 17 +- 10 files changed, 367 insertions(+), 221 deletions(-)
diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c index 88d01ae..3c81d7c 100644 --- a/src/gtk-helpers/config_dialog.c +++ b/src/gtk-helpers/config_dialog.c @@ -34,19 +34,55 @@ enum TYPE_POINTER };
+struct config_dialog +{ + GtkWidget *dialog; + gpointer *data; + config_save_fun_t save_data; +}; + GtkListStore *new_conf_liststore(void) { /* Create data store for the list and attach it - * COLUMN_EVENT_UINAME -> name+description - * COLUMN_EVENT_NAME -> event name so we can retrieve it from the row + * COLUMN_UINAME -> name+description + * COLUMN_NAME -> config name so we can retrieve it from the row */ return gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, /* Event name + description */ G_TYPE_STRING, /* event name */ - G_TYPE_POINTER + G_TYPE_POINTER, /* dialog */ + G_TYPE_POINTER /* option_list */ ); }
+ +config_dialog_t *new_config_dialog(GtkWidget *dialog, + gpointer config_data, + config_save_fun_t save_fun) +{ + config_dialog_t *cdialog = (config_dialog_t *)xmalloc(sizeof(*cdialog)); + cdialog->dialog = dialog; + cdialog->data = config_data; + cdialog->save_data = save_fun; + return cdialog; +} + +void cdialog_set_widget(config_dialog_t *cdialog, GtkWidget *widget) +{ + //TODO destroy(cdialog-dialog) ?? + cdialog->dialog = widget; +} + +GtkWidget *cdialog_get_widget(config_dialog_t *cdialog) +{ + return cdialog->dialog; +} + +gpointer cdialog_get_data(config_dialog_t *cdialog) +{ + return cdialog->data; +} + static const void *get_column_value_from_row(GtkTreeView *treeview, int column, int type) { GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); @@ -71,40 +107,39 @@ static const void *get_column_value_from_row(GtkTreeView *treeview, int column, return retval; }
-static void on_row_changed_cb(GtkTreeView *treeview, gpointer user_data) +static void save_value_from_widget(gpointer data, gpointer user_data) { - VERB1 log("activated row: '%s'", (const char*)get_column_value_from_row(treeview, COLUMN_NAME, TYPE_STR)); + option_widget_t *ow = (option_widget_t *)data;
- const void *dialog = get_column_value_from_row(treeview, CONFIG_DIALOG, TYPE_POINTER); - gtk_widget_set_sensitive(GTK_WIDGET(user_data), dialog != NULL); -} - -static void on_configure_button_cb(GtkWidget *button, gpointer user_data) -{ - GtkTreeView *tv = (GtkTreeView *)user_data; - const void * dialog = get_column_value_from_row(tv, CONFIG_DIALOG, TYPE_POINTER); - - if (dialog != NULL) + const char *val = NULL; + switch (ow->option->eo_type) { - int result = gtk_dialog_run(GTK_DIALOG(dialog)); - if (result == GTK_RESPONSE_APPLY) - { - //TODO: saving!!! - g_print("apply\n"); - } - //else if (result == GTK_RESPONSE_CANCEL) - // log("log"); - gtk_widget_hide(GTK_WIDGET(dialog)); + case OPTION_TYPE_TEXT: + case OPTION_TYPE_NUMBER: + case OPTION_TYPE_PASSWORD: + val = (char *)gtk_entry_get_text(GTK_ENTRY(ow->widget)); + break; + case OPTION_TYPE_BOOL: + val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ow->widget)) ? "yes" : "no"; + break; + default: + log("unsupported option type"); + } + if (val) + { + free(ow->option->eo_value); + ow->option->eo_value = xstrdup(val); + VERB1 log("saved: %s:%s", ow->option->eo_name, ow->option->eo_value); } }
-static void on_close_list_cb(GtkWidget *button, gpointer user_data) +void dehydrate_config_dialog(GList *option_widgets) { - GtkWidget *window = (GtkWidget *)user_data; - gtk_widget_destroy(window); + if (option_widgets != NULL) + g_list_foreach(option_widgets, &save_value_from_widget, NULL); }
-void add_item_to_config_liststore(gpointer dialog, gpointer inf, gpointer user_data) +void add_item_to_config_liststore(gpointer cdialog, gpointer inf, gpointer user_data) { GtkListStore *list_store = (GtkListStore *)user_data; config_item_info_t *info = (config_item_info_t *)inf; @@ -115,24 +150,20 @@ void add_item_to_config_liststore(gpointer dialog, gpointer inf, gpointer user_d label = xasprintf("<b>%s</b>\n%s",ci_get_screen_name(info), ci_get_description(info)); else //if event has no xml description - label = xasprintf("<b>%s</b>\nNo description available", ci_get_name(info)); + label = xasprintf("<b>%s</b>\n%s", _("No description available"), ci_get_name(info));
GtkTreeIter iter; gtk_list_store_append(list_store, &iter); gtk_list_store_set(list_store, &iter, COLUMN_UINAME, label, COLUMN_NAME, ci_get_name(info), - CONFIG_DIALOG, dialog, + CONFIG_DIALOG, cdialog, -1); free(label); }
-GtkWidget *create_config_list_dialog(const char *column_label, - GHashTable *items, - GtkWindow *dialog, - GHFunc item_to_config_info, - GCallback on_config_cb, - GCallback on_row_change) +GtkWidget *create_config_tab_content(const char *column_label, + GtkListStore *store) { GtkWidget *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); @@ -161,37 +192,148 @@ GtkWidget *create_config_list_dialog(const char *column_label, gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tv), TRUE); // TODO: gtk_tree_view_set_headers_visible(FALSE)? We have only one column anyway...
- /* Create data store for the list and attach it - * COLUMN_UINAME -> name+description - * COLUMN_NAME -> workflow name so we can retrieve it from the row - */ - GtkListStore *list_store = new_conf_liststore(); - gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(list_store)); + gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store)); + gtk_container_add(GTK_CONTAINER(scroll), tv);
- g_hash_table_foreach(items, - item_to_config_info, - list_store); -//TODO: can unref workflows_list_store? treeview holds one ref. + gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10); + return main_vbox; +}
- /* Double click/Enter handler */ - //g_signal_connect(workflows_tv, "row-activated", G_CALLBACK(on_workflow_row_activated_cb), NULL); +static void add_config_tabs(const char *name, GtkListStore *store, gpointer nb) +{ + GtkNotebook *ntb = (GtkNotebook *)nb;
- gtk_container_add(GTK_CONTAINER(scroll), tv); + GtkWidget *config_list_vbox = create_config_tab_content( + name, + store);
- GtkWidget *configure_btn = gtk_button_new_with_mnemonic(_("C_onfigure")); - gtk_widget_set_sensitive(configure_btn, false); - g_signal_connect(configure_btn, "clicked", G_CALLBACK(on_configure_button_cb), tv); - g_signal_connect(tv, "cursor-changed", G_CALLBACK(on_row_changed_cb), configure_btn); + gtk_notebook_append_page(ntb, config_list_vbox, gtk_label_new(name)); +} + +static void on_configure_cb(GtkWidget *btn, gpointer user_data) +{ + GtkNotebook *nb = (GtkNotebook *)user_data; + + guint current_page_n = gtk_notebook_get_current_page(nb); + GtkWidget *vbox = gtk_notebook_get_nth_page(nb, current_page_n); + GList *children = gtk_container_get_children(GTK_CONTAINER(vbox)); + GtkScrolledWindow *sw = (GtkScrolledWindow *)children->data; + GtkTreeView *tv = (GtkTreeView *)gtk_bin_get_child(GTK_BIN(sw)); + config_dialog_t *cdialog = (config_dialog_t *)get_column_value_from_row(tv, CONFIG_DIALOG, TYPE_POINTER); + const char *name = (const char *)get_column_value_from_row(tv, COLUMN_NAME, TYPE_STR);
+ + if (cdialog == NULL || cdialog->dialog == NULL) + { + log("There is no configurable option for: '%s'", name); + return; + } + + int result = gtk_dialog_run(GTK_DIALOG(cdialog->dialog)); + if (result == GTK_RESPONSE_APPLY) + { + if (cdialog->save_data) + cdialog->save_data(cdialog->data, name); + } + else if (result == GTK_RESPONSE_CANCEL) + VERB1 log("Cancelling on user request"); + + gtk_widget_hide(GTK_WIDGET(cdialog->dialog)); +} + +static void on_close_cb(GtkWidget *btn, gpointer config_list_w) +{ + GtkWidget *w = (GtkWidget *)config_list_w; + gtk_widget_hide(w); +} + +GtkWindow *create_config_list_window(GHashTable *configs, GtkWindow *parent) +{ + + // config window + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(window), 5); + gtk_window_set_title(GTK_WINDOW(window), _("Configuration")); + gtk_window_set_default_size(GTK_WINDOW(window), 450, 400); + gtk_window_set_position(GTK_WINDOW(window), parent + ? GTK_WIN_POS_CENTER_ON_PARENT + : GTK_WIN_POS_CENTER); + + if (parent != NULL) + { + gtk_window_set_modal(GTK_WINDOW(window), true); + gtk_window_set_transient_for(GTK_WINDOW(window), parent); + } + + //g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + GtkWidget *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + GtkWidget *config_nb = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(main_vbox), config_nb, 1, 1, 0); + + /* we can't use this, because we want the workflows first and hashtable + * doesn't return the items in the order they were added + */ + //g_hash_table_foreach(configs, (GHFunc)add_config_tabs, config_nb); + + gpointer config = g_hash_table_lookup(configs, _("Workflows")); + if (config != NULL); + add_config_tabs(_("Workflows"), config, config_nb); + + config = g_hash_table_lookup(configs, _("Events")); + if (config != NULL); + add_config_tabs(_("Events"), config, config_nb); + + //buttons + GtkWidget *btn_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,5); + GtkWidget *configure_btn = gtk_button_new_with_mnemonic(_("C_onfigure")); + GtkWidget *align = gtk_alignment_new(0, 0, 0, 0); GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_list_cb), dialog); + GtkSizeGroup *sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); + //force apply and close to have the same size + gtk_size_group_add_widget(sg, close_btn); + gtk_size_group_add_widget(sg, configure_btn);
- GtkWidget *btnbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_end(GTK_BOX(btnbox), close_btn, false, false, 0); - gtk_box_pack_end(GTK_BOX(btnbox), configure_btn, false, false, 0); + g_signal_connect(configure_btn, "clicked", (GCallback)on_configure_cb, config_nb); + g_signal_connect(close_btn, "clicked", (GCallback)on_close_cb, window);
- gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10); - gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0); + gtk_box_pack_start(GTK_BOX(btn_box), close_btn, 0, 0, 5); + gtk_box_pack_start(GTK_BOX(btn_box), align, true, true, 5); + gtk_box_pack_start(GTK_BOX(btn_box), configure_btn, 0, 0, 5);
- return main_vbox; + + gtk_box_pack_start(GTK_BOX(main_vbox), btn_box, 0, 0, 0); + gtk_container_add(GTK_CONTAINER(window), main_vbox); + + //gtk_widget_show_all(window); + return GTK_WINDOW(window); +} + +/* Name | vbox with the gtk_Tree + * <String name, GtkWidget *vbox> +*/ + +void show_config_list_dialog(GtkWindow *parent) +{ + GHashTable *confs = g_hash_table_new_full( + /*hash_func*/ g_str_hash, + /*key_equal_func:*/ g_str_equal, + /*key_destroy_func:*/ g_free, + /*value_destroy_func:*/ NULL); + + + //TODO: free the hashtables somewhere!! + GHashTable *events = load_event_config_data(); + load_event_config_data_from_user_storage(events); + + GHashTable *workflows = load_workflow_config_data(WORKFLOWS_DIR); + load_workflow_config_data_from_user_storage(workflows); + GtkListStore *workflows_store = add_workflows_to_liststore(workflows); + g_hash_table_insert(confs, _("Workflows"), workflows_store); + + GtkListStore *events_store = add_events_to_liststore(events); + g_hash_table_insert(confs, _("Events"), events_store); + + GtkWindow *window = create_config_list_window(confs, parent); + gtk_widget_show_all(GTK_WIDGET(window)); } diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c index 01527ec..82d07df 100644 --- a/src/gtk-helpers/event_config_dialog.c +++ b/src/gtk-helpers/event_config_dialog.c @@ -20,7 +20,8 @@ #include "internal_libreport_gtk.h"
static GtkWindow *g_event_list_window; -static GList *option_widget_list; +static GList *g_option_list = NULL; + static bool has_password_option;
enum @@ -30,14 +31,6 @@ enum NUM_COLUMNS };
-typedef struct -{ - event_option_t *option; - GtkWidget *widget; -} option_widget_t; - -int show_event_config_dialog(const char *event_name, GtkWindow *parent); - static GtkWidget *gtk_label_new_justify_left(const gchar *label_str) { GtkWidget *label = gtk_label_new(label_str); @@ -48,12 +41,14 @@ static GtkWidget *gtk_label_new_justify_left(const gchar *label_str) return label; }
-static void add_option_widget(GtkWidget *widget, event_option_t *option) +GList *add_option_widget(GList *options, GtkWidget *widget, event_option_t *option) { - option_widget_t *ow = (option_widget_t *)xmalloc(sizeof(option_widget_t)); + option_widget_t *ow = (option_widget_t *)xmalloc(sizeof(*ow)); ow->widget = widget; ow->option = option; - option_widget_list = g_list_prepend(option_widget_list, ow); + options = g_list_prepend(options, ow); + + return options; }
static void on_show_pass_cb(GtkToggleButton *tb, gpointer user_data) @@ -75,6 +70,23 @@ static unsigned add_one_row_to_grid(GtkGrid *table) return rows; }
+void save_data_from_event_config_dialog(GList *widgets, event_config_t *ec) +{ + dehydrate_config_dialog(widgets); + const char *const store_passwords_s = get_user_setting("store_passwords"); + save_event_config_data_to_user_storage(ec_get_name(ec), + ec, + !(store_passwords_s && !strcmp(store_passwords_s, "no"))); +} + +static void save_data_from_event_dialog_name(GList *widgets, const char *name) +{ + event_config_t *ec = get_event_config(name); + + save_data_from_event_config_dialog(widgets, ec); +} + + static void add_option_to_table(gpointer data, gpointer user_data) { event_option_t *option = data; @@ -116,7 +128,7 @@ static void add_option_to_table(gpointer data, gpointer user_data) gtk_grid_attach(option_table, option_input, /*left,top:*/ 1, last_row, /*width,height:*/ 1, 1); - add_option_widget(option_input, option); + g_option_list = add_option_widget(g_option_list, option_input, option); if (option->eo_type == OPTION_TYPE_PASSWORD) { gtk_entry_set_visibility(GTK_ENTRY(option_input), 0); @@ -151,7 +163,7 @@ static void add_option_to_table(gpointer data, gpointer user_data) if (option->eo_value != NULL) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(option_input), string_to_bool(option->eo_value)); - add_option_widget(option_input, option); + g_option_list = add_option_widget(g_option_list, option_input, option); break;
default: @@ -177,39 +189,7 @@ static void add_option_to_table(gpointer data, gpointer user_data) free(option_label); }
-static void save_value_from_widget(gpointer data, gpointer user_data) -{ - option_widget_t *ow = (option_widget_t *)data; - - const char *val = NULL; - switch (ow->option->eo_type) - { - case OPTION_TYPE_TEXT: - case OPTION_TYPE_NUMBER: - case OPTION_TYPE_PASSWORD: - val = (char *)gtk_entry_get_text(GTK_ENTRY(ow->widget)); - break; - case OPTION_TYPE_BOOL: - val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ow->widget)) ? "yes" : "no"; - break; - default: - log("unsupported option type"); - } - if (val) - { - free(ow->option->eo_value); - ow->option->eo_value = xstrdup(val); - VERB1 log("saved: %s:%s", ow->option->eo_name, ow->option->eo_value); - } -} - -static void dehydrate_config_dialog() -{ - if (option_widget_list != NULL) - g_list_foreach(option_widget_list, &save_value_from_widget, NULL); -} - -GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *content) +config_dialog_t *create_event_config_dialog_content(event_config_t *event, GtkWidget *content) { if (content == NULL) content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); @@ -238,6 +218,13 @@ GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget * g_object_set_data(G_OBJECT(option_table), "advanced-options", adv_option_table);
has_password_option = false; + /* it's already stored in config_dialog_t from the previous call + * we need to set it to null so we create a new list for the actual + * event_config + * note: say *NO* to the global variables! + */ + g_option_list = NULL; + /* this fills the g_option_list, so we can use it for new_config_dialog */ g_list_foreach(event->options, &add_option_to_table, option_table);
/* if there is at least one password option, add checkbox to disable storing passwords */ @@ -275,17 +262,17 @@ GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *
gtk_widget_show_all(content); //make it all visible
- return content; + //g_option_list is filled on + config_dialog_t *cdialog = new_config_dialog(NULL, + g_option_list, + (config_save_fun_t)save_data_from_event_dialog_name + ); + + return cdialog; }
-GtkWidget *create_config_dialog(const char *event_name, GtkWindow *parent) +config_dialog_t *create_event_config_dialog(const char *event_name, GtkWindow *parent) { - if (option_widget_list != NULL) - { - g_list_free(option_widget_list); - option_widget_list = NULL; - } - event_config_t *event = get_event_config(event_name);
if(!ec_is_configurable(event)) @@ -320,26 +307,30 @@ GtkWidget *create_config_dialog(const char *event_name, GtkWindow *parent) }
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - content = create_event_config_dialog_content(event, content); + config_dialog_t *cdialog = create_event_config_dialog_content(event, content); + cdialog_set_widget(cdialog, dialog);
- return dialog; + return cdialog; }
-static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) +static void add_event_to_liststore(gpointer key, gpointer value, gpointer list_store) { config_item_info_t *info = ec_get_config_info((event_config_t *)value); - GtkWidget *dialog = create_config_dialog(key, NULL); - add_item_to_config_liststore(dialog, info, user_data); + config_dialog_t *cdialog = create_event_config_dialog(key, NULL); + + add_item_to_config_liststore(cdialog, info, list_store); }
-int show_event_config_dialog(const char *event_name, GtkWindow *parent) +GtkListStore *add_events_to_liststore(GHashTable *events) { - if (option_widget_list != NULL) - { - g_list_free(option_widget_list); - option_widget_list = NULL; - } + GtkListStore *list_store = new_conf_liststore(); + g_hash_table_foreach(events, (GHFunc)add_event_to_liststore, list_store); + + return list_store; +}
+int show_event_config_dialog(const char *event_name, GtkWindow *parent) +{ event_config_t *event = get_event_config(event_name);
GtkWindow *parent_window = parent ? parent : g_event_list_window; @@ -371,14 +362,14 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) }
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); - content = create_event_config_dialog_content(event, content); + content = cdialog_get_widget(create_event_config_dialog_content(event, content));
gtk_widget_show_all(content);
int result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_APPLY) { - dehydrate_config_dialog(); + dehydrate_config_dialog(g_option_list); const char *const store_passwords_s = get_user_setting("store_passwords"); save_event_config_data_to_user_storage(event_name, get_event_config(event_name), @@ -390,34 +381,3 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) return result; }
-void show_events_list_dialog(GtkWindow *parent) -{ - /*remove this line if we want to reload the config - *everytime we show the config dialog - */ - if (g_event_config_list == NULL) - { - load_event_config_data(); - load_event_config_data_from_user_storage(g_event_config_list); - } - - GtkWidget *event_list_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_event_list_window = (GtkWindow*)event_list_window; - gtk_window_set_title(g_event_list_window, _("Event Configuration")); - gtk_window_set_default_size(g_event_list_window, 450, 400); - gtk_window_set_position(g_event_list_window, parent ? GTK_WIN_POS_CENTER_ON_PARENT : GTK_WIN_POS_CENTER); - if (parent != NULL) - { - gtk_window_set_transient_for(g_event_list_window, parent); - // modal = parent window can't steal focus - gtk_window_set_modal(g_event_list_window, true); - gtk_window_set_icon_name(g_event_list_window, - gtk_window_get_icon_name(parent)); - } - - GtkWidget *main_vbox = create_config_list_dialog(_("Event"), g_event_config_list, GTK_WINDOW(event_list_window), &add_event_to_liststore, NULL, NULL); - - gtk_container_add(GTK_CONTAINER(event_list_window), main_vbox); - - gtk_widget_show_all(event_list_window); -} diff --git a/src/gtk-helpers/internal_libreport_gtk.h b/src/gtk-helpers/internal_libreport_gtk.h index 5e631cb..c59158e 100644 --- a/src/gtk-helpers/internal_libreport_gtk.h +++ b/src/gtk-helpers/internal_libreport_gtk.h @@ -27,6 +27,15 @@ extern "C" { #endif
+typedef struct config_dialog config_dialog_t; +typedef void (* config_save_fun_t)(gpointer data, const char *event_name); + +typedef struct +{ + event_option_t *option; + GtkWidget *widget; +} option_widget_t; + #define make_label_autowrap_on_resize libreport_make_label_autowrap_on_resize void make_label_autowrap_on_resize(GtkLabel *label);
@@ -51,22 +60,28 @@ void save_event_config_data_to_user_storage(const char *event_name, int show_event_config_dialog(const char *event_name, GtkWindow *parent);
#define create_event_config_dialog_content libreport_create_event_config_dialog_content -GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *content); +config_dialog_t *create_event_config_dialog_content(event_config_t *event, GtkWidget *content); + +//#define show_workflow_list_dialog libreport_show_workflow_list_dialog +//void show_workflow_list_dialog(GtkWindow *parent);
-#define show_workflow_list_dialog libreport_show_workflow_list_dialog -void show_workflow_list_dialog(GtkWindow *parent); +void save_data_from_event_config_dialog(GList *widgets, event_config_t *ec);
#define add_item_to_config_liststore libreport_add_item_to_config_liststore -void add_item_to_config_liststore(gpointer key, gpointer value, gpointer user_data); - -#define create_config_list_dialog libreport_create_config_list_dialog -GtkWidget *create_config_list_dialog(const char *column_label, - GHashTable *items, - GtkWindow *dialog, - GHFunc item_to_config_info, - GCallback on_config_cb, - GCallback on_row_change); +void add_item_to_config_liststore(gpointer cdialog, gpointer inf, gpointer user_data); + GtkListStore *new_conf_liststore(void); +void show_config_list_dialog(GtkWindow *parent); +GtkListStore *add_events_to_liststore(GHashTable *events); +GtkListStore *add_workflows_to_liststore(GHashTable *workflows); +config_dialog_t *new_config_dialog(GtkWidget *dialog, gpointer config_data, config_save_fun_t save_fun); +void load_workflow_config_data_from_user_storage(GHashTable *workflows); + +void cdialog_set_widget(config_dialog_t *cdialog, GtkWidget *widget); +GtkWidget *cdialog_get_widget(config_dialog_t *cdialog); +gpointer cdialog_get_data(config_dialog_t *cdialog); + +void dehydrate_config_dialog(GList *option_widgets);
char * tag_url(const char* line, const char* prefix);
diff --git a/src/gtk-helpers/workflow_config_dialog.c b/src/gtk-helpers/workflow_config_dialog.c index de10134..93dd622 100644 --- a/src/gtk-helpers/workflow_config_dialog.c +++ b/src/gtk-helpers/workflow_config_dialog.c @@ -27,13 +27,42 @@ enum };
static GtkWindow *g_parent_window; +static GHashTable *g_events_options = NULL;
static void create_event_config_dialog_content_cb(event_config_t *ec, gpointer content) { - create_event_config_dialog_content(ec, (GtkWidget *)content); + if (ec->options) + { + GtkWidget *ev_lbl = gtk_label_new(ec_get_screen_name(ec)); + gtk_box_pack_start(GTK_BOX(content), ev_lbl, false, false, 0); + } + + config_dialog_t *cdialog = create_event_config_dialog_content(ec, (GtkWidget *)content); + if (g_events_options == NULL) + { + g_events_options = g_hash_table_new_full( + /*hash_func*/ g_str_hash, + /*key_equal_func:*/ g_str_equal, + /*key_destroy_func:*/ g_free, + /*value_destroy_func:*/ NULL); + } + g_hash_table_insert(g_events_options, ec, cdialog); + }
-GtkWidget *create_workflow_config_dialog(const char *workflow_name, GtkWindow *parent) +static void save_event_config_data_foreach(event_config_t *ec, + config_dialog_t *cdialog, + gpointer user_data) +{ + save_data_from_event_config_dialog(cdialog_get_data(cdialog), ec); +} + +void save_data_from_worfklow_dialog(gpointer data, /* not needed */ const char *name) +{ + g_hash_table_foreach((GHashTable *)data, (GHFunc)save_event_config_data_foreach, NULL); +} + +config_dialog_t *create_workflow_config_dialog(const char *workflow_name, GtkWindow *parent) { workflow_t *workflow = get_workflow(workflow_name); GList *events = wf_get_event_list(workflow); @@ -61,16 +90,28 @@ GtkWidget *create_workflow_config_dialog(const char *workflow_name, GtkWindow *p
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ g_events_options = NULL; g_list_foreach(events, (GFunc)create_event_config_dialog_content_cb, content);
- return dialog; + config_dialog_t *cdialog = new_config_dialog(dialog, + g_events_options, + (config_save_fun_t)save_data_from_worfklow_dialog); + return cdialog; }
static void add_workflow_to_liststore(gpointer key, gpointer value, gpointer user_data) { config_item_info_t *info = workflow_get_config_info((workflow_t *)value); - GtkWidget *dialog = create_workflow_config_dialog(key, g_parent_window); - add_item_to_config_liststore(dialog, info, user_data); + config_dialog_t *cdialog = create_workflow_config_dialog(key, g_parent_window); + add_item_to_config_liststore(cdialog, info, user_data); +} + +GtkListStore *add_workflows_to_liststore(GHashTable *workflows) +{ + GtkListStore *list_store = new_conf_liststore(); + g_hash_table_foreach(workflows, (GHFunc)add_workflow_to_liststore, list_store); + + return list_store; }
static void load_single_event_config_foreach(event_config_t *ec, gpointer user_data) @@ -83,35 +124,7 @@ static void load_events_foreach_workflow(const char *name, workflow_t *workflow, g_list_foreach(wf_get_event_list(workflow), (GFunc)load_single_event_config_foreach, NULL); }
-void show_workflow_list_dialog(GtkWindow *parent) +void load_workflow_config_data_from_user_storage(GHashTable *workflows) { - g_parent_window = parent; - //g_verbose = 3; - if (g_workflow_list == NULL) - { - VERB1 log("workflow list is empty - reloading"); - load_workflow_config_data(WORKFLOWS_DIR); - } - - g_hash_table_foreach(g_workflow_list, (GHFunc)load_events_foreach_workflow, NULL); - - GtkWindow *workflow_list_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); - gtk_window_set_title(workflow_list_window, _("Workflow Configuration")); - gtk_window_set_default_size(workflow_list_window, 450, 400); - gtk_window_set_position(workflow_list_window, parent ? GTK_WIN_POS_CENTER_ON_PARENT : GTK_WIN_POS_CENTER); - if (parent != NULL) - { - gtk_window_set_transient_for(workflow_list_window, parent); - // modal = parent window can't steal focus - gtk_window_set_modal(workflow_list_window, true); - gtk_window_set_icon_name(workflow_list_window, - gtk_window_get_icon_name(parent)); - } - - GtkWidget *main_vbox = create_config_list_dialog(_("Workflow"), g_workflow_list, workflow_list_window, add_workflow_to_liststore, NULL, NULL); - - gtk_container_add(GTK_CONTAINER(workflow_list_window), main_vbox); - - gtk_widget_show_all(GTK_WIDGET(workflow_list_window)); - + g_hash_table_foreach(workflows, (GHFunc)load_events_foreach_workflow, NULL); } diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c index 03f8fd2..b47687b 100644 --- a/src/gui-wizard-gtk/main.c +++ b/src/gui-wizard-gtk/main.c @@ -140,7 +140,7 @@ int main(int argc, char **argv)
/* load /etc/abrt/events/foo.{conf,xml} stuff and $XDG_CACHE_HOME/abrt/events/foo.conf */ - load_event_config_data(); + g_event_config_list = load_event_config_data(); load_event_config_data_from_user_storage(g_event_config_list); load_user_settings("report-gtk");
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index dae4e80..0abcbba 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -1522,9 +1522,6 @@ static bool is_processing_finished()
static void hide_next_step_button() { - if(gtk_widget_get_visible(GTK_WIDGET(g_btn_next)) == false) - return - /* replace 'Forward' with 'Close' button */ /* 1. hide next button */ gtk_widget_hide(g_btn_next); @@ -1534,9 +1531,6 @@ static void hide_next_step_button()
static void show_next_step_button() { - if(gtk_widget_get_visible(GTK_WIDGET(g_btn_next)) == true) - return - gtk_box_reorder_child(g_box_buttons, g_btn_close, 0); gtk_widget_show(g_btn_next); } @@ -2044,7 +2038,7 @@ static void on_no_comment_toggled(GtkToggleButton *togglebutton, gpointer user_d
static void on_show_event_list_cb(GtkWidget *button, gpointer user_data) { - show_events_list_dialog(GTK_WINDOW(g_wnd_assistant)); + show_config_list_dialog(GTK_WINDOW(g_wnd_assistant)); }
#if 0 diff --git a/src/include/event_config.h b/src/include/event_config.h index 68463d3..24e1eac 100644 --- a/src/include/event_config.h +++ b/src/include/event_config.h @@ -103,12 +103,14 @@ void free_event_config(event_config_t *p); void load_event_description_from_file(event_config_t *event_config, const char* filename);
// (Re)loads data from /etc/abrt/events/*.{conf,xml} -void load_event_config_data(void); +GHashTable *load_event_config_data(void); /* Frees all loaded data */ void free_event_config_data(void); event_config_t *get_event_config(const char *event_name); event_option_t *get_event_option_from_list(const char *option_name, GList *event_options);
+/* for debugging */ +void ec_print(event_config_t *ec);
extern GHashTable *g_event_config_list; // for iterating through entire list of all loaded configs
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h index 4f85b2a..88a1f25 100644 --- a/src/include/internal_libreport.h +++ b/src/include/internal_libreport.h @@ -644,7 +644,7 @@ file_obj_t *new_file_obj(const char* fullpath, const char* filename); #define free_file_obj libreport_free_file_obj void free_file_obj(file_obj_t *f); #define load_workflow_config_data libreport_load_workflow_config_data -void load_workflow_config_data(const char* path); +GHashTable *load_workflow_config_data(const char* path);
/* Connect to abrtd over unix domain socket, issue DELETE command */ int delete_dump_dir_possibly_using_abrtd(const char *dump_dir_name); diff --git a/src/lib/event_config.c b/src/lib/event_config.c index e6ae269..88041ff 100644 --- a/src/lib/event_config.c +++ b/src/lib/event_config.c @@ -79,6 +79,15 @@ bool ec_is_configurable(event_config_t* ec) return g_list_length(ec->options) > 0; }
+void ec_print(event_config_t *ec) +{ + printf("%s\n\t%s\n\t%s\n", + ec_get_name(ec), + ec_get_screen_name(ec), + ec_get_description(ec) + ); +} + void free_event_option(event_option_t *p) { if (!p) @@ -183,7 +192,7 @@ static void load_config_files(const char *dir_path) }
/* (Re)loads data from /etc/abrt/events/foo.{xml,conf} and $XDG_CACHE_HOME/abrt/events/foo.conf */ -void load_event_config_data(void) +GHashTable *load_event_config_data(void) { free_event_config_data();
@@ -227,6 +236,8 @@ void load_event_config_data(void) cachedir = concat_path_file(g_get_user_cache_dir(), "abrt/events"); load_config_files(cachedir); free(cachedir); + + return g_event_config_list; }
/* Frees all loaded data */ diff --git a/src/lib/workflow.c b/src/lib/workflow.c index 1b92283..6fa2634 100644 --- a/src/lib/workflow.c +++ b/src/lib/workflow.c @@ -53,10 +53,14 @@ static void free_workflow_cb(const char *name, workflow_t *w, gpointer user_data free_workflow(w); }
-void free_workflow_list(GHashTable *wl) +void free_workflow_list(GHashTable **wl) { - g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL); - g_hash_table_destroy(wl); + if(*wl != NULL) + { + g_hash_table_foreach(*wl, (GHFunc)free_workflow_cb, NULL); + g_hash_table_destroy(*wl); + *wl = NULL; + } }
workflow_t *get_workflow(const char *name) @@ -74,8 +78,11 @@ workflow_t *get_workflow(const char *name) return g_hash_table_lookup(g_workflow_list, name); }
-void load_workflow_config_data(const char* path) +GHashTable *load_workflow_config_data(const char* path) { + if (g_workflow_list) + return g_workflow_list; + if (g_workflow_list == NULL) { g_workflow_list = g_hash_table_new_full( @@ -104,6 +111,8 @@ void load_workflow_config_data(const char* path) workflow_files = g_list_next(workflow_files); } free_file_list(workflow_files); + + return g_workflow_list; }
config_item_info_t *workflow_get_config_info(workflow_t *w)
--- src/gtk-helpers/config_dialog.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c index 3c81d7c..75e26a9 100644 --- a/src/gtk-helpers/config_dialog.c +++ b/src/gtk-helpers/config_dialog.c @@ -162,6 +162,22 @@ void add_item_to_config_liststore(gpointer cdialog, gpointer inf, gpointer user_ free(label); }
+//filters configuration - show only those with configurable options trac#881 +static gboolean config_filter_func(GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gboolean visible = FALSE; + gpointer cdialog; + + GValue value = { 0 }; + gtk_tree_model_get_value(model, iter, CONFIG_DIALOG, &value); + cdialog = g_value_get_pointer(&value); + visible = (cdialog != NULL); + + return visible; +} + GtkWidget *create_config_tab_content(const char *column_label, GtkListStore *store) { @@ -191,8 +207,10 @@ GtkWidget *create_config_tab_content(const char *column_label, /* "Please draw rows in alternating colors": */ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tv), TRUE); // TODO: gtk_tree_view_set_headers_visible(FALSE)? We have only one column anyway... + GtkTreeModel *model = gtk_tree_model_filter_new(GTK_TREE_MODEL(store), NULL); + gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), config_filter_func, NULL, NULL);
- gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store)); + gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(model)); gtk_container_add(GTK_CONTAINER(scroll), tv);
gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10);
Push it!
On Monday 03 of December 2012 16:47:38 Jiri Moskovcak wrote:
src/gtk-helpers/config_dialog.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c index 3c81d7c..75e26a9 100644 --- a/src/gtk-helpers/config_dialog.c +++ b/src/gtk-helpers/config_dialog.c @@ -162,6 +162,22 @@ void add_item_to_config_liststore(gpointer cdialog, gpointer inf, gpointer user_ free(label); }
+//filters configuration - show only those with configurable options trac#881 +static gboolean config_filter_func(GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
+{
- gboolean visible = FALSE;
- gpointer cdialog;
- GValue value = { 0 };
- gtk_tree_model_get_value(model, iter, CONFIG_DIALOG, &value);
- cdialog = g_value_get_pointer(&value);
- visible = (cdialog != NULL);
- return visible;
+}
GtkWidget *create_config_tab_content(const char *column_label, GtkListStore *store) { @@ -191,8 +207,10 @@ GtkWidget *create_config_tab_content(const char *column_label, /* "Please draw rows in alternating colors": */ gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tv), TRUE); // TODO: gtk_tree_view_set_headers_visible(FALSE)? We have only one column anyway...
- GtkTreeModel *model = gtk_tree_model_filter_new(GTK_TREE_MODEL(store), NULL);
- gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(model), config_filter_func, NULL, NULL);
- gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(store));
gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(model)); gtk_container_add(GTK_CONTAINER(scroll), tv);
gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10);
It works as expected and looks good to me.
I found only few minor things.
On Monday 03 of December 2012 16:47:37 Jiri Moskovcak wrote:
+++ b/src/include/internal_libreport.h +GHashTable *load_workflow_config_data(const char* path);
^^^^ coding style violation
-void free_workflow_list(GHashTable *wl) +void free_workflow_list(GHashTable **wl) {
- g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL);
- g_hash_table_destroy(wl);
- if(*wl != NULL)
^^^^ coding style violation
- {
g_hash_table_foreach(*wl, (GHFunc)free_workflow_cb, NULL);
The workflow hash table is initialized by g_hash_table_new_full(): g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) free_workflow);
According to the GLib documentation [1] it is not necessary to free items before g_hash_table_destroy()
-g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL);
http://developer.gnome.org/glib/2.32/glib-Hash-Tables.html#g-hash-table-dest...
g_hash_table_destroy(*wl);
*wl = NULL;
- }
}
+GHashTable *load_workflow_config_data(const char* path)
^^^^ coding style violation
crash-catcher@lists.fedorahosted.org