[ABRT PATCH 5/5] GUI config: add Close/Defaults button

Jakub Filak jfilak at redhat.com
Wed Aug 14 12:43:09 UTC 2013


Closes #680 and closes #681

Signed-off-by: Jakub Filak <jfilak at redhat.com>
---
 src/configuration-gui/abrt-config-widget.c | 107 +++++++++++++++++++--------
 src/configuration-gui/abrt-config-widget.h |   4 +
 src/configuration-gui/main.c               |  21 +++++-
 src/configuration-gui/system-config-abrt.c | 115 ++++++++++++++++++++++++++---
 src/configuration-gui/system-config-abrt.h |  32 ++++++++
 5 files changed, 237 insertions(+), 42 deletions(-)

diff --git a/src/configuration-gui/abrt-config-widget.c b/src/configuration-gui/abrt-config-widget.c
index 847c70a..223193f 100644
--- a/src/configuration-gui/abrt-config-widget.c
+++ b/src/configuration-gui/abrt-config-widget.c
@@ -23,6 +23,7 @@
 #include "abrt-config-widget.h"
 
 #include "libabrt.h"
+#include <assert.h>
 
 #define ABRT_CONFIG_WIDGET_GET_PRIVATE(o) \
     (G_TYPE_INSTANCE_GET_PRIVATE((o), TYPE_ABRT_CONFIG_WIDGET, AbrtConfigWidgetPrivate))
@@ -33,19 +34,31 @@
 
 typedef struct {
     const char *name;
+    GtkSwitch *widget;
+    gboolean default_value;
+    gboolean current_value;
     map_string_t *config;
 } AbrtConfigWidgetOption;
 
+enum AbrtOptions
+{
+    _ABRT_OPT_BEGIN_,
+
+    ABRT_OPT_UPLOAD_COREDUMP = _ABRT_OPT_BEGIN_,
+    ABRT_OPT_STEAL_DIRECTORY,
+    ABRT_OPT_SEND_UREPORT,
+    ABRT_OPT_SHORTENED_REPORTING,
+    ABRT_OPT_SILENT_SHORTENED_REPORTING,
+
+    _ABRT_OPT_END_,
+};
+
 struct AbrtConfigWidgetPrivate {
     GtkBuilder   *builder;
     map_string_t *report_gtk_conf;
     map_string_t *abrt_applet_conf;
 
-    AbrtConfigWidgetOption opt_upload_coredump;
-    AbrtConfigWidgetOption opt_steal_directory;
-    AbrtConfigWidgetOption opt_send_ureport;
-    AbrtConfigWidgetOption opt_shortened_reporting;
-    AbrtConfigWidgetOption opt_silent_shortened_reporting;
+    AbrtConfigWidgetOption options[_ABRT_OPT_END_];
 };
 
 G_DEFINE_TYPE(AbrtConfigWidget, abrt_config_widget, GTK_TYPE_BOX)
@@ -119,15 +132,29 @@ on_switch_activate(GObject       *object,
 }
 
 static void
-connect_switch_with_option(GtkSwitch *gsw, AbrtConfigWidget *config, AbrtConfigWidgetOption *option, gboolean def)
+update_option_current_value(AbrtConfigWidget *self, enum AbrtOptions opid)
 {
+    assert((opid >= _ABRT_OPT_BEGIN_ && opid < _ABRT_OPT_END_) || !"Out of range Option ID value");
+
+    AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
     const char *val = get_app_user_setting(option->config, option->name);
-    const gboolean state = val ? string_to_bool(val) : def;
+    option->current_value = val ? string_to_bool(val) : option->default_value;;
+}
+
+static void
+connect_switch_with_option(AbrtConfigWidget *self, enum AbrtOptions opid, const char *switch_name)
+{
+    assert((opid >= _ABRT_OPT_BEGIN_ && opid < _ABRT_OPT_END_) || !"Out of range Option ID value");
+
+    AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
+    update_option_current_value(self, opid);
 
-    gtk_switch_set_active(gsw, state);
+    GtkSwitch *gsw = GTK_SWITCH(WID(switch_name));
+    option->widget = gsw;
+    gtk_switch_set_active(gsw, option->current_value);
     g_object_set_data(G_OBJECT(gsw), "abrt-option", option);
     g_signal_connect(G_OBJECT(gsw), "notify::active",
-            G_CALLBACK(on_switch_activate), config);
+            G_CALLBACK(on_switch_activate), self);
 }
 
 static void
