[gnome-control-center] user-accounts: Cleaner interaction with UmAccountDialog actions



commit 2e228b99926a199489a664178e034714864770af
Author: Stef Walter <stefw gnome org>
Date:   Wed Jun 6 22:51:19 2012 +0200

    user-accounts: Cleaner interaction with UmAccountDialog actions
    
    More clear scoping and interaction with running actions in
    UmAccountDialog. In later 'enterprise login' patches we have long
    running actions that's why this needs cleaning up.
    
    In particular:
    
     * Show errors as children of the dialog.
     * Errors don't make the account dialog go away, user can correct
       problems.
     * Use more standard GAsyncResult style callbacks:
       um_account_dialog_perform() um_account_dialog_finish()
     * Disable controls while the operation is happening.
     * Allow the user to cancel long actions in UmAccountDialog by
       pressing the cancel button.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=677548

 panels/user-accounts/um-account-dialog.c |  157 +++++++++++++++++++++++-------
 panels/user-accounts/um-account-dialog.h |    8 +-
 panels/user-accounts/um-user-manager.c   |    3 +-
 panels/user-accounts/um-user-manager.h   |    1 +
 panels/user-accounts/um-user-panel.c     |   14 +++-
 5 files changed, 142 insertions(+), 41 deletions(-)
---
diff --git a/panels/user-accounts/um-account-dialog.c b/panels/user-accounts/um-account-dialog.c
index 4301d1b..dcc5158 100644
--- a/panels/user-accounts/um-account-dialog.c
+++ b/panels/user-accounts/um-account-dialog.c
@@ -37,15 +37,16 @@
 
 struct _UmAccountDialog {
         GtkDialog parent;
+        GtkWidget *container_widget;
+        GSimpleAsyncResult *async;
+        GCancellable *cancellable;
+
         GtkWidget *username_combo;
         GtkWidget *name_entry;
         GtkWidget *account_type_combo;
 
         gboolean valid_name;
         gboolean valid_username;
-
-        UserCreatedCallback user_created_callback;
-        gpointer            user_created_data;
 };
 
 struct _UmAccountDialogClass {
@@ -55,8 +56,50 @@ struct _UmAccountDialogClass {
 G_DEFINE_TYPE (UmAccountDialog, um_account_dialog, GTK_TYPE_DIALOG);
 
 static void
-cancel_account_dialog (UmAccountDialog *self)
+show_error_dialog (UmAccountDialog *self,
+                   const gchar *message,
+                   GError *error)
+{
+        GtkWidget *dialog;
+
+        dialog = gtk_message_dialog_new (GTK_WINDOW (self),
+                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                         GTK_MESSAGE_ERROR,
+                                         GTK_BUTTONS_CLOSE,
+                                         message);
+
+        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                  "%s", error->message);
+
+        g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+        gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+begin_action (UmAccountDialog *self)
+{
+        gtk_widget_set_sensitive (self->container_widget, FALSE);
+        gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, FALSE);
+}
+
+static void
+finish_action (UmAccountDialog *self)
+{
+        gtk_widget_set_sensitive (self->container_widget, TRUE);
+        gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, TRUE);
+}
+
+static void
+complete_dialog (UmAccountDialog *self,
+                 UmUser *user)
 {
+        if (user != NULL) {
+                g_simple_async_result_set_op_res_gpointer (self->async,
+                                                           g_object_ref (user),
+                                                           g_object_unref);
+        }
+
+        g_simple_async_result_complete_in_idle (self->async);
         gtk_widget_hide (GTK_WIDGET (self));
 }
 
@@ -68,29 +111,18 @@ create_user_done (UmUserManager   *manager,
         UmUser *user;
         GError *error;
 
-        error = NULL;
-        if (!um_user_manager_create_user_finish (manager, res, &user, &error)) {
-
-                if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED)) {
-                        GtkWidget *dialog;
-
-                        dialog = gtk_message_dialog_new (gtk_window_get_transient_for (GTK_WINDOW (self)),
-                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                         GTK_MESSAGE_ERROR,
-                                                         GTK_BUTTONS_CLOSE,
-                                                         _("Failed to create user"));
+        finish_action (self);
 
-                        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
-                                                                  "%s", error->message);
+        /* Note that user is returned without an extra reference */
 
-                        g_signal_connect (G_OBJECT (dialog), "response",
-                                          G_CALLBACK (gtk_widget_destroy), NULL);
-                        gtk_window_present (GTK_WINDOW (dialog));
-                }
+        error = NULL;
+        if (!um_user_manager_create_user_finish (manager, res, &user, &error)) {
+                if (!g_error_matches (error, UM_USER_MANAGER_ERROR, UM_USER_MANAGER_ERROR_PERMISSION_DENIED))
+                       show_error_dialog (self, _("Failed to create user"), error);
                 g_error_free (error);
-        }
-        else {
-                self->user_created_callback (user, self->user_created_data);
+                gtk_widget_grab_focus (self->name_entry);
+        } else {
+                complete_dialog (self, user);
         }
 }
 
