From b89e812251efdbbc83ed84932c7dc0d0852d153c Mon Sep 17 00:00:00 2001
From: Matej Habrnal <mhabrnal@redhat.com>
Date: Mon, 8 Jun 2015 10:31:07 +0200
Subject: [PATCH] configui: add option always generate backtrace locally

The option 'Ask before uploading coredump' is replaced by 'Upload coredump for
backtrace generation'. The new config option allows the user to choose the option always
generate the backtrace locally ('Never').

Related to rhbz#986876
Related to abrt/gnome-abrt#131

Signed-off-by: Matej Habrnal <mhabrnal@redhat.com>
Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
 src/configuration-gui/abrt-config-widget.c     | 152 ++++++++++++++++++++++---
 src/configuration-gui/abrt-config-widget.glade | 119 +++++++++++++------
 2 files changed, 219 insertions(+), 52 deletions(-)

diff --git a/src/configuration-gui/abrt-config-widget.c b/src/configuration-gui/abrt-config-widget.c
index 664180d..7d2430b 100644
--- a/src/configuration-gui/abrt-config-widget.c
+++ b/src/configuration-gui/abrt-config-widget.c
@@ -38,10 +38,11 @@ typedef struct {
 } AbrtAppConfiguration;
 
 typedef struct {
-    const char *name;
-    GtkSwitch *widget;
-    gboolean default_value;
-    gboolean current_value;
+    const char *name;           ///< e.g. ask_steal_dir, report-technical-problems
+    GtkSwitch *switch_widget;
+    GtkWidget *radio_button_widget[3];
+    int default_value;
+    int current_value;
     AbrtAppConfiguration *config;
 } AbrtConfigWidgetOption;
 
@@ -49,17 +50,34 @@ enum AbrtOptions
 {
     _ABRT_OPT_BEGIN_,
 
-    ABRT_OPT_UPLOAD_COREDUMP = _ABRT_OPT_BEGIN_,
-    ABRT_OPT_STEAL_DIRECTORY,
+    _ABRT_OPT_SWITCH_BEGIN_= _ABRT_OPT_BEGIN_,
+
+    ABRT_OPT_STEAL_DIRECTORY= _ABRT_OPT_BEGIN_,
     ABRT_OPT_PRIVATE_TICKET,
     ABRT_OPT_SEND_UREPORT,
     ABRT_OPT_SHORTENED_REPORTING,
     ABRT_OPT_SILENT_SHORTENED_REPORTING,
     ABRT_OPT_NOTIFY_INCOMPLETE_PROBLEMS,
 
+    _ABRT_OPT_SWITCH_END_,
+
+    _ABRT_RADIOBUTTON_OPT_BEGIN_= _ABRT_OPT_SWITCH_END_,
+
+    ABRT_OPT_UPLOAD_COREDUMP= _ABRT_OPT_SWITCH_END_,
+
     _ABRT_OPT_END_,
 };
 
+enum AbrtRadioButtonOptions
+{
+    _ABRT_RADIOBUTTON_OPT_ = -1,
+    ABRT_RADIOBUTTON_OPT_NEVER = 0,
+    ABRT_RADIOBUTTON_OPT_ALWAYS = 1,
+    ABRT_RADIOBUTTON_OPT_ASK = 2,
+};
+
+/* This structure holds private data of AbrtConfigWidget
+ */
 struct AbrtConfigWidgetPrivate {
     GtkBuilder   *builder;
     AbrtAppConfiguration *report_gtk_conf;
@@ -103,7 +121,13 @@ abrt_app_configuration_set_value(AbrtAppConfiguration *conf, const char *name, c
 static const char *
 abrt_app_configuration_get_value(AbrtAppConfiguration *conf, const char *name)
 {
-    return get_app_user_setting(conf->settings, name);
+    if (conf->settings)
+    {
+        const char *val = get_app_user_setting(conf->settings, name);
+        return (val == NULL || strcmp(val, "") == 0) ? NULL : val;
+    }
+
+    assert(!"BUG: not properly initialized AbrtAppConfiguration");
 }
 
 static void
@@ -186,9 +210,30 @@ on_switch_activate(GObject       *object,
 }
 
 static void
-update_option_current_value(AbrtConfigWidget *self, enum AbrtOptions opid)
+on_radio_button_toggle(GObject       *object,
+        AbrtConfigWidget *config)
 {
-    assert((opid >= _ABRT_OPT_BEGIN_ && opid < _ABRT_OPT_END_) || !"Out of range Option ID value");
+    /* inactive radio button */
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(object)) == false)
+        return;
+
+    AbrtConfigWidgetOption *option = g_object_get_data(G_OBJECT(object), "abrt-option");
+    if (option->config == NULL)
+        return;
+
+    /* get active radio button */
+    const char *val = g_object_get_data(G_OBJECT(object), "abrt-triple-switch-value");
+    log_debug("%s : %s", option->name, val);
+
+    abrt_app_configuration_set_value(option->config, option->name, val);
+    abrt_app_configuration_save(option->config);
+    emit_change(config);
+}
+
+static void
+update_option_switch_current_value(AbrtConfigWidget *self, enum AbrtOptions opid)
+{
+    assert((opid >= _ABRT_OPT_SWITCH_BEGIN_ && opid < _ABRT_OPT_SWITCH_END_) || !"Out of range Option ID value");
 
     AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
     const char *val = abrt_app_configuration_get_value(option->config, option->name);
@@ -196,19 +241,80 @@ update_option_current_value(AbrtConfigWidget *self, enum AbrtOptions opid)
 }
 
 static void