@@ -168,33 +195,33 @@ abrt_config_widget_init(AbrtConfigWidget *self)
 
     /* Initialize options */
     /* report-gtk */
-    self->priv->opt_steal_directory.name = "ask_steal_dir";
-    self->priv->opt_steal_directory.config = self->priv->report_gtk_conf;
+    self->priv->options[ABRT_OPT_STEAL_DIRECTORY].name = "ask_steal_dir";
+    self->priv->options[ABRT_OPT_STEAL_DIRECTORY].default_value = TRUE;
+    self->priv->options[ABRT_OPT_STEAL_DIRECTORY].config = self->priv->report_gtk_conf;
 
-    self->priv->opt_upload_coredump.name = "abrt_analyze_smart_ask_upload_coredump";
-    self->priv->opt_upload_coredump.config = self->priv->report_gtk_conf;
+    self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].name = "abrt_analyze_smart_ask_upload_coredump";
+    self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].default_value = TRUE;
+    self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].config = self->priv->report_gtk_conf;
 
     /* abrt-applet */
-    self->priv->opt_send_ureport.name = "AutoreportingEnabled";
-    self->priv->opt_send_ureport.config = self->priv->abrt_applet_conf;
+    self->priv->options[ABRT_OPT_SEND_UREPORT].name = "AutoreportingEnabled";
+    self->priv->options[ABRT_OPT_SEND_UREPORT].default_value = g_settings_autoreporting;
+    self->priv->options[ABRT_OPT_SEND_UREPORT].config = self->priv->abrt_applet_conf;
 
-    self->priv->opt_shortened_reporting.name = "ShortenedReporting";
-    self->priv->opt_shortened_reporting.config = self->priv->abrt_applet_conf;
+    self->priv->options[ABRT_OPT_SHORTENED_REPORTING].name = "ShortenedReporting";
+    self->priv->options[ABRT_OPT_SHORTENED_REPORTING].default_value = g_settings_shortenedreporting;
+    self->priv->options[ABRT_OPT_SHORTENED_REPORTING].config = self->priv->abrt_applet_conf;
 
-    self->priv->opt_silent_shortened_reporting.name = "SilentShortenedReporting";
-    self->priv->opt_silent_shortened_reporting.config = self->priv->abrt_applet_conf;
+    self->priv->options[ABRT_OPT_SILENT_SHORTENED_REPORTING].name = "SilentShortenedReporting";
+    self->priv->options[ABRT_OPT_SILENT_SHORTENED_REPORTING].default_value = FALSE;
+    self->priv->options[ABRT_OPT_SILENT_SHORTENED_REPORTING].config = self->priv->abrt_applet_conf;
 
     /* Connect widgets with options */
