summaryrefslogtreecommitdiffstats
path: root/libreport/src/gtk-helpers
diff options
context:
space:
mode:
Diffstat (limited to 'libreport/src/gtk-helpers')
-rw-r--r--libreport/src/gtk-helpers/Makefile.am34
-rw-r--r--libreport/src/gtk-helpers/abrt-keyring.c166
-rw-r--r--libreport/src/gtk-helpers/autowrapped_label.c107
-rw-r--r--libreport/src/gtk-helpers/event_config_dialog.c454
-rw-r--r--libreport/src/gtk-helpers/libreport-gtk.h31
-rw-r--r--libreport/src/gtk-helpers/libreport-gtk.pc.in11
6 files changed, 803 insertions, 0 deletions
diff --git a/libreport/src/gtk-helpers/Makefile.am b/libreport/src/gtk-helpers/Makefile.am
new file mode 100644
index 00000000..38f9c1d0
--- /dev/null
+++ b/libreport/src/gtk-helpers/Makefile.am
@@ -0,0 +1,34 @@
+# libreportgtk - the stuff shared among gtk clients (abrt-gui, wizard)
+libreport_gtk_includedir = \
+ $(includedir)/libreport
+
+libreport_gtk_include_HEADERS = \
+ libreport-gtk.h
+
+lib_LTLIBRARIES = \
+ libreport-gtk.la
+
+libreport_gtk_la_SOURCES = \
+ event_config_dialog.c \
+ abrt-keyring.c \
+ autowrapped_label.c
+
+libreport_gtk_la_CPPFLAGS = \
+ -Wall -Wwrite-strings -Werror \
+ -I$(srcdir)/../include \
+ -I$(srcdir)/../lib \
+ $(GTK_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(GNOME_KEYRING_CFLAGS) \
+ -D_GNU_SOURCE
+libreport_gtk_la_LDFLAGS = \
+ -version-info 0:1:0
+libreport_gtk_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(GLIB_LIBS) \
+ $(GNOME_KEYRING_LIBS)
+
+EXTRA_DIST = libreport-gtk.pc.in
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libreport-gtk.pc
diff --git a/libreport/src/gtk-helpers/abrt-keyring.c b/libreport/src/gtk-helpers/abrt-keyring.c
new file mode 100644
index 00000000..a6097a27
--- /dev/null
+++ b/libreport/src/gtk-helpers/abrt-keyring.c
@@ -0,0 +1,166 @@
+/*
+ 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 <gnome-keyring.h>
+#include "libreport.h"
+
+static char *keyring_name;
+static bool got_keyring = 0;
+
+static guint32 search_item_id(const char *event_name)
+{
+ GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
+ GList *found = NULL;
+ gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig", event_name);
+ GnomeKeyringResult result = gnome_keyring_find_items_sync(
+ GNOME_KEYRING_ITEM_GENERIC_SECRET,
+ attrs,
+ &found);
+ gnome_keyring_attribute_list_free(attrs);
+
+ //let's hope 0 is not valid item_id
+ guint32 item_id = 0;
+ if (result != GNOME_KEYRING_RESULT_OK)
+ goto ret;
+ if (found)
+ item_id = ((GnomeKeyringFound *)found->data)->item_id;
+ ret:
+ if (found)
+ gnome_keyring_found_list_free(found);
+ VERB2 log("keyring has %sconfiguration for event '%s'", (item_id != 0) ? "" : "no ", event_name);
+ return item_id;
+}
+
+void abrt_keyring_save_settings(const char *event_name)
+{
+ GList *l;
+ GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
+ event_config_t *ec = get_event_config(event_name);
+ /* add string id which we use to search for items */
+ gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig", event_name);
+ for (l = g_list_first(ec->options); l != NULL; l = g_list_next(l))
+ {
+ event_option_t *op = (event_option_t *)l->data;
+ gnome_keyring_attribute_list_append_string(attrs, op->eo_name, op->eo_value);
+ }
+
+ GnomeKeyringResult result;
+ guint32 item_id = search_item_id(event_name);
+ if (item_id)
+ {
+ /* found existing item, so just update the values */
+ result = gnome_keyring_item_set_attributes_sync(keyring_name, item_id, attrs);
+ VERB2 log("updated item with id: %i", item_id);
+ }
+ else
+ {
+ /* did't find existing item, so create a new one */
+ result = gnome_keyring_item_create_sync(keyring_name,
+ GNOME_KEYRING_ITEM_GENERIC_SECRET, /* type */
+ event_name, /* display name */
+ attrs, /* attributes */
+ NULL, /* secret - no special handling for password it's stored in attrs */
+ 1, /* update if exist */
+ &item_id);
+ VERB2 log("created new item with id: %i", item_id);
+ }
+ gnome_keyring_attribute_list_free(attrs);
+
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error_msg("Error saving event '%s' configuration to keyring", event_name);
+ return;
+ }
+ VERB2 log("saved event '%s' configuration to keyring", event_name);
+}
+
+static void abrt_keyring_load_settings(const char *event_name, event_config_t *ec)
+{
+ guint item_id = search_item_id(event_name);
+ if (!item_id)
+ return;
+ GnomeKeyringAttributeList *attrs = NULL;
+ GnomeKeyringResult result = gnome_keyring_item_get_attributes_sync(
+ keyring_name,
+ item_id,
+ &attrs);
+ if (result == GNOME_KEYRING_RESULT_OK && attrs)
+ {
+ VERB3 log("num attrs %i", attrs->len);
+ guint index;
+ for (index = 0; index < attrs->len; index++)
+ {
+ char *name = g_array_index(attrs, GnomeKeyringAttribute, index).name;
+ VERB2 log("keyring has name '%s'", name);
+ event_option_t *option = get_event_option_from_list(name, ec->options);
+ if (option)
+ {
+ free(option->eo_value);
+ option->eo_value = xstrdup(g_array_index(attrs, GnomeKeyringAttribute, index).value.string);
+ VERB2 log("added or replaced in event config:'%s=%s'", name, option->eo_value);
+ }
+ }
+ }
+ if (attrs)
+ gnome_keyring_attribute_list_free(attrs);
+}
+
+static void init_keyring()
+{
+ /* Called again? */
+ if (got_keyring)
+ return;
+
+ if (!gnome_keyring_is_available())
+ {
+ error_msg("Cannot connect to Gnome keyring daemon");
+ return;
+ }
+
+ GnomeKeyringResult result = gnome_keyring_get_default_keyring_sync(&keyring_name);
+ if (result != GNOME_KEYRING_RESULT_OK)
+ {
+ error_msg("Can't get default keyring (result:%d)", result);
+ return;
+ }
+
+ got_keyring = 1;
+ /*
+ * Note: The default keyring name can be NULL. It is a valid name.
+ */
+ VERB2 log("keyring:'%s'", keyring_name);
+}
+
+static void load_event_config(gpointer key, gpointer value, gpointer user_data)
+{
+ char* event_name = (char*)key;
+ event_config_t *ec = (event_config_t *)value;
+ VERB2 log("loading event '%s' configuration from keyring", event_name);
+ abrt_keyring_load_settings(event_name, ec);
+}
+
+/*
+ * Tries to load settings for all events in g_event_config_list
+*/
+void load_event_config_data_from_keyring()
+{
+ init_keyring();
+ if (!got_keyring)
+ return;
+ g_hash_table_foreach(g_event_config_list, &load_event_config, NULL);
+}
diff --git a/libreport/src/gtk-helpers/autowrapped_label.c b/libreport/src/gtk-helpers/autowrapped_label.c
new file mode 100644
index 00000000..981cb709
--- /dev/null
+++ b/libreport/src/gtk-helpers/autowrapped_label.c
@@ -0,0 +1,107 @@
+/*
+ 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 "libreport.h"
+
+/*
+ * GTK doesn't re-wrap GtkLabels which have line wrapping set to true.
+ * The line wrapped label in VBox looks like this:
+ * |----------------------------------------|
+ * |----------------------------------------|
+ * | word word word word |
+ * | word word word word |
+ * | word word |
+ * |----------------------------------------|
+ * |----------------------------------------|
+ * So every project copy-pastes this code to make labels widen
+ * and shrink horizontally on resize.
+ */
+
+static void rewrap_label_to_parent_size(GtkWidget *widget,
+ GtkAllocation *allocation,
+ gpointer data)
+{
+ GtkLabel *label = GTK_LABEL(widget);
+ PangoLayout *layout = gtk_label_get_layout(label);
+
+ int lw_old, lh_old;
+ pango_layout_get_pixel_size(layout, &lw_old, &lh_old);
+
+ /* Already right size? */
+ if (lw_old == allocation->width)
+ return;
+
+ /* Rewrap text to new width */
+ pango_layout_set_width(layout, allocation->width * PANGO_SCALE);
+
+ /* Did text height change as a result? */
+ int lh;
+ pango_layout_get_pixel_size(layout, NULL, &lh);
+ if (lh != lh_old) /* yes, resize label height */
+ gtk_widget_set_size_request(widget, -1, lh);
+}
+
+void make_label_autowrap_on_resize(GtkLabel *label)
+{
+ // So far, only tested to work on labels which were set up as:
+ //gtk_label_set_justify(label, GTK_JUSTIFY_LEFT);
+ //gtk_misc_set_alignment(GTK_MISC(label), /*x,yalign:*/ 0.0, 0.0);
+ // yalign != 0 definitely breaks things!
+ // also, <property name="ypad">NONZERO</property> would be bad
+
+ /* Makes no sense on non-wrapped labels, so we can as well
+ * set wrapping to "on" unconditionally, istead of making it a requirement
+ */
+ gtk_label_set_line_wrap(label, TRUE);
+ g_signal_connect(G_OBJECT(label), "size-allocate", G_CALLBACK(rewrap_label_to_parent_size), NULL);
+
+ // So far, only tested to work on labels which were set up as:
+ //gtk_box_pack_start(box, label, /*expand*/ false, /*fill*/ false, /*padding*/ 0);
+}
+
+static void fixer(GtkWidget *widget, gpointer data_unused)
+{
+ if (GTK_IS_CONTAINER(widget))
+ {
+ gtk_container_foreach((GtkContainer*)widget, fixer, NULL);
+ return;
+ }
+ if (GTK_IS_LABEL(widget))
+ {
+ GtkLabel *label = (GtkLabel*)widget;
+ //const char *txt = gtk_label_get_label(label);
+ GtkMisc *misc = (GtkMisc*)widget;
+ gfloat yalign; //= 1;
+ gint ypad; //= 1;
+ if (gtk_label_get_line_wrap(label)
+ && (gtk_misc_get_alignment(misc, NULL, &yalign), yalign == 0)
+ && (gtk_misc_get_padding(misc, NULL, &ypad), ypad == 0)
+ ) {
+ //log("label '%s' set to wrap", txt);
+ make_label_autowrap_on_resize(label);
+ return;
+ }
+ //log("label '%s' not set to wrap %g %d", txt, yalign, ypad);
+ }
+}
+
+void fix_all_wrapped_labels(GtkWidget *widget)
+{
+ fixer(widget, NULL);
+}
diff --git a/libreport/src/gtk-helpers/event_config_dialog.c b/libreport/src/gtk-helpers/event_config_dialog.c
new file mode 100644
index 00000000..e98b50b7
--- /dev/null
+++ b/libreport/src/gtk-helpers/event_config_dialog.c
@@ -0,0 +1,454 @@
+/*
+ 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 "libreport-gtk.h"
+
+static GtkWindow *g_event_list_window;
+static GList *option_widget_list;
+GtkWindow *g_parent_window;
+
+enum
+{
+ COLUMN_EVENT_UINAME,
+ COLUMN_EVENT_NAME,
+ NUM_COLUMNS
+};
+
+typedef struct
+{
+ event_option_t *option;
+ GtkWidget *widget;
+} option_widget_t;
+
+static void show_event_config_dialog(const char *event_name);
+
+static GtkWidget *gtk_label_new_justify_left(const gchar *label_str)
+{
+ GtkWidget *label = gtk_label_new(label_str);
+ gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
+ gtk_misc_set_alignment(GTK_MISC(label), /*xalign:*/ 0, /*yalign:*/ 0.5);
+ /* Make some space between label and input field to the right of it: */
+ gtk_misc_set_padding(GTK_MISC(label), /*xpad:*/ 5, /*ypad:*/ 0);
+ return label;
+}
+
+static void add_option_widget(GtkWidget *widget, event_option_t *option)
+{
+ option_widget_t *ow = (option_widget_t *)xmalloc(sizeof(option_widget_t));
+ ow->widget = widget;
+ ow->option = option;
+ option_widget_list = g_list_prepend(option_widget_list, ow);
+}
+
+static void on_show_pass_cb(GtkToggleButton *tb, gpointer user_data)
+{
+ GtkEntry *entry = (GtkEntry *)user_data;
+ gtk_entry_set_visibility(entry, gtk_toggle_button_get_active(tb));
+}
+
+static unsigned grow_table_by_1(GtkTable *table)
+{
+ guint rows, columns;
+ //needs gtk 2.22: gtk_table_get_size(table, &rows, &columns);
+ g_object_get(table, "n-rows", &rows, NULL);
+ g_object_get(table, "n-columns", &columns, NULL);
+ gtk_table_resize(table, rows + 1, columns);
+ return rows;
+}
+
+static void add_option_to_table(gpointer data, gpointer user_data)
+{
+ event_option_t *option = data;
+ GtkTable *option_table = user_data;
+
+ GtkWidget *label;
+ GtkWidget *option_input;
+ unsigned last_row;
+
+ char *option_label;
+ if (option->eo_label != NULL)
+ option_label = xstrdup(option->eo_label);
+ else
+ {
+ option_label = xstrdup(option->eo_name ? option->eo_name : "");
+ /* Replace '_' with ' ' */
+ char *p = option_label - 1;
+ while (*++p)
+ if (*p == '_')
+ *p = ' ';
+ }
+
+ switch (option->eo_type)
+ {
+ case OPTION_TYPE_TEXT:
+ case OPTION_TYPE_NUMBER:
+ case OPTION_TYPE_PASSWORD:
+ last_row = grow_table_by_1(option_table);
+ label = gtk_label_new_justify_left(option_label);
+ gtk_table_attach(option_table, label,
+ /*left,right_attach:*/ 0, 1,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ option_input = gtk_entry_new();
+ if (option->eo_value != NULL)
+ gtk_entry_set_text(GTK_ENTRY(option_input), option->eo_value);
+ gtk_table_attach(option_table, option_input,
+ /*left,right_attach:*/ 1, 2,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL | GTK_EXPAND, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ add_option_widget(option_input, option);
+ if (option->eo_type == OPTION_TYPE_PASSWORD)
+ {
+ gtk_entry_set_visibility(GTK_ENTRY(option_input), 0);
+ last_row = grow_table_by_1(option_table);
+ GtkWidget *pass_cb = gtk_check_button_new_with_label(_("Show password"));
+ gtk_table_attach(option_table, pass_cb,
+ /*left,right_attach:*/ 1, 2,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ g_signal_connect(pass_cb, "toggled", G_CALLBACK(on_show_pass_cb), option_input);
+ }
+ break;
+
+ case OPTION_TYPE_HINT_HTML:
+ label = gtk_label_new(option_label);
+ gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), /*x,yalign:*/ 0.0, 0.0);
+ make_label_autowrap_on_resize(GTK_LABEL(label));
+
+ last_row = grow_table_by_1(option_table);
+ gtk_table_attach(option_table, label,
+ /*left,right_attach:*/ 0, 2,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ break;
+
+ case OPTION_TYPE_BOOL:
+ last_row = grow_table_by_1(option_table);
+ option_input = gtk_check_button_new_with_label(option_label);
+ gtk_table_attach(option_table, option_input,
+ /*left,right_attach:*/ 0, 2,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ if (option->eo_value != NULL)
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(option_input),
+ string_to_bool(option->eo_value));
+ add_option_widget(option_input, option);
+ break;
+
+ default:
+ //option_input = gtk_label_new_justify_left("WTF?");
+ log("unsupported option type");
+ free(option_label);
+ return;
+ }
+
+ if (option->eo_note_html)
+ {
+ label = gtk_label_new(option->eo_note_html);
+ gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
+ gtk_misc_set_alignment(GTK_MISC(label), /*x,yalign:*/ 0.0, 0.0);
+ make_label_autowrap_on_resize(GTK_LABEL(label));
+
+ last_row = grow_table_by_1(option_table);
+ gtk_table_attach(option_table, label,
+ /*left,right_attach:*/ 1, 2,
+ /*top,bottom_attach:*/ last_row, last_row+1,
+ /*x,yoptions:*/ GTK_FILL, GTK_FILL,
+ /*x,ypadding:*/ 0, 0);
+ }
+
+ 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);
+ //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);
+}
+
+static void on_event_row_changed_cb(GtkTreeView *treeview, gpointer user_data)
+{
+ event_config_t *ec = get_event_config(get_event_name_from_row(treeview));
+ 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;
+
+ const char *val = NULL;
+ switch (ow->option->eo_type)
+ {
+ case OPTION_TYPE_TEXT:
+ case OPTION_TYPE_NUMBER:
+ case OPTION_TYPE_PASSWORD:
+ val = (char *)gtk_entry_get_text(GTK_ENTRY(ow->widget));
+ break;
+ case OPTION_TYPE_BOOL:
+ val = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ow->widget)) ? "yes" : "no";
+ break;
+ default:
+ log("unsupported option type");
+ }
+ if (val)
+ {
+ free(ow->option->eo_value);
+ ow->option->eo_value = xstrdup(val);
+ VERB1 log("saved: %s:%s", ow->option->eo_name, ow->option->eo_value);
+ }
+}
+
+static void dehydrate_config_dialog()
+{
+ if (option_widget_list != NULL)
+ g_list_foreach(option_widget_list, &save_value_from_widget, NULL);
+}
+
+static void show_event_config_dialog(const char *event_name)
+{
+ if (option_widget_list != NULL)
+ {
+ g_list_free(option_widget_list);
+ option_widget_list = NULL;
+ }
+
+ event_config_t *event = get_event_config(event_name);
+
+ GtkWidget *dialog = gtk_dialog_new_with_buttons(
+ /*title:*/ event->screen_name ? event->screen_name : event_name,
+ g_event_list_window,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_APPLY,
+ NULL);
+ if (g_event_list_window != NULL)
+ {
+ gtk_window_set_icon_name(GTK_WINDOW(dialog),
+ gtk_window_get_icon_name(g_event_list_window));
+ }
+
+ GtkWidget *option_table = gtk_table_new(/*rows*/ 0, /*cols*/ 2, /*homogeneous*/ FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(option_table), 2);
+ g_list_foreach(event->options, &add_option_to_table, option_table);
+
+ GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ gtk_box_pack_start(GTK_BOX(content), option_table, false, false, 20);
+ gtk_widget_show_all(option_table);
+
+ int result = gtk_dialog_run(GTK_DIALOG(dialog));
+ if (result == GTK_RESPONSE_APPLY)
+ {
+ dehydrate_config_dialog();
+ abrt_keyring_save_settings(event_name);
+ }
+ //else if (result == GTK_RESPONSE_CANCEL)
+ // log("log");
+ gtk_widget_destroy(dialog);
+}
+
+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_keyring();
+ }
+
+ 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_vbox_new(0, 0);
+ GtkWidget *events_scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(events_scroll),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ /* event list treeview */
+ GtkWidget *events_tv = gtk_tree_view_new();
+ /* column with event 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(_("Event"),
+ renderer,
+ "markup",
+ COLUMN_EVENT_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_EVENT_NAME);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(events_tv), column);
+ /* "Please draw rows in alternating colors": */
+ 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 */
+ );
+ 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,
+ events_list_store);
+//TODO: can unref events_list_store? treeview holds one ref.
+
+ /* Double click/Enter handler */
+ g_signal_connect(events_tv, "row-activated", G_CALLBACK(on_event_row_activated_cb), NULL);
+
+ gtk_container_add(GTK_CONTAINER(events_scroll), events_tv);
+
+ GtkWidget *configure_event_btn = gtk_button_new_with_mnemonic(_("Configure E_vent"));
+ gtk_widget_set_sensitive(configure_event_btn, false);
+ g_signal_connect(configure_event_btn, "clicked", G_CALLBACK(on_configure_event_cb), events_tv);
+ g_signal_connect(events_tv, "cursor-changed", G_CALLBACK(on_event_row_changed_cb), configure_event_btn);
+
+ GtkWidget *close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+ g_signal_connect(close_btn, "clicked", G_CALLBACK(on_close_event_list_cb), g_event_list_window);
+
+ GtkWidget *btnbox = gtk_hbutton_box_new();
+ gtk_box_pack_end(GTK_BOX(btnbox), close_btn, false, false, 0);
+ gtk_box_pack_end(GTK_BOX(btnbox), configure_event_btn, false, false, 0);
+
+ 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);
+
+ gtk_container_add(GTK_CONTAINER(event_list_window), main_vbox);
+
+ gtk_widget_show_all(event_list_window);
+}
+
+static void show_event_opt_error_dialog(const char *event_name)
+{
+ event_config_t *ec = get_event_config(event_name);
+ char *message = xasprintf(_("Wrong settings detected for %s, "
+ "reporting will probably fail if you continue "
+ "with the current configuration."),
+ ec->screen_name);
+ char *markup_message = xasprintf(_("Wrong settings detected for <b>%s</b>, "
+ "reporting will probably fail if you continue "
+ "with the current configuration."),
+ ec->screen_name);
+ GtkWidget *wrong_settings = gtk_message_dialog_new(g_parent_window,
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ message);
+ gtk_window_set_transient_for(GTK_WINDOW(wrong_settings), g_parent_window);
+ free(message);
+ gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(wrong_settings),
+ markup_message);
+ free(markup_message);
+ gtk_dialog_run(GTK_DIALOG(wrong_settings));
+ gtk_widget_destroy(wrong_settings);
+}
+
+//TODO: move this code to its only callsite?
+// (in which case, move show_event_opt_error_dialog and g_parent_window too)
+void g_validate_event(const char* event_name)
+{
+ GHashTable *errors = validate_event(event_name);
+ if (errors != NULL)
+ show_event_opt_error_dialog(event_name);
+}
diff --git a/libreport/src/gtk-helpers/libreport-gtk.h b/libreport/src/gtk-helpers/libreport-gtk.h
new file mode 100644
index 00000000..417f6053
--- /dev/null
+++ b/libreport/src/gtk-helpers/libreport-gtk.h
@@ -0,0 +1,31 @@
+/*
+ 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 "libreport.h"
+#include "report.h"
+
+void make_label_autowrap_on_resize(GtkLabel *label);
+void fix_all_wrapped_labels(GtkWidget *widget);
+
+void show_events_list_dialog(GtkWindow *parent);
+
+void abrt_keyring_save_settings(const char *event_name);
+void load_event_config_data_from_keyring();
+void g_validate_event(const char* event_name);
+extern GtkWindow *g_parent_window;
diff --git a/libreport/src/gtk-helpers/libreport-gtk.pc.in b/libreport/src/gtk-helpers/libreport-gtk.pc.in
new file mode 100644
index 00000000..2d842977
--- /dev/null
+++ b/libreport/src/gtk-helpers/libreport-gtk.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libreport-gtk
+Description: libreport bindings for GTK apps
+Version: @VERSION@
+Requires: libreport
+Libs: -L${libdir} -lreport-gtk
+Cflags: -fPIC -I${includedir}/libreport