diff options
author | Cosimo Cecchi <cosimoc@gnome.org> | 2009-08-31 21:55:39 +0800 |
---|---|---|
committer | Cosimo Cecchi <cosimoc@gnome.org> | 2009-08-31 21:55:39 +0800 |
commit | 647858dc34ec9786c88b22fea74fc45ff3bb14f6 (patch) | |
tree | 9a2750ca1e0f835f797ff5c9ea9a2253aba47f62 | |
parent | 5a1342eb769353967062163bad6258edf18e460a (diff) | |
parent | cd277c0c7cbe0389c242abb58b995389000f3e53 (diff) | |
download | gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar.gz gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar.bz2 gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar.lz gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar.xz gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.tar.zst gsoc2013-empathy-647858dc34ec9786c88b22fea74fc45ff3bb14f6.zip |
Merge commit 'jtellier/confirm-lose-accounts-settings'
-rw-r--r-- | libempathy-gtk/empathy-account-widget.c | 52 | ||||
-rw-r--r-- | libempathy-gtk/empathy-account-widget.h | 5 | ||||
-rw-r--r-- | src/empathy-accounts-dialog.c | 335 |
3 files changed, 330 insertions, 62 deletions
diff --git a/libempathy-gtk/empathy-account-widget.c b/libempathy-gtk/empathy-account-widget.c index 02ca44cf3..df0dc967b 100644 --- a/libempathy-gtk/empathy-account-widget.c +++ b/libempathy-gtk/empathy-account-widget.c @@ -61,6 +61,9 @@ typedef struct { gboolean simple; + gboolean contains_pending_changes; + gboolean original_enabled_checkbox_value; + /* An EmpathyAccountWidget can be used to either create an account or * modify it. When we are creating an account, this member is set to TRUE */ gboolean creating_account; @@ -97,6 +100,7 @@ account_widget_set_control_buttons_sensitivity (EmpathyAccountWidget *self, { gtk_widget_set_sensitive (priv->apply_button, sensitive); gtk_widget_set_sensitive (priv->cancel_button, sensitive); + priv->contains_pending_changes = sensitive; } } @@ -109,10 +113,7 @@ account_widget_handle_control_buttons_sensitivity (EmpathyAccountWidget *self) is_valid = empathy_account_settings_is_valid (priv->settings); if (!priv->simple) - { - gtk_widget_set_sensitive (priv->apply_button, is_valid); - gtk_widget_set_sensitive (priv->cancel_button, is_valid); - } + account_widget_set_control_buttons_sensitivity (self, is_valid); g_signal_emit (self, signals[HANDLE_APPLY], 0, is_valid); } @@ -150,16 +151,6 @@ account_widget_entry_changed_common (EmpathyAccountWidget *self, } } -static gboolean -account_widget_entry_focus_cb (GtkWidget *widget, - GdkEventFocus *event, - EmpathyAccountWidget *self) -{ - account_widget_entry_changed_common (self, GTK_ENTRY (widget), TRUE); - - return FALSE; -} - static void account_widget_entry_changed_cb (GtkEditable *entry, EmpathyAccountWidget *self) @@ -355,9 +346,6 @@ account_widget_setup_widget (EmpathyAccountWidget *self, gtk_entry_set_visibility (GTK_ENTRY (widget), FALSE); } - g_signal_connect (widget, "focus-out-event", - G_CALLBACK (account_widget_entry_focus_cb), - self); g_signal_connect (widget, "changed", G_CALLBACK (account_widget_entry_changed_cb), self); } @@ -1044,7 +1032,7 @@ empathy_account_widget_enabled_cb (EmpathyAccount *account, } static void -account_widget_enabled_toggled_cb (GtkToggleButton *toggle_button, +account_widget_enabled_released_cb (GtkToggleButton *toggle_button, gpointer user_data) { account_widget_handle_control_buttons_sensitivity ( @@ -1237,9 +1225,11 @@ do_constructed (GObject *obj) priv->enabled_checkbox = gtk_check_button_new_with_label (_("Enabled")); + priv->original_enabled_checkbox_value = + empathy_account_is_enabled (account); gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON (priv->enabled_checkbox), - empathy_account_is_enabled (account)); + priv->original_enabled_checkbox_value); g_object_get (priv->table_common_settings, "n-rows", &nb_rows, "n-columns", &nb_columns, NULL); @@ -1253,8 +1243,8 @@ do_constructed (GObject *obj) gtk_widget_show (priv->enabled_checkbox); - g_signal_connect (G_OBJECT (priv->enabled_checkbox), "toggled", - G_CALLBACK (account_widget_enabled_toggled_cb), self); + g_signal_connect (G_OBJECT (priv->enabled_checkbox), "released", + G_CALLBACK (account_widget_enabled_released_cb), self); } /* hook up to widget destruction to unref ourselves */ @@ -1388,6 +1378,26 @@ empathy_account_widget_init (EmpathyAccountWidget *self) /* public methods */ void +empathy_account_widget_discard_pending_changes + (EmpathyAccountWidget *widget) +{ + EmpathyAccountWidgetPriv *priv = GET_PRIV (widget); + + empathy_account_settings_discard_changes (priv->settings); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->enabled_checkbox), + priv->original_enabled_checkbox_value); + priv->contains_pending_changes = FALSE; +} + +gboolean +empathy_account_widget_contains_pending_changes (EmpathyAccountWidget *widget) +{ + EmpathyAccountWidgetPriv *priv = GET_PRIV (widget); + + return priv->contains_pending_changes; +} + +void empathy_account_widget_handle_params (EmpathyAccountWidget *self, const gchar *first_widget, ...) diff --git a/libempathy-gtk/empathy-account-widget.h b/libempathy-gtk/empathy-account-widget.h index d4111eba2..75214fac8 100644 --- a/libempathy-gtk/empathy-account-widget.h +++ b/libempathy-gtk/empathy-account-widget.h @@ -65,6 +65,11 @@ EmpathyAccountWidget * empathy_account_widget_new_for_protocol ( EmpathyAccountSettings *settings, gboolean simple); +gboolean empathy_account_widget_contains_pending_changes + (EmpathyAccountWidget *widget); +void empathy_account_widget_discard_pending_changes + (EmpathyAccountWidget *widget); + G_END_DECLS #endif /* __EMPATHY_ACCOUNT_WIDGET_H__ */ diff --git a/src/empathy-accounts-dialog.c b/src/empathy-accounts-dialog.c index c28dbd30d..a00c1b5eb 100644 --- a/src/empathy-accounts-dialog.c +++ b/src/empathy-accounts-dialog.c @@ -57,6 +57,11 @@ /* Flashing delay for icons (milliseconds). */ #define FLASH_TIMEOUT 500 +/* The primary text of the dialog shown to the user when he is about to lose + * unsaved changes */ +#define PENDING_CHANGES_QUESTION_PRIMARY_TEXT \ + _("There are unsaved modification regarding your %s account.") + #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountsDialog) G_DEFINE_TYPE (EmpathyAccountsDialog, empathy_accounts_dialog, G_TYPE_OBJECT); @@ -87,6 +92,14 @@ typedef struct { GtkWidget *label_type; GtkWidget *settings_widget; + /* We have to keep a reference on the actual EmpathyAccountWidget, not just + * his GtkWidget. It is the only reliable source we can query to know if + * there are any unsaved changes to the currently selected account. We can't + * look at the account settings because it does not contain everything that + * can be changed using the EmpathyAccountWidget. For instance, it does not + * contain the state of the "Enabled" checkbox. */ + EmpathyAccountWidget *setting_widget_object; + gboolean connecting_show; guint connecting_id; @@ -98,6 +111,16 @@ typedef struct { GtkWindow *parent_window; EmpathyAccount *initial_selection; + + /* Those are needed when changing the selected row. When a user selects + * another account and there are unsaved changes on the currently selected + * one, a confirmation message box is presented to him. Since his answer + * is retrieved asynchronously, we keep some information as member of the + * EmpathyAccountsDialog object. */ + gboolean force_change_row; + GtkTreeRowReference *destination_row; + + } EmpathyAccountsDialogPriv; enum { @@ -120,6 +143,11 @@ static void accounts_dialog_account_display_name_changed_cb ( static EmpathyAccountSettings * accounts_dialog_model_get_selected_settings ( EmpathyAccountsDialog *dialog); +static gboolean accounts_dialog_get_settings_iter ( + EmpathyAccountsDialog *dialog, + EmpathyAccountSettings *settings, + GtkTreeIter *iter); + static void accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog); static void accounts_dialog_update (EmpathyAccountsDialog *dialog, @@ -163,7 +191,7 @@ empathy_account_dialog_widget_cancelled_cb (EmpathyAccountWidget *widget_object, COL_ACCOUNT_SETTINGS_POINTER, &settings, COL_ACCOUNT_POINTER, &account, -1); - empathy_account_settings_discard_changes (settings); + empathy_account_widget_discard_pending_changes (priv->setting_widget_object); if (account == NULL) { @@ -194,7 +222,7 @@ get_default_display_name (EmpathyAccountSettings *settings) if (login_id != NULL) { - if (!tp_strdiff(protocol, "irc")) + if (!tp_strdiff (protocol, "irc")) { const gchar* server; server = empathy_account_settings_get_string (settings, "server"); @@ -251,17 +279,20 @@ static void account_dialog_create_settings_widget (EmpathyAccountsDialog *dialog, EmpathyAccountSettings *settings) { - EmpathyAccountWidget *widget_object = NULL; EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); gchar *icon_name; - widget_object = empathy_account_widget_new_for_protocol (settings, FALSE); + priv->setting_widget_object = + empathy_account_widget_new_for_protocol (settings, FALSE); - priv->settings_widget = empathy_account_widget_get_widget (widget_object); + priv->settings_widget = + empathy_account_widget_get_widget (priv->setting_widget_object); - g_signal_connect (widget_object, "account-created", + priv->settings_widget = + empathy_account_widget_get_widget (priv->setting_widget_object); + g_signal_connect (priv->setting_widget_object, "account-created", G_CALLBACK (empathy_account_dialog_account_created_cb), dialog); - g_signal_connect (widget_object, "cancelled", + g_signal_connect (priv->setting_widget_object, "cancelled", G_CALLBACK (empathy_account_dialog_widget_cancelled_cb), dialog); gtk_container_add (GTK_CONTAINER (priv->alignment_settings), @@ -313,6 +344,25 @@ accounts_dialog_model_select_first (EmpathyAccountsDialog *dialog) } } +static gboolean +accounts_dialog_has_pending_change (EmpathyAccountsDialog *dialog, + EmpathyAccount **account) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (model, &iter, COL_ACCOUNT_POINTER, account, -1); + + return *account != NULL && priv->setting_widget_object != NULL + && empathy_account_widget_contains_pending_changes ( + priv->setting_widget_object); +} + static void accounts_dialog_protocol_changed_cb (GtkWidget *widget, EmpathyAccountsDialog *dialog) @@ -347,11 +397,10 @@ accounts_dialog_protocol_changed_cb (GtkWidget *widget, } static void -accounts_dialog_button_add_clicked_cb (GtkWidget *button, - EmpathyAccountsDialog *dialog) +accounts_dialog_setup_ui_to_add_account (EmpathyAccountsDialog *dialog) { - GtkTreeView *view; - GtkTreeModel *model; + GtkTreeView *view; + GtkTreeModel *model; EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); view = GTK_TREE_VIEW (priv->treeview); @@ -376,6 +425,93 @@ accounts_dialog_button_add_clicked_cb (GtkWidget *button, } static void +accounts_dialog_show_question_dialog (EmpathyAccountsDialog *dialog, + gchar *primary_text, + gchar *secondary_text, + GCallback response_callback, + gpointer user_data, + const gchar *first_button_text, + ...) +{ + va_list button_args; + GtkWidget *message_dialog; + const gchar *button_text; + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + + message_dialog = gtk_message_dialog_new (GTK_WINDOW (priv->window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + primary_text); + + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (message_dialog), secondary_text); + + va_start (button_args, first_button_text); + for (button_text = first_button_text; + button_text; + button_text = va_arg (button_args, const gchar *)) + { + gint response_id; + response_id = va_arg (button_args, gint); + + gtk_dialog_add_button (GTK_DIALOG (message_dialog), button_text, response_id); + } + va_end (button_args); + + g_signal_connect (message_dialog, "response", response_callback, user_data); + + gtk_widget_show (message_dialog); +} + +static void +accounts_dialog_add_pending_changes_response_cb (GtkDialog *message_dialog, + gint response_id, + gpointer *user_data) +{ + EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (user_data); + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + + gtk_widget_destroy (GTK_WIDGET (message_dialog)); + + if (response_id == GTK_RESPONSE_YES) + { + empathy_account_widget_discard_pending_changes ( + priv->setting_widget_object); + accounts_dialog_setup_ui_to_add_account (dialog); + } +} + +static void +accounts_dialog_button_add_clicked_cb (GtkWidget *button, + EmpathyAccountsDialog *dialog) +{ + EmpathyAccount *account = NULL; + + if (accounts_dialog_has_pending_change (dialog, &account)) + { + gchar *question_dialog_primary_text = g_strdup_printf ( + PENDING_CHANGES_QUESTION_PRIMARY_TEXT, + empathy_account_get_display_name (account)); + + accounts_dialog_show_question_dialog (dialog, + question_dialog_primary_text, + _("You are about to create a new account, which will discard\n" + "your changes. Are you sure you want to proceed?"), + G_CALLBACK (accounts_dialog_add_pending_changes_response_cb), + dialog, + GTK_STOCK_CANCEL, GTK_RESPONSE_NO, + GTK_STOCK_DISCARD, GTK_RESPONSE_YES, NULL); + + g_free (question_dialog_primary_text); + } + else + { + accounts_dialog_setup_ui_to_add_account (dialog); + } +} + +static void accounts_dialog_update_settings (EmpathyAccountsDialog *dialog, EmpathyAccountSettings *settings) { @@ -609,6 +745,7 @@ accounts_dialog_delete_account_response_cb (GtkDialog *message_dialog, accounts_dialog_account_display_name_changed_cb, account_dialog); empathy_account_remove_async (account, NULL, NULL); g_object_unref (account); + account = NULL; } gtk_list_store_remove (GTK_LIST_STORE (model), &iter); @@ -626,7 +763,7 @@ accounts_dialog_view_delete_activated_cb (EmpathyCellRendererActivatable *cell, EmpathyAccount *account; GtkTreeModel *model; GtkTreeIter iter; - GtkWidget *message_dialog; + gchar *question_dialog_primary_text; EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview)); @@ -643,37 +780,29 @@ accounts_dialog_view_delete_activated_cb (EmpathyCellRendererActivatable *cell, return; } - message_dialog = gtk_message_dialog_new - (GTK_WINDOW (priv->window), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, - _("You are about to remove your %s account!\n" - "Are you sure you want to proceed?"), - empathy_account_get_display_name (account)); - - gtk_message_dialog_format_secondary_text - (GTK_MESSAGE_DIALOG (message_dialog), + question_dialog_primary_text = g_strdup_printf ( + _("You are about to remove your %s account!\n" + "Are you sure you want to proceed?"), + empathy_account_get_display_name (account)); + + accounts_dialog_show_question_dialog (dialog, question_dialog_primary_text, _("Any associated conversations and chat rooms will NOT be " "removed if you decide to proceed.\n" "\n" "Should you decide to add the account back at a later time, " - "they will still be available.")); - - gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_CANCEL, - GTK_RESPONSE_NO); - gtk_dialog_add_button (GTK_DIALOG (message_dialog), - GTK_STOCK_REMOVE, - GTK_RESPONSE_YES); - - g_signal_connect (message_dialog, "response", - G_CALLBACK (accounts_dialog_delete_account_response_cb), dialog); + "they will still be available."), + G_CALLBACK (accounts_dialog_delete_account_response_cb), + dialog, + GTK_STOCK_CANCEL, GTK_RESPONSE_NO, + GTK_STOCK_REMOVE, GTK_RESPONSE_YES, NULL); - gtk_widget_show (message_dialog); + g_free (question_dialog_primary_text); if (account != NULL) - g_object_unref (account); + { + g_object_unref (account); + account = NULL; + } } static void @@ -763,10 +892,6 @@ accounts_dialog_model_selection_changed (GtkTreeSelection *selection, is_selection = gtk_tree_selection_get_selected (selection, &model, &iter); settings = accounts_dialog_model_get_selected_settings (dialog); - - if (settings != NULL) - empathy_account_settings_discard_changes (settings); - accounts_dialog_update_settings (dialog, settings); if (settings != NULL) @@ -774,6 +899,99 @@ accounts_dialog_model_selection_changed (GtkTreeSelection *selection, } static void +accounts_dialog_selection_change_response_cb (GtkDialog *message_dialog, + gint response_id, + gpointer *user_data) +{ + EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (user_data); + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + + gtk_widget_destroy (GTK_WIDGET (message_dialog)); + + if (response_id == GTK_RESPONSE_YES && priv->destination_row != NULL) + { + /* The user wants to lose unsaved changes to the currently selected + * account and select another account. We discard the changes and + * select the other account. */ + GtkTreePath *path; + GtkTreeSelection *selection; + + priv->force_change_row = TRUE; + empathy_account_widget_discard_pending_changes ( + priv->setting_widget_object); + + path = gtk_tree_row_reference_get_path (priv->destination_row); + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (priv->treeview)); + + if (path != NULL) + { + /* This will trigger a call to + * accounts_dialog_account_selection_change() */ + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + } + + gtk_tree_row_reference_free (priv->destination_row); + } + else + { + priv->force_change_row = FALSE; + } +} + +static gboolean +accounts_dialog_account_selection_change (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + gpointer data) +{ + EmpathyAccount *account = NULL; + EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (data); + EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog); + + if (priv->force_change_row) + { + /* We came back here because the user wants to discard changes to his + * modified account. The changes have already been discarded so we + * just change the selected row. */ + priv->force_change_row = FALSE; + return TRUE; + } + + if (accounts_dialog_has_pending_change (dialog, &account)) + { + /* The currently selected account has some unsaved changes. We ask + * the user if he really wants to lose his changes and select another + * account */ + gchar *question_dialog_primary_text; + priv->destination_row = gtk_tree_row_reference_new (model, path); + + question_dialog_primary_text = g_strdup_printf ( + PENDING_CHANGES_QUESTION_PRIMARY_TEXT, + empathy_account_get_display_name (account)); + + accounts_dialog_show_question_dialog (dialog, + question_dialog_primary_text, + _("You are about to select another account, which will discard\n" + "your changes. Are you sure you want to proceed?"), + G_CALLBACK (accounts_dialog_selection_change_response_cb), + dialog, + GTK_STOCK_CANCEL, GTK_RESPONSE_NO, + GTK_STOCK_DISCARD, GTK_RESPONSE_YES, NULL); + + g_free (question_dialog_primary_text); + } + else + { + return TRUE; + } + + return FALSE; +} + +static void accounts_dialog_model_setup (EmpathyAccountsDialog *dialog) { GtkListStore *store; @@ -791,6 +1009,8 @@ accounts_dialog_model_setup (EmpathyAccountsDialog *dialog) selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + gtk_tree_selection_set_select_function (selection, + accounts_dialog_account_selection_change, dialog, NULL); g_signal_connect (selection, "changed", G_CALLBACK (accounts_dialog_model_selection_changed), @@ -1214,11 +1434,44 @@ accounts_dialog_button_help_clicked_cb (GtkWidget *button, } static void +accounts_dialog_close_response_cb (GtkDialog *message_dialog, + gint response_id, + gpointer user_data) +{ + GtkWidget *account_dialog = GTK_WIDGET (user_data); + + gtk_widget_destroy (GTK_WIDGET (message_dialog)); + + if (response_id == GTK_RESPONSE_YES) + gtk_widget_destroy (account_dialog); +} + +static void accounts_dialog_response_cb (GtkWidget *widget, gint response, EmpathyAccountsDialog *dialog) { - if (response == GTK_RESPONSE_CLOSE) + EmpathyAccount *account = NULL; + + if (accounts_dialog_has_pending_change (dialog, &account)) + { + gchar *question_dialog_primary_text; + question_dialog_primary_text = g_strdup_printf ( + PENDING_CHANGES_QUESTION_PRIMARY_TEXT, + empathy_account_get_display_name (account)); + + accounts_dialog_show_question_dialog (dialog, + question_dialog_primary_text, + _("You are about to close the window, which will discard\n" + "your changes. Are you sure you want to proceed?"), + G_CALLBACK (accounts_dialog_close_response_cb), + widget, + GTK_STOCK_CANCEL, GTK_RESPONSE_NO, + GTK_STOCK_DISCARD, GTK_RESPONSE_YES, NULL); + + g_free (question_dialog_primary_text); + } + else if (response == GTK_RESPONSE_CLOSE) gtk_widget_destroy (widget); } |