-    connect_switch_with_option(GTK_SWITCH(WID("switch_upload_coredump")), self,
-            &(self->priv->opt_upload_coredump), /* default: */ FALSE);
-    connect_switch_with_option(GTK_SWITCH(WID("switch_steal_directory")), self,
-            &(self->priv->opt_steal_directory), /* default: */ FALSE);
-    connect_switch_with_option(GTK_SWITCH(WID("switch_send_ureport")), self,
-            &(self->priv->opt_send_ureport), g_settings_autoreporting);
-    connect_switch_with_option(GTK_SWITCH(WID("switch_shortened_reporting")), self,
-            &(self->priv->opt_shortened_reporting), g_settings_shortenedreporting);
-    connect_switch_with_option(GTK_SWITCH(WID("switch_silent_shortened_reporting")), self,
-            &(self->priv->opt_silent_shortened_reporting), FALSE);
+    connect_switch_with_option(self, ABRT_OPT_UPLOAD_COREDUMP, "switch_upload_coredump");
+    connect_switch_with_option(self, ABRT_OPT_STEAL_DIRECTORY, "switch_steal_directory");
+    connect_switch_with_option(self, ABRT_OPT_SEND_UREPORT, "switch_send_ureport");
+    connect_switch_with_option(self, ABRT_OPT_SHORTENED_REPORTING, "switch_shortened_reporting");
+    connect_switch_with_option(self, ABRT_OPT_SILENT_SHORTENED_REPORTING, "switch_silent_shortened_reporting");
 
     gtk_widget_reparent(WID("grid"), GTK_WIDGET(self));
 
@@ -214,4 +241,26 @@ abrt_config_widget_save_chnages(AbrtConfigWidget *config)
     /* Save configuration */
     save_app_conf_file("report-gtk", config->priv->report_gtk_conf);
     save_app_conf_file("abrt-applet", config->priv->abrt_applet_conf);