@@ -104,6 +136,8 @@ accept_account_dialog (UmAccountDialog *self)
         GtkTreeModel *model;
         GtkTreeIter iter;
 
+        begin_action (self);
+
         name = gtk_entry_get_text (GTK_ENTRY (self->name_entry));
         username = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (self->username_combo));
         model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->account_type_combo));
@@ -115,12 +149,11 @@ accept_account_dialog (UmAccountDialog *self)
                                      username,
                                      name,
                                      account_type,
+                                     self->cancellable,
                                      (GAsyncReadyCallback)create_user_done,
                                      self,
                                      NULL);
         g_object_unref (manager);
-
-        gtk_widget_hide (GTK_WIDGET (self));
 }
 
 static void
@@ -212,6 +245,7 @@ um_account_dialog_init (UmAccountDialog *self)
 
         widget = (GtkWidget *) gtk_builder_get_object (builder, "account-dialog");
         gtk_container_add (GTK_CONTAINER (content), widget);
+        self->container_widget = widget;
 
         widget = (GtkWidget *) gtk_builder_get_object (builder, "username-combo");
         g_signal_connect (widget, "changed",
@@ -241,16 +275,43 @@ um_account_dialog_response (GtkDialog *dialog,
                 break;
         case GTK_RESPONSE_CANCEL:
         case GTK_RESPONSE_DELETE_EVENT:
-                cancel_account_dialog (self);
+                g_cancellable_cancel (self->cancellable);
+                complete_dialog (self, NULL);
                 break;
         }
 }
 
 static void
+um_account_dialog_dispose (GObject *obj)
+{
+        UmAccountDialog *self = UM_ACCOUNT_DIALOG (obj);
+
+        if (self->cancellable)
+                g_cancellable_cancel (self->cancellable);
+
+        G_OBJECT_CLASS (um_account_dialog_parent_class)->dispose (obj);
+}
+
+static void
+um_account_dialog_finalize (GObject *obj)
+{
+        UmAccountDialog *self = UM_ACCOUNT_DIALOG (obj);
+
+        if (self->cancellable)
+                g_object_unref (self->cancellable);
+
+        G_OBJECT_CLASS (um_account_dialog_parent_class)->finalize (obj);
+}
+
+static void
 um_account_dialog_class_init (UmAccountDialogClass *klass)
 {
+        GObjectClass *object_class = G_OBJECT_CLASS (klass);
         GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
 
+        object_class->dispose = um_account_dialog_dispose;
+        object_class->finalize = um_account_dialog_finalize;
+
         dialog_class->response = um_account_dialog_response;
 }
 
@@ -263,26 +324,54 @@ um_account_dialog_new (void)
 void
 um_account_dialog_show (UmAccountDialog     *self,
                         GtkWindow           *parent,
-                        UserCreatedCallback  user_created_callback,
-                        gpointer             user_created_data)
+                        GAsyncReadyCallback  callback,
+                        gpointer             user_data)
 {
         GtkTreeModel *model;
 
+        g_return_if_fail (UM_IS_ACCOUNT_DIALOG (self));
+
+        /* Make sure not already doing an operation */
+        g_return_if_fail (self->async == NULL);
+
+        self->async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+                                                 um_account_dialog_show);
+
+        if (self->cancellable)
+                g_object_unref (self->cancellable);
+        self->cancellable = g_cancellable_new ();
+
         gtk_entry_set_text (GTK_ENTRY (self->name_entry), "");
         gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (self->username_combo))), "");
         model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->username_combo));
         gtk_list_store_clear (GTK_LIST_STORE (model));
         gtk_combo_box_set_active (GTK_COMBO_BOX (self->account_type_combo), 0);
 
+        self->valid_name = self->valid_username = FALSE;
+        gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK,
+                                           self->valid_name && self->valid_username);
+
         gtk_window_set_modal (GTK_WINDOW (self), parent != NULL);
         gtk_window_set_transient_for (GTK_WINDOW (self), parent);
         gtk_window_present (GTK_WINDOW (self));
         gtk_widget_grab_focus (self->name_entry);
+}
 
-        self->valid_name = self->valid_username = FALSE;
-        gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK,
-                                           self->valid_name && self->valid_username);
+UmUser *
+um_account_dialog_finish (UmAccountDialog     *self,
+                          GAsyncResult        *result)
+{
+        UmUser *user;
+
+        g_return_val_if_fail (UM_IS_ACCOUNT_DIALOG (self), NULL);
+        g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+                              um_account_dialog_show), NULL);
+        g_return_val_if_fail (result == G_ASYNC_RESULT (self->async), NULL);
+
+        user = g_simple_async_result_get_op_res_gpointer (self->async);
+        if (user != NULL)
+                g_object_ref (user);
 
