--- configure.ac | 3 + libreport.spec.in | 16 ++ po/POTFILES.in | 27 +-- src/Makefile.am | 2 +- src/cli/cli-report.c | 8 +- src/gtk-helpers/Makefile.am | 5 +- src/gtk-helpers/config_dialog.c | 216 ++++++++++++++++++++++++ src/gtk-helpers/event_config_dialog.c | 279 +++++++++++++++---------------- src/gtk-helpers/internal_libreport_gtk.h | 20 ++- src/gtk-helpers/secrets.c | 4 +- src/gtk-helpers/workflow_config_dialog.c | 119 +++++++++++++ src/gui-wizard-gtk/Makefile.am | 1 + src/gui-wizard-gtk/main.c | 10 +- src/gui-wizard-gtk/wizard.c | 111 +++++++++--- src/gui-wizard-gtk/wizard.glade | 20 ++- src/gui-wizard-gtk/wizard.h | 2 +- src/include/Makefile.am | 2 + src/include/config_item_info.h | 45 +++++ src/include/event_config.h | 19 ++- src/include/file_obj.h | 2 + src/include/internal_libreport.h | 3 + src/include/workflow.h | 51 ++++++ src/lib/Makefile.am | 6 +- src/lib/config_item_info.c | 85 ++++++++++ src/lib/event_config.c | 51 +++++- src/lib/event_xml_parser.c | 19 ++- src/lib/workflow.c | 146 ++++++++++++++++ src/lib/workflow_xml_parser.c | 173 +++++++++++++++++++ src/report-newt/report-newt.c | 8 +- src/workflows/Makefile.am | 10 ++ src/workflows/report_Fedora.xml.in | 13 ++ src/workflows/report_fedora.conf | 3 + 32 files changed, 1269 insertions(+), 210 deletions(-) create mode 100644 src/gtk-helpers/config_dialog.c create mode 100644 src/gtk-helpers/workflow_config_dialog.c create mode 100644 src/include/config_item_info.h create mode 100644 src/include/workflow.h create mode 100644 src/lib/config_item_info.c create mode 100644 src/lib/workflow.c create mode 100644 src/lib/workflow_xml_parser.c create mode 100644 src/workflows/Makefile.am create mode 100644 src/workflows/report_Fedora.xml.in create mode 100644 src/workflows/report_fedora.conf
diff --git a/configure.ac b/configure.ac index 07b3cf8..1607880 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,7 @@ PLUGINS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/plugins' REPORT_PLUGINS_CONF_DIR='${sysconfdir}/libreport/plugins' EVENTS_DIR='${sysconfdir}/${PACKAGE_NAME}/events' EVENTS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/events.d' +WORKFLOWS_DIR='${sysconfdir}/${PACKAGE_NAME}/workflows' PLUGINS_LIB_DIR='${libdir}/${PACKAGE_NAME}' LIBEXEC_DIR='${libexecdir}'
@@ -195,6 +196,7 @@ AC_SUBST(EVENTS_DIR) AC_SUBST(PLUGINS_LIB_DIR) AC_SUBST(DEBUG_DUMPS_DIR) AC_SUBST(LIBEXEC_DIR) +AC_SUBST(WORKFLOWS_DIR)
# Initialize the test suite. AC_CONFIG_TESTDIR(tests) @@ -222,6 +224,7 @@ AC_CONFIG_FILES([ src/client-python/Makefile po/Makefile.in doc/Makefile + src/workflows/Makefile ])
# src/plugins/Makefile diff --git a/libreport.spec.in b/libreport.spec.in index 8eefb3d..018b39d 100644 --- a/libreport.spec.in +++ b/libreport.spec.in @@ -217,6 +217,15 @@ Obsoletes: report-config-scp < 0:0.23-1 %description plugin-reportuploader Plugin to report bugs into anonymous FTP site associated with ticketing system.
+%package fedora +Summary: Default configuration for reporting bugs via Fedora infrastructure +Group: Applications/File + +%description fedora +Default configuration for reporting bugs via Fedora infrastructure +used to easy configure the reporting process for Fedora sytems. Just +install this package and you're done. + %prep %setup -q
@@ -290,6 +299,8 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_includedir}/libreport/report.h %{_includedir}/libreport/run_event.h %{_includedir}/libreport/file_obj.h +%{_includedir}/libreport/config_item_info.h +%{_includedir}/libreport/workflow.h # Private api headers: %{_includedir}/libreport/internal_abrt_dbus.h %{_includedir}/libreport/internal_libreport.h @@ -393,6 +404,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_sysconfdir}/libreport/events/report_Uploader.xml %config(noreplace) %{_sysconfdir}/libreport/events.d/uploader_event.conf
+%files fedora +%defattr(-,root,root,-) +%{_sysconfdir}/libreport/workflows/report_Fedora.xml +%{_sysconfdir}/libreport/workflows/report_fedora.conf + %changelog * Wed Nov 14 2012 Jakub Filak jfilak@redhat.com 2.0.19-1 - bugzilla_format[_libreport].conf: emit truncated backtrace into its own paragraph diff --git a/po/POTFILES.in b/po/POTFILES.in index 668c526..90d4285 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,31 +3,27 @@ # Please keep this file sorted alphabetically. src/cli/cli.c src/cli/cli-report.c -src/client-python/__init__.py src/client-python/debuginfo.py +src/client-python/__init__.py +src/gtk-helpers/config_dialog.c src/gtk-helpers/event_config_dialog.c src/gtk-helpers/secrets.c +src/gtk-helpers/workflow_config_dialog.c src/gui-wizard-gtk/main.c src/gui-wizard-gtk/wizard.c src/gui-wizard-gtk/wizard.glade src/include/internal_libreport.h src/lib/abrt_sock.c +src/lib/client.c src/lib/create_dump_dir.c +src/lib/curl.c src/lib/event_config.c src/lib/parse_options.c -src/lib/curl.c -src/lib/client.c -src/lib/run_event.c src/lib/problem_data.c +src/lib/run_event.c src/plugins/abrt_rh_support.c -src/plugins/report.c src/plugins/report_Bugzilla.xml.in -src/plugins/report_Kerneloops.xml.in -src/plugins/report_Logger.xml.in -src/plugins/report_Mailx.xml.in -src/plugins/report_RHTSupport.xml.in -src/plugins/report_Uploader.xml.in -src/plugins/report_uReport.xml.in +src/plugins/report.c src/plugins/reporter-bugzilla.c src/plugins/reporter-kerneloops.c src/plugins/reporter-mailx.c @@ -35,6 +31,13 @@ src/plugins/reporter-print.c src/plugins/reporter-rhtsupport.c src/plugins/reporter-rhtsupport-parse.c src/plugins/reporter-upload.c +src/plugins/report_Kerneloops.xml.in +src/plugins/report_Logger.xml.in +src/plugins/report_Mailx.xml.in +src/plugins/report_RHTSupport.xml.in +src/plugins/report_Uploader.xml.in +src/plugins/report_uReport.xml.in src/plugins/rhbz.c -src/report-newt/report-newt.c src/plugins/ureport.c +src/report-newt/report-newt.c +src/workflows/report_Fedora.xml.in diff --git a/src/Makefile.am b/src/Makefile.am index 68bd1c0..c15928c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,4 +8,4 @@ if BUILD_NEWT sub_dirs += report-newt endif
-SUBDIRS = include lib plugins report-python cli client-python $(sub_dirs) +SUBDIRS = include lib plugins report-python cli client-python workflows $(sub_dirs) diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c index f256e25..d6697e9 100644 --- a/src/cli/cli-report.c +++ b/src/cli/cli-report.c @@ -617,7 +617,7 @@ char *select_event_option(GList *list_options) if (config) { ++pos; - printf(" %i) %s\n", pos, config->screen_name); + printf(" %i) %s\n", pos, ec_get_screen_name(config)); } }
@@ -717,7 +717,7 @@ int collect(const char *dump_dir_name, int batch) if (!config) VERB1 log("No configuration file found for collector '%s'", collector_name);
- printf(" %d) %s\n", i, (config && config->screen_name) ? config->screen_name : collector_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : collector_name); }
read_from_stdin(_("Select collector(s): "), wanted_collectors, sizeof(wanted_collectors)); @@ -901,7 +901,7 @@ int report(const char *dump_dir_name, int flags) char *reporter_name = (char *) li->data; event_config_t *config = get_event_config(reporter_name);
- printf(" %d) %s\n", i, (config && config->screen_name) ? config->screen_name : reporter_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : reporter_name); }
read_from_stdin(_("Select reporter(s): "), wanted_reporters, sizeof(wanted_reporters)); @@ -1007,7 +1007,7 @@ int run_events_chain(const char *dump_dir_name, GList *chain) { char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data." " Do you want to continue?"), - config->screen_name ? config->screen_name : event); + ec_get_screen_name(config) ? ec_get_screen_name(config) : event); const bool response = ask_yesno(msg); free(msg); if (!response) diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am index a821b5d..0d3f9d8 100644 --- a/src/gtk-helpers/Makefile.am +++ b/src/gtk-helpers/Makefile.am @@ -12,7 +12,9 @@ libreport_gtk_la_SOURCES = \ event_config_dialog.c \ secrets.c \ hyperlinks.c \ - autowrapped_label.c + autowrapped_label.c \ + workflow_config_dialog.c \ + config_dialog.c
libreport_gtk_la_CPPFLAGS = \ -I$(srcdir)/../include \ @@ -20,6 +22,7 @@ libreport_gtk_la_CPPFLAGS = \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \ + -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -D_GNU_SOURCE libreport_gtk_la_LDFLAGS = \ -version-info 0:1:0 diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c new file mode 100644 index 0000000..8d09d53 --- /dev/null +++ b/src/gtk-helpers/config_dialog.c @@ -0,0 +1,216 @@ +/* + Copyright (C) 2011 ABRT Team + Copyright (C) 2011 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include <gtk/gtk.h> +#include "internal_libreport_gtk.h" + +enum +{ + COLUMN_UINAME, + COLUMN_NAME, + CONFIG_DIALOG, + NUM_COLUMNS +}; + +enum +{ + TYPE_STR, + TYPE_POINTER +}; + +GtkListStore *new_conf_liststore() +{ + /* 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 + */ + return gtk_list_store_new(NUM_COLUMNS, + G_TYPE_STRING, /* Event name + description */ + G_TYPE_STRING, /* event name */ + G_TYPE_POINTER + ); +} + +static const void *get_column_value_from_row(GtkTreeView *treeview, int column, int type) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); + const void *retval = NULL; + if (selection) + { + GtkTreeIter iter; + GtkTreeModel *store = gtk_tree_view_get_model(treeview); + if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) + { + GValue value = { 0 }; + gtk_tree_model_get_value(store, &iter, column, &value); + switch(type){ + case TYPE_STR: + retval = g_value_get_string(&value); + break; + case TYPE_POINTER: + retval = g_value_get_pointer(&value); + } + } + } + return retval; +} + +static void on_row_changed_cb(GtkTreeView *treeview, gpointer user_data) +{ + VERB1 log("activated row: '%s'", (const char*)get_column_value_from_row(treeview, COLUMN_NAME, TYPE_STR)); + + const void *dialog = get_column_value_from_row(treeview, CONFIG_DIALOG, TYPE_POINTER); + gtk_widget_set_sensitive(GTK_WIDGET(user_data), dialog != NULL); + + /* + void (*handler)(void) = (void (*)(void))get_column_value_from_row(treeview, ON_ROWCHANGE_CB, TYPE_POINTER); + + if (handler == NULL) + return; + + handler(); + */ + + /* + const char *event_name = get_event_name_from_row(treeview); + + if (event_name) + { + event_config_t *ec = get_event_config(event_name); + gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options != 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) + { + 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)); + } +} + +static void on_close_list_cb(GtkWidget *button, gpointer user_data) +{ + GtkWidget *window = (GtkWidget *)user_data; + gtk_widget_destroy(window); +} + +void add_item_to_config_liststore(gpointer dialog, gpointer inf, gpointer user_data) +{ + GtkListStore *list_store = (GtkListStore *)user_data; + config_item_info_t *info = (config_item_info_t *)inf; + + VERB1 log("adding '%s' to workflow list\n", info->screen_name); + char *label; + if (ci_get_screen_name(info) != NULL && ci_get_description(info) != NULL) + 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)); + + 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, + -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 *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + /* workflow list treeview */ + GtkWidget *tv = gtk_tree_view_new(); + /* column with workflow name and description */ + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + /* add column to tree view */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes(column_label, + renderer, + "markup", + COLUMN_UINAME, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD, NULL); + g_object_set(G_OBJECT(renderer), "wrap-width", 440, NULL); + gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME); + gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); + /* "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... + + /* 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)); + + g_hash_table_foreach(items, + item_to_config_info, + list_store); +//TODO: can unref workflows_list_store? treeview holds one ref. + + /* Double click/Enter handler */ + //g_signal_connect(workflows_tv, "row-activated", G_CALLBACK(on_workflow_row_activated_cb), NULL); + + gtk_container_add(GTK_CONTAINER(scroll), tv); + + 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); + + GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_list_cb), dialog); + + 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); + + gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10); + gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0); + + return main_vbox; +} diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c index a067511..a2e1085 100644 --- a/src/gtk-helpers/event_config_dialog.c +++ b/src/gtk-helpers/event_config_dialog.c @@ -177,80 +177,6 @@ static void add_option_to_table(gpointer data, gpointer user_data) free(option_label); }
-static void on_close_event_list_cb(GtkWidget *button, gpointer user_data) -{ - GtkWidget *window = (GtkWidget *)user_data; - gtk_widget_destroy(window); -} - -static char *get_event_name_from_row(GtkTreeView *treeview) -{ - GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview); - char *event_name = NULL; - if (selection) - { - GtkTreeIter iter; - GtkTreeModel *store = gtk_tree_view_get_model(treeview); - if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE) - { - GValue value = { 0 }; - gtk_tree_model_get_value(store, &iter, COLUMN_EVENT_NAME, &value); - event_name = (char *)g_value_get_string(&value); - } - } - return event_name; -} - -static void on_configure_event_cb(GtkWidget *button, gpointer user_data) -{ - GtkTreeView *events_tv = (GtkTreeView *)user_data; - char *event_name = get_event_name_from_row(events_tv); - if (event_name != NULL) - show_event_config_dialog(event_name, NULL); - //else - // error_msg(_("Please select a plugin from the list to edit its options.")); -} - -static void on_event_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) -{ - char *event_name = get_event_name_from_row(treeview); - event_config_t *ec = get_event_config(event_name); - if (ec->options != NULL) //We need to have some options to show - show_event_config_dialog(event_name, NULL); -} - -static void on_event_row_changed_cb(GtkTreeView *treeview, gpointer user_data) -{ - const char *event_name = get_event_name_from_row(treeview); - - if (event_name) - { - event_config_t *ec = get_event_config(event_name); - gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options != NULL); - } -} - -static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) -{ - GtkListStore *events_list_store = (GtkListStore *)user_data; - event_config_t *ec = (event_config_t *)value; - - char *event_label; - if (ec->screen_name != NULL && ec->description != NULL) - event_label = xasprintf("<b>%s</b>\n%s", ec->screen_name, ec->description); - else - //if event has no xml description - event_label = xasprintf("<b>%s</b>\nNo description available", key); - - GtkTreeIter iter; - gtk_list_store_append(events_list_store, &iter); - gtk_list_store_set(events_list_store, &iter, - COLUMN_EVENT_UINAME, event_label, - COLUMN_EVENT_NAME, key, - -1); - free(event_label); -} - static void save_value_from_widget(gpointer data, gpointer user_data) { option_widget_t *ow = (option_widget_t *)data; @@ -283,43 +209,12 @@ static void dehydrate_config_dialog() g_list_foreach(option_widget_list, &save_value_from_widget, NULL); }
-int show_event_config_dialog(const char *event_name, GtkWindow *parent) +GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *content) { - if (option_widget_list != NULL) - { - g_list_free(option_widget_list); - option_widget_list = NULL; - } - - event_config_t *event = get_event_config(event_name); - - GtkWindow *parent_window = parent ? parent : g_event_list_window; - - GtkWidget *dialog = gtk_dialog_new_with_buttons( - /*title:*/ event->screen_name ? event->screen_name : event_name, - parent_window, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, - GTK_RESPONSE_APPLY, - NULL); - - /* Allow resize? - * W/o resize, e.g. upload configuration hint looks awfully - * line wrapped. - * With resize, there are some somewhat not nice effects: - * for one, opening an expander will enlarge window, - * but won't contract it back when expander is closed. - */ - gtk_window_set_resizable(GTK_WINDOW(dialog), true); - gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1); + if (content == NULL) + content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- if (parent_window != NULL) - { - gtk_window_set_icon_name(GTK_WINDOW(dialog), - gtk_window_get_icon_name(parent_window)); - } + //event_config_t *event = get_event_config(event_name);
GtkWidget *option_table = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(option_table), FALSE); @@ -359,7 +254,6 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) g_signal_connect(pass_store_cb, "toggled", G_CALLBACK(on_show_pass_store_cb), NULL); }
- GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_box_pack_start(GTK_BOX(content), option_table, false, false, 20);
/* add the adv_option_table to the dialog only if there is some adv option */ @@ -379,6 +273,103 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) gtk_box_pack_start(GTK_BOX(content), keyring_warn_lbl, false, false, 0); }
+ gtk_widget_show_all(content); //make it all visible + + return content; +} + +GtkWidget *create_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); + + GtkWindow *parent_window = parent ? parent : g_event_list_window; + + GtkWidget *dialog = gtk_dialog_new_with_buttons( + /*title:*/ec_get_screen_name(event) ? ec_get_screen_name(event) : event_name, + parent_window, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_APPLY, + NULL); + + /* Allow resize? + * W/o resize, e.g. upload configuration hint looks awfully + * line wrapped. + * With resize, there are some somewhat not nice effects: + * for one, opening an expander will enlarge window, + * but won't contract it back when expander is closed. + */ + gtk_window_set_resizable(GTK_WINDOW(dialog), true); + gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1); + + if (parent_window != NULL) + { + gtk_window_set_icon_name(GTK_WINDOW(dialog), + gtk_window_get_icon_name(parent_window)); + } + + GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + content = create_event_config_dialog_content(event, content); + + return dialog; +} + +static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) +{ + 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); +} + +int show_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); + + GtkWindow *parent_window = parent ? parent : g_event_list_window; + + GtkWidget *dialog = gtk_dialog_new_with_buttons( + /*title:*/ec_get_screen_name(event) ? ec_get_screen_name(event) : event_name, + parent_window, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_APPLY, + NULL); + + /* Allow resize? + * W/o resize, e.g. upload configuration hint looks awfully + * line wrapped. + * With resize, there are some somewhat not nice effects: + * for one, opening an expander will enlarge window, + * but won't contract it back when expander is closed. + */ + gtk_window_set_resizable(GTK_WINDOW(dialog), true); + gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1); + + if (parent_window != NULL) + { + gtk_window_set_icon_name(GTK_WINDOW(dialog), + gtk_window_get_icon_name(parent_window)); + } + + GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + content = create_event_config_dialog_content(event, content); + gtk_widget_show_all(content);
int result = gtk_dialog_run(GTK_DIALOG(dialog)); @@ -396,31 +387,9 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) return result; }
-void show_events_list_dialog(GtkWindow *parent) +#if 0 +GtkWidget *create_event_list_config_dialog() { - /*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 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *events_scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(events_scroll), @@ -448,18 +417,13 @@ void show_events_list_dialog(GtkWindow *parent) gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(events_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_EVENT_UINAME -> name+description - * COLUMN_EVENT_NAME -> event name so we can retrieve it from the row - */ - GtkListStore *events_list_store = gtk_list_store_new(NUM_COLUMNS, - G_TYPE_STRING, /* Event name + description */ - G_TYPE_STRING /* event name */ + ); + events_list_store = new_conf_liststore(); gtk_tree_view_set_model(GTK_TREE_VIEW(events_tv), GTK_TREE_MODEL(events_list_store));
g_hash_table_foreach(g_event_config_list, - &add_event_to_liststore, + &add_event_to_liststore_wrap, events_list_store); //TODO: can unref events_list_store? treeview holds one ref.
@@ -483,6 +447,37 @@ void show_events_list_dialog(GtkWindow *parent) gtk_box_pack_start(GTK_BOX(main_vbox), events_scroll, true, true, 10); gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
+ return main_vbox; +} +#endif + +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 5cb965c..ff3d653 100644 --- a/src/gtk-helpers/internal_libreport_gtk.h +++ b/src/gtk-helpers/internal_libreport_gtk.h @@ -37,7 +37,7 @@ void show_events_list_dialog(GtkWindow *parent); bool is_event_config_user_storage_available();
#define load_single_event_config_data_from_user_storage libreport_load_single_event_config_data_from_user_storage -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config); +void load_single_event_config_data_from_user_storage(event_config_t *config);
#define load_event_config_data_from_user_storage libreport_load_event_config_data_from_user_storage void load_event_config_data_from_user_storage(GHashTable *event_config_list); @@ -50,6 +50,24 @@ void save_event_config_data_to_user_storage(const char *event_name, #define show_event_config_dialog libreport_show_event_config_dialog 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); + +#define show_workflow_list_dialog libreport_show_workflow_list_dialog +void show_workflow_list_dialog(GtkWindow *parent); + +#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); +GtkListStore *new_conf_liststore(); + char * tag_url(const char* line, const char* prefix);
#define url_token libreport_url_token diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c index 468c508..9de2284 100644 --- a/src/gtk-helpers/secrets.c +++ b/src/gtk-helpers/secrets.c @@ -1378,7 +1378,7 @@ bool is_event_config_user_storage_available() * @param name Event name * @param config Event config */ -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config) +void load_single_event_config_data_from_user_storage(event_config_t *config) { GHashTable *tmp = g_hash_table_new_full( /*hash_func*/ g_str_hash, @@ -1386,7 +1386,7 @@ void load_single_event_config_data_from_user_storage(const char *event_name, eve /*key_destroy_func:*/ g_free, /*value_destroy_func:*/ NULL);
- g_hash_table_insert(tmp, xstrdup(event_name), config); + g_hash_table_insert(tmp, xstrdup(ec_get_name(config)), config);
load_event_config_data_from_user_storage(tmp);
diff --git a/src/gtk-helpers/workflow_config_dialog.c b/src/gtk-helpers/workflow_config_dialog.c new file mode 100644 index 0000000..acdc81d --- /dev/null +++ b/src/gtk-helpers/workflow_config_dialog.c @@ -0,0 +1,119 @@ +/* + Copyright (C) 2011 ABRT Team + Copyright (C) 2011 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <gtk/gtk.h> +#include "internal_libreport_gtk.h" + +enum +{ + COLUMN_WORKFLOW_UINAME, + COLUMN_WORKFLOW_NAME, + NUM_COLUMNS +}; + +static GtkWindow *g_parent_window; + +GtkWidget *create_workflow_config_dialog(const char *workflow_name, GtkWindow *parent) +{ + workflow_t *workflow = get_workflow(workflow_name); + GList *events = workflow->events; + + GtkWindow *parent_window = parent ? parent : g_parent_window; + + GtkWidget *dialog = gtk_dialog_new_with_buttons( + /*title:*/ wf_get_screen_name(workflow) ? wf_get_screen_name(workflow) : workflow_name, + parent_window, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, + GTK_RESPONSE_APPLY, + NULL); + + gtk_window_set_resizable(GTK_WINDOW(dialog), true); + gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1); + + if (parent_window != NULL) + { + gtk_window_set_icon_name(GTK_WINDOW(dialog), + gtk_window_get_icon_name(parent_window)); + } + + GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + + //GtkWidget *event_conf_widg = NULL; + while(events) + { + event_config_t *ec = (event_config_t *)events->data; + create_event_config_dialog_content(ec, content); + //gtk_box_pack_start(GTK_BOX(content), event_conf_widg, true, true, 0); + events = g_list_next(events); + } + + return dialog; +} + +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); +} + +static void load_single_event_config_foreach(event_config_t *ec, gpointer user_data) +{ + load_single_event_config_data_from_user_storage(ec); +} + +static void load_events_foreach_workflow(const char *name, workflow_t *workflow, gpointer user_data) +{ + g_list_foreach(wf_get_event_list(workflow), (GFunc)load_single_event_config_foreach, NULL); +} + +void show_workflow_list_dialog(GtkWindow *parent) +{ + 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)); + +} diff --git a/src/gui-wizard-gtk/Makefile.am b/src/gui-wizard-gtk/Makefile.am index ecd1887..46c1d65 100644 --- a/src/gui-wizard-gtk/Makefile.am +++ b/src/gui-wizard-gtk/Makefile.am @@ -19,6 +19,7 @@ report_gtk_CFLAGS = \ -DPLUGINS_LIB_DIR="$(PLUGINS_LIB_DIR)" \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DICON_DIR="${datadir}/abrt/icons/hicolor/48x48/status" \ + -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ $(GLIB_CFLAGS) \ $(GTK_CFLAGS) \ -D_GNU_SOURCE diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c index fab88f1..1bb9af1 100644 --- a/src/gui-wizard-gtk/main.c +++ b/src/gui-wizard-gtk/main.c @@ -74,6 +74,8 @@ void problem_data_reload_from_dump_dir(void)
int main(int argc, char **argv) { + bool expert_mode = false; + const char *prgname = "abrt"; abrt_init(argv);
@@ -110,6 +112,7 @@ int main(int argc, char **argv) OPT_p = 1 << 2, OPT_d = 1 << 3, OPT_e = 1 << 4, + OPT_x = 1 << 5, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { @@ -119,6 +122,7 @@ int main(int argc, char **argv) /* for use from 3rd party apps to show just a reporter selector */ OPT_BOOL( 'd', "delete", NULL, _("Remove DIR after reporting")), OPT_LIST( 'e', "event", &g_auto_event_list, "EVENT", _("Run only this event")), + OPT_BOOL( 'x', "expert", &expert_mode, _("Run wizard in expert mode - shows advanced options")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); @@ -130,6 +134,8 @@ int main(int argc, char **argv) for (GList *elem = g_auto_event_list; elem; elem = g_list_next(elem)) elem->data = xstrdup((const char *)elem->data);
+ g_auto_event_list = NULL; + export_abrt_envvars(opts & OPT_p);
g_dump_dir_name = xstrdup(argv[0]); @@ -140,9 +146,11 @@ int main(int argc, char **argv) load_event_config_data_from_user_storage(g_event_config_list); load_user_settings("report-gtk");
+ load_workflow_config_data(WORKFLOWS_DIR); + problem_data_reload_from_dump_dir();
- create_assistant(); + create_assistant(expert_mode);
g_custom_logger = &show_error_as_msgbox;
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index f351988..04dc961 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -64,6 +64,7 @@ static GtkWidget *g_btn_close; static GtkWidget *g_btn_next;
static GtkBox *g_box_events; +static GtkBox *g_box_workflows; /* List of event_gui_data's */ static GList *g_list_events; static GtkLabel *g_lbl_event_log; @@ -104,6 +105,9 @@ static GtkImage *g_img_process_ok;
static GtkWidget *g_top_most_window;
+static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func); +static void set_auto_event_chain(GtkButton *button, gpointer user_data); + typedef struct { int page; //which tab in notepad @@ -162,8 +166,8 @@ enum { * instead of strcmp. */ static const gchar PAGE_SUMMARY[] = "page_0"; -static const gchar PAGE_EVENT_SELECTOR[] = "page_2"; -static const gchar PAGE_EDIT_COMMENT[] = "page_1"; +static const gchar PAGE_EVENT_SELECTOR[] = "page_1"; +static const gchar PAGE_EDIT_COMMENT[] = "page_2"; static const gchar PAGE_EDIT_ELEMENTS[] = "page_3"; static const gchar PAGE_REVIEW_DATA[] = "page_4"; static const gchar PAGE_EVENT_PROGRESS[] = "page_5"; @@ -273,12 +277,12 @@ static void show_event_opt_error_dialog(const char *event_name) "reporting will probably fail if you continue " "with the current configuration.\n\n" "Read more about the configuration at: https://fedorahosted.org/abrt/wiki/AbrtConfiguration"), - ec->screen_name); + ec_get_screen_name(ec)); char *markup_message = xasprintf(_("Wrong settings detected for <b>%s</b>, " "reporting will probably fail if you continue " "with the current configuration.\n\n" "<a href="https://fedorahosted.org/abrt/wiki/AbrtConfiguration%5C%22%3ERead more about the configuration</a>"), - ec->screen_name); + ec_get_screen_name(ec)); GtkWidget *wrong_settings = g_top_most_window = gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, @@ -292,7 +296,7 @@ static void show_event_opt_error_dialog(const char *event_name) free(markup_message);
GtkWidget *act_area = gtk_dialog_get_content_area(GTK_DIALOG(wrong_settings)); - char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec->screen_name); + char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec_get_screen_name(ec)); GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(conf_btn_lbl); g_signal_connect(configure_event_btn, "clicked", G_CALLBACK(on_configure_event_cb), (gpointer)event_name); free(conf_btn_lbl); @@ -972,6 +976,7 @@ static char *missing_items_in_comma_list(const char *input_item_list) } return result; } + static event_gui_data_t *add_event_buttons(GtkBox *box, GList **p_event_list, char *event_name, @@ -1016,9 +1021,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (cfg) { /* .xml has (presumably) prettier description, use it: */ - if (cfg->screen_name) - event_screen_name = cfg->screen_name; - event_description = cfg->description; + if (ec_get_screen_name(cfg)) + event_screen_name = ec_get_screen_name(cfg); + event_description = ec_get_description(cfg);
char *missing = missing_items_in_comma_list(cfg->ec_requires_items); if (missing) @@ -1078,8 +1083,8 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (func) g_signal_connect(G_OBJECT(button), "toggled", func, xstrdup(event_name));
- if (cfg && cfg->long_descr) - gtk_widget_set_tooltip_text(button, cfg->long_descr); + if (cfg && ec_get_long_desc(cfg)) + gtk_widget_set_tooltip_text(button, ec_get_long_desc(cfg));
event_gui_data_t *event_gui_data = new_event_gui_data_t(); event_gui_data->event_name = xstrdup(event_name); @@ -1099,7 +1104,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, event_name = event_name_end + 1;
gtk_box_pack_start(box, button, /*expand*/ false, /*fill*/ false, /*padding*/ 0); + gtk_widget_show_all(GTK_WIDGET(button)); } + gtk_widget_show_all(GTK_WIDGET(box));
return active_button; } @@ -1316,13 +1323,24 @@ void update_gui_state_from_problem_data(int flags)
load_text_to_text_view(g_tv_comment, FILENAME_COMMENT);
- /* Update event radio buttons */ - event_gui_data_t *active_button = add_event_buttons( - g_box_events, - &g_list_events, - g_events, - G_CALLBACK(event_rb_was_toggled) - ); + add_workflow_buttons(g_box_workflows, g_workflow_list, + G_CALLBACK(set_auto_event_chain)); + + /* Update event radio buttons + * show them only in expert mode + */ + event_gui_data_t *active_button = NULL; + if (g_expert_mode == true) + { + //this widget doesn't react to show_all, so we need to "force" it + gtk_widget_show(GTK_WIDGET(g_box_events)); + active_button = add_event_buttons( + g_box_events, + &g_list_events, + g_events, + G_CALLBACK(event_rb_was_toggled) + ); + }
if (flags & UPDATE_SELECTED_EVENT && g_expert_mode) { @@ -1335,7 +1353,6 @@ void update_gui_state_from_problem_data(int flags) } VERB2 log("g_event_selected='%s'", g_event_selected); } - /* We can't just do gtk_widget_show_all once in main: * We created new widgets (buttons). Need to make them visible. */ @@ -2400,6 +2417,50 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer us } }
+//static void event_rb_was_toggled(GtkButton *button, gpointer user_data) +static void set_auto_event_chain(GtkButton *button, gpointer user_data) +{ + //event is selected, so make sure the expert mode is disabled + g_expert_mode = false; + + workflow_t *w = (workflow_t *)user_data; + config_item_info_t *info = workflow_get_config_info(w); + VERB1 log("selected workflow '%s'", info->screen_name); + + GList *wf_event_list = wf_get_event_list(w); + while(wf_event_list) + { + g_auto_event_list = g_list_append(g_auto_event_list, xstrdup(ec_get_name(wf_event_list->data))); + load_single_event_config_data_from_user_storage((event_config_t *)wf_event_list->data); + + wf_event_list = g_list_next(wf_event_list); + } + + gint current_page_no = gtk_notebook_get_current_page(g_assistant); + gint next_page_no = select_next_page_no(current_page_no, NULL); + + /* if pageno is not change 'switch-page' signal is not emitted */ + if (current_page_no == next_page_no) + on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant, next_page_no), NULL); + else + gtk_notebook_set_current_page(g_assistant, next_page_no); +} + +static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func) +{ + GList *keys = g_hash_table_get_keys(g_workflow_list); + while(keys) + { + workflow_t *workflow = g_hash_table_lookup(g_workflow_list, keys->data); + config_item_info_t *info = workflow_get_config_info(workflow); + GtkWidget *button = gtk_button_new_with_label(info->screen_name); + g_signal_connect(button, "clicked", func, workflow); + gtk_box_pack_start(box, button, true, false, 0); + keys = g_list_next(keys); + } + +} + static char *setup_next_processed_event(GList **events_list) { free(g_event_selected); @@ -2431,7 +2492,7 @@ static bool get_sensitive_data_permission(const char *event_name)
char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data." "\nDo you want to continue?"), - event_cfg->screen_name ? event_cfg->screen_name : event_name); + ec_get_screen_name(event_cfg) ? ec_get_screen_name(event_cfg) : event_name); const bool response = ask_yes_no_save_result(msg, "ask_send_sensitive_data"); free(msg);
@@ -2449,6 +2510,11 @@ static gint select_next_page_no(gint current_page_no, gpointer data)
if (pages[PAGENO_EVENT_SELECTOR].page_widget == page) { + if (!g_expert_mode && (g_auto_event_list == NULL)) + { + return current_page_no; //stay here and let user select the workflow + } + if (!g_expert_mode) { /* (note: this frees and sets to NULL g_event_selected) */ @@ -2881,6 +2947,7 @@ static void add_pages(void) /* Set pointers to objects we might need to work with */ g_lbl_cd_reason = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_cd_reason")); g_box_events = GTK_BOX( gtk_builder_get_object(g_builder, "vb_events")); + g_box_workflows = GTK_BOX( gtk_builder_get_object(g_builder, "vb_workflows")); g_lbl_event_log = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_event_log")); g_tv_event_log = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_event_log")); g_tv_comment = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_comment")); @@ -2989,7 +3056,7 @@ static void init_page(page_obj_t *page, const char *name, const char *title) static void init_pages(void) { init_page(&pages[0], PAGE_SUMMARY , _("Problem description") ); - init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select operation") ); + init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select how to report this problem")); init_page(&pages[2], PAGE_EDIT_COMMENT,_("Provide additional information")); init_page(&pages[3], PAGE_EDIT_ELEMENTS , _("Review the data") ); init_page(&pages[4], PAGE_REVIEW_DATA , _("Confirm data to report")); @@ -3005,11 +3072,11 @@ static void assistant_quit_cb(void *obj, void *data) gtk_main_quit(); }
-void create_assistant(void) +void create_assistant(bool expert_mode) { g_loaded_texts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
- g_expert_mode = !g_auto_event_list; + g_expert_mode = expert_mode;
g_monospace_font = pango_font_description_from_string("monospace"); g_builder = gtk_builder_new(); diff --git a/src/gui-wizard-gtk/wizard.glade b/src/gui-wizard-gtk/wizard.glade index 53e215e..15a5697 100644 --- a/src/gui-wizard-gtk/wizard.glade +++ b/src/gui-wizard-gtk/wizard.glade @@ -83,7 +83,7 @@ <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_1"> + <object class="GtkVBox" id="page_2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> @@ -177,15 +177,31 @@ <object class="GtkWindow" id="window2"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_2"> + <object class="GtkVBox" id="page_1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> <property name="spacing">3</property> <child> + <object class="GtkBox" id="vb_workflows"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> <object class="GtkVBox" id="vb_events"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="no_show_all">True</property> <child> <placeholder/> </child> diff --git a/src/gui-wizard-gtk/wizard.h b/src/gui-wizard-gtk/wizard.h index d2caaa6..a6d8b5d 100644 --- a/src/gui-wizard-gtk/wizard.h +++ b/src/gui-wizard-gtk/wizard.h @@ -21,7 +21,7 @@
#include "internal_libreport_gtk.h"
-void create_assistant(void); +void create_assistant(bool expert_mode);
enum { diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 948662e..a4dc133 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -7,7 +7,9 @@ libreport_include_HEADERS = \ report.h \ run_event.h \ libreport_curl.h \ + workflow.h \ \ + config_item_info.h \ file_obj.h \ internal_libreport.h \ internal_abrt_dbus.h diff --git a/src/include/config_item_info.h b/src/include/config_item_info.h new file mode 100644 index 0000000..ac49bd5 --- /dev/null +++ b/src/include/config_item_info.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2011 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef LIBREPORT_CONFIG_ITEM_H +#define LIBREPORT_CONFIG_ITEM_H + +typedef struct +{ + char *name; //the event name (from it's filename) + char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat Support Upload" + char *description; // "Report to..."/"Save to file". Should be one sentence, not long + char *long_desc; // Long(er) explanation, if needed + +} config_item_info_t; + +config_item_info_t *new_config_info(); +void free_config_info(config_item_info_t *info); + +void ci_set_screen_name(config_item_info_t *ci, const char *screen_name); +void ci_set_name(config_item_info_t *ci, const char *name); +void ci_set_description(config_item_info_t *ci, const char *description); +void ci_set_long_desc(config_item_info_t *ci, const char *long_description); + +const char *ci_get_screen_name(config_item_info_t *ci); +const char *ci_get_name(config_item_info_t *ci); +const char *ci_get_description(config_item_info_t *ci); +const char *ci_get_long_desc(config_item_info_t *ci); + +#endif diff --git a/src/include/event_config.h b/src/include/event_config.h index 438c723..60fa5c6 100644 --- a/src/include/event_config.h +++ b/src/include/event_config.h @@ -22,6 +22,7 @@ #include <stdbool.h> #include <glib.h> #include "problem_data.h" +#include "config_item_info.h"
#ifdef __cplusplus extern "C" { @@ -68,10 +69,7 @@ void free_event_option(event_option_t *p); //structure to hold the option data typedef struct { - char *name; //the event name (from it's filename) - char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat Support Upload" - char *description; // "Report to..."/"Save to file". Should be one sentence, not long - char *long_descr; // Long(er) explanation, if needed + config_item_info_t *info;
char *ec_creates_items; char *ec_requires_items; @@ -87,6 +85,18 @@ typedef struct } event_config_t;
event_config_t *new_event_config(void); +config_item_info_t *ec_get_config_info(event_config_t * ec); +const char *ec_get_screen_name(event_config_t *ec); +void ec_set_screen_name(event_config_t *ec, const char *screen_name); +void ec_set_name(event_config_t *ec, const char *name); + +const char *ec_get_description(event_config_t *ec); +void ec_set_description(event_config_t *ec, const char *description); + +const char *ec_get_name(event_config_t *ec); +const char *ec_get_long_desc(event_config_t *ec); +void ec_set_long_desc(event_config_t *ec, const char *long_desc); + void free_event_config(event_config_t *p);
@@ -99,6 +109,7 @@ 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);
+ extern GHashTable *g_event_config_list; // for iterating through entire list of all loaded configs
GList *export_event_config(const char *event_name); diff --git a/src/include/file_obj.h b/src/include/file_obj.h index 9cb293f..08823af 100644 --- a/src/include/file_obj.h +++ b/src/include/file_obj.h @@ -24,6 +24,8 @@ typedef struct file_obj * e.g: * if fullpath is: /foo/bar/report_Bugzilla.xml * then filename is: report_Bugzilla + * in case of symlink the filename is created from the symlink name + * and the fullpath is the symlink target */ char *filename; char *fullpath; //the full path with extension diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h index d22bcbe..4f85b2a 100644 --- a/src/include/internal_libreport.h +++ b/src/include/internal_libreport.h @@ -93,6 +93,7 @@ int vdprintf(int d, const char *format, va_list ap); #include "problem_data.h" #include "report.h" #include "run_event.h" +#include "workflow.h" #include "file_obj.h"
#ifdef __cplusplus @@ -642,6 +643,8 @@ void free_file_list(GList *filelist); 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);
/* 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/include/workflow.h b/src/include/workflow.h new file mode 100644 index 0000000..dc2768c --- /dev/null +++ b/src/include/workflow.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2011 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef LIBREPORT_WORKFLOW_H +#define LIBREPORT_WORKFLOW_H + +#include <glib.h> +#include "event_config.h" +#include "config_item_info.h" + +typedef struct +{ + config_item_info_t *info; + + GList *events; //list of event_option_t +} workflow_t; + +extern GHashTable *g_workflow_list; + +workflow_t *new_workflow(void); +workflow_t *get_workflow(const char *name); +void free_workflow(workflow_t *w); + +void load_workflow_description_from_file(workflow_t *w, const char *filename); +config_item_info_t *workflow_get_config_info(workflow_t *w); +const char *wf_get_name(workflow_t *w); +GList *wf_get_event_list(workflow_t *w); +const char *wf_get_screen_name(workflow_t *w); +const char *wf_get_description(workflow_t *w); +const char *wf_get_long_desc(workflow_t *w); + +void wf_set_name(workflow_t *w, const char* name); +void wf_set_description(workflow_t *w, const char* description); +void wf_set_long_desc(workflow_t *w, const char* long_desc); + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2865624..dad9f89 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -49,7 +49,10 @@ libreport_la_SOURCES = \ client.c \ utf8.c \ file_list.c \ - file_obj.c + file_obj.c \ + workflow.c \ + workflow_xml_parser.c \ + config_item_info.c libreport_la_CPPFLAGS = \ -I$(srcdir)/../include \ -DLOCALSTATEDIR='"$(localstatedir)"' \ @@ -59,6 +62,7 @@ libreport_la_CPPFLAGS = \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DCONF_DIR="$(CONF_DIR)" \ -DEVENTS_DIR="$(EVENTS_DIR)" \ + -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -DBIN_DIR="$(bindir)" \ $(GLIB_CFLAGS) \ -D_GNU_SOURCE diff --git a/src/lib/config_item_info.c b/src/lib/config_item_info.c new file mode 100644 index 0000000..c8e2d78 --- /dev/null +++ b/src/lib/config_item_info.c @@ -0,0 +1,85 @@ +/* + Copyright (C) 2011 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "internal_libreport.h" +//#include "config_item_info.h" + + +config_item_info_t *new_config_info() +{ + config_item_info_t *info = (config_item_info_t *)xzalloc(sizeof(config_item_info_t)); + return info; +} + +void free_config_info(config_item_info_t *info) +{ + if (info == NULL) + return; + + free(info->name); + free(info->screen_name); + free(info->description); + free(info->long_desc); + + free(info); +} + +void ci_set_screen_name(config_item_info_t *ci, const char *screen_name) +{ + free(ci->screen_name); + ci->screen_name = xstrdup(screen_name); +} + +void ci_set_name(config_item_info_t *ci, const char *name) +{ + free(ci->name); + ci->name = xstrdup(name); +} + +void ci_set_description(config_item_info_t *ci, const char *description) +{ + free(ci->description); + ci->description = xstrdup(description); +} + +void ci_set_long_desc(config_item_info_t *ci, const char *long_description) +{ + free(ci->long_desc); + ci->long_desc = xstrdup(long_description); +} + +const char *ci_get_screen_name(config_item_info_t *ci) +{ + return ci->screen_name; +} + +const char *ci_get_name(config_item_info_t *ci) +{ + return ci->name; +} + +const char *ci_get_description(config_item_info_t *ci) +{ + return ci->description; +} + +const char *ci_get_long_desc(config_item_info_t *ci) +{ + return ci->long_desc; +} diff --git a/src/lib/event_config.c b/src/lib/event_config.c index 2019e53..402a09f 100644 --- a/src/lib/event_config.c +++ b/src/lib/event_config.c @@ -16,6 +16,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #include "internal_libreport.h"
GHashTable *g_event_config_list; @@ -29,9 +30,55 @@ event_option_t *new_event_option(void) event_config_t *new_event_config(void) { event_config_t *e = xzalloc(sizeof(event_config_t)); + e->info = new_config_info(); return e; }
+config_item_info_t *ec_get_config_info(event_config_t * ec) +{ + return ec->info; +} + +void ec_set_name(event_config_t *ec, const char *name) +{ + ci_set_name(ec->info, name); +} + +void ec_set_screen_name(event_config_t *ec, const char *screen_name) +{ + ci_set_screen_name(ec->info, screen_name); +} + +const char *ec_get_screen_name(event_config_t *ec) +{ + return ci_get_screen_name(ec->info); +} + +const char *ec_get_description(event_config_t *ec) +{ + return ci_get_description(ec->info); +} + +void ec_set_description(event_config_t *ec, const char *description) +{ + ci_set_description(ec->info, description); +} + +const char *ec_get_name(event_config_t *ec) +{ + return ci_get_name(ec->info); +} + +const char *ec_get_long_desc(event_config_t *ec) +{ + return ci_get_long_desc(ec->info); +} + +void ec_set_long_desc(event_config_t *ec, const char *long_descr) +{ + ci_set_long_desc(ec->info, long_descr); +} + void free_event_option(event_option_t *p) { if (!p) @@ -50,9 +97,7 @@ void free_event_config(event_config_t *p) if (!p) return;
- free(p->screen_name); - free(p->description); - free(p->long_descr); + free_config_info(p->info); free(p->ec_creates_items); free(p->ec_requires_items); free(p->ec_exclude_items_by_default); diff --git a/src/lib/event_xml_parser.c b/src/lib/event_xml_parser.c index 157b717..585e2e5 100644 --- a/src/lib/event_xml_parser.c +++ b/src/lib/event_xml_parser.c @@ -336,11 +336,11 @@ static void text(GMarkupParseContext *context, * OR the label is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0' - || !ui->screen_name /* && parse_data->attribute_lang is "" - always true */ + || !ec_get_screen_name(ui) /* && parse_data->attribute_lang is "" - always true */ ) { VERB2 log("event name:'%s'", text_copy); - free(ui->screen_name); - ui->screen_name = text_copy; + ec_set_screen_name(ui, text_copy); + free(text_copy); text_copy = NULL; } } @@ -355,10 +355,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0' - || !ui->description /* && parse_data->attribute_lang is "" - always true */ + || !ec_get_description(ui) /* && parse_data->attribute_lang is "" - always true */ ) { - free(ui->description); - ui->description = text_copy; + ec_set_description(ui, text_copy); + free(text_copy); text_copy = NULL; } } @@ -373,10 +373,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0' - || !ui->long_descr /* && parse_data->attribute_lang is "" - always true */ + || !ec_get_long_desc(ui) /* && parse_data->attribute_lang is "" - always true */ ) { - free(ui->long_descr); - ui->long_descr = text_copy; + ec_set_long_desc(ui, text_copy); + free(text_copy); text_copy = NULL; } } @@ -463,6 +463,7 @@ static void error(GMarkupParseContext *context,
void load_event_description_from_file(event_config_t *event_config, const char* filename) { + VERB1 log("loading event: '%s'", filename); struct my_parse_data parse_data = { event_config, NULL, NULL, NULL }; parse_data.cur_locale = setlocale(LC_ALL, NULL);
diff --git a/src/lib/workflow.c b/src/lib/workflow.c new file mode 100644 index 0000000..9b17a73 --- /dev/null +++ b/src/lib/workflow.c @@ -0,0 +1,146 @@ +/* + Copyright (C) 2011 ABRT team + Copyright (C) 2010 RedHat Inc + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "event_config.h" +#include "workflow.h" +#include "internal_libreport.h" + +GHashTable *g_workflow_list; + +workflow_t *new_workflow(void) +{ + workflow_t *w = xzalloc(sizeof(event_config_t)); + w->info = new_config_info(); + return w; +} + +void free_workflow(workflow_t *w) +{ + if (!w) + return; + + free_config_info(w->info); + g_list_free_full(w->events, (GDestroyNotify)free_event_config); + free(w); + w = NULL; +} + +static void free_workflow_cb(const char *name, workflow_t *w, gpointer user_data) +{ + free_workflow(w); +} + +void free_workflow_list(GHashTable *wl) +{ + g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL); + g_hash_table_destroy(wl); + wl = NULL; +} + +workflow_t *get_workflow(const char *name) +{ + if (!g_workflow_list) + return NULL; + /* @@ FIXME: SYMLINKS@!!! + if (g_event_config_symlinks) + { + char *link = g_hash_table_lookup(g_event_config_symlinks, name); + if (link) + name = link; + } + */ + return g_hash_table_lookup(g_workflow_list, name); +} + +void load_workflow_config_data(const char* path) +{ + if (g_workflow_list == NULL) + { + g_workflow_list = g_hash_table_new_full( + g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) free_workflow + ); + } + + GList *workflow_files = get_file_list(path, "xml"); + while(workflow_files) + { + file_obj_t *file = (file_obj_t *)workflow_files->data; + + workflow_t *workflow = get_workflow(file->filename); + bool nw_workflow = (!workflow); + if (nw_workflow) + workflow = new_workflow(); + + load_workflow_description_from_file(workflow, file->fullpath); + + if (nw_workflow) + g_hash_table_replace(g_workflow_list, xstrdup(file->filename), workflow); + + workflow_files = g_list_next(workflow_files); + } + free_file_list(workflow_files); +} + +config_item_info_t *workflow_get_config_info(workflow_t *w) +{ + return w->info; +} + +GList *wf_get_event_list(workflow_t *w) +{ + return w->events; +} + +const char *wf_get_name(workflow_t *w) +{ + return ci_get_name(workflow_get_config_info(w)); +} + +const char *wf_get_screen_name(workflow_t *w) +{ + return ci_get_screen_name(workflow_get_config_info(w)); +} + +const char *wf_get_description(workflow_t *w) +{ + return ci_get_description(workflow_get_config_info(w)); +} + +const char *wf_get_long_desc(workflow_t *w) +{ + return ci_get_long_desc(workflow_get_config_info(w)); +} + +void wf_set_name(workflow_t *w, const char* name) +{ + ci_set_name(workflow_get_config_info(w), name); +} + +void wf_set_description(workflow_t *w, const char* description) +{ + ci_set_description(workflow_get_config_info(w), description); +} + +void wf_set_long_desc(workflow_t *w, const char* long_desc) +{ + ci_set_long_desc(workflow_get_config_info(w), long_desc); +} diff --git a/src/lib/workflow_xml_parser.c b/src/lib/workflow_xml_parser.c new file mode 100644 index 0000000..abea00b --- /dev/null +++ b/src/lib/workflow_xml_parser.c @@ -0,0 +1,173 @@ +/* + Copyright (C) 2011 ABRT Team + Copyright (C) 2011 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "workflow.h" +#include "internal_libreport.h" + +//workflow elements +#define WORKFLOW_ELEMENT "workflow" +#define EVENTS_ELEMENT "events" +#define EVENT_ELEMENT "event" +#define DESCRIPTION_ELEMENT "description" +#define NAME_ELEMENT "name" + +struct my_parse_data +{ + workflow_t *workflow; + const char *cur_locale; + char *attribute_lang; + bool in_event_list; +}; + +static void start_element(GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + //log("start: %s", element_name); + + struct my_parse_data *parse_data = user_data; + if (strcmp(element_name, EVENTS_ELEMENT) == 0) + { + parse_data->in_event_list = true; + } +} + +// Called for close tags </foo> +static void end_element(GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + struct my_parse_data *parse_data = user_data; + + free(parse_data->attribute_lang); + parse_data->attribute_lang = NULL; + + if (strcmp(element_name, EVENT_ELEMENT) == 0) + { + if (parse_data->in_event_list == true) + { + //pass + } + } + + if (strcmp(element_name, EVENTS_ELEMENT) == 0) + { + parse_data->in_event_list = false; + } +} + +// Called for character data +// text is not nul-terminated +static void text(GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + struct my_parse_data *parse_data = user_data; + workflow_t *workflow = parse_data->workflow; + + const gchar *inner_element = g_markup_parse_context_get_element(context); + + if(parse_data->in_event_list && strcmp(inner_element, EVENT_ELEMENT) == 0) + { + event_config_t *ec = new_event_config(); + char *subevent_filename = xasprintf(EVENTS_DIR"/%s.xml", text); + + load_event_description_from_file(ec, subevent_filename); + //HACK: need to make ec = NULL if the loading fails + if (ec_get_screen_name(ec)) + { + workflow->events = g_list_append(workflow->events, ec); + VERB2 log("added to ev list: '%s'", ec_get_screen_name(ec)); + } + ec_set_name(ec, text); + free(subevent_filename); + } + + if(strcmp(inner_element, NAME_ELEMENT) == 0) + { + workflow->info->screen_name = xstrdup(text); + } + + if(strcmp(inner_element, DESCRIPTION_ELEMENT) == 0) + { + workflow->info->description = xstrdup(text); + } +} + + // Called for strings that should be re-saved verbatim in this same + // position, but are not otherwise interpretable. At the moment + // this includes comments and processing instructions. + // text is not nul-terminated +static void passthrough(GMarkupParseContext *context, + const gchar *passthrough_text, + gsize text_len, + gpointer user_data, + GError **error) +{ + VERB3 log("passthrough"); +} + +// Called on error, including one set by other +// methods in the vtable. The GError should not be freed. +static void error(GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + error_msg("error in XML parsing"); +} + +void load_workflow_description_from_file(workflow_t *workflow, const char* filename) +{ + VERB1 log("loading workflow: '%s'", filename); + struct my_parse_data parse_data = { workflow, NULL, NULL, 0}; + parse_data.cur_locale = setlocale(LC_ALL, NULL); + + GMarkupParser parser; + memset(&parser, 0, sizeof(parser)); /* just in case */ + parser.start_element = &start_element; + parser.end_element = &end_element; + parser.text = &text; + parser.passthrough = &passthrough; + parser.error = &error; + + GMarkupParseContext *context = g_markup_parse_context_new( + &parser, G_MARKUP_TREAT_CDATA_AS_TEXT, + &parse_data, /*GDestroyNotify:*/ NULL); + + FILE* fin = fopen(filename, "r"); + if (fin != NULL) + { + size_t read_bytes; + char buff[1024]; + while ((read_bytes = fread(buff, 1, 1024, fin)) != 0) + { + g_markup_parse_context_parse(context, buff, read_bytes, NULL); + } + fclose(fin); + } + + g_markup_parse_context_free(context); + + free(parse_data.attribute_lang); /* just in case */ +} diff --git a/src/report-newt/report-newt.c b/src/report-newt/report-newt.c index 8532e82..44d30bd 100644 --- a/src/report-newt/report-newt.c +++ b/src/report-newt/report-newt.c @@ -60,8 +60,8 @@ static int select_reporters(GArray *reporters) { struct reporter *r = &g_array_index(reporters, struct reporter, i);
- checkboxes[i] = newtCheckbox(20, i + 1, r->config && r->config->screen_name ? - r->config->screen_name : r->name, 0, NULL, NULL); + checkboxes[i] = newtCheckbox(20, i + 1, r->config && ec_get_screen_name(r->config) ? + ec_get_screen_name(r->config) : r->name, 0, NULL, NULL); newtGridSetField(cgrid, 0, i, NEWT_GRID_COMPONENT, checkboxes[i], 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); }
@@ -104,8 +104,8 @@ static int configure_reporter(struct reporter *r, bool skip_if_valid) while ((error_table = validate_event(r->name)) || (!skip_if_valid && first && r->config)) { - text = newtTextboxReflowed(0, 0, r->config->screen_name ? - r->config->screen_name : r->name, 35, 5, 5, 0); + text = newtTextboxReflowed(0, 0, ec_get_screen_name(r->config) ? + xstrdup(ec_get_screen_name(r->config)) : r->name, 35, 5, 5, 0);
num_opts = g_list_length(r->config->options); options = xmalloc(sizeof (newtComponent) * num_opts); diff --git a/src/workflows/Makefile.am b/src/workflows/Makefile.am new file mode 100644 index 0000000..28dc024 --- /dev/null +++ b/src/workflows/Makefile.am @@ -0,0 +1,10 @@ +workflowsdir = $(WORKFLOWS_DIR) + +dist_workflows_DATA = \ + report_Fedora.xml \ + report_fedora.conf + +@INTLTOOL_XML_RULE@ + +EXTRA_DIST = \ + report_Fedora.xml.in diff --git a/src/workflows/report_Fedora.xml.in b/src/workflows/report_Fedora.xml.in new file mode 100644 index 0000000..f9df177 --- /dev/null +++ b/src/workflows/report_Fedora.xml.in @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<workflow> + <_name>Report to Fedora</_name> + <_description>Process the report using the Fedora infrastructure</_description> + + <events> + <event>report_uReport</event> + <event>collect_*</event> + <event>analyze_CCpp</event> + <event>report_Bugzilla</event> + <event>post_report</event> + </events> +</workflow> diff --git a/src/workflows/report_fedora.conf b/src/workflows/report_fedora.conf new file mode 100644 index 0000000..9dd86ce --- /dev/null +++ b/src/workflows/report_fedora.conf @@ -0,0 +1,3 @@ +EVENT=report_Fedora analyzer=CCpp +# this is just a meta event which consists of other events +# the list is defined in the xml file
Notes:
- Forward button is always visible and does nothing - The main page looks weird to me
On Thursday 22 of November 2012 16:51:43 Jiri Moskovcak wrote:
configure.ac | 3 + libreport.spec.in | 16 ++ po/POTFILES.in | 27 +-- src/Makefile.am | 2 +- src/cli/cli-report.c | 8 +- src/gtk-helpers/Makefile.am | 5 +- src/gtk-helpers/config_dialog.c | 216 ++++++++++++++++++++++++ src/gtk-helpers/event_config_dialog.c | 279 +++++++++++++++---------------- src/gtk-helpers/internal_libreport_gtk.h | 20 ++- src/gtk-helpers/secrets.c | 4 +- src/gtk-helpers/workflow_config_dialog.c | 119 +++++++++++++ src/gui-wizard-gtk/Makefile.am | 1 + src/gui-wizard-gtk/main.c | 10 +- src/gui-wizard-gtk/wizard.c | 111 +++++++++--- src/gui-wizard-gtk/wizard.glade | 20 ++- src/gui-wizard-gtk/wizard.h | 2 +- src/include/Makefile.am | 2 + src/include/config_item_info.h | 45 +++++ src/include/event_config.h | 19 ++- src/include/file_obj.h | 2 + src/include/internal_libreport.h | 3 + src/include/workflow.h | 51 ++++++ src/lib/Makefile.am | 6 +- src/lib/config_item_info.c | 85 ++++++++++ src/lib/event_config.c | 51 +++++- src/lib/event_xml_parser.c | 19 ++- src/lib/workflow.c | 146 ++++++++++++++++ src/lib/workflow_xml_parser.c | 173 +++++++++++++++++++ src/report-newt/report-newt.c | 8 +- src/workflows/Makefile.am | 10 ++ src/workflows/report_Fedora.xml.in | 13 ++ src/workflows/report_fedora.conf | 3 + 32 files changed, 1269 insertions(+), 210 deletions(-) create mode 100644 src/gtk-helpers/config_dialog.c create mode 100644 src/gtk-helpers/workflow_config_dialog.c create mode 100644 src/include/config_item_info.h create mode 100644 src/include/workflow.h create mode 100644 src/lib/config_item_info.c create mode 100644 src/lib/workflow.c create mode 100644 src/lib/workflow_xml_parser.c create mode 100644 src/workflows/Makefile.am create mode 100644 src/workflows/report_Fedora.xml.in create mode 100644 src/workflows/report_fedora.conf
diff --git a/configure.ac b/configure.ac index 07b3cf8..1607880 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,7 @@ PLUGINS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/plugins' REPORT_PLUGINS_CONF_DIR='${sysconfdir}/libreport/plugins' EVENTS_DIR='${sysconfdir}/${PACKAGE_NAME}/events' EVENTS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/events.d' +WORKFLOWS_DIR='${sysconfdir}/${PACKAGE_NAME}/workflows'
Is it possible to keep names of the configuration directories consistent? (suffix ".d")
PLUGINS_LIB_DIR='${libdir}/${PACKAGE_NAME}' LIBEXEC_DIR='${libexecdir}'
@@ -195,6 +196,7 @@ AC_SUBST(EVENTS_DIR) AC_SUBST(PLUGINS_LIB_DIR) AC_SUBST(DEBUG_DUMPS_DIR) AC_SUBST(LIBEXEC_DIR) +AC_SUBST(WORKFLOWS_DIR)
# Initialize the test suite. AC_CONFIG_TESTDIR(tests) @@ -222,6 +224,7 @@ AC_CONFIG_FILES([ src/client-python/Makefile po/Makefile.in doc/Makefile
- src/workflows/Makefile
])
# src/plugins/Makefile diff --git a/libreport.spec.in b/libreport.spec.in index 8eefb3d..018b39d 100644 --- a/libreport.spec.in +++ b/libreport.spec.in @@ -217,6 +217,15 @@ Obsoletes: report-config-scp < 0:0.23-1 %description plugin-reportuploader Plugin to report bugs into anonymous FTP site associated with ticketing system.
+%package fedora +Summary: Default configuration for reporting bugs via Fedora infrastructure +Group: Applications/File
+%description fedora +Default configuration for reporting bugs via Fedora infrastructure +used to easy configure the reporting process for Fedora sytems. Just +install this package and you're done.
%prep %setup -q
@@ -290,6 +299,8 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_includedir}/libreport/report.h %{_includedir}/libreport/run_event.h %{_includedir}/libreport/file_obj.h +%{_includedir}/libreport/config_item_info.h +%{_includedir}/libreport/workflow.h # Private api headers: %{_includedir}/libreport/internal_abrt_dbus.h %{_includedir}/libreport/internal_libreport.h @@ -393,6 +404,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_sysconfdir}/libreport/events/report_Uploader.xml %config(noreplace) %{_sysconfdir}/libreport/events.d/uploader_event.conf
+%files fedora +%defattr(-,root,root,-) +%{_sysconfdir}/libreport/workflows/report_Fedora.xml +%{_sysconfdir}/libreport/workflows/report_fedora.conf
Mark the lines with %config(noreplace) https://bugzilla.redhat.com/show_bug.cgi?id=875260
%changelog
- Wed Nov 14 2012 Jakub Filak jfilak@redhat.com 2.0.19-1
- bugzilla_format[_libreport].conf: emit truncated backtrace into its own
paragraph diff --git a/po/POTFILES.in b/po/POTFILES.in index 668c526..90d4285 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,31 +3,27 @@ # Please keep this file sorted alphabetically. src/cli/cli.c src/cli/cli-report.c -src/client-python/__init__.py src/client-python/debuginfo.py +src/client-python/__init__.py +src/gtk-helpers/config_dialog.c src/gtk-helpers/event_config_dialog.c src/gtk-helpers/secrets.c +src/gtk-helpers/workflow_config_dialog.c src/gui-wizard-gtk/main.c src/gui-wizard-gtk/wizard.c src/gui-wizard-gtk/wizard.glade src/include/internal_libreport.h src/lib/abrt_sock.c +src/lib/client.c src/lib/create_dump_dir.c +src/lib/curl.c src/lib/event_config.c src/lib/parse_options.c -src/lib/curl.c -src/lib/client.c -src/lib/run_event.c src/lib/problem_data.c +src/lib/run_event.c src/plugins/abrt_rh_support.c -src/plugins/report.c src/plugins/report_Bugzilla.xml.in -src/plugins/report_Kerneloops.xml.in -src/plugins/report_Logger.xml.in -src/plugins/report_Mailx.xml.in -src/plugins/report_RHTSupport.xml.in -src/plugins/report_Uploader.xml.in -src/plugins/report_uReport.xml.in +src/plugins/report.c src/plugins/reporter-bugzilla.c src/plugins/reporter-kerneloops.c src/plugins/reporter-mailx.c @@ -35,6 +31,13 @@ src/plugins/reporter-print.c src/plugins/reporter-rhtsupport.c src/plugins/reporter-rhtsupport-parse.c src/plugins/reporter-upload.c +src/plugins/report_Kerneloops.xml.in +src/plugins/report_Logger.xml.in +src/plugins/report_Mailx.xml.in +src/plugins/report_RHTSupport.xml.in +src/plugins/report_Uploader.xml.in +src/plugins/report_uReport.xml.in src/plugins/rhbz.c -src/report-newt/report-newt.c src/plugins/ureport.c +src/report-newt/report-newt.c +src/workflows/report_Fedora.xml.in diff --git a/src/Makefile.am b/src/Makefile.am index 68bd1c0..c15928c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,4 +8,4 @@ if BUILD_NEWT sub_dirs += report-newt endif
-SUBDIRS = include lib plugins report-python cli client-python $(sub_dirs) +SUBDIRS = include lib plugins report-python cli client-python workflows $(sub_dirs) diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c index f256e25..d6697e9 100644 --- a/src/cli/cli-report.c +++ b/src/cli/cli-report.c @@ -617,7 +617,7 @@ char *select_event_option(GList *list_options) if (config) { ++pos;
printf(" %i) %s\n", pos, config->screen_name);
}printf(" %i) %s\n", pos, ec_get_screen_name(config)); }
@@ -717,7 +717,7 @@ int collect(const char *dump_dir_name, int batch) if (!config) VERB1 log("No configuration file found for collector '%s'", collector_name);
printf(" %d) %s\n", i, (config && config->screen_name) ?
config->screen_name : collector_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : collector_name); }
read_from_stdin(_("Select collector(s): "), wanted_collectors,
sizeof(wanted_collectors)); @@ -901,7 +901,7 @@ int report(const char *dump_dir_name, int flags) char *reporter_name = (char *) li->data; event_config_t *config = get_event_config(reporter_name);
printf(" %d) %s\n", i, (config && config->screen_name) ?
config->screen_name : reporter_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : reporter_name); }
read_from_stdin(_("Select reporter(s): "), wanted_reporters,
sizeof(wanted_reporters)); @@ -1007,7 +1007,7 @@ int run_events_chain(const char *dump_dir_name, GList *chain) { char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data." " Do you want to continue?"), - config->screen_name ? config->screen_name : event); + ec_get_screen_name(config) ? ec_get_screen_name(config)
I would add function like ec_get_screen_name_or_default()
: event); const bool response = ask_yesno(msg); free(msg); if (!response) diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am index a821b5d..0d3f9d8 100644 --- a/src/gtk-helpers/Makefile.am +++ b/src/gtk-helpers/Makefile.am @@ -12,7 +12,9 @@ libreport_gtk_la_SOURCES = \ event_config_dialog.c \ secrets.c \ hyperlinks.c \
- autowrapped_label.c
- autowrapped_label.c \
- workflow_config_dialog.c \
- config_dialog.c
libreport_gtk_la_CPPFLAGS = \ -I$(srcdir)/../include \ @@ -20,6 +22,7 @@ libreport_gtk_la_CPPFLAGS = \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -D_GNU_SOURCE
libreport_gtk_la_LDFLAGS = \ -version-info 0:1:0 diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c new file mode 100644 index 0000000..8d09d53 --- /dev/null +++ b/src/gtk-helpers/config_dialog.c @@ -0,0 +1,216 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include <gtk/gtk.h> +#include "internal_libreport_gtk.h"
+enum +{
- COLUMN_UINAME,
- COLUMN_NAME,
- CONFIG_DIALOG,
- NUM_COLUMNS
+};
+enum +{
- TYPE_STR,
- TYPE_POINTER
+};
Just a question. Why do we still use untyped enums? Is there some rationale for doing this?
+GtkListStore *new_conf_liststore()
Shouldn't be there "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
*/
- return gtk_list_store_new(NUM_COLUMNS,
G_TYPE_STRING, /* Event name + description */
G_TYPE_STRING, /* event name */
G_TYPE_POINTER
);
+}
+static const void *get_column_value_from_row(GtkTreeView *treeview, int column, int type) +{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- const void *retval = NULL;
- if (selection)
- {
GtkTreeIter iter;
GtkTreeModel *store = gtk_tree_view_get_model(treeview);
if (gtk_tree_selection_get_selected(selection, &store, &iter) ==
TRUE) + {
GValue value = { 0 };
gtk_tree_model_get_value(store, &iter, column, &value);
switch(type){
case TYPE_STR:
retval = g_value_get_string(&value);
break;
case TYPE_POINTER:
retval = g_value_get_pointer(&value);
}
}
- }
- return retval;
+}
+static void on_row_changed_cb(GtkTreeView *treeview, gpointer user_data) +{
- VERB1 log("activated row: '%s'", (const
char*)get_column_value_from_row(treeview, COLUMN_NAME, TYPE_STR)); +
- const void *dialog = get_column_value_from_row(treeview, CONFIG_DIALOG,
TYPE_POINTER); + gtk_widget_set_sensitive(GTK_WIDGET(user_data), dialog != NULL); +
- /*
- void (*handler)(void) = (void
(*)(void))get_column_value_from_row(treeview, ON_ROWCHANGE_CB, TYPE_POINTER); +
- if (handler == NULL)
return;
- handler();
- */
- /*
- const char *event_name = get_event_name_from_row(treeview);
- if (event_name)
- {
event_config_t *ec = get_event_config(event_name);
gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options !=
NULL); + }
- */
I guess, the commented code above could be deleted.
+}
+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)
- {
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));
- }
+}
+static void on_close_list_cb(GtkWidget *button, gpointer user_data) +{
- GtkWidget *window = (GtkWidget *)user_data;
- gtk_widget_destroy(window);
+}
+void add_item_to_config_liststore(gpointer dialog, gpointer inf, gpointer user_data) +{
- GtkListStore *list_store = (GtkListStore *)user_data;
- config_item_info_t *info = (config_item_info_t *)inf;
- VERB1 log("adding '%s' to workflow list\n", info->screen_name);
- char *label;
- if (ci_get_screen_name(info) != NULL && ci_get_description(info) !=
NULL) + 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)); +
- 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,
-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 *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
- /* workflow list treeview */
- GtkWidget *tv = gtk_tree_view_new();
- /* column with workflow name and description */
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
- /* add column to tree view */
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(column_label,
renderer,
"markup",
COLUMN_UINAME,
NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD, NULL);
- g_object_set(G_OBJECT(renderer), "wrap-width", 440, NULL);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME);
- gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column);
- /* "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... +
- /* 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));
- g_hash_table_foreach(items,
item_to_config_info,
list_store);
+//TODO: can unref workflows_list_store? treeview holds one ref.
- /* Double click/Enter handler */
- //g_signal_connect(workflows_tv, "row-activated",
G_CALLBACK(on_workflow_row_activated_cb), NULL); +
- gtk_container_add(GTK_CONTAINER(scroll), tv);
- 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); +
- GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
- g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_list_cb),
dialog); +
- 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);
- gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10);
- gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
- return main_vbox;
+} diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c index a067511..a2e1085 100644 --- a/src/gtk-helpers/event_config_dialog.c +++ b/src/gtk-helpers/event_config_dialog.c @@ -177,80 +177,6 @@ static void add_option_to_table(gpointer data, gpointer user_data) free(option_label); }
-static void on_close_event_list_cb(GtkWidget *button, gpointer user_data) -{
- GtkWidget *window = (GtkWidget *)user_data;
- gtk_widget_destroy(window);
-}
-static char *get_event_name_from_row(GtkTreeView *treeview) -{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- char *event_name = NULL;
- if (selection)
- {
GtkTreeIter iter;
GtkTreeModel *store = gtk_tree_view_get_model(treeview);
if (gtk_tree_selection_get_selected(selection, &store, &iter) ==
TRUE) - {
GValue value = { 0 };
gtk_tree_model_get_value(store, &iter, COLUMN_EVENT_NAME,
&value); - event_name = (char *)g_value_get_string(&value);
}
- }
- return event_name;
-}
-static void on_configure_event_cb(GtkWidget *button, gpointer user_data) -{
- GtkTreeView *events_tv = (GtkTreeView *)user_data;
- char *event_name = get_event_name_from_row(events_tv);
- if (event_name != NULL)
show_event_config_dialog(event_name, NULL);
- //else
- // error_msg(_("Please select a plugin from the list to edit its
options.")); -}
-static void on_event_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) -{
- char *event_name = get_event_name_from_row(treeview);
- event_config_t *ec = get_event_config(event_name);
- if (ec->options != NULL) //We need to have some options to show
show_event_config_dialog(event_name, NULL);
-}
-static void on_event_row_changed_cb(GtkTreeView *treeview, gpointer user_data) -{
- const char *event_name = get_event_name_from_row(treeview);
- if (event_name)
- {
event_config_t *ec = get_event_config(event_name);
gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options !=
NULL); - } -}
-static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) -{
- GtkListStore *events_list_store = (GtkListStore *)user_data;
- event_config_t *ec = (event_config_t *)value;
- char *event_label;
- if (ec->screen_name != NULL && ec->description != NULL)
event_label = xasprintf("<b>%s</b>\n%s", ec->screen_name,
ec->description); - else
//if event has no xml description
event_label = xasprintf("<b>%s</b>\nNo description available",
key); -
- GtkTreeIter iter;
- gtk_list_store_append(events_list_store, &iter);
- gtk_list_store_set(events_list_store, &iter,
COLUMN_EVENT_UINAME, event_label,
COLUMN_EVENT_NAME, key,
-1);
- free(event_label);
-}
static void save_value_from_widget(gpointer data, gpointer user_data) { option_widget_t *ow = (option_widget_t *)data; @@ -283,43 +209,12 @@ static void dehydrate_config_dialog() g_list_foreach(option_widget_list, &save_value_from_widget, NULL); }
-int show_event_config_dialog(const char *event_name, GtkWindow *parent) +GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *content) {
- if (option_widget_list != NULL)
- {
g_list_free(option_widget_list);
option_widget_list = NULL;
- }
- event_config_t *event = get_event_config(event_name);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ event->screen_name ? event->screen_name
: event_name, - parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- /* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (content == NULL)
content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
//event_config_t *event = get_event_config(event_name);
GtkWidget *option_table = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(option_table), FALSE);
@@ -359,7 +254,6 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) g_signal_connect(pass_store_cb, "toggled", G_CALLBACK(on_show_pass_store_cb), NULL); }
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_box_pack_start(GTK_BOX(content), option_table, false, false, 20);
/* add the adv_option_table to the dialog only if there is some adv
option */ @@ -379,6 +273,103 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) gtk_box_pack_start(GTK_BOX(content), keyring_warn_lbl, false, false, 0); }
- gtk_widget_show_all(content); //make it all visible
- return content;
+}
+GtkWidget *create_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);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ec_get_screen_name(event) ?
ec_get_screen_name(event) : event_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- /* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
- GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- content = create_event_config_dialog_content(event, content);
- return dialog;
+}
+static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) +{
- 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);
+}
+int show_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);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ec_get_screen_name(event) ?
ec_get_screen_name(event) : event_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
/* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
gtk_window_set_resizable(GTK_WINDOW(dialog), true);
gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
if (parent_window != NULL)
{
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
}
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
content = create_event_config_dialog_content(event, content);
gtk_widget_show_all(content);
int result = gtk_dialog_run(GTK_DIALOG(dialog));
@@ -396,31 +387,9 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) return result; }
-void show_events_list_dialog(GtkWindow *parent)
Why not to delete the following function?
+#if 0 +GtkWidget *create_event_list_config_dialog() {
- /*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 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *events_scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(events_scroll),
@@ -448,18 +417,13 @@ void show_events_list_dialog(GtkWindow *parent) gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(events_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_EVENT_UINAME -> name+description
* COLUMN_EVENT_NAME -> event name so we can retrieve it from the row
*/
- GtkListStore *events_list_store = gtk_list_store_new(NUM_COLUMNS,
G_TYPE_STRING, /* Event
name + description */ - G_TYPE_STRING /* event name */ + );
- events_list_store = new_conf_liststore(); gtk_tree_view_set_model(GTK_TREE_VIEW(events_tv),
GTK_TREE_MODEL(events_list_store));
g_hash_table_foreach(g_event_config_list,
&add_event_to_liststore,
&add_event_to_liststore_wrap, events_list_store);
//TODO: can unref events_list_store? treeview holds one ref.
@@ -483,6 +447,37 @@ void show_events_list_dialog(GtkWindow *parent) gtk_box_pack_start(GTK_BOX(main_vbox), events_scroll, true, true, 10); gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
- return main_vbox;
+} +#endif
+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 5cb965c..ff3d653 100644 --- a/src/gtk-helpers/internal_libreport_gtk.h +++ b/src/gtk-helpers/internal_libreport_gtk.h @@ -37,7 +37,7 @@ void show_events_list_dialog(GtkWindow *parent); bool is_event_config_user_storage_available();
#define load_single_event_config_data_from_user_storage libreport_load_single_event_config_data_from_user_storage -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config); +void load_single_event_config_data_from_user_storage(event_config_t *config);
#define load_event_config_data_from_user_storage libreport_load_event_config_data_from_user_storage void load_event_config_data_from_user_storage(GHashTable *event_config_list); @@ -50,6 +50,24 @@ void save_event_config_data_to_user_storage(const char *event_name, #define show_event_config_dialog libreport_show_event_config_dialog 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); + +#define show_workflow_list_dialog libreport_show_workflow_list_dialog +void show_workflow_list_dialog(GtkWindow *parent);
+#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);
+GtkListStore *new_conf_liststore();
char * tag_url(const char* line, const char* prefix);
#define url_token libreport_url_token diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c index 468c508..9de2284 100644 --- a/src/gtk-helpers/secrets.c +++ b/src/gtk-helpers/secrets.c @@ -1378,7 +1378,7 @@ bool is_event_config_user_storage_available()
- @param name Event name
- @param config Event config
*/ -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config) +void load_single_event_config_data_from_user_storage(event_config_t *config) { GHashTable *tmp = g_hash_table_new_full( /*hash_func*/ g_str_hash, @@ -1386,7 +1386,7 @@ void load_single_event_config_data_from_user_storage(const char *event_name, eve /*key_destroy_func:*/ g_free, /*value_destroy_func:*/ NULL);
- g_hash_table_insert(tmp, xstrdup(event_name), config);
g_hash_table_insert(tmp, xstrdup(ec_get_name(config)), config);
load_event_config_data_from_user_storage(tmp);
diff --git a/src/gtk-helpers/workflow_config_dialog.c b/src/gtk-helpers/workflow_config_dialog.c new file mode 100644 index 0000000..acdc81d --- /dev/null +++ b/src/gtk-helpers/workflow_config_dialog.c @@ -0,0 +1,119 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <gtk/gtk.h> +#include "internal_libreport_gtk.h"
+enum +{
- COLUMN_WORKFLOW_UINAME,
- COLUMN_WORKFLOW_NAME,
- NUM_COLUMNS
+};
+static GtkWindow *g_parent_window;
+GtkWidget *create_workflow_config_dialog(const char *workflow_name, GtkWindow *parent) +{
- workflow_t *workflow = get_workflow(workflow_name);
- GList *events = workflow->events;
- GtkWindow *parent_window = parent ? parent : g_parent_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ wf_get_screen_name(workflow) ?
wf_get_screen_name(workflow) : workflow_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
- GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- //GtkWidget *event_conf_widg = NULL;
g_list_foreach() should work
- while(events)
- {
event_config_t *ec = (event_config_t *)events->data;
create_event_config_dialog_content(ec, content);
//gtk_box_pack_start(GTK_BOX(content), event_conf_widg, true, true,
0); + events = g_list_next(events);
- }
- return dialog;
+}
+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); +}
+static void load_single_event_config_foreach(event_config_t *ec, gpointer user_data) +{
- load_single_event_config_data_from_user_storage(ec);
+}
+static void load_events_foreach_workflow(const char *name, workflow_t *workflow, gpointer user_data) +{
- g_list_foreach(wf_get_event_list(workflow),
(GFunc)load_single_event_config_foreach, NULL); +}
+void show_workflow_list_dialog(GtkWindow *parent) +{
- 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));
+} diff --git a/src/gui-wizard-gtk/Makefile.am b/src/gui-wizard-gtk/Makefile.am index ecd1887..46c1d65 100644 --- a/src/gui-wizard-gtk/Makefile.am +++ b/src/gui-wizard-gtk/Makefile.am @@ -19,6 +19,7 @@ report_gtk_CFLAGS = \ -DPLUGINS_LIB_DIR="$(PLUGINS_LIB_DIR)" \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DICON_DIR="${datadir}/abrt/icons/hicolor/48x48/status" \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ $(GLIB_CFLAGS) \ $(GTK_CFLAGS) \ -D_GNU_SOURCE
diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c index fab88f1..1bb9af1 100644 --- a/src/gui-wizard-gtk/main.c +++ b/src/gui-wizard-gtk/main.c @@ -74,6 +74,8 @@ void problem_data_reload_from_dump_dir(void)
int main(int argc, char **argv) {
- bool expert_mode = false;
- const char *prgname = "abrt"; abrt_init(argv);
@@ -110,6 +112,7 @@ int main(int argc, char **argv) OPT_p = 1 << 2, OPT_d = 1 << 3, OPT_e = 1 << 4,
}; /* Keep enum above and order of options below in sync! */ struct options program_options[] = {OPT_x = 1 << 5,
@@ -119,6 +122,7 @@ int main(int argc, char **argv) /* for use from 3rd party apps to show just a reporter selector */ OPT_BOOL( 'd', "delete", NULL, _("Remove DIR after reporting")), OPT_LIST( 'e', "event", &g_auto_event_list, "EVENT", _("Run only this event")), + OPT_BOOL( 'x', "expert", &expert_mode, _("Run wizard in expert mode - shows advanced options")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); @@ -130,6 +134,8 @@ int main(int argc, char **argv) for (GList *elem = g_auto_event_list; elem; elem = g_list_next(elem)) elem->data = xstrdup((const char *)elem->data);
- g_auto_event_list = NULL;
What if somebody passes "-e event" on command line?
export_abrt_envvars(opts & OPT_p);
g_dump_dir_name = xstrdup(argv[0]);
@@ -140,9 +146,11 @@ int main(int argc, char **argv) load_event_config_data_from_user_storage(g_event_config_list); load_user_settings("report-gtk");
- load_workflow_config_data(WORKFLOWS_DIR);
- problem_data_reload_from_dump_dir();
- create_assistant();
create_assistant(expert_mode);
g_custom_logger = &show_error_as_msgbox;
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index f351988..04dc961 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -64,6 +64,7 @@ static GtkWidget *g_btn_close; static GtkWidget *g_btn_next;
static GtkBox *g_box_events; +static GtkBox *g_box_workflows; /* List of event_gui_data's */ static GList *g_list_events; static GtkLabel *g_lbl_event_log; @@ -104,6 +105,9 @@ static GtkImage *g_img_process_ok;
static GtkWidget *g_top_most_window;
+static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func); +static void set_auto_event_chain(GtkButton *button, gpointer user_data); + typedef struct { int page; //which tab in notepad @@ -162,8 +166,8 @@ enum {
- instead of strcmp.
*/ static const gchar PAGE_SUMMARY[] = "page_0"; -static const gchar PAGE_EVENT_SELECTOR[] = "page_2"; -static const gchar PAGE_EDIT_COMMENT[] = "page_1"; +static const gchar PAGE_EVENT_SELECTOR[] = "page_1"; +static const gchar PAGE_EDIT_COMMENT[] = "page_2"; static const gchar PAGE_EDIT_ELEMENTS[] = "page_3"; static const gchar PAGE_REVIEW_DATA[] = "page_4"; static const gchar PAGE_EVENT_PROGRESS[] = "page_5"; @@ -273,12 +277,12 @@ static void show_event_opt_error_dialog(const char *event_name) "reporting will probably fail if you continue " "with the current configuration.\n\n" "Read more about the configuration at: https://fedorahosted.org/abrt/wiki/AbrtConfiguration"), - ec->screen_name);
char *markup_message = xasprintf(_("Wrong settings detected forec_get_screen_name(ec));
<b>%s</b>, " "reporting will probably fail if you continue " "with the current configuration.\n\n" "<a href="https://fedorahosted.org/abrt/wiki/AbrtConfiguration%5C%22%3ERead more about the configuration</a>"), - ec->screen_name);
GtkWidget *wrong_settings = g_top_most_window =ec_get_screen_name(ec));
gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, @@ -292,7 +296,7 @@ static void show_event_opt_error_dialog(const char *event_name) free(markup_message);
GtkWidget *act_area =
gtk_dialog_get_content_area(GTK_DIALOG(wrong_settings)); - char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec->screen_name); + char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec_get_screen_name(ec)); GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(conf_btn_lbl); g_signal_connect(configure_event_btn, "clicked", G_CALLBACK(on_configure_event_cb), (gpointer)event_name); free(conf_btn_lbl); @@ -972,6 +976,7 @@ static char *missing_items_in_comma_list(const char *input_item_list) } return result; }
static event_gui_data_t *add_event_buttons(GtkBox *box, GList **p_event_list, char *event_name, @@ -1016,9 +1021,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (cfg) { /* .xml has (presumably) prettier description, use it: */
if (cfg->screen_name)
event_screen_name = cfg->screen_name;
event_description = cfg->description;
if (ec_get_screen_name(cfg))
event_screen_name = ec_get_screen_name(cfg);
event_description = ec_get_description(cfg); char *missing =
missing_items_in_comma_list(cfg->ec_requires_items); if (missing) @@ -1078,8 +1083,8 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (func) g_signal_connect(G_OBJECT(button), "toggled", func, xstrdup(event_name));
if (cfg && cfg->long_descr)
gtk_widget_set_tooltip_text(button, cfg->long_descr);
if (cfg && ec_get_long_desc(cfg))
gtk_widget_set_tooltip_text(button, ec_get_long_desc(cfg)); event_gui_data_t *event_gui_data = new_event_gui_data_t(); event_gui_data->event_name = xstrdup(event_name);
@@ -1099,7 +1104,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, event_name = event_name_end + 1;
gtk_box_pack_start(box, button, /*expand*/ false, /*fill*/ false,
/*padding*/ 0); + gtk_widget_show_all(GTK_WIDGET(button)); }
gtk_widget_show_all(GTK_WIDGET(box));
return active_button;
} @@ -1316,13 +1323,24 @@ void update_gui_state_from_problem_data(int flags)
load_text_to_text_view(g_tv_comment, FILENAME_COMMENT);
- /* Update event radio buttons */
- event_gui_data_t *active_button = add_event_buttons(
g_box_events,
&g_list_events,
g_events,
G_CALLBACK(event_rb_was_toggled)
- );
add_workflow_buttons(g_box_workflows, g_workflow_list,
G_CALLBACK(set_auto_event_chain));
/* Update event radio buttons
* show them only in expert mode
*/
event_gui_data_t *active_button = NULL;
if (g_expert_mode == true)
{
//this widget doesn't react to show_all, so we need to "force" it
gtk_widget_show(GTK_WIDGET(g_box_events));
active_button = add_event_buttons(
g_box_events,
&g_list_events,
g_events,
G_CALLBACK(event_rb_was_toggled)
);
}
if (flags & UPDATE_SELECTED_EVENT && g_expert_mode) {
@@ -1335,7 +1353,6 @@ void update_gui_state_from_problem_data(int flags) } VERB2 log("g_event_selected='%s'", g_event_selected); }
- /* We can't just do gtk_widget_show_all once in main: * We created new widgets (buttons). Need to make them visible. */
@@ -2400,6 +2417,50 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer us } }
+//static void event_rb_was_toggled(GtkButton *button, gpointer user_data) +static void set_auto_event_chain(GtkButton *button, gpointer user_data) +{
- //event is selected, so make sure the expert mode is disabled
- g_expert_mode = false;
- workflow_t *w = (workflow_t *)user_data;
- config_item_info_t *info = workflow_get_config_info(w);
- VERB1 log("selected workflow '%s'", info->screen_name);
- GList *wf_event_list = wf_get_event_list(w);
- while(wf_event_list)
- {
g_auto_event_list = g_list_append(g_auto_event_list,
xstrdup(ec_get_name(wf_event_list->data))); + load_single_event_config_data_from_user_storage((event_config_t *)wf_event_list->data); +
wf_event_list = g_list_next(wf_event_list);
- }
- gint current_page_no = gtk_notebook_get_current_page(g_assistant);
- gint next_page_no = select_next_page_no(current_page_no, NULL);
- /* if pageno is not change 'switch-page' signal is not emitted */
- if (current_page_no == next_page_no)
on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant,
next_page_no), NULL); + else
gtk_notebook_set_current_page(g_assistant, next_page_no);
+}
+static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func) +{
- GList *keys = g_hash_table_get_keys(g_workflow_list);
- while(keys)
- {
workflow_t *workflow = g_hash_table_lookup(g_workflow_list,
keys->data); + config_item_info_t *info = workflow_get_config_info(workflow); + GtkWidget *button = gtk_button_new_with_label(info->screen_name); + g_signal_connect(button, "clicked", func, workflow);
gtk_box_pack_start(box, button, true, false, 0);
keys = g_list_next(keys);
- }
+}
static char *setup_next_processed_event(GList **events_list) { free(g_event_selected); @@ -2431,7 +2492,7 @@ static bool get_sensitive_data_permission(const char *event_name)
char *msg = xasprintf(_("Event '%s' requires permission to send
possibly sensitive data." "\nDo you want to continue?"),
event_cfg->screen_name ? event_cfg->screen_name
: event_name); + ec_get_screen_name(event_cfg) ? ec_get_screen_name(event_cfg) : event_name); const bool response = ask_yes_no_save_result(msg, "ask_send_sensitive_data"); free(msg);
@@ -2449,6 +2510,11 @@ static gint select_next_page_no(gint current_page_no, gpointer data)
if (pages[PAGENO_EVENT_SELECTOR].page_widget == page) {
if (!g_expert_mode && (g_auto_event_list == NULL))
{
return current_page_no; //stay here and let user select the
workflow + }
if (!g_expert_mode) { /* (note: this frees and sets to NULL g_event_selected) */
@@ -2881,6 +2947,7 @@ static void add_pages(void) /* Set pointers to objects we might need to work with */ g_lbl_cd_reason = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_cd_reason")); g_box_events = GTK_BOX( gtk_builder_get_object(g_builder, "vb_events")); + g_box_workflows = GTK_BOX( gtk_builder_get_object(g_builder, "vb_workflows")); g_lbl_event_log = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_event_log")); g_tv_event_log = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_event_log")); g_tv_comment = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_comment")); @@ -2989,7 +3056,7 @@ static void init_page(page_obj_t *page, const char *name, const char *title) static void init_pages(void) { init_page(&pages[0], PAGE_SUMMARY , _("Problem description") ); - init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select operation") ); + init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select how to report this problem")); init_page(&pages[2], PAGE_EDIT_COMMENT,_("Provide additional information")); init_page(&pages[3], PAGE_EDIT_ELEMENTS , _("Review the data") ); init_page(&pages[4], PAGE_REVIEW_DATA , _("Confirm data to report")); @@ -3005,11 +3072,11 @@ static void assistant_quit_cb(void *obj, void *data) gtk_main_quit(); }
-void create_assistant(void) +void create_assistant(bool expert_mode) { g_loaded_texts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
- g_expert_mode = !g_auto_event_list;
g_expert_mode = expert_mode;
g_monospace_font = pango_font_description_from_string("monospace"); g_builder = gtk_builder_new();
diff --git a/src/gui-wizard-gtk/wizard.glade b/src/gui-wizard-gtk/wizard.glade index 53e215e..15a5697 100644 --- a/src/gui-wizard-gtk/wizard.glade +++ b/src/gui-wizard-gtk/wizard.glade @@ -83,7 +83,7 @@
<object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_1"> + <object class="GtkVBox" id="page_2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> @@ -177,15 +177,31 @@ <object class="GtkWindow" id="window2"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_2"> + <object class="GtkVBox" id="page_1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> <property name="spacing">3</property> <child> + <object class="GtkBox" id="vb_workflows"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> <object class="GtkVBox" id="vb_events"> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="no_show_all">True</property> <child> <placeholder/> </child> diff --git a/src/gui-wizard-gtk/wizard.h b/src/gui-wizard-gtk/wizard.h index d2caaa6..a6d8b5d 100644 --- a/src/gui-wizard-gtk/wizard.h +++ b/src/gui-wizard-gtk/wizard.h @@ -21,7 +21,7 @@
#include "internal_libreport_gtk.h"
-void create_assistant(void); +void create_assistant(bool expert_mode);
enum { diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 948662e..a4dc133 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -7,7 +7,9 @@ libreport_include_HEADERS = \ report.h \ run_event.h \ libreport_curl.h \
- workflow.h \ \
- config_item_info.h \ file_obj.h \ internal_libreport.h \ internal_abrt_dbus.h
diff --git a/src/include/config_item_info.h b/src/include/config_item_info.h new file mode 100644 index 0000000..ac49bd5 --- /dev/null +++ b/src/include/config_item_info.h @@ -0,0 +1,45 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#ifndef LIBREPORT_CONFIG_ITEM_H +#define LIBREPORT_CONFIG_ITEM_H
+typedef struct +{
- char *name; //the event name (from it's filename)
- char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat
Support Upload" + char *description; // "Report to..."/"Save to file". Should be one sentence, not long + char *long_desc; // Long(er) explanation, if needed
+} config_item_info_t;
+config_item_info_t *new_config_info();
hmm, missing void?
+void free_config_info(config_item_info_t *info);
+void ci_set_screen_name(config_item_info_t *ci, const char *screen_name); +void ci_set_name(config_item_info_t *ci, const char *name); +void ci_set_description(config_item_info_t *ci, const char *description); +void ci_set_long_desc(config_item_info_t *ci, const char *long_description); + +const char *ci_get_screen_name(config_item_info_t *ci); +const char *ci_get_name(config_item_info_t *ci); +const char *ci_get_description(config_item_info_t *ci); +const char *ci_get_long_desc(config_item_info_t *ci);
+#endif diff --git a/src/include/event_config.h b/src/include/event_config.h index 438c723..60fa5c6 100644 --- a/src/include/event_config.h +++ b/src/include/event_config.h @@ -22,6 +22,7 @@ #include <stdbool.h> #include <glib.h> #include "problem_data.h" +#include "config_item_info.h"
#ifdef __cplusplus extern "C" { @@ -68,10 +69,7 @@ void free_event_option(event_option_t *p); //structure to hold the option data typedef struct {
- char *name; //the event name (from it's filename)
- char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat
Support Upload" - char *description; // "Report to..."/"Save to file". Should be one sentence, not long - char *long_descr; // Long(er) explanation, if needed
config_item_info_t *info;
char *ec_creates_items; char *ec_requires_items;
@@ -87,6 +85,18 @@ typedef struct } event_config_t;
event_config_t *new_event_config(void); +config_item_info_t *ec_get_config_info(event_config_t * ec); +const char *ec_get_screen_name(event_config_t *ec); +void ec_set_screen_name(event_config_t *ec, const char *screen_name); +void ec_set_name(event_config_t *ec, const char *name);
+const char *ec_get_description(event_config_t *ec); +void ec_set_description(event_config_t *ec, const char *description);
+const char *ec_get_name(event_config_t *ec); +const char *ec_get_long_desc(event_config_t *ec); +void ec_set_long_desc(event_config_t *ec, const char *long_desc);
void free_event_config(event_config_t *p);
@@ -99,6 +109,7 @@ 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);
extern GHashTable *g_event_config_list; // for iterating through entire list of all loaded configs
GList *export_event_config(const char *event_name); diff --git a/src/include/file_obj.h b/src/include/file_obj.h index 9cb293f..08823af 100644 --- a/src/include/file_obj.h +++ b/src/include/file_obj.h @@ -24,6 +24,8 @@ typedef struct file_obj * e.g: * if fullpath is: /foo/bar/report_Bugzilla.xml * then filename is: report_Bugzilla
* in case of symlink the filename is created from the symlink name
char *filename; char *fullpath; //the full path with extension* and the fullpath is the symlink target */
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h index d22bcbe..4f85b2a 100644 --- a/src/include/internal_libreport.h +++ b/src/include/internal_libreport.h @@ -93,6 +93,7 @@ int vdprintf(int d, const char *format, va_list ap); #include "problem_data.h" #include "report.h" #include "run_event.h" +#include "workflow.h" #include "file_obj.h"
#ifdef __cplusplus @@ -642,6 +643,8 @@ void free_file_list(GList *filelist); 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);
/* 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/include/workflow.h b/src/include/workflow.h new file mode 100644 index 0000000..dc2768c --- /dev/null +++ b/src/include/workflow.h @@ -0,0 +1,51 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef LIBREPORT_WORKFLOW_H +#define LIBREPORT_WORKFLOW_H
+#include <glib.h> +#include "event_config.h" +#include "config_item_info.h"
+typedef struct +{
- config_item_info_t *info;
- GList *events; //list of event_option_t
+} workflow_t;
+extern GHashTable *g_workflow_list;
+workflow_t *new_workflow(void); +workflow_t *get_workflow(const char *name); +void free_workflow(workflow_t *w);
+void load_workflow_description_from_file(workflow_t *w, const char *filename); +config_item_info_t *workflow_get_config_info(workflow_t *w); +const char *wf_get_name(workflow_t *w); +GList *wf_get_event_list(workflow_t *w); +const char *wf_get_screen_name(workflow_t *w); +const char *wf_get_description(workflow_t *w); +const char *wf_get_long_desc(workflow_t *w);
+void wf_set_name(workflow_t *w, const char* name); +void wf_set_description(workflow_t *w, const char* description); +void wf_set_long_desc(workflow_t *w, const char* long_desc);
+#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2865624..dad9f89 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -49,7 +49,10 @@ libreport_la_SOURCES = \ client.c \ utf8.c \ file_list.c \
- file_obj.c
- file_obj.c \
- workflow.c \
- workflow_xml_parser.c \
- config_item_info.c
libreport_la_CPPFLAGS = \ -I$(srcdir)/../include \ -DLOCALSTATEDIR='"$(localstatedir)"' \ @@ -59,6 +62,7 @@ libreport_la_CPPFLAGS = \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DCONF_DIR="$(CONF_DIR)" \ -DEVENTS_DIR="$(EVENTS_DIR)" \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -DBIN_DIR="$(bindir)" \ $(GLIB_CFLAGS) \ -D_GNU_SOURCE
diff --git a/src/lib/config_item_info.c b/src/lib/config_item_info.c new file mode 100644 index 0000000..c8e2d78 --- /dev/null +++ b/src/lib/config_item_info.c @@ -0,0 +1,85 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include "internal_libreport.h" +//#include "config_item_info.h"
+config_item_info_t *new_config_info()
mising void
+{
- config_item_info_t *info = (config_item_info_t
*)xzalloc(sizeof(config_item_info_t)); + return info;
sizeof(*info)
+}
+void free_config_info(config_item_info_t *info) +{
- if (info == NULL)
return;
- free(info->name);
- free(info->screen_name);
- free(info->description);
- free(info->long_desc);
- free(info);
+}
+void ci_set_screen_name(config_item_info_t *ci, const char *screen_name) +{
- free(ci->screen_name);
- ci->screen_name = xstrdup(screen_name);
+}
+void ci_set_name(config_item_info_t *ci, const char *name) +{
- free(ci->name);
- ci->name = xstrdup(name);
+}
+void ci_set_description(config_item_info_t *ci, const char *description) +{
- free(ci->description);
- ci->description = xstrdup(description);
+}
+void ci_set_long_desc(config_item_info_t *ci, const char *long_description) +{
- free(ci->long_desc);
- ci->long_desc = xstrdup(long_description);
+}
+const char *ci_get_screen_name(config_item_info_t *ci) +{
- return ci->screen_name;
+}
+const char *ci_get_name(config_item_info_t *ci) +{
- return ci->name;
+}
+const char *ci_get_description(config_item_info_t *ci) +{
- return ci->description;
+}
+const char *ci_get_long_desc(config_item_info_t *ci) +{
- return ci->long_desc;
+} diff --git a/src/lib/event_config.c b/src/lib/event_config.c index 2019e53..402a09f 100644 --- a/src/lib/event_config.c +++ b/src/lib/event_config.c @@ -16,6 +16,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "internal_libreport.h"
GHashTable *g_event_config_list; @@ -29,9 +30,55 @@ event_option_t *new_event_option(void) event_config_t *new_event_config(void) { event_config_t *e = xzalloc(sizeof(event_config_t));
- e->info = new_config_info(); return e;
}
+config_item_info_t *ec_get_config_info(event_config_t * ec) +{
- return ec->info;
+}
+void ec_set_name(event_config_t *ec, const char *name) +{
- ci_set_name(ec->info, name);
+}
+void ec_set_screen_name(event_config_t *ec, const char *screen_name) +{
- ci_set_screen_name(ec->info, screen_name);
+}
+const char *ec_get_screen_name(event_config_t *ec) +{
- return ci_get_screen_name(ec->info);
+}
+const char *ec_get_description(event_config_t *ec) +{
- return ci_get_description(ec->info);
+}
+void ec_set_description(event_config_t *ec, const char *description) +{
- ci_set_description(ec->info, description);
+}
+const char *ec_get_name(event_config_t *ec) +{
- return ci_get_name(ec->info);
+}
+const char *ec_get_long_desc(event_config_t *ec) +{
- return ci_get_long_desc(ec->info);
+}
+void ec_set_long_desc(event_config_t *ec, const char *long_descr) +{
- ci_set_long_desc(ec->info, long_descr);
+}
void free_event_option(event_option_t *p) { if (!p) @@ -50,9 +97,7 @@ void free_event_config(event_config_t *p) if (!p) return;
- free(p->screen_name);
- free(p->description);
- free(p->long_descr);
- free_config_info(p->info); free(p->ec_creates_items); free(p->ec_requires_items); free(p->ec_exclude_items_by_default);
diff --git a/src/lib/event_xml_parser.c b/src/lib/event_xml_parser.c index 157b717..585e2e5 100644 --- a/src/lib/event_xml_parser.c +++ b/src/lib/event_xml_parser.c @@ -336,11 +336,11 @@ static void text(GMarkupParseContext *context, * OR the label is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->screen_name /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_screen_name(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) { VERB2 log("event name:'%s'", text_copy);
free(ui->screen_name);
ui->screen_name = text_copy;
ec_set_screen_name(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -355,10 +355,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->description /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_description(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) {
free(ui->description);
ui->description = text_copy;
ec_set_description(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -373,10 +373,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->long_descr /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_long_desc(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) {
free(ui->long_descr);
ui->long_descr = text_copy;
ec_set_long_desc(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -463,6 +463,7 @@ static void error(GMarkupParseContext *context,
void load_event_description_from_file(event_config_t *event_config, const char* filename) {
- VERB1 log("loading event: '%s'", filename); struct my_parse_data parse_data = { event_config, NULL, NULL, NULL }; parse_data.cur_locale = setlocale(LC_ALL, NULL);
diff --git a/src/lib/workflow.c b/src/lib/workflow.c new file mode 100644 index 0000000..9b17a73 --- /dev/null +++ b/src/lib/workflow.c @@ -0,0 +1,146 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include "event_config.h" +#include "workflow.h" +#include "internal_libreport.h"
+GHashTable *g_workflow_list;
+workflow_t *new_workflow(void) +{
- workflow_t *w = xzalloc(sizeof(event_config_t));
sizeof(*w)
- w->info = new_config_info();
- return w;
+}
+void free_workflow(workflow_t *w) +{
- if (!w)
return;
- free_config_info(w->info);
- g_list_free_full(w->events, (GDestroyNotify)free_event_config);
- free(w);
- w = NULL;
the last line is not necessary
+}
+static void free_workflow_cb(const char *name, workflow_t *w, gpointer user_data) +{
- free_workflow(w);
+}
+void free_workflow_list(GHashTable *wl) +{
- g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL);
- g_hash_table_destroy(wl);
- wl = NULL;
the last line is not necessary
+}
+workflow_t *get_workflow(const char *name) +{
- if (!g_workflow_list)
return NULL;
- /* @@ FIXME: SYMLINKS@!!!
- if (g_event_config_symlinks)
- {
char *link = g_hash_table_lookup(g_event_config_symlinks, name);
if (link)
name = link;
- }
- */
- return g_hash_table_lookup(g_workflow_list, name);
+}
+void load_workflow_config_data(const char* path) +{
- if (g_workflow_list == NULL)
- {
g_workflow_list = g_hash_table_new_full(
g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) free_workflow
);
- }
- GList *workflow_files = get_file_list(path, "xml");
- while(workflow_files)
- {
file_obj_t *file = (file_obj_t *)workflow_files->data;
workflow_t *workflow = get_workflow(file->filename);
bool nw_workflow = (!workflow);
if (nw_workflow)
workflow = new_workflow();
load_workflow_description_from_file(workflow, file->fullpath);
if (nw_workflow)
g_hash_table_replace(g_workflow_list, xstrdup(file->filename),
workflow); +
workflow_files = g_list_next(workflow_files);
- }
- free_file_list(workflow_files);
+}
+config_item_info_t *workflow_get_config_info(workflow_t *w) +{
- return w->info;
+}
+GList *wf_get_event_list(workflow_t *w) +{
- return w->events;
+}
+const char *wf_get_name(workflow_t *w) +{
- return ci_get_name(workflow_get_config_info(w));
+}
+const char *wf_get_screen_name(workflow_t *w) +{
- return ci_get_screen_name(workflow_get_config_info(w));
+}
+const char *wf_get_description(workflow_t *w) +{
- return ci_get_description(workflow_get_config_info(w));
+}
+const char *wf_get_long_desc(workflow_t *w) +{
- return ci_get_long_desc(workflow_get_config_info(w));
+}
+void wf_set_name(workflow_t *w, const char* name) +{
- ci_set_name(workflow_get_config_info(w), name);
+}
+void wf_set_description(workflow_t *w, const char* description) +{
- ci_set_description(workflow_get_config_info(w), description);
+}
+void wf_set_long_desc(workflow_t *w, const char* long_desc) +{
- ci_set_long_desc(workflow_get_config_info(w), long_desc);
+} diff --git a/src/lib/workflow_xml_parser.c b/src/lib/workflow_xml_parser.c new file mode 100644 index 0000000..abea00b --- /dev/null +++ b/src/lib/workflow_xml_parser.c @@ -0,0 +1,173 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "workflow.h" +#include "internal_libreport.h"
+//workflow elements +#define WORKFLOW_ELEMENT "workflow" +#define EVENTS_ELEMENT "events" +#define EVENT_ELEMENT "event" +#define DESCRIPTION_ELEMENT "description" +#define NAME_ELEMENT "name"
+struct my_parse_data +{
- workflow_t *workflow;
- const char *cur_locale;
- char *attribute_lang;
- bool in_event_list;
+};
+static void start_element(GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
+{
- //log("start: %s", element_name);
- struct my_parse_data *parse_data = user_data;
- if (strcmp(element_name, EVENTS_ELEMENT) == 0)
- {
parse_data->in_event_list = true;
- }
+}
+// Called for close tags </foo> +static void end_element(GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
+{
- struct my_parse_data *parse_data = user_data;
- free(parse_data->attribute_lang);
- parse_data->attribute_lang = NULL;
- if (strcmp(element_name, EVENT_ELEMENT) == 0)
- {
if (parse_data->in_event_list == true)
{
//pass
can't find any reasonable explanation
}
- }
- if (strcmp(element_name, EVENTS_ELEMENT) == 0)
- {
parse_data->in_event_list = false;
- }
+}
+// Called for character data +// text is not nul-terminated +static void text(GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
+{
- struct my_parse_data *parse_data = user_data;
- workflow_t *workflow = parse_data->workflow;
- const gchar *inner_element =
g_markup_parse_context_get_element(context); +
- if(parse_data->in_event_list && strcmp(inner_element, EVENT_ELEMENT) ==
- {
event_config_t *ec = new_event_config();
char *subevent_filename = xasprintf(EVENTS_DIR"/%s.xml", text);
load_event_description_from_file(ec, subevent_filename);
//HACK: need to make ec = NULL if the loading fails
if (ec_get_screen_name(ec))
{
workflow->events = g_list_append(workflow->events, ec);
VERB2 log("added to ev list: '%s'", ec_get_screen_name(ec));
}
ec_set_name(ec, text);
free(subevent_filename);
lost reference on ec if ec_get_screen_name() returned NULL
- }
- if(strcmp(inner_element, NAME_ELEMENT) == 0)
- {
workflow->info->screen_name = xstrdup(text);
- }
- if(strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
- {
workflow->info->description = xstrdup(text);
- }
+}
- // Called for strings that should be re-saved verbatim in this same
- // position, but are not otherwise interpretable. At the moment
- // this includes comments and processing instructions.
- // text is not nul-terminated
+static void passthrough(GMarkupParseContext *context,
const gchar *passthrough_text,
gsize text_len,
gpointer user_data,
GError **error)
+{
- VERB3 log("passthrough");
+}
+// Called on error, including one set by other +// methods in the vtable. The GError should not be freed. +static void error(GMarkupParseContext *context,
GError *error,
gpointer user_data)
+{
- error_msg("error in XML parsing");
+}
+void load_workflow_description_from_file(workflow_t *workflow, const char* filename) +{
- VERB1 log("loading workflow: '%s'", filename);
- struct my_parse_data parse_data = { workflow, NULL, NULL, 0};
- parse_data.cur_locale = setlocale(LC_ALL, NULL);
- GMarkupParser parser;
- memset(&parser, 0, sizeof(parser)); /* just in case */
- parser.start_element = &start_element;
- parser.end_element = &end_element;
- parser.text = &text;
- parser.passthrough = &passthrough;
- parser.error = &error;
- GMarkupParseContext *context = g_markup_parse_context_new(
&parser, G_MARKUP_TREAT_CDATA_AS_TEXT,
&parse_data, /*GDestroyNotify:*/ NULL);
- FILE* fin = fopen(filename, "r");
- if (fin != NULL)
- {
size_t read_bytes;
char buff[1024];
while ((read_bytes = fread(buff, 1, 1024, fin)) != 0)
fread(buff, 1, sizeof(buf), fin) instead of fread(buff, 1, 1024, fin)
I guess, we have some xfunc which do that work.
{
g_markup_parse_context_parse(context, buff, read_bytes, NULL);
}
fclose(fin);
- }
- g_markup_parse_context_free(context);
- free(parse_data.attribute_lang); /* just in case */
+} diff --git a/src/report-newt/report-newt.c b/src/report-newt/report-newt.c index 8532e82..44d30bd 100644 --- a/src/report-newt/report-newt.c +++ b/src/report-newt/report-newt.c @@ -60,8 +60,8 @@ static int select_reporters(GArray *reporters) { struct reporter *r = &g_array_index(reporters, struct reporter, i);
checkboxes[i] = newtCheckbox(20, i + 1, r->config &&
r->config->screen_name ? - r->config->screen_name : r->name, 0, NULL, NULL); + checkboxes[i] = newtCheckbox(20, i + 1, r->config && ec_get_screen_name(r->config) ? + ec_get_screen_name(r->config) : r->name, 0, NULL, NULL); newtGridSetField(cgrid, 0, i, NEWT_GRID_COMPONENT, checkboxes[i], 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); }
@@ -104,8 +104,8 @@ static int configure_reporter(struct reporter *r, bool skip_if_valid) while ((error_table = validate_event(r->name)) || (!skip_if_valid && first && r->config)) {
text = newtTextboxReflowed(0, 0, r->config->screen_name ?
r->config->screen_name : r->name, 35, 5, 5, 0);
text = newtTextboxReflowed(0, 0, ec_get_screen_name(r->config) ?
xstrdup(ec_get_screen_name(r->config)) : r->name, 35, 5, 5,
0);
num_opts = g_list_length(r->config->options); options = xmalloc(sizeof (newtComponent) * num_opts);
diff --git a/src/workflows/Makefile.am b/src/workflows/Makefile.am new file mode 100644 index 0000000..28dc024 --- /dev/null +++ b/src/workflows/Makefile.am @@ -0,0 +1,10 @@ +workflowsdir = $(WORKFLOWS_DIR)
+dist_workflows_DATA = \
- report_Fedora.xml \
- report_fedora.conf
+@INTLTOOL_XML_RULE@
+EXTRA_DIST = \
- report_Fedora.xml.in
diff --git a/src/workflows/report_Fedora.xml.in b/src/workflows/report_Fedora.xml.in new file mode 100644 index 0000000..f9df177 --- /dev/null +++ b/src/workflows/report_Fedora.xml.in @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<workflow>
- <_name>Report to Fedora</_name>
- <_description>Process the report using the Fedora
infrastructure</_description> +
<events>
<event>report_uReport</event>
<event>collect_*</event>
<event>analyze_CCpp</event>
<event>report_Bugzilla</event>
<event>post_report</event>
</events>
+</workflow> diff --git a/src/workflows/report_fedora.conf b/src/workflows/report_fedora.conf new file mode 100644 index 0000000..9dd86ce --- /dev/null +++ b/src/workflows/report_fedora.conf @@ -0,0 +1,3 @@ +EVENT=report_Fedora analyzer=CCpp +# this is just a meta event which consists of other events +# the list is defined in the xml file
On 11/22/2012 06:21 PM, Jakub Filak wrote:
Notes:
- Forward button is always visible and does nothing
- fixed
- The main page looks weird to me
- improved (hopefully)
On Thursday 22 of November 2012 16:51:43 Jiri Moskovcak wrote:
configure.ac | 3 + libreport.spec.in | 16 ++ po/POTFILES.in | 27 +-- src/Makefile.am | 2 +- src/cli/cli-report.c | 8 +- src/gtk-helpers/Makefile.am | 5 +- src/gtk-helpers/config_dialog.c | 216 ++++++++++++++++++++++++ src/gtk-helpers/event_config_dialog.c | 279 +++++++++++++++---------------- src/gtk-helpers/internal_libreport_gtk.h | 20 ++- src/gtk-helpers/secrets.c | 4 +- src/gtk-helpers/workflow_config_dialog.c | 119 +++++++++++++ src/gui-wizard-gtk/Makefile.am | 1 + src/gui-wizard-gtk/main.c | 10 +- src/gui-wizard-gtk/wizard.c | 111 +++++++++--- src/gui-wizard-gtk/wizard.glade | 20 ++- src/gui-wizard-gtk/wizard.h | 2 +- src/include/Makefile.am | 2 + src/include/config_item_info.h | 45 +++++ src/include/event_config.h | 19 ++- src/include/file_obj.h | 2 + src/include/internal_libreport.h | 3 + src/include/workflow.h | 51 ++++++ src/lib/Makefile.am | 6 +- src/lib/config_item_info.c | 85 ++++++++++ src/lib/event_config.c | 51 +++++- src/lib/event_xml_parser.c | 19 ++- src/lib/workflow.c | 146 ++++++++++++++++ src/lib/workflow_xml_parser.c | 173 +++++++++++++++++++ src/report-newt/report-newt.c | 8 +- src/workflows/Makefile.am | 10 ++ src/workflows/report_Fedora.xml.in | 13 ++ src/workflows/report_fedora.conf | 3 + 32 files changed, 1269 insertions(+), 210 deletions(-) create mode 100644 src/gtk-helpers/config_dialog.c create mode 100644 src/gtk-helpers/workflow_config_dialog.c create mode 100644 src/include/config_item_info.h create mode 100644 src/include/workflow.h create mode 100644 src/lib/config_item_info.c create mode 100644 src/lib/workflow.c create mode 100644 src/lib/workflow_xml_parser.c create mode 100644 src/workflows/Makefile.am create mode 100644 src/workflows/report_Fedora.xml.in create mode 100644 src/workflows/report_fedora.conf
diff --git a/configure.ac b/configure.ac index 07b3cf8..1607880 100644 --- a/configure.ac +++ b/configure.ac @@ -176,6 +176,7 @@ PLUGINS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/plugins' REPORT_PLUGINS_CONF_DIR='${sysconfdir}/libreport/plugins' EVENTS_DIR='${sysconfdir}/${PACKAGE_NAME}/events' EVENTS_CONF_DIR='${sysconfdir}/${PACKAGE_NAME}/events.d' +WORKFLOWS_DIR='${sysconfdir}/${PACKAGE_NAME}/workflows'
Is it possible to keep names of the configuration directories consistent? (suffix ".d")
- ok, xml files are in workflows/ - conf files in workflows.d - please note that the conf files are actually events
PLUGINS_LIB_DIR='${libdir}/${PACKAGE_NAME}' LIBEXEC_DIR='${libexecdir}'
@@ -195,6 +196,7 @@ AC_SUBST(EVENTS_DIR) AC_SUBST(PLUGINS_LIB_DIR) AC_SUBST(DEBUG_DUMPS_DIR) AC_SUBST(LIBEXEC_DIR) +AC_SUBST(WORKFLOWS_DIR)
# Initialize the test suite. AC_CONFIG_TESTDIR(tests) @@ -222,6 +224,7 @@ AC_CONFIG_FILES([ src/client-python/Makefile po/Makefile.in doc/Makefile
src/workflows/Makefile ])
# src/plugins/Makefile
diff --git a/libreport.spec.in b/libreport.spec.in index 8eefb3d..018b39d 100644 --- a/libreport.spec.in +++ b/libreport.spec.in @@ -217,6 +217,15 @@ Obsoletes: report-config-scp < 0:0.23-1 %description plugin-reportuploader Plugin to report bugs into anonymous FTP site associated with ticketing system.
+%package fedora +Summary: Default configuration for reporting bugs via Fedora infrastructure +Group: Applications/File
+%description fedora +Default configuration for reporting bugs via Fedora infrastructure +used to easy configure the reporting process for Fedora sytems. Just +install this package and you're done.
- %prep %setup -q
@@ -290,6 +299,8 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_includedir}/libreport/report.h %{_includedir}/libreport/run_event.h %{_includedir}/libreport/file_obj.h +%{_includedir}/libreport/config_item_info.h +%{_includedir}/libreport/workflow.h # Private api headers: %{_includedir}/libreport/internal_abrt_dbus.h %{_includedir}/libreport/internal_libreport.h @@ -393,6 +404,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %{_sysconfdir}/libreport/events/report_Uploader.xml %config(noreplace) %{_sysconfdir}/libreport/events.d/uploader_event.conf
+%files fedora +%defattr(-,root,root,-) +%{_sysconfdir}/libreport/workflows/report_Fedora.xml +%{_sysconfdir}/libreport/workflows/report_fedora.conf
Mark the lines with %config(noreplace) https://bugzilla.redhat.com/show_bug.cgi?id=875260
- fixed
- %changelog
- Wed Nov 14 2012 Jakub Filak jfilak@redhat.com 2.0.19-1
- bugzilla_format[_libreport].conf: emit truncated backtrace into its own
paragraph diff --git a/po/POTFILES.in b/po/POTFILES.in index 668c526..90d4285 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,31 +3,27 @@ # Please keep this file sorted alphabetically. src/cli/cli.c src/cli/cli-report.c -src/client-python/__init__.py src/client-python/debuginfo.py +src/client-python/__init__.py +src/gtk-helpers/config_dialog.c src/gtk-helpers/event_config_dialog.c src/gtk-helpers/secrets.c +src/gtk-helpers/workflow_config_dialog.c src/gui-wizard-gtk/main.c src/gui-wizard-gtk/wizard.c src/gui-wizard-gtk/wizard.glade src/include/internal_libreport.h src/lib/abrt_sock.c +src/lib/client.c src/lib/create_dump_dir.c +src/lib/curl.c src/lib/event_config.c src/lib/parse_options.c -src/lib/curl.c -src/lib/client.c -src/lib/run_event.c src/lib/problem_data.c +src/lib/run_event.c src/plugins/abrt_rh_support.c -src/plugins/report.c src/plugins/report_Bugzilla.xml.in -src/plugins/report_Kerneloops.xml.in -src/plugins/report_Logger.xml.in -src/plugins/report_Mailx.xml.in -src/plugins/report_RHTSupport.xml.in -src/plugins/report_Uploader.xml.in -src/plugins/report_uReport.xml.in +src/plugins/report.c src/plugins/reporter-bugzilla.c src/plugins/reporter-kerneloops.c src/plugins/reporter-mailx.c @@ -35,6 +31,13 @@ src/plugins/reporter-print.c src/plugins/reporter-rhtsupport.c src/plugins/reporter-rhtsupport-parse.c src/plugins/reporter-upload.c +src/plugins/report_Kerneloops.xml.in +src/plugins/report_Logger.xml.in +src/plugins/report_Mailx.xml.in +src/plugins/report_RHTSupport.xml.in +src/plugins/report_Uploader.xml.in +src/plugins/report_uReport.xml.in src/plugins/rhbz.c -src/report-newt/report-newt.c src/plugins/ureport.c +src/report-newt/report-newt.c +src/workflows/report_Fedora.xml.in diff --git a/src/Makefile.am b/src/Makefile.am index 68bd1c0..c15928c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,4 +8,4 @@ if BUILD_NEWT sub_dirs += report-newt endif
-SUBDIRS = include lib plugins report-python cli client-python $(sub_dirs) +SUBDIRS = include lib plugins report-python cli client-python workflows $(sub_dirs) diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c index f256e25..d6697e9 100644 --- a/src/cli/cli-report.c +++ b/src/cli/cli-report.c @@ -617,7 +617,7 @@ char *select_event_option(GList *list_options) if (config) { ++pos;
printf(" %i) %s\n", pos, config->screen_name);
printf(" %i) %s\n", pos, ec_get_screen_name(config)); } }
@@ -717,7 +717,7 @@ int collect(const char *dump_dir_name, int batch) if (!config) VERB1 log("No configuration file found for collector '%s'", collector_name);
printf(" %d) %s\n", i, (config && config->screen_name) ?
config->screen_name : collector_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : collector_name); }
read_from_stdin(_("Select collector(s): "), wanted_collectors,
sizeof(wanted_collectors)); @@ -901,7 +901,7 @@ int report(const char *dump_dir_name, int flags) char *reporter_name = (char *) li->data; event_config_t *config = get_event_config(reporter_name);
printf(" %d) %s\n", i, (config && config->screen_name) ?
config->screen_name : reporter_name); + printf(" %d) %s\n", i, (config && ec_get_screen_name(config)) ? ec_get_screen_name(config) : reporter_name); }
read_from_stdin(_("Select reporter(s): "), wanted_reporters,
sizeof(wanted_reporters)); @@ -1007,7 +1007,7 @@ int run_events_chain(const char *dump_dir_name, GList *chain) { char *msg = xasprintf(_("Event '%s' requires permission to send possibly sensitive data." " Do you want to continue?"), - config->screen_name ? config->screen_name : event); + ec_get_screen_name(config) ? ec_get_screen_name(config)
I would add function like ec_get_screen_name_or_default()
- I would rather do it in next separate patch
: event); const bool response = ask_yesno(msg); free(msg); if (!response) diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am index a821b5d..0d3f9d8 100644 --- a/src/gtk-helpers/Makefile.am +++ b/src/gtk-helpers/Makefile.am @@ -12,7 +12,9 @@ libreport_gtk_la_SOURCES = \ event_config_dialog.c \ secrets.c \ hyperlinks.c \
- autowrapped_label.c
autowrapped_label.c \
workflow_config_dialog.c \
config_dialog.c
libreport_gtk_la_CPPFLAGS = \ -I$(srcdir)/../include \
@@ -20,6 +22,7 @@ libreport_gtk_la_CPPFLAGS = \ $(GTK_CFLAGS) \ $(GLIB_CFLAGS) \ $(GIO_CFLAGS) \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -D_GNU_SOURCE libreport_gtk_la_LDFLAGS = \ -version-info 0:1:0
diff --git a/src/gtk-helpers/config_dialog.c b/src/gtk-helpers/config_dialog.c new file mode 100644 index 0000000..8d09d53 --- /dev/null +++ b/src/gtk-helpers/config_dialog.c @@ -0,0 +1,216 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include <gtk/gtk.h> +#include "internal_libreport_gtk.h"
+enum +{
- COLUMN_UINAME,
- COLUMN_NAME,
- CONFIG_DIALOG,
- NUM_COLUMNS
+};
+enum +{
- TYPE_STR,
- TYPE_POINTER
+};
Just a question. Why do we still use untyped enums? Is there some rationale for doing this?
- don't know, I was just follwing the code style :) I agree that it would be more readable if we use a type for it - grep would work much better on that :)
+GtkListStore *new_conf_liststore()
Shouldn't be there "void"?
- fixed - it's not required, but to be super safe
+{
- /* 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
*/
- return gtk_list_store_new(NUM_COLUMNS,
G_TYPE_STRING, /* Event name + description */
G_TYPE_STRING, /* event name */
G_TYPE_POINTER
);
+}
+static const void *get_column_value_from_row(GtkTreeView *treeview, int column, int type) +{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- const void *retval = NULL;
- if (selection)
- {
GtkTreeIter iter;
GtkTreeModel *store = gtk_tree_view_get_model(treeview);
if (gtk_tree_selection_get_selected(selection, &store, &iter) ==
TRUE) + {
GValue value = { 0 };
gtk_tree_model_get_value(store, &iter, column, &value);
switch(type){
case TYPE_STR:
retval = g_value_get_string(&value);
break;
case TYPE_POINTER:
retval = g_value_get_pointer(&value);
}
}
- }
- return retval;
+}
+static void on_row_changed_cb(GtkTreeView *treeview, gpointer user_data) +{
- VERB1 log("activated row: '%s'", (const
char*)get_column_value_from_row(treeview, COLUMN_NAME, TYPE_STR)); +
- const void *dialog = get_column_value_from_row(treeview, CONFIG_DIALOG,
TYPE_POINTER); + gtk_widget_set_sensitive(GTK_WIDGET(user_data), dialog != NULL); +
- /*
- void (*handler)(void) = (void
(*)(void))get_column_value_from_row(treeview, ON_ROWCHANGE_CB, TYPE_POINTER); +
- if (handler == NULL)
return;
- handler();
- */
- /*
- const char *event_name = get_event_name_from_row(treeview);
- if (event_name)
- {
event_config_t *ec = get_event_config(event_name);
gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options !=
NULL); + }
- */
I guess, the commented code above could be deleted.
- fixed
+}
+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)
- {
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));
- }
+}
+static void on_close_list_cb(GtkWidget *button, gpointer user_data) +{
- GtkWidget *window = (GtkWidget *)user_data;
- gtk_widget_destroy(window);
+}
+void add_item_to_config_liststore(gpointer dialog, gpointer inf, gpointer user_data) +{
- GtkListStore *list_store = (GtkListStore *)user_data;
- config_item_info_t *info = (config_item_info_t *)inf;
- VERB1 log("adding '%s' to workflow list\n", info->screen_name);
- char *label;
- if (ci_get_screen_name(info) != NULL && ci_get_description(info) !=
NULL) + 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)); +
- 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,
-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 *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
- /* workflow list treeview */
- GtkWidget *tv = gtk_tree_view_new();
- /* column with workflow name and description */
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
- /* add column to tree view */
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(column_label,
renderer,
"markup",
COLUMN_UINAME,
NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD, NULL);
- g_object_set(G_OBJECT(renderer), "wrap-width", 440, NULL);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_NAME);
- gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column);
- /* "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... +
- /* 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));
- g_hash_table_foreach(items,
item_to_config_info,
list_store);
+//TODO: can unref workflows_list_store? treeview holds one ref.
- /* Double click/Enter handler */
- //g_signal_connect(workflows_tv, "row-activated",
G_CALLBACK(on_workflow_row_activated_cb), NULL); +
- gtk_container_add(GTK_CONTAINER(scroll), tv);
- 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); +
- GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
- g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_list_cb),
dialog); +
- 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);
- gtk_box_pack_start(GTK_BOX(main_vbox), scroll, true, true, 10);
- gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
- return main_vbox;
+} diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c index a067511..a2e1085 100644 --- a/src/gtk-helpers/event_config_dialog.c +++ b/src/gtk-helpers/event_config_dialog.c @@ -177,80 +177,6 @@ static void add_option_to_table(gpointer data, gpointer user_data) free(option_label); }
-static void on_close_event_list_cb(GtkWidget *button, gpointer user_data) -{
- GtkWidget *window = (GtkWidget *)user_data;
- gtk_widget_destroy(window);
-}
-static char *get_event_name_from_row(GtkTreeView *treeview) -{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- char *event_name = NULL;
- if (selection)
- {
GtkTreeIter iter;
GtkTreeModel *store = gtk_tree_view_get_model(treeview);
if (gtk_tree_selection_get_selected(selection, &store, &iter) ==
TRUE) - {
GValue value = { 0 };
gtk_tree_model_get_value(store, &iter, COLUMN_EVENT_NAME,
&value); - event_name = (char *)g_value_get_string(&value);
}
- }
- return event_name;
-}
-static void on_configure_event_cb(GtkWidget *button, gpointer user_data) -{
- GtkTreeView *events_tv = (GtkTreeView *)user_data;
- char *event_name = get_event_name_from_row(events_tv);
- if (event_name != NULL)
show_event_config_dialog(event_name, NULL);
- //else
- // error_msg(_("Please select a plugin from the list to edit its
options.")); -}
-static void on_event_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data) -{
- char *event_name = get_event_name_from_row(treeview);
- event_config_t *ec = get_event_config(event_name);
- if (ec->options != NULL) //We need to have some options to show
show_event_config_dialog(event_name, NULL);
-}
-static void on_event_row_changed_cb(GtkTreeView *treeview, gpointer user_data) -{
- const char *event_name = get_event_name_from_row(treeview);
- if (event_name)
- {
event_config_t *ec = get_event_config(event_name);
gtk_widget_set_sensitive(GTK_WIDGET(user_data), ec->options !=
NULL); - } -}
-static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) -{
- GtkListStore *events_list_store = (GtkListStore *)user_data;
- event_config_t *ec = (event_config_t *)value;
- char *event_label;
- if (ec->screen_name != NULL && ec->description != NULL)
event_label = xasprintf("<b>%s</b>\n%s", ec->screen_name,
ec->description); - else
//if event has no xml description
event_label = xasprintf("<b>%s</b>\nNo description available",
key); -
- GtkTreeIter iter;
- gtk_list_store_append(events_list_store, &iter);
- gtk_list_store_set(events_list_store, &iter,
COLUMN_EVENT_UINAME, event_label,
COLUMN_EVENT_NAME, key,
-1);
- free(event_label);
-}
- static void save_value_from_widget(gpointer data, gpointer user_data) { option_widget_t *ow = (option_widget_t *)data;
@@ -283,43 +209,12 @@ static void dehydrate_config_dialog() g_list_foreach(option_widget_list, &save_value_from_widget, NULL); }
-int show_event_config_dialog(const char *event_name, GtkWindow *parent) +GtkWidget *create_event_config_dialog_content(event_config_t *event, GtkWidget *content) {
- if (option_widget_list != NULL)
- {
g_list_free(option_widget_list);
option_widget_list = NULL;
- }
- event_config_t *event = get_event_config(event_name);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ event->screen_name ? event->screen_name
: event_name, - parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- /* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (content == NULL)
content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
//event_config_t *event = get_event_config(event_name);
GtkWidget *option_table = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(option_table), FALSE);
@@ -359,7 +254,6 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) g_signal_connect(pass_store_cb, "toggled", G_CALLBACK(on_show_pass_store_cb), NULL); }
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); gtk_box_pack_start(GTK_BOX(content), option_table, false, false, 20);
/* add the adv_option_table to the dialog only if there is some adv
option */ @@ -379,6 +273,103 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) gtk_box_pack_start(GTK_BOX(content), keyring_warn_lbl, false, false, 0); }
- gtk_widget_show_all(content); //make it all visible
- return content;
+}
+GtkWidget *create_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);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ec_get_screen_name(event) ?
ec_get_screen_name(event) : event_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- /* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
- GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- content = create_event_config_dialog_content(event, content);
- return dialog;
+}
+static void add_event_to_liststore(gpointer key, gpointer value, gpointer user_data) +{
- 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);
+}
+int show_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);
- GtkWindow *parent_window = parent ? parent : g_event_list_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ec_get_screen_name(event) ?
ec_get_screen_name(event) : event_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
/* Allow resize?
* W/o resize, e.g. upload configuration hint looks awfully
* line wrapped.
* With resize, there are some somewhat not nice effects:
* for one, opening an expander will enlarge window,
* but won't contract it back when expander is closed.
*/
gtk_window_set_resizable(GTK_WINDOW(dialog), true);
gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
if (parent_window != NULL)
{
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
}
GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
content = create_event_config_dialog_content(event, content);
gtk_widget_show_all(content); int result = gtk_dialog_run(GTK_DIALOG(dialog));
@@ -396,31 +387,9 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent) return result; }
-void show_events_list_dialog(GtkWindow *parent)
Why not to delete the following function?
- done
+#if 0 +GtkWidget *create_event_list_config_dialog() {
- /*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 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); GtkWidget *events_scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(events_scroll),
@@ -448,18 +417,13 @@ void show_events_list_dialog(GtkWindow *parent) gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(events_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_EVENT_UINAME -> name+description
* COLUMN_EVENT_NAME -> event name so we can retrieve it from the row
*/
- GtkListStore *events_list_store = gtk_list_store_new(NUM_COLUMNS,
G_TYPE_STRING, /* Event
name + description */ - G_TYPE_STRING /* event name */ + );
- events_list_store = new_conf_liststore(); gtk_tree_view_set_model(GTK_TREE_VIEW(events_tv),
GTK_TREE_MODEL(events_list_store));
g_hash_table_foreach(g_event_config_list,
&add_event_to_liststore,
//TODO: can unref events_list_store? treeview holds one ref.&add_event_to_liststore_wrap, events_list_store);
@@ -483,6 +447,37 @@ void show_events_list_dialog(GtkWindow *parent) gtk_box_pack_start(GTK_BOX(main_vbox), events_scroll, true, true, 10); gtk_box_pack_start(GTK_BOX(main_vbox), btnbox, false, false, 0);
- return main_vbox;
+} +#endif
+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 5cb965c..ff3d653 100644 --- a/src/gtk-helpers/internal_libreport_gtk.h +++ b/src/gtk-helpers/internal_libreport_gtk.h @@ -37,7 +37,7 @@ void show_events_list_dialog(GtkWindow *parent); bool is_event_config_user_storage_available();
#define load_single_event_config_data_from_user_storage libreport_load_single_event_config_data_from_user_storage -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config); +void load_single_event_config_data_from_user_storage(event_config_t *config);
#define load_event_config_data_from_user_storage libreport_load_event_config_data_from_user_storage void load_event_config_data_from_user_storage(GHashTable *event_config_list); @@ -50,6 +50,24 @@ void save_event_config_data_to_user_storage(const char *event_name, #define show_event_config_dialog libreport_show_event_config_dialog 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); + +#define show_workflow_list_dialog libreport_show_workflow_list_dialog +void show_workflow_list_dialog(GtkWindow *parent);
+#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);
+GtkListStore *new_conf_liststore();
char * tag_url(const char* line, const char* prefix);
#define url_token libreport_url_token
diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c index 468c508..9de2284 100644 --- a/src/gtk-helpers/secrets.c +++ b/src/gtk-helpers/secrets.c @@ -1378,7 +1378,7 @@ bool is_event_config_user_storage_available()
- @param name Event name
- @param config Event config
*/ -void load_single_event_config_data_from_user_storage(const char *event_name, event_config_t *config) +void load_single_event_config_data_from_user_storage(event_config_t *config) { GHashTable *tmp = g_hash_table_new_full( /*hash_func*/ g_str_hash, @@ -1386,7 +1386,7 @@ void load_single_event_config_data_from_user_storage(const char *event_name, eve /*key_destroy_func:*/ g_free, /*value_destroy_func:*/ NULL);
- g_hash_table_insert(tmp, xstrdup(event_name), config);
g_hash_table_insert(tmp, xstrdup(ec_get_name(config)), config);
load_event_config_data_from_user_storage(tmp);
diff --git a/src/gtk-helpers/workflow_config_dialog.c b/src/gtk-helpers/workflow_config_dialog.c new file mode 100644 index 0000000..acdc81d --- /dev/null +++ b/src/gtk-helpers/workflow_config_dialog.c @@ -0,0 +1,119 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <gtk/gtk.h> +#include "internal_libreport_gtk.h"
+enum +{
- COLUMN_WORKFLOW_UINAME,
- COLUMN_WORKFLOW_NAME,
- NUM_COLUMNS
+};
+static GtkWindow *g_parent_window;
+GtkWidget *create_workflow_config_dialog(const char *workflow_name, GtkWindow *parent) +{
- workflow_t *workflow = get_workflow(workflow_name);
- GList *events = workflow->events;
- GtkWindow *parent_window = parent ? parent : g_parent_window;
- GtkWidget *dialog = gtk_dialog_new_with_buttons(
/*title:*/ wf_get_screen_name(workflow) ?
wf_get_screen_name(workflow) : workflow_name, + parent_window,
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
GTK_STOCK_OK,
GTK_RESPONSE_APPLY,
NULL);
- gtk_window_set_resizable(GTK_WINDOW(dialog), true);
- gtk_window_set_default_size(GTK_WINDOW(dialog), 450, -1);
- if (parent_window != NULL)
- {
gtk_window_set_icon_name(GTK_WINDOW(dialog),
gtk_window_get_icon_name(parent_window));
- }
- GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
- //GtkWidget *event_conf_widg = NULL;
g_list_foreach() should work
- done
- while(events)
- {
event_config_t *ec = (event_config_t *)events->data;
create_event_config_dialog_content(ec, content);
//gtk_box_pack_start(GTK_BOX(content), event_conf_widg, true, true,
0); + events = g_list_next(events);
- }
- return dialog;
+}
+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); +}
+static void load_single_event_config_foreach(event_config_t *ec, gpointer user_data) +{
- load_single_event_config_data_from_user_storage(ec);
+}
+static void load_events_foreach_workflow(const char *name, workflow_t *workflow, gpointer user_data) +{
- g_list_foreach(wf_get_event_list(workflow),
(GFunc)load_single_event_config_foreach, NULL); +}
+void show_workflow_list_dialog(GtkWindow *parent) +{
- 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));
+} diff --git a/src/gui-wizard-gtk/Makefile.am b/src/gui-wizard-gtk/Makefile.am index ecd1887..46c1d65 100644 --- a/src/gui-wizard-gtk/Makefile.am +++ b/src/gui-wizard-gtk/Makefile.am @@ -19,6 +19,7 @@ report_gtk_CFLAGS = \ -DPLUGINS_LIB_DIR="$(PLUGINS_LIB_DIR)" \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DICON_DIR="${datadir}/abrt/icons/hicolor/48x48/status" \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ $(GLIB_CFLAGS) \ $(GTK_CFLAGS) \ -D_GNU_SOURCE
diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c index fab88f1..1bb9af1 100644 --- a/src/gui-wizard-gtk/main.c +++ b/src/gui-wizard-gtk/main.c @@ -74,6 +74,8 @@ void problem_data_reload_from_dump_dir(void)
int main(int argc, char **argv) {
- bool expert_mode = false;
const char *prgname = "abrt"; abrt_init(argv);
@@ -110,6 +112,7 @@ int main(int argc, char **argv) OPT_p = 1 << 2, OPT_d = 1 << 3, OPT_e = 1 << 4,
OPT_x = 1 << 5, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = {
@@ -119,6 +122,7 @@ int main(int argc, char **argv) /* for use from 3rd party apps to show just a reporter selector */ OPT_BOOL( 'd', "delete", NULL, _("Remove DIR after reporting")), OPT_LIST( 'e', "event", &g_auto_event_list, "EVENT", _("Run only this event")), + OPT_BOOL( 'x', "expert", &expert_mode, _("Run wizard in expert mode - shows advanced options")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); @@ -130,6 +134,8 @@ int main(int argc, char **argv) for (GList *elem = g_auto_event_list; elem; elem = g_list_next(elem)) elem->data = xstrdup((const char *)elem->data);
- g_auto_event_list = NULL;
What if somebody passes "-e event" on command line?
- fixed
export_abrt_envvars(opts & OPT_p); g_dump_dir_name = xstrdup(argv[0]);
@@ -140,9 +146,11 @@ int main(int argc, char **argv) load_event_config_data_from_user_storage(g_event_config_list); load_user_settings("report-gtk");
- load_workflow_config_data(WORKFLOWS_DIR);
problem_data_reload_from_dump_dir();
- create_assistant();
create_assistant(expert_mode);
g_custom_logger = &show_error_as_msgbox;
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c index f351988..04dc961 100644 --- a/src/gui-wizard-gtk/wizard.c +++ b/src/gui-wizard-gtk/wizard.c @@ -64,6 +64,7 @@ static GtkWidget *g_btn_close; static GtkWidget *g_btn_next;
static GtkBox *g_box_events; +static GtkBox *g_box_workflows; /* List of event_gui_data's */ static GList *g_list_events; static GtkLabel *g_lbl_event_log; @@ -104,6 +105,9 @@ static GtkImage *g_img_process_ok;
static GtkWidget *g_top_most_window;
+static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func); +static void set_auto_event_chain(GtkButton *button, gpointer user_data); + typedef struct { int page; //which tab in notepad @@ -162,8 +166,8 @@ enum {
- instead of strcmp.
*/ static const gchar PAGE_SUMMARY[] = "page_0"; -static const gchar PAGE_EVENT_SELECTOR[] = "page_2"; -static const gchar PAGE_EDIT_COMMENT[] = "page_1"; +static const gchar PAGE_EVENT_SELECTOR[] = "page_1"; +static const gchar PAGE_EDIT_COMMENT[] = "page_2"; static const gchar PAGE_EDIT_ELEMENTS[] = "page_3"; static const gchar PAGE_REVIEW_DATA[] = "page_4"; static const gchar PAGE_EVENT_PROGRESS[] = "page_5"; @@ -273,12 +277,12 @@ static void show_event_opt_error_dialog(const char *event_name) "reporting will probably fail if you continue " "with the current configuration.\n\n" "Read more about the configuration at: https://fedorahosted.org/abrt/wiki/AbrtConfiguration"), - ec->screen_name);
ec_get_screen_name(ec)); char *markup_message = xasprintf(_("Wrong settings detected for
<b>%s</b>, " "reporting will probably fail if you continue " "with the current configuration.\n\n" "<a href="https://fedorahosted.org/abrt/wiki/AbrtConfiguration%5C%22%3ERead more about the configuration</a>"), - ec->screen_name);
ec_get_screen_name(ec)); GtkWidget *wrong_settings = g_top_most_window =
gtk_message_dialog_new(GTK_WINDOW(g_wnd_assistant), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, @@ -292,7 +296,7 @@ static void show_event_opt_error_dialog(const char *event_name) free(markup_message);
GtkWidget *act_area =
gtk_dialog_get_content_area(GTK_DIALOG(wrong_settings)); - char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec->screen_name); + char * conf_btn_lbl = xasprintf(_("Con_figure %s"), ec_get_screen_name(ec)); GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(conf_btn_lbl); g_signal_connect(configure_event_btn, "clicked", G_CALLBACK(on_configure_event_cb), (gpointer)event_name); free(conf_btn_lbl); @@ -972,6 +976,7 @@ static char *missing_items_in_comma_list(const char *input_item_list) } return result; }
- static event_gui_data_t *add_event_buttons(GtkBox *box, GList **p_event_list, char *event_name,
@@ -1016,9 +1021,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (cfg) { /* .xml has (presumably) prettier description, use it: */
if (cfg->screen_name)
event_screen_name = cfg->screen_name;
event_description = cfg->description;
if (ec_get_screen_name(cfg))
event_screen_name = ec_get_screen_name(cfg);
event_description = ec_get_description(cfg); char *missing =
missing_items_in_comma_list(cfg->ec_requires_items); if (missing) @@ -1078,8 +1083,8 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, if (func) g_signal_connect(G_OBJECT(button), "toggled", func, xstrdup(event_name));
if (cfg && cfg->long_descr)
gtk_widget_set_tooltip_text(button, cfg->long_descr);
if (cfg && ec_get_long_desc(cfg))
gtk_widget_set_tooltip_text(button, ec_get_long_desc(cfg)); event_gui_data_t *event_gui_data = new_event_gui_data_t(); event_gui_data->event_name = xstrdup(event_name);
@@ -1099,7 +1104,9 @@ static event_gui_data_t *add_event_buttons(GtkBox *box, event_name = event_name_end + 1;
gtk_box_pack_start(box, button, /*expand*/ false, /*fill*/ false,
/*padding*/ 0); + gtk_widget_show_all(GTK_WIDGET(button)); }
gtk_widget_show_all(GTK_WIDGET(box));
return active_button; }
@@ -1316,13 +1323,24 @@ void update_gui_state_from_problem_data(int flags)
load_text_to_text_view(g_tv_comment, FILENAME_COMMENT);
- /* Update event radio buttons */
- event_gui_data_t *active_button = add_event_buttons(
g_box_events,
&g_list_events,
g_events,
G_CALLBACK(event_rb_was_toggled)
- );
add_workflow_buttons(g_box_workflows, g_workflow_list,
G_CALLBACK(set_auto_event_chain));
/* Update event radio buttons
* show them only in expert mode
*/
event_gui_data_t *active_button = NULL;
if (g_expert_mode == true)
{
//this widget doesn't react to show_all, so we need to "force" it
gtk_widget_show(GTK_WIDGET(g_box_events));
active_button = add_event_buttons(
g_box_events,
&g_list_events,
g_events,
G_CALLBACK(event_rb_was_toggled)
);
}
if (flags & UPDATE_SELECTED_EVENT && g_expert_mode) {
@@ -1335,7 +1353,6 @@ void update_gui_state_from_problem_data(int flags) } VERB2 log("g_event_selected='%s'", g_event_selected); }
/* We can't just do gtk_widget_show_all once in main: * We created new widgets (buttons). Need to make them visible. */
@@ -2400,6 +2417,50 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer us } }
+//static void event_rb_was_toggled(GtkButton *button, gpointer user_data) +static void set_auto_event_chain(GtkButton *button, gpointer user_data) +{
- //event is selected, so make sure the expert mode is disabled
- g_expert_mode = false;
- workflow_t *w = (workflow_t *)user_data;
- config_item_info_t *info = workflow_get_config_info(w);
- VERB1 log("selected workflow '%s'", info->screen_name);
- GList *wf_event_list = wf_get_event_list(w);
- while(wf_event_list)
- {
g_auto_event_list = g_list_append(g_auto_event_list,
xstrdup(ec_get_name(wf_event_list->data))); + load_single_event_config_data_from_user_storage((event_config_t *)wf_event_list->data); +
wf_event_list = g_list_next(wf_event_list);
- }
- gint current_page_no = gtk_notebook_get_current_page(g_assistant);
- gint next_page_no = select_next_page_no(current_page_no, NULL);
- /* if pageno is not change 'switch-page' signal is not emitted */
- if (current_page_no == next_page_no)
on_page_prepare(g_assistant, gtk_notebook_get_nth_page(g_assistant,
next_page_no), NULL); + else
gtk_notebook_set_current_page(g_assistant, next_page_no);
+}
+static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback func) +{
- GList *keys = g_hash_table_get_keys(g_workflow_list);
- while(keys)
- {
workflow_t *workflow = g_hash_table_lookup(g_workflow_list,
keys->data); + config_item_info_t *info = workflow_get_config_info(workflow); + GtkWidget *button = gtk_button_new_with_label(info->screen_name); + g_signal_connect(button, "clicked", func, workflow);
gtk_box_pack_start(box, button, true, false, 0);
keys = g_list_next(keys);
- }
+}
- static char *setup_next_processed_event(GList **events_list) { free(g_event_selected);
@@ -2431,7 +2492,7 @@ static bool get_sensitive_data_permission(const char *event_name)
char *msg = xasprintf(_("Event '%s' requires permission to send
possibly sensitive data." "\nDo you want to continue?"),
event_cfg->screen_name ? event_cfg->screen_name
: event_name); + ec_get_screen_name(event_cfg) ? ec_get_screen_name(event_cfg) : event_name); const bool response = ask_yes_no_save_result(msg, "ask_send_sensitive_data"); free(msg);
@@ -2449,6 +2510,11 @@ static gint select_next_page_no(gint current_page_no, gpointer data)
if (pages[PAGENO_EVENT_SELECTOR].page_widget == page) {
if (!g_expert_mode && (g_auto_event_list == NULL))
{
return current_page_no; //stay here and let user select the
workflow + }
if (!g_expert_mode) { /* (note: this frees and sets to NULL g_event_selected) */
@@ -2881,6 +2947,7 @@ static void add_pages(void) /* Set pointers to objects we might need to work with */ g_lbl_cd_reason = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_cd_reason")); g_box_events = GTK_BOX( gtk_builder_get_object(g_builder, "vb_events")); + g_box_workflows = GTK_BOX( gtk_builder_get_object(g_builder, "vb_workflows")); g_lbl_event_log = GTK_LABEL( gtk_builder_get_object(g_builder, "lbl_event_log")); g_tv_event_log = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_event_log")); g_tv_comment = GTK_TEXT_VIEW( gtk_builder_get_object(g_builder, "tv_comment")); @@ -2989,7 +3056,7 @@ static void init_page(page_obj_t *page, const char *name, const char *title) static void init_pages(void) { init_page(&pages[0], PAGE_SUMMARY , _("Problem description") ); - init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select operation") ); + init_page(&pages[1], PAGE_EVENT_SELECTOR , _("Select how to report this problem")); init_page(&pages[2], PAGE_EDIT_COMMENT,_("Provide additional information")); init_page(&pages[3], PAGE_EDIT_ELEMENTS , _("Review the data") ); init_page(&pages[4], PAGE_REVIEW_DATA , _("Confirm data to report")); @@ -3005,11 +3072,11 @@ static void assistant_quit_cb(void *obj, void *data) gtk_main_quit(); }
-void create_assistant(void) +void create_assistant(bool expert_mode) { g_loaded_texts = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
- g_expert_mode = !g_auto_event_list;
g_expert_mode = expert_mode;
g_monospace_font = pango_font_description_from_string("monospace"); g_builder = gtk_builder_new();
diff --git a/src/gui-wizard-gtk/wizard.glade b/src/gui-wizard-gtk/wizard.glade index 53e215e..15a5697 100644 --- a/src/gui-wizard-gtk/wizard.glade +++ b/src/gui-wizard-gtk/wizard.glade @@ -83,7 +83,7 @@ <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child>
<object class="GtkVBox" id="page_1">
<object class="GtkVBox" id="page_2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property>
@@ -177,15 +177,31 @@ <object class="GtkWindow" id="window2"> <property name="can_focus">False</property> <child>
<object class="GtkVBox" id="page_2">
<object class="GtkVBox" id="page_1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> <property name="spacing">3</property> <child>
<object class="GtkBox" id="vb_workflows">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child> <object class="GtkVBox" id="vb_events"> <property name="visible">True</property> <property name="can_focus">False</property>
<property name="no_show_all">True</property> <child> <placeholder/> </child>
diff --git a/src/gui-wizard-gtk/wizard.h b/src/gui-wizard-gtk/wizard.h index d2caaa6..a6d8b5d 100644 --- a/src/gui-wizard-gtk/wizard.h +++ b/src/gui-wizard-gtk/wizard.h @@ -21,7 +21,7 @@
#include "internal_libreport_gtk.h"
-void create_assistant(void); +void create_assistant(bool expert_mode);
enum { diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 948662e..a4dc133 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -7,7 +7,9 @@ libreport_include_HEADERS = \ report.h \ run_event.h \ libreport_curl.h \
- workflow.h \ \
- config_item_info.h \ file_obj.h \ internal_libreport.h \ internal_abrt_dbus.h
diff --git a/src/include/config_item_info.h b/src/include/config_item_info.h new file mode 100644 index 0000000..ac49bd5 --- /dev/null +++ b/src/include/config_item_info.h @@ -0,0 +1,45 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#ifndef LIBREPORT_CONFIG_ITEM_H +#define LIBREPORT_CONFIG_ITEM_H
+typedef struct +{
- char *name; //the event name (from it's filename)
- char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat
Support Upload" + char *description; // "Report to..."/"Save to file". Should be one sentence, not long + char *long_desc; // Long(er) explanation, if needed
+} config_item_info_t;
+config_item_info_t *new_config_info();
hmm, missing void?
- fixed
+void free_config_info(config_item_info_t *info);
+void ci_set_screen_name(config_item_info_t *ci, const char *screen_name); +void ci_set_name(config_item_info_t *ci, const char *name); +void ci_set_description(config_item_info_t *ci, const char *description); +void ci_set_long_desc(config_item_info_t *ci, const char *long_description); + +const char *ci_get_screen_name(config_item_info_t *ci); +const char *ci_get_name(config_item_info_t *ci); +const char *ci_get_description(config_item_info_t *ci); +const char *ci_get_long_desc(config_item_info_t *ci);
+#endif diff --git a/src/include/event_config.h b/src/include/event_config.h index 438c723..60fa5c6 100644 --- a/src/include/event_config.h +++ b/src/include/event_config.h @@ -22,6 +22,7 @@ #include <stdbool.h> #include <glib.h> #include "problem_data.h" +#include "config_item_info.h"
#ifdef __cplusplus extern "C" { @@ -68,10 +69,7 @@ void free_event_option(event_option_t *p); //structure to hold the option data typedef struct {
- char *name; //the event name (from it's filename)
- char *screen_name; //ui friendly name of the event: "Bugzilla" "RedHat
Support Upload" - char *description; // "Report to..."/"Save to file". Should be one sentence, not long - char *long_descr; // Long(er) explanation, if needed
config_item_info_t *info;
char *ec_creates_items; char *ec_requires_items;
@@ -87,6 +85,18 @@ typedef struct } event_config_t;
event_config_t *new_event_config(void); +config_item_info_t *ec_get_config_info(event_config_t * ec); +const char *ec_get_screen_name(event_config_t *ec); +void ec_set_screen_name(event_config_t *ec, const char *screen_name); +void ec_set_name(event_config_t *ec, const char *name);
+const char *ec_get_description(event_config_t *ec); +void ec_set_description(event_config_t *ec, const char *description);
+const char *ec_get_name(event_config_t *ec); +const char *ec_get_long_desc(event_config_t *ec); +void ec_set_long_desc(event_config_t *ec, const char *long_desc);
- void free_event_config(event_config_t *p);
@@ -99,6 +109,7 @@ 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);
- extern GHashTable *g_event_config_list; // for iterating through entire
list of all loaded configs
GList *export_event_config(const char *event_name); diff --git a/src/include/file_obj.h b/src/include/file_obj.h index 9cb293f..08823af 100644 --- a/src/include/file_obj.h +++ b/src/include/file_obj.h @@ -24,6 +24,8 @@ typedef struct file_obj * e.g: * if fullpath is: /foo/bar/report_Bugzilla.xml * then filename is: report_Bugzilla
* in case of symlink the filename is created from the symlink name
* and the fullpath is the symlink target */ char *filename; char *fullpath; //the full path with extension
diff --git a/src/include/internal_libreport.h b/src/include/internal_libreport.h index d22bcbe..4f85b2a 100644 --- a/src/include/internal_libreport.h +++ b/src/include/internal_libreport.h @@ -93,6 +93,7 @@ int vdprintf(int d, const char *format, va_list ap); #include "problem_data.h" #include "report.h" #include "run_event.h" +#include "workflow.h" #include "file_obj.h"
#ifdef __cplusplus @@ -642,6 +643,8 @@ void free_file_list(GList *filelist); 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);
/* 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/include/workflow.h b/src/include/workflow.h new file mode 100644 index 0000000..dc2768c --- /dev/null +++ b/src/include/workflow.h @@ -0,0 +1,51 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef LIBREPORT_WORKFLOW_H +#define LIBREPORT_WORKFLOW_H
+#include <glib.h> +#include "event_config.h" +#include "config_item_info.h"
+typedef struct +{
- config_item_info_t *info;
- GList *events; //list of event_option_t
+} workflow_t;
+extern GHashTable *g_workflow_list;
+workflow_t *new_workflow(void); +workflow_t *get_workflow(const char *name); +void free_workflow(workflow_t *w);
+void load_workflow_description_from_file(workflow_t *w, const char *filename); +config_item_info_t *workflow_get_config_info(workflow_t *w); +const char *wf_get_name(workflow_t *w); +GList *wf_get_event_list(workflow_t *w); +const char *wf_get_screen_name(workflow_t *w); +const char *wf_get_description(workflow_t *w); +const char *wf_get_long_desc(workflow_t *w);
+void wf_set_name(workflow_t *w, const char* name); +void wf_set_description(workflow_t *w, const char* description); +void wf_set_long_desc(workflow_t *w, const char* long_desc);
+#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2865624..dad9f89 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -49,7 +49,10 @@ libreport_la_SOURCES = \ client.c \ utf8.c \ file_list.c \
- file_obj.c
- file_obj.c \
- workflow.c \
- workflow_xml_parser.c \
- config_item_info.c libreport_la_CPPFLAGS = \ -I$(srcdir)/../include \ -DLOCALSTATEDIR='"$(localstatedir)"' \
@@ -59,6 +62,7 @@ libreport_la_CPPFLAGS = \ -DPLUGINS_CONF_DIR="$(PLUGINS_CONF_DIR)" \ -DCONF_DIR="$(CONF_DIR)" \ -DEVENTS_DIR="$(EVENTS_DIR)" \
- -DWORKFLOWS_DIR="$(WORKFLOWS_DIR)" \ -DBIN_DIR="$(bindir)" \ $(GLIB_CFLAGS) \ -D_GNU_SOURCE
diff --git a/src/lib/config_item_info.c b/src/lib/config_item_info.c new file mode 100644 index 0000000..c8e2d78 --- /dev/null +++ b/src/lib/config_item_info.c @@ -0,0 +1,85 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include "internal_libreport.h" +//#include "config_item_info.h"
+config_item_info_t *new_config_info()
mising void
- fixed
+{
- config_item_info_t *info = (config_item_info_t
*)xzalloc(sizeof(config_item_info_t)); + return info;
sizeof(*info)
- fixed
+}
+void free_config_info(config_item_info_t *info) +{
- if (info == NULL)
return;
- free(info->name);
- free(info->screen_name);
- free(info->description);
- free(info->long_desc);
- free(info);
+}
+void ci_set_screen_name(config_item_info_t *ci, const char *screen_name) +{
- free(ci->screen_name);
- ci->screen_name = xstrdup(screen_name);
+}
+void ci_set_name(config_item_info_t *ci, const char *name) +{
- free(ci->name);
- ci->name = xstrdup(name);
+}
+void ci_set_description(config_item_info_t *ci, const char *description) +{
- free(ci->description);
- ci->description = xstrdup(description);
+}
+void ci_set_long_desc(config_item_info_t *ci, const char *long_description) +{
- free(ci->long_desc);
- ci->long_desc = xstrdup(long_description);
+}
+const char *ci_get_screen_name(config_item_info_t *ci) +{
- return ci->screen_name;
+}
+const char *ci_get_name(config_item_info_t *ci) +{
- return ci->name;
+}
+const char *ci_get_description(config_item_info_t *ci) +{
- return ci->description;
+}
+const char *ci_get_long_desc(config_item_info_t *ci) +{
- return ci->long_desc;
+} diff --git a/src/lib/event_config.c b/src/lib/event_config.c index 2019e53..402a09f 100644 --- a/src/lib/event_config.c +++ b/src/lib/event_config.c @@ -16,6 +16,7 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "internal_libreport.h"
GHashTable *g_event_config_list;
@@ -29,9 +30,55 @@ event_option_t *new_event_option(void) event_config_t *new_event_config(void) { event_config_t *e = xzalloc(sizeof(event_config_t));
- e->info = new_config_info(); return e; }
+config_item_info_t *ec_get_config_info(event_config_t * ec) +{
- return ec->info;
+}
+void ec_set_name(event_config_t *ec, const char *name) +{
- ci_set_name(ec->info, name);
+}
+void ec_set_screen_name(event_config_t *ec, const char *screen_name) +{
- ci_set_screen_name(ec->info, screen_name);
+}
+const char *ec_get_screen_name(event_config_t *ec) +{
- return ci_get_screen_name(ec->info);
+}
+const char *ec_get_description(event_config_t *ec) +{
- return ci_get_description(ec->info);
+}
+void ec_set_description(event_config_t *ec, const char *description) +{
- ci_set_description(ec->info, description);
+}
+const char *ec_get_name(event_config_t *ec) +{
- return ci_get_name(ec->info);
+}
+const char *ec_get_long_desc(event_config_t *ec) +{
- return ci_get_long_desc(ec->info);
+}
+void ec_set_long_desc(event_config_t *ec, const char *long_descr) +{
- ci_set_long_desc(ec->info, long_descr);
+}
- void free_event_option(event_option_t *p) { if (!p)
@@ -50,9 +97,7 @@ void free_event_config(event_config_t *p) if (!p) return;
- free(p->screen_name);
- free(p->description);
- free(p->long_descr);
- free_config_info(p->info); free(p->ec_creates_items); free(p->ec_requires_items); free(p->ec_exclude_items_by_default);
diff --git a/src/lib/event_xml_parser.c b/src/lib/event_xml_parser.c index 157b717..585e2e5 100644 --- a/src/lib/event_xml_parser.c +++ b/src/lib/event_xml_parser.c @@ -336,11 +336,11 @@ static void text(GMarkupParseContext *context, * OR the label is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->screen_name /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_screen_name(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) { VERB2 log("event name:'%s'", text_copy);
free(ui->screen_name);
ui->screen_name = text_copy;
ec_set_screen_name(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -355,10 +355,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->description /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_description(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) {
free(ui->description);
ui->description = text_copy;
ec_set_description(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -373,10 +373,10 @@ static void text(GMarkupParseContext *context, * OR the description is still not set and we found the default value */ if (parse_data->attribute_lang[0] != '\0'
|| !ui->long_descr /* && parse_data->attribute_lang is ""
- always true */ + || !ec_get_long_desc(ui) /* &&
parse_data->attribute_lang is "" - always true */ ) {
free(ui->long_descr);
ui->long_descr = text_copy;
ec_set_long_desc(ui, text_copy);
free(text_copy); text_copy = NULL; } }
@@ -463,6 +463,7 @@ static void error(GMarkupParseContext *context,
void load_event_description_from_file(event_config_t *event_config, const char* filename) {
- VERB1 log("loading event: '%s'", filename); struct my_parse_data parse_data = { event_config, NULL, NULL, NULL }; parse_data.cur_locale = setlocale(LC_ALL, NULL);
diff --git a/src/lib/workflow.c b/src/lib/workflow.c new file mode 100644 index 0000000..9b17a73 --- /dev/null +++ b/src/lib/workflow.c @@ -0,0 +1,146 @@ +/*
- Copyright (C) 2011 ABRT team
- Copyright (C) 2010 RedHat Inc
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/
+#include "event_config.h" +#include "workflow.h" +#include "internal_libreport.h"
+GHashTable *g_workflow_list;
+workflow_t *new_workflow(void) +{
- workflow_t *w = xzalloc(sizeof(event_config_t));
sizeof(*w)
- fixed
- w->info = new_config_info();
- return w;
+}
+void free_workflow(workflow_t *w) +{
- if (!w)
return;
- free_config_info(w->info);
- g_list_free_full(w->events, (GDestroyNotify)free_event_config);
- free(w);
- w = NULL;
the last line is not necessary
+}
+static void free_workflow_cb(const char *name, workflow_t *w, gpointer user_data) +{
- free_workflow(w);
+}
+void free_workflow_list(GHashTable *wl) +{
- g_hash_table_foreach(wl, (GHFunc)free_workflow_cb, NULL);
- g_hash_table_destroy(wl);
- wl = NULL;
the last line is not necessary
- ficed
+}
+workflow_t *get_workflow(const char *name) +{
- if (!g_workflow_list)
return NULL;
- /* @@ FIXME: SYMLINKS@!!!
- if (g_event_config_symlinks)
- {
char *link = g_hash_table_lookup(g_event_config_symlinks, name);
if (link)
name = link;
- }
- */
- return g_hash_table_lookup(g_workflow_list, name);
+}
+void load_workflow_config_data(const char* path) +{
- if (g_workflow_list == NULL)
- {
g_workflow_list = g_hash_table_new_full(
g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) free_workflow
);
- }
- GList *workflow_files = get_file_list(path, "xml");
- while(workflow_files)
- {
file_obj_t *file = (file_obj_t *)workflow_files->data;
workflow_t *workflow = get_workflow(file->filename);
bool nw_workflow = (!workflow);
if (nw_workflow)
workflow = new_workflow();
load_workflow_description_from_file(workflow, file->fullpath);
if (nw_workflow)
g_hash_table_replace(g_workflow_list, xstrdup(file->filename),
workflow); +
workflow_files = g_list_next(workflow_files);
- }
- free_file_list(workflow_files);
+}
+config_item_info_t *workflow_get_config_info(workflow_t *w) +{
- return w->info;
+}
+GList *wf_get_event_list(workflow_t *w) +{
- return w->events;
+}
+const char *wf_get_name(workflow_t *w) +{
- return ci_get_name(workflow_get_config_info(w));
+}
+const char *wf_get_screen_name(workflow_t *w) +{
- return ci_get_screen_name(workflow_get_config_info(w));
+}
+const char *wf_get_description(workflow_t *w) +{
- return ci_get_description(workflow_get_config_info(w));
+}
+const char *wf_get_long_desc(workflow_t *w) +{
- return ci_get_long_desc(workflow_get_config_info(w));
+}
+void wf_set_name(workflow_t *w, const char* name) +{
- ci_set_name(workflow_get_config_info(w), name);
+}
+void wf_set_description(workflow_t *w, const char* description) +{
- ci_set_description(workflow_get_config_info(w), description);
+}
+void wf_set_long_desc(workflow_t *w, const char* long_desc) +{
- ci_set_long_desc(workflow_get_config_info(w), long_desc);
+} diff --git a/src/lib/workflow_xml_parser.c b/src/lib/workflow_xml_parser.c new file mode 100644 index 0000000..abea00b --- /dev/null +++ b/src/lib/workflow_xml_parser.c @@ -0,0 +1,173 @@ +/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation,
Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "workflow.h" +#include "internal_libreport.h"
+//workflow elements +#define WORKFLOW_ELEMENT "workflow" +#define EVENTS_ELEMENT "events" +#define EVENT_ELEMENT "event" +#define DESCRIPTION_ELEMENT "description" +#define NAME_ELEMENT "name"
+struct my_parse_data +{
- workflow_t *workflow;
- const char *cur_locale;
- char *attribute_lang;
- bool in_event_list;
+};
+static void start_element(GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
+{
- //log("start: %s", element_name);
- struct my_parse_data *parse_data = user_data;
- if (strcmp(element_name, EVENTS_ELEMENT) == 0)
- {
parse_data->in_event_list = true;
- }
+}
+// Called for close tags </foo> +static void end_element(GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
+{
- struct my_parse_data *parse_data = user_data;
- free(parse_data->attribute_lang);
- parse_data->attribute_lang = NULL;
- if (strcmp(element_name, EVENT_ELEMENT) == 0)
- {
if (parse_data->in_event_list == true)
{
//pass
can't find any reasonable explanation
- removed
}
- }
- if (strcmp(element_name, EVENTS_ELEMENT) == 0)
- {
parse_data->in_event_list = false;
- }
+}
+// Called for character data +// text is not nul-terminated +static void text(GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
+{
- struct my_parse_data *parse_data = user_data;
- workflow_t *workflow = parse_data->workflow;
- const gchar *inner_element =
g_markup_parse_context_get_element(context); +
- if(parse_data->in_event_list && strcmp(inner_element, EVENT_ELEMENT) ==
- {
event_config_t *ec = new_event_config();
char *subevent_filename = xasprintf(EVENTS_DIR"/%s.xml", text);
load_event_description_from_file(ec, subevent_filename);
//HACK: need to make ec = NULL if the loading fails
if (ec_get_screen_name(ec))
{
workflow->events = g_list_append(workflow->events, ec);
VERB2 log("added to ev list: '%s'", ec_get_screen_name(ec));
}
ec_set_name(ec, text);
free(subevent_filename);
lost reference on ec if ec_get_screen_name() returned NULL
- fixed
- }
- if(strcmp(inner_element, NAME_ELEMENT) == 0)
- {
workflow->info->screen_name = xstrdup(text);
- }
- if(strcmp(inner_element, DESCRIPTION_ELEMENT) == 0)
- {
workflow->info->description = xstrdup(text);
- }
+}
- // Called for strings that should be re-saved verbatim in this same
- // position, but are not otherwise interpretable. At the moment
- // this includes comments and processing instructions.
- // text is not nul-terminated
+static void passthrough(GMarkupParseContext *context,
const gchar *passthrough_text,
gsize text_len,
gpointer user_data,
GError **error)
+{
- VERB3 log("passthrough");
+}
+// Called on error, including one set by other +// methods in the vtable. The GError should not be freed. +static void error(GMarkupParseContext *context,
GError *error,
gpointer user_data)
+{
- error_msg("error in XML parsing");
+}
+void load_workflow_description_from_file(workflow_t *workflow, const char* filename) +{
- VERB1 log("loading workflow: '%s'", filename);
- struct my_parse_data parse_data = { workflow, NULL, NULL, 0};
- parse_data.cur_locale = setlocale(LC_ALL, NULL);
- GMarkupParser parser;
- memset(&parser, 0, sizeof(parser)); /* just in case */
- parser.start_element = &start_element;
- parser.end_element = &end_element;
- parser.text = &text;
- parser.passthrough = &passthrough;
- parser.error = &error;
- GMarkupParseContext *context = g_markup_parse_context_new(
&parser, G_MARKUP_TREAT_CDATA_AS_TEXT,
&parse_data, /*GDestroyNotify:*/ NULL);
- FILE* fin = fopen(filename, "r");
- if (fin != NULL)
- {
size_t read_bytes;
char buff[1024];
while ((read_bytes = fread(buff, 1, 1024, fin)) != 0)
fread(buff, 1, sizeof(buf), fin) instead of fread(buff, 1, 1024, fin)
I guess, we have some xfunc which do that work.
- ok, will re-factor that in next patch
{
g_markup_parse_context_parse(context, buff, read_bytes, NULL);
}
fclose(fin);
- }
- g_markup_parse_context_free(context);
- free(parse_data.attribute_lang); /* just in case */
+} diff --git a/src/report-newt/report-newt.c b/src/report-newt/report-newt.c index 8532e82..44d30bd 100644 --- a/src/report-newt/report-newt.c +++ b/src/report-newt/report-newt.c @@ -60,8 +60,8 @@ static int select_reporters(GArray *reporters) { struct reporter *r = &g_array_index(reporters, struct reporter, i);
checkboxes[i] = newtCheckbox(20, i + 1, r->config &&
r->config->screen_name ? - r->config->screen_name : r->name, 0, NULL, NULL); + checkboxes[i] = newtCheckbox(20, i + 1, r->config && ec_get_screen_name(r->config) ? + ec_get_screen_name(r->config) : r->name, 0, NULL, NULL); newtGridSetField(cgrid, 0, i, NEWT_GRID_COMPONENT, checkboxes[i], 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); }
@@ -104,8 +104,8 @@ static int configure_reporter(struct reporter *r, bool skip_if_valid) while ((error_table = validate_event(r->name)) || (!skip_if_valid && first && r->config)) {
text = newtTextboxReflowed(0, 0, r->config->screen_name ?
r->config->screen_name : r->name, 35, 5, 5, 0);
text = newtTextboxReflowed(0, 0, ec_get_screen_name(r->config) ?
xstrdup(ec_get_screen_name(r->config)) : r->name, 35, 5, 5,
0);
num_opts = g_list_length(r->config->options); options = xmalloc(sizeof (newtComponent) * num_opts);
diff --git a/src/workflows/Makefile.am b/src/workflows/Makefile.am new file mode 100644 index 0000000..28dc024 --- /dev/null +++ b/src/workflows/Makefile.am @@ -0,0 +1,10 @@ +workflowsdir = $(WORKFLOWS_DIR)
+dist_workflows_DATA = \
- report_Fedora.xml \
- report_fedora.conf
+@INTLTOOL_XML_RULE@
+EXTRA_DIST = \
- report_Fedora.xml.in
diff --git a/src/workflows/report_Fedora.xml.in b/src/workflows/report_Fedora.xml.in new file mode 100644 index 0000000..f9df177 --- /dev/null +++ b/src/workflows/report_Fedora.xml.in @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<workflow>
- <_name>Report to Fedora</_name>
- <_description>Process the report using the Fedora
infrastructure</_description> +
<events>
<event>report_uReport</event>
<event>collect_*</event>
<event>analyze_CCpp</event>
<event>report_Bugzilla</event>
<event>post_report</event>
</events>
+</workflow> diff --git a/src/workflows/report_fedora.conf b/src/workflows/report_fedora.conf new file mode 100644 index 0000000..9dd86ce --- /dev/null +++ b/src/workflows/report_fedora.conf @@ -0,0 +1,3 @@ +EVENT=report_Fedora analyzer=CCpp +# this is just a meta event which consists of other events +# the list is defined in the xml file
On 11/22/2012 04:51 PM, Jiri Moskovcak wrote:
configure.ac | 3 + libreport.spec.in | 16 ++ po/POTFILES.in | 27 +-- src/Makefile.am | 2 +- src/cli/cli-report.c | 8 +- src/gtk-helpers/Makefile.am | 5 +- src/gtk-helpers/config_dialog.c | 216 ++++++++++++++++++++++++ src/gtk-helpers/event_config_dialog.c | 279 +++++++++++++++---------------- src/gtk-helpers/internal_libreport_gtk.h | 20 ++- src/gtk-helpers/secrets.c | 4 +- src/gtk-helpers/workflow_config_dialog.c | 119 +++++++++++++ src/gui-wizard-gtk/Makefile.am | 1 + src/gui-wizard-gtk/main.c | 10 +- src/gui-wizard-gtk/wizard.c | 111 +++++++++--- src/gui-wizard-gtk/wizard.glade | 20 ++- src/gui-wizard-gtk/wizard.h | 2 +- src/include/Makefile.am | 2 + src/include/config_item_info.h | 45 +++++ src/include/event_config.h | 19 ++- src/include/file_obj.h | 2 + src/include/internal_libreport.h | 3 + src/include/workflow.h | 51 ++++++ src/lib/Makefile.am | 6 +- src/lib/config_item_info.c | 85 ++++++++++ src/lib/event_config.c | 51 +++++- src/lib/event_xml_parser.c | 19 ++- src/lib/workflow.c | 146 ++++++++++++++++ src/lib/workflow_xml_parser.c | 173 +++++++++++++++++++ src/report-newt/report-newt.c | 8 +- src/workflows/Makefile.am | 10 ++ src/workflows/report_Fedora.xml.in | 13 ++ src/workflows/report_fedora.conf | 3 + 32 files changed, 1269 insertions(+), 210 deletions(-) create mode 100644 src/gtk-helpers/config_dialog.c create mode 100644 src/gtk-helpers/workflow_config_dialog.c create mode 100644 src/include/config_item_info.h create mode 100644 src/include/workflow.h create mode 100644 src/lib/config_item_info.c create mode 100644 src/lib/workflow.c create mode 100644 src/lib/workflow_xml_parser.c create mode 100644 src/workflows/Makefile.am create mode 100644 src/workflows/report_Fedora.xml.in create mode 100644 src/workflows/report_fedora.conf
Let's split it in smaller patches.
Say, we can start with global s/x->screen_name/ec_get_screen_name(x)/g change.
(Having a 2-deep call chain to fetch a word: ... +const char *ec_get_screen_name(event_config_t *ec) +{ + return ci_get_screen_name(ec->info); +} ... +const char *ci_get_screen_name(config_item_info_t *ci) +{ + return ci->screen_name; +} ... hurts my feelings :] Let's inline them? )
Other bits which can be applied separately:
diff -x '*.po' -d -urpN libreport.6/src/gui-wizard-gtk/wizard.c libreport.7/src/gui-wizard-gtk/wizard.c --- libreport.6/src/gui-wizard-gtk/wizard.c 2012-11-14 12:05:22.000000000 +0100 +++ libreport.7/src/gui-wizard-gtk/wizard.c 2012-11-23 13:13:31.720807837 +0100 @@ -162,8 +162,8 @@ enum { * instead of strcmp. */ static const gchar PAGE_SUMMARY[] = "page_0"; -static const gchar PAGE_EVENT_SELECTOR[] = "page_2"; -static const gchar PAGE_EDIT_COMMENT[] = "page_1"; +static const gchar PAGE_EVENT_SELECTOR[] = "page_1"; +static const gchar PAGE_EDIT_COMMENT[] = "page_2"; static const gchar PAGE_EDIT_ELEMENTS[] = "page_3"; static const gchar PAGE_REVIEW_DATA[] = "page_4"; static const gchar PAGE_EVENT_PROGRESS[] = "page_5"; @@ -1099,7 +1099,9 @@ static event_gui_data_t *add_event_butto event_name = event_name_end + 1;
gtk_box_pack_start(box, button, /*expand*/ false, /*fill*/ false, /*padding*/ 0); + gtk_widget_show_all(GTK_WIDGET(button)); } + gtk_widget_show_all(GTK_WIDGET(box));
return active_button; } diff -x '*.po' -d -urpN libreport.6/src/gui-wizard-gtk/wizard.glade libreport.7/src/gui-wizard-gtk/wizard.glade --- libreport.6/src/gui-wizard-gtk/wizard.glade 2012-11-14 12:05:22.000000000 +0100 +++ libreport.7/src/gui-wizard-gtk/wizard.glade 2012-11-23 13:13:43.493771487 +0100 @@ -83,7 +83,7 @@ <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_1"> + <object class="GtkVBox" id="page_2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> @@ -177,7 +177,7 @@ <object class="GtkWindow" id="window2"> <property name="can_focus">False</property> <child> - <object class="GtkVBox" id="page_2"> + <object class="GtkVBox" id="page_1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property> diff -x '*.po' -d -urpN libreport.6/src/lib/event_xml_parser.c libreport.7/src/lib/event_xml_parser.c --- libreport.6/src/lib/event_xml_parser.c 2012-11-14 12:05:15.000000000 +0100 +++ libreport.7/src/lib/event_xml_parser.c 2012-11-23 13:13:31.723807834 +0100 @@ -463,6 +463,7 @@ static void error(GMarkupParseContext *c
void load_event_description_from_file(event_config_t *event_config, const char* filename) { + VERB1 log("loading event: '%s'", filename); struct my_parse_data parse_data = { event_config, NULL, NULL, NULL }; parse_data.cur_locale = setlocale(LC_ALL, NULL);
On 11/23/2012 01:14 PM, Denys Vlasenko wrote:
On 11/22/2012 04:51 PM, Jiri Moskovcak wrote:
configure.ac | 3 + libreport.spec.in | 16 ++ po/POTFILES.in | 27 +-- src/Makefile.am | 2 +- src/cli/cli-report.c | 8 +- src/gtk-helpers/Makefile.am | 5 +- src/gtk-helpers/config_dialog.c | 216 ++++++++++++++++++++++++ src/gtk-helpers/event_config_dialog.c | 279 +++++++++++++++---------------- src/gtk-helpers/internal_libreport_gtk.h | 20 ++- src/gtk-helpers/secrets.c | 4 +- src/gtk-helpers/workflow_config_dialog.c | 119 +++++++++++++ src/gui-wizard-gtk/Makefile.am | 1 + src/gui-wizard-gtk/main.c | 10 +- src/gui-wizard-gtk/wizard.c | 111 +++++++++--- src/gui-wizard-gtk/wizard.glade | 20 ++- src/gui-wizard-gtk/wizard.h | 2 +- src/include/Makefile.am | 2 + src/include/config_item_info.h | 45 +++++ src/include/event_config.h | 19 ++- src/include/file_obj.h | 2 + src/include/internal_libreport.h | 3 + src/include/workflow.h | 51 ++++++ src/lib/Makefile.am | 6 +- src/lib/config_item_info.c | 85 ++++++++++ src/lib/event_config.c | 51 +++++- src/lib/event_xml_parser.c | 19 ++- src/lib/workflow.c | 146 ++++++++++++++++ src/lib/workflow_xml_parser.c | 173 +++++++++++++++++++ src/report-newt/report-newt.c | 8 +- src/workflows/Makefile.am | 10 ++ src/workflows/report_Fedora.xml.in | 13 ++ src/workflows/report_fedora.conf | 3 + 32 files changed, 1269 insertions(+), 210 deletions(-) create mode 100644 src/gtk-helpers/config_dialog.c create mode 100644 src/gtk-helpers/workflow_config_dialog.c create mode 100644 src/include/config_item_info.h create mode 100644 src/include/workflow.h create mode 100644 src/lib/config_item_info.c create mode 100644 src/lib/workflow.c create mode 100644 src/lib/workflow_xml_parser.c create mode 100644 src/workflows/Makefile.am create mode 100644 src/workflows/report_Fedora.xml.in create mode 100644 src/workflows/report_fedora.conf
Let's split it in smaller patches.
Say, we can start with global s/x->screen_name/ec_get_screen_name(x)/g change.
(Having a 2-deep call chain to fetch a word: ... +const char *ec_get_screen_name(event_config_t *ec) +{
- return ci_get_screen_name(ec->info);
+} ... +const char *ci_get_screen_name(config_item_info_t *ci) +{
- return ci->screen_name;
+} ... hurts my feelings :] Let's inline them? )
- ok, no problem
Other bits which can be applied separately:
diff -x '*.po' -d -urpN libreport.6/src/gui-wizard-gtk/wizard.c libreport.7/src/gui-wizard-gtk/wizard.c --- libreport.6/src/gui-wizard-gtk/wizard.c 2012-11-14 12:05:22.000000000 +0100 +++ libreport.7/src/gui-wizard-gtk/wizard.c 2012-11-23 13:13:31.720807837 +0100 @@ -162,8 +162,8 @@ enum {
- instead of strcmp.
*/ static const gchar PAGE_SUMMARY[] = "page_0"; -static const gchar PAGE_EVENT_SELECTOR[] = "page_2"; -static const gchar PAGE_EDIT_COMMENT[] = "page_1"; +static const gchar PAGE_EVENT_SELECTOR[] = "page_1"; +static const gchar PAGE_EDIT_COMMENT[] = "page_2"; static const gchar PAGE_EDIT_ELEMENTS[] = "page_3"; static const gchar PAGE_REVIEW_DATA[] = "page_4"; static const gchar PAGE_EVENT_PROGRESS[] = "page_5"; @@ -1099,7 +1099,9 @@ static event_gui_data_t *add_event_butto event_name = event_name_end + 1;
gtk_box_pack_start(box, button, /*expand*/ false, /*fill*/ false, /*padding*/ 0);
gtk_widget_show_all(GTK_WIDGET(button)); }
gtk_widget_show_all(GTK_WIDGET(box));
return active_button; }
diff -x '*.po' -d -urpN libreport.6/src/gui-wizard-gtk/wizard.glade libreport.7/src/gui-wizard-gtk/wizard.glade --- libreport.6/src/gui-wizard-gtk/wizard.glade 2012-11-14 12:05:22.000000000 +0100 +++ libreport.7/src/gui-wizard-gtk/wizard.glade 2012-11-23 13:13:43.493771487 +0100 @@ -83,7 +83,7 @@ <object class="GtkWindow" id="window1"> <property name="can_focus">False</property> <child>
<object class="GtkVBox" id="page_1">
<object class="GtkVBox" id="page_2"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property>
@@ -177,7 +177,7 @@ <object class="GtkWindow" id="window2"> <property name="can_focus">False</property> <child>
<object class="GtkVBox" id="page_2">
<object class="GtkVBox" id="page_1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="border_width">10</property>
diff -x '*.po' -d -urpN libreport.6/src/lib/event_xml_parser.c libreport.7/src/lib/event_xml_parser.c --- libreport.6/src/lib/event_xml_parser.c 2012-11-14 12:05:15.000000000 +0100 +++ libreport.7/src/lib/event_xml_parser.c 2012-11-23 13:13:31.723807834 +0100 @@ -463,6 +463,7 @@ static void error(GMarkupParseContext *c
void load_event_description_from_file(event_config_t *event_config, const char* filename) {
- VERB1 log("loading event: '%s'", filename); struct my_parse_data parse_data = { event_config, NULL, NULL, NULL }; parse_data.cur_locale = setlocale(LC_ALL, NULL);
- ok I'll try, but I'm not sure if it makes sense to have this as a separate commit as it will break some of our use-cases which made us to switch these pages
crash-catcher@lists.fedorahosted.org