+
+    for(unsigned i = _ABRT_OPT_BEGIN_; i < _ABRT_OPT_END_; ++i)
+        update_option_current_value(config, i);
+}
+
+gboolean
+abrt_config_widget_get_changed(AbrtConfigWidget *self)
+{
+    for(unsigned i = _ABRT_OPT_BEGIN_; i < _ABRT_OPT_END_; ++i)
+    {
+        if (gtk_switch_get_active(self->priv->options[i].widget) != self->priv->options[i].current_value)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+void
+abrt_config_widget_reset_to_defaults(AbrtConfigWidget *self)
+{
+    for(unsigned i = _ABRT_OPT_BEGIN_; i < _ABRT_OPT_END_; ++i)
+        gtk_switch_set_active(self->priv->options[i].widget, self->priv->options[i].default_value);
 }
diff --git a/src/configuration-gui/abrt-config-widget.h b/src/configuration-gui/abrt-config-widget.h
index e3cf100..1f25400 100644
--- a/src/configuration-gui/abrt-config-widget.h
+++ b/src/configuration-gui/abrt-config-widget.h
@@ -53,8 +53,12 @@ GType abrt_config_widget_get_type (void) G_GNUC_CONST;
 
 AbrtConfigWidget *abrt_config_widget_new();
 
+void abrt_config_widget_reset_to_defaults(AbrtConfigWidget *self);
+
 void abrt_config_widget_save_chnages(AbrtConfigWidget *config);
 
+gboolean abrt_config_widget_get_changed(AbrtConfigWidget *config);
+
 G_END_DECLS
 
 #ifdef __cplusplus
diff --git a/src/configuration-gui/main.c b/src/configuration-gui/main.c
index b07b852..1c0b39d 100644
--- a/src/configuration-gui/main.c
+++ b/src/configuration-gui/main.c
@@ -22,6 +22,22 @@
 
 #define APP_NAME "System Config ABRT"
 
+static void
+system_config_abrt_window_close_cb(gpointer user_data)
+{
+    GtkWidget *sca = GTK_WIDGET(g_object_get_data(G_OBJECT(user_data), "system-config-abrt"));
+
+    if (system_config_abrt_check_before_close(sca))
+        gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+static gboolean
+system_config_abrt_window_delete_event(GtkWidget *window, GdkEvent *event, gpointer user_data)
+{
+    GtkWidget *sca = GTK_WIDGET(g_object_get_data(G_OBJECT(window), "system-config-abrt"));
+    return !system_config_abrt_check_before_close(sca);
+}
+
 static GtkWidget *
 system_config_abrt_window_new(GApplication *app)
 {
@@ -29,7 +45,10 @@ system_config_abrt_window_new(GApplication *app)
     gtk_window_set_default_size(GTK_WINDOW(wnd), 500, 300);
     gtk_window_set_title(GTK_WINDOW(wnd), _("Problem Reporting Configuration"));
 
-    GtkWidget *sca = system_config_abrt_widget_new();
+    GtkWidget *sca = system_config_abrt_widget_new_with_close_button(
+                        system_config_abrt_window_close_cb, wnd);
+    g_object_set_data(G_OBJECT(wnd), "system-config-abrt", sca);
+    g_signal_connect(wnd, "delete-event", G_CALLBACK(system_config_abrt_window_delete_event), /*user_data*/NULL);
     gtk_container_add(GTK_CONTAINER(wnd), sca);
 
     return wnd;
diff --git a/src/configuration-gui/system-config-abrt.c b/src/configuration-gui/system-config-abrt.c
index 8945a48..c61dec8 100644
--- a/src/configuration-gui/system-config-abrt.c
+++ b/src/configuration-gui/system-config-abrt.c
@@ -20,6 +20,8 @@
 
 #include <libabrt.h>
 
+#define CLOSE_BUTTON_DATA_NAME_CALLBACK "my-close-callback"
+#define CLOSE_BUTTON_DATA_NAME_USER_DATA "my-close-user-data"
 
 static void
 system_config_abrt_apply_cb(GtkButton *button, gpointer user_data)
@@ -30,14 +32,80 @@ system_config_abrt_apply_cb(GtkButton *button, gpointer user_data)
 }
 
 static void
+system_config_abrt_close_cb(GtkButton *button, gpointer user_data)
+{
+    system_config_abrt_widget_close_callback callback = g_object_get_data(G_OBJECT(button), CLOSE_BUTTON_DATA_NAME_CALLBACK);
+    gpointer callback_user_data = g_object_get_data(G_OBJECT(button), CLOSE_BUTTON_DATA_NAME_USER_DATA);
+
+    callback(callback_user_data);
+}
+
+static void
+system_config_abrt_defaults_cb(GtkButton *button, gpointer user_data)
+{
+    AbrtConfigWidget *config = ABRT_CONFIG_WIDGET(user_data);
+    abrt_config_widget_reset_to_defaults(config);
+}
+
+static void
 system_config_abrt_changed_cb(AbrtConfigWidget *config, gpointer user_data)
 {
     GtkWidget *button = GTK_WIDGET(user_data);
-    gtk_widget_set_sensitive(button, TRUE);
+    gtk_widget_set_sensitive(button, abrt_config_widget_get_changed(config));
+}
+
+gboolean
+system_config_abrt_check_before_close(GtkWidget *config)
+{
+    GList *children = gtk_container_get_children(GTK_CONTAINER(config));
+    AbrtConfigWidget *acw = ABRT_CONFIG_WIDGET(children->data);
+    g_list_free(children);
+
+    if (abrt_config_widget_get_changed(acw))
+    {
+        GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Apply setting changes"),
+                /*unknown parent window*/NULL,
+                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                _("_Apply"), GTK_RESPONSE_ACCEPT,
+                _("_Discard"), GTK_RESPONSE_REJECT,
+                _("_Cancel"), GTK_RESPONSE_CANCEL,
+                NULL);
+
+        GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+        GtkWidget *box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /*spacing*/0);
+        gtk_widget_set_margin_top(box, 15);
+        gtk_widget_set_margin_bottom(box, 10);
+        GtkWidget *image = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_DIALOG);
+        gtk_box_pack_start(GTK_BOX(box), image, /*expand*/TRUE, /*fill*/TRUE, /*padding*/10);
+
+        GtkWidget *label = gtk_label_new("The settings have changed.\nDo you want to apply the changes or discard them?");
+        gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+        gtk_box_pack_start(GTK_BOX(box), label, /*expand*/TRUE, /*fill*/TRUE, /*padding*/10);
+
+        gtk_container_add(GTK_CONTAINER (content_area), box);
+        gtk_widget_show_all(dialog);
+
+        const gint response = gtk_dialog_run(GTK_DIALOG(dialog));
+        gtk_widget_destroy (dialog);
+
+        if (response == GTK_RESPONSE_ACCEPT)
+            abrt_config_widget_save_chnages(acw);
+
+        return response != GTK_RESPONSE_CANCEL;
+    }
+
+    return TRUE;
 }
 
 GtkWidget *system_config_abrt_widget_new(void)
 {
+    return system_config_abrt_widget_new_with_close_button(/*no close button*/NULL,
+                                                           /*no user data*/NULL);
+}
+
+GtkWidget *system_config_abrt_widget_new_with_close_button(system_config_abrt_widget_close_callback close_cb, gpointer user_data)
+{
     GtkBox *box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, /*spacing*/0));
 
     AbrtConfigWidget *config = abrt_config_widget_new();