+update_option_radio_button_current_value(AbrtConfigWidget *self, enum AbrtOptions opid)
+{
+    assert((opid >= _ABRT_RADIOBUTTON_OPT_BEGIN_ && opid < _ABRT_OPT_END_) || !"Out of range Option ID value");
+
+    AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
+
+    const char *val = NULL;
+    if (option->config != NULL)
+        val = abrt_app_configuration_get_value(option->config, option->name);
+
+    if (val == NULL)
+        option->current_value = option->default_value;
+    else if (string_to_bool(val))
+        option->current_value = ABRT_RADIOBUTTON_OPT_ALWAYS;
+    else
+        option->current_value = ABRT_RADIOBUTTON_OPT_NEVER;
+}
+
+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");
+    assert((opid >= _ABRT_OPT_SWITCH_BEGIN_ && opid < _ABRT_OPT_SWITCH_END_) || !"Out of range Option ID value");
 
     AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
-    update_option_current_value(self, opid);
+    update_option_switch_current_value(self, opid);
 
     GtkSwitch *gsw = GTK_SWITCH(WID(switch_name));
-    option->widget = gsw;
-    gtk_switch_set_active(gsw, option->current_value);
+    option->switch_widget = gsw;
+    gtk_switch_set_active(gsw, (gboolean)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), self);
+
+    /* If the option has no config, make the corresponding insensitive. */
+    gtk_widget_set_sensitive(GTK_WIDGET(gsw), option->config != NULL);
+}
+
+static void
+connect_radio_buttons_with_option(AbrtConfigWidget *self, enum AbrtOptions opid,
+                 const char *btn_always_name, const char *btn_never_name,
+                 const char *btn_ask_name)
+{
+    assert((opid >= _ABRT_RADIOBUTTON_OPT_BEGIN_ && opid < _ABRT_OPT_END_) || !"Out of range Option ID value");
+
+    AbrtConfigWidgetOption *option = &(self->priv->options[opid]);
+    update_option_radio_button_current_value(self, opid);
+
+    GtkWidget *btn_always = WID(btn_always_name);
+    GtkWidget *btn_never = WID(btn_never_name);
+    GtkWidget *btn_ask = WID(btn_ask_name);
+
+    option->radio_button_widget[ABRT_RADIOBUTTON_OPT_ALWAYS] = btn_always;
+    option->radio_button_widget[ABRT_RADIOBUTTON_OPT_NEVER] = btn_never;
+    option->radio_button_widget[ABRT_RADIOBUTTON_OPT_ASK] = btn_ask;
+
+    GtkWidget *active_button = option->radio_button_widget[option->current_value];
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(active_button), TRUE);
+
+    g_object_set_data(G_OBJECT(btn_always), "abrt-option", option);
+    g_object_set_data(G_OBJECT(btn_always), "abrt-triple-switch-value", (char *)"yes");
+    g_object_set_data(G_OBJECT(btn_never), "abrt-option", option);
+    g_object_set_data(G_OBJECT(btn_never), "abrt-triple-switch-value", (char *)"no");
+    g_object_set_data(G_OBJECT(btn_ask), "abrt-option", option);
+    g_object_set_data(G_OBJECT(btn_ask), "abrt-triple-switch-value", NULL);
+
+    g_signal_connect(btn_always, "toggled", G_CALLBACK(on_radio_button_toggle), self);
+    g_signal_connect(btn_never, "toggled", G_CALLBACK(on_radio_button_toggle), self);
+    g_signal_connect(btn_ask, "toggled", G_CALLBACK(on_radio_button_toggle), self);
+
+    /* If the option has no config, make the corresponding insensitive. */
+    gtk_widget_set_sensitive(GTK_WIDGET(btn_always), option->config != NULL);
+    gtk_widget_set_sensitive(GTK_WIDGET(btn_never), option->config != NULL);
+    gtk_widget_set_sensitive(GTK_WIDGET(btn_ask), option->config != NULL);
 }
 
 static void
@@ -246,8 +352,8 @@ abrt_config_widget_init(AbrtConfigWidget *self)
     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->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].name = "abrt_analyze_upload_coredump";
+    self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].default_value = ABRT_RADIOBUTTON_OPT_ASK;
     self->priv->options[ABRT_OPT_UPLOAD_COREDUMP].config = self->priv->report_gtk_conf;
 
     self->priv->options[ABRT_OPT_PRIVATE_TICKET].name = CREATE_PRIVATE_TICKET;
@@ -271,8 +377,11 @@ abrt_config_widget_init(AbrtConfigWidget *self)
     self->priv->options[ABRT_OPT_NOTIFY_INCOMPLETE_PROBLEMS].default_value = FALSE;
     self->priv->options[ABRT_OPT_NOTIFY_INCOMPLETE_PROBLEMS].config = self->priv->abrt_applet_conf;
 
+    /* Connect radio buttons with options */
+    connect_radio_buttons_with_option(self, ABRT_OPT_UPLOAD_COREDUMP,
+                                        "bg_always", "bg_never", "bg_ask" );
+
     /* Connect widgets with options */
-    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_PRIVATE_TICKET, "switch_private_ticket");
     connect_switch_with_option(self, ABRT_OPT_SEND_UREPORT, "switch_send_ureport");
@@ -302,6 +411,13 @@ abrt_config_widget_new()
 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);
+    for(unsigned i = _ABRT_OPT_SWITCH_BEGIN_; i < _ABRT_OPT_SWITCH_END_; ++i)
+        gtk_switch_set_active(self->priv->options[i].switch_widget, self->priv->options[i].default_value);
+
+    for(unsigned i = _ABRT_RADIOBUTTON_OPT_BEGIN_; i < _ABRT_OPT_END_; ++i)
+    {
+        unsigned default_value = self->priv->options[i].default_value;
+        GtkWidget *radio_button = self->priv->options[i].radio_button_widget[default_value];
+        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button), TRUE);
+    }
 }
diff --git a/src/configuration-gui/abrt-config-widget.glade b/src/configuration-gui/abrt-config-widget.glade
index 3aa566c..30737ff 100644
--- a/src/configuration-gui/abrt-config-widget.glade
+++ b/src/configuration-gui/abrt-config-widget.glade
@@ -49,21 +49,6 @@
           </packing>
         </child>
         <child>
-          <object class="GtkSwitch" id="switch_upload_coredump">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="halign">end</property>
-            <property name="valign">center</property>
-            <property name="margin_left">10</property>
-          </object>
-          <packing>
-            <property name="left_attach">1</property>
-            <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
           <object class="GtkSwitch" id="switch_steal_directory">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -163,7 +148,7 @@
           <object class="GtkImage" id="image1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="tooltip_text" translatable="yes">The coredump file is necessary for generating stack trace which is time and space consuming operation. ABRT provides a service which generates the stack trace from the coredump but you have to upload the coredump to this service. With this option disabled ABRT will upload the coredump without asking.</property>
+            <property name="tooltip_text" translatable="yes">The coredump file is necessary for generating stack trace which is time and space consuming operation. ABRT provides a service which generates the stack trace from the coredump but you have to upload the coredump to this service. With option 'Always' ABRT will always upload the coredump without asking. With option 'Never' the stack trace will be always generated locally. With option 'Ask' ABRT will always ask the user.</property>
             <property name="halign">end</property>
             <property name="margin_left">5</property>
             <property name="margin_right">1</property>
@@ -241,24 +226,6 @@
           </packing>
         </child>
         <child>
-          <object class="GtkLabel" id="label1">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="halign">start</property>
-            <property name="hexpand">True</property>
-            <property name="ypad">10</property>
-            <property name="label" translatable="yes">Ask before uploading coredump</property>
-            <signal name="enter-notify-event" handler="label_enter_notify_event_cb" swapped="no"/>
-            <signal name="leave-notify-event" handler="label_leave_notify_event_cb" swapped="no"/>
-          </object>
-          <packing>
-            <property name="left_attach">0</property>
-            <property name="top_attach">0</property>
-            <property name="width">1</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
           <object class="GtkImage" id="image6">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
@@ -352,6 +319,90 @@
             <property name="height">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkButtonBox" id="bg_button_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">end</property>
+            <property name="valign">center</property>
+            <property name="hexpand">False</property>
+            <property name="vexpand">False</property>
+            <property name="resize_mode">immediate</property>
+            <property name="layout_style">expand</property>
+            <child>
+              <object class="GtkRadioButton" id="bg_always">
+                <property name="label" translatable="yes">Always</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">False</property>
+                <property name="group">bg_ask</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+                <property name="non_homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="bg_never">
+                <property name="label" translatable="yes">Never</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">False</property>
+                <property name="group">bg_ask</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="bg_ask">
+                <property name="label" translatable="yes">Ask</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">False</property>
+                <property name="xalign">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">False</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="ypad">10</property>
+            <property name="label" translatable="yes">Upload coredump for backtrace generation</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
       </object>
     </child>
   </object>
-- 
2.1.0