-        self->user_created_callback = user_created_callback;
-        self->user_created_data = user_created_data;
+        g_clear_object (&self->async);
+        return user;
 }
diff --git a/panels/user-accounts/um-account-dialog.h b/panels/user-accounts/um-account-dialog.h
index 9745532..a86194a 100644
--- a/panels/user-accounts/um-account-dialog.h
+++ b/panels/user-accounts/um-account-dialog.h
@@ -34,14 +34,14 @@ G_BEGIN_DECLS
 typedef struct _UmAccountDialog UmAccountDialog;
 typedef struct _UmAccountDialogClass UmAccountDialogClass;
 
-typedef void (*UserCreatedCallback) (UmUser *user, gpointer data);
-
 GType            um_account_dialog_get_type (void) G_GNUC_CONST;
 UmAccountDialog *um_account_dialog_new      (void);
 void             um_account_dialog_show     (UmAccountDialog     *self,
                                              GtkWindow           *parent,
-                                             UserCreatedCallback  user_created,
-                                             gpointer             data);
+                                             GAsyncReadyCallback  callback,
+                                             gpointer             user_data);
+UmUser *         um_account_dialog_finish   (UmAccountDialog     *self,
+                                             GAsyncResult        *result);
 
 G_END_DECLS
 
diff --git a/panels/user-accounts/um-user-manager.c b/panels/user-accounts/um-user-manager.c
index 432fe8d..f95ad86 100644
--- a/panels/user-accounts/um-user-manager.c
+++ b/panels/user-accounts/um-user-manager.c
@@ -518,6 +518,7 @@ um_user_manager_create_user (UmUserManager       *manager,
                              const char          *user_name,
                              const char          *real_name,
                              gint                 account_type,
+                             GCancellable        *cancellable,
                              GAsyncReadyCallback  done,
                              gpointer             done_data,
                              GDestroyNotify       destroy)
@@ -536,7 +537,7 @@ um_user_manager_create_user (UmUserManager       *manager,
                            g_variant_new ("(ssi)", user_name, real_name, account_type),
                            G_DBUS_CALL_FLAGS_NONE,
                            -1,
-                           NULL,
+                           cancellable,
                            create_user_done,
                            data);
 }
diff --git a/panels/user-accounts/um-user-manager.h b/panels/user-accounts/um-user-manager.h
index abf6e42..c47ecb5 100644
--- a/panels/user-accounts/um-user-manager.h
+++ b/panels/user-accounts/um-user-manager.h
@@ -88,6 +88,7 @@ void               um_user_manager_create_user           (UmUserManager       *m
                                                           const char          *user_name,
                                                           const char          *real_name,
                                                           gint                 account_type,
+                                                          GCancellable        *cancellable,
                                                           GAsyncReadyCallback  done,
                                                           gpointer             user_data,
                                                           GDestroyNotify       destroy);
diff --git a/panels/user-accounts/um-user-panel.c b/panels/user-accounts/um-user-panel.c
index 3793862..65e132a 100644
--- a/panels/user-accounts/um-user-panel.c
+++ b/panels/user-accounts/um-user-panel.c
@@ -299,14 +299,22 @@ user_changed (UmUserManager *um, UmUser *user, UmUserPanelPrivate *d)
 }
 
 static void
-select_created_user (UmUser *user, UmUserPanelPrivate *d)
+select_created_user (GObject *object,
+                     GAsyncResult *result,
+                     gpointer user_data)
 {
+        UmUserPanelPrivate *d = user_data;
         GtkTreeView *tv;
         GtkTreeModel *model;
         GtkTreeSelection *selection;
         GtkTreeIter iter;
         UmUser *current;
         GtkTreePath *path;
+        UmUser *user;
+
+        user = um_account_dialog_finish (UM_ACCOUNT_DIALOG (object), result);
+        if (user == NULL)
+                return;
 
         tv = (GtkTreeView *)get_widget (d, "list-treeview");
         model = gtk_tree_view_get_model (tv);
@@ -326,6 +334,8 @@ select_created_user (UmUser *user, UmUserPanelPrivate *d)
                 if (current)
                         g_object_unref (current);
         } while (gtk_tree_model_iter_next (model, &iter));
+
+        g_object_unref (user);
 }
 
 static void
@@ -333,7 +343,7 @@ add_user (GtkButton *button, UmUserPanelPrivate *d)
 {
         um_account_dialog_show (d->account_dialog,
                                 GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)),
-                                (UserCreatedCallback)select_created_user, d);
+                                select_created_user, d);
 }
 
 static void



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]