@@ -48,22 +116,36 @@ GtkWidget *system_config_abrt_widget_new(void)
             gtk_alignment_new(/*xalign*/.5, /*yalign*/.5, /*xscale*/.5, /*yscale*/.5),
             /*expand*/TRUE, /*fill*/TRUE, /*padding*/0);
 
-    GtkWidget *buttons = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
-    gtk_box_pack_start(GTK_BOX(box), buttons, /*expand*/FALSE, /*fill*/FALSE, /*padding*/0);
+    GtkWidget *buttons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /*spacing*/0);
+    gtk_box_pack_start(GTK_BOX(box), buttons, /*expand*/TRUE, /*fill*/FALSE, /*padding*/0);
 
     gtk_widget_set_margin_left(buttons, 10);
     gtk_widget_set_margin_right(buttons, 10);
     gtk_widget_set_margin_top(buttons, 10);
     gtk_widget_set_margin_bottom(buttons, 10);
 
-    gtk_box_pack_start(GTK_BOX(buttons),
-            gtk_alignment_new(/*xalign*/.5, /*yalign*/.5, /*xscale*/.5, /*yscale*/.5),
-            /*expand*/TRUE, /*fill*/TRUE, /*padding*/0);
+    if (close_cb != NULL)
+    {
+        GtkWidget *btn_close = gtk_button_new_with_mnemonic(_("_Close"));
+        gtk_box_pack_start(GTK_BOX(buttons), btn_close, /*expand*/FALSE, /*fill*/FALSE, /*padding*/0);
+
+        g_object_set_data(G_OBJECT(btn_close), CLOSE_BUTTON_DATA_NAME_CALLBACK, close_cb);
+        g_object_set_data(G_OBJECT(btn_close), CLOSE_BUTTON_DATA_NAME_USER_DATA, user_data);
+
+        g_signal_connect(btn_close, "clicked", G_CALLBACK(system_config_abrt_close_cb), /*user_data*/NULL);
+    }
+
+    GtkWidget *btn_defaults = gtk_button_new_with_mnemonic(_("_Defaults"));
+    gtk_box_pack_start(GTK_BOX(buttons), btn_defaults, /*expand*/FALSE, /*fill*/FALSE, /*padding*/0);
+    g_signal_connect(btn_defaults, "clicked", G_CALLBACK(system_config_abrt_defaults_cb), config);
+    if (close_cb != NULL)
+        gtk_widget_set_margin_left(GTK_WIDGET(btn_defaults), 10);
+
+    GtkWidget *align = gtk_alignment_new(/*xalign*/.5, /*yalign*/.5, /*xscale*/1.0, /*yscale*/1.0);
+    gtk_box_pack_start(GTK_BOX(buttons), align, /*expand*/TRUE, /*fill*/FALSE, /*padding*/0);
 
     GtkWidget *btn_apply = gtk_button_new_with_mnemonic(_("_Apply"));
     gtk_widget_set_sensitive(btn_apply, FALSE);
-    gtk_widget_set_halign(btn_apply, GTK_ALIGN_END);
-    gtk_widget_set_valign(btn_apply, GTK_ALIGN_END);
     gtk_box_pack_end(GTK_BOX(buttons), btn_apply, /*expand*/FALSE, /*fill*/FALSE, /*padding*/0);
     g_signal_connect(btn_apply, "clicked", G_CALLBACK(system_config_abrt_apply_cb), config);
     g_signal_connect(config, "changed", G_CALLBACK(system_config_abrt_changed_cb), btn_apply);
@@ -74,15 +156,23 @@ GtkWidget *system_config_abrt_widget_new(void)
 }
 
 static void
+system_config_abrt_dialog_close_cb(gpointer user_data)
+{
+    GtkWidget *sca = GTK_WIDGET(g_object_get_data(G_OBJECT(user_data), "system-config-abrt"));
+    if (system_config_abrt_check_before_close(sca))
+        gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+static void
 system_config_abrt_dialog_close(GtkDialog *dialog, gpointer user_data)
 {
-    gtk_widget_destroy(GTK_WIDGET(dialog));
+    system_config_abrt_dialog_close_cb(dialog);
 }
 
 static gboolean
 system_config_abrt_dialog_delete_event(GtkWidget *dialog, GdkEvent *event, gpointer user_data)
 {
-    gtk_widget_destroy(GTK_WIDGET(dialog));
+    system_config_abrt_dialog_close_cb(dialog);
     return TRUE; /*do not propagate the event*/
 }
 
@@ -103,10 +193,11 @@ void show_system_config_abrt_dialog(GtkWindow *parent)
 
     /* Have to handle these signals on our own otherwise users must press close button twice */
     g_signal_connect(dialog, "close", G_CALLBACK(system_config_abrt_dialog_close), /*user_data*/NULL);
-    g_signal_connect(dialog, "delete_event", G_CALLBACK(system_config_abrt_dialog_delete_event), /*user_data*/NULL);
+    g_signal_connect(dialog, "delete-event", G_CALLBACK(system_config_abrt_dialog_delete_event), /*user_data*/NULL);
 
     GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-    GtkWidget *sca = system_config_abrt_widget_new();
+    GtkWidget *sca = system_config_abrt_widget_new_with_close_button(system_config_abrt_dialog_close_cb, dialog);
+    g_object_set_data(G_OBJECT(dialog), "system-config-abrt", sca);
     gtk_box_pack_start(GTK_BOX(content), sca, /*expand*/TRUE, /*fill*/TRUE, /*padding*/0);
 
     gtk_widget_show_all(content);
diff --git a/src/configuration-gui/system-config-abrt.h b/src/configuration-gui/system-config-abrt.h
index 453090c..3d469ff 100644
--- a/src/configuration-gui/system-config-abrt.h
+++ b/src/configuration-gui/system-config-abrt.h
@@ -24,8 +24,40 @@
 extern "C" {
 #endif /* __cplusplus */
 
+/*
+ * Creates a new System Config ABRT widget without close button
+ *
+ * @returns the new System Config ABRT widget
+ */
 GtkWidget *system_config_abrt_widget_new(void);
 
+/*
+ * A callback function for Close button on System Config ABRT widget
+ *
+ * @param user_data user data set when System Config ABRT was created
+ */
+typedef void (* system_config_abrt_widget_close_callback)(gpointer user_data);
+
+/*
+ * Creates a new System Config ABRT widget with close button
+ *
+ * @param close_cb Close button click handler
+ * @param user_data User data passed to @close_cb as the first argument
+ */
+GtkWidget *system_config_abrt_widget_new_with_close_button(system_config_abrt_widget_close_callback close_cb, gpointer user_data);
+
+/*
+ * If changes were not applied, asks user for action via dialog.
+ *
+ * @returns TRUE if application can exit, otherwise FALSE
+ */
+gboolean system_config_abrt_check_before_close(GtkWidget *config);
+
+/*
+ * Shows the System Config ABRT dialog
+ *
+ * @param parent A window for which the dialog is modal
+ */
 void show_system_config_abrt_dialog(GtkWindow *parent);
 
 #ifdef __cplusplus
-- 
1.8.3.1



More information about the Crash-catcher mailing list