[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