[polari/wip/bastianilso/error-handling] let application.js handle the errors



commit 4555914f0a548454218f728d54d33abade91c406
Author: Bastian Ilsø <bastianilso src gnome org>
Date:   Wed Jul 22 09:04:48 2015 +0200

    let application.js handle the errors

 src/appNotifications.js |  219 +++++++++++++++++++++++++---------------------
 src/application.js      |   45 ++++++----
 src/connections.js      |    2 +-
 src/mainWindow.js       |   10 +--
 4 files changed, 153 insertions(+), 123 deletions(-)
---
diff --git a/src/appNotifications.js b/src/appNotifications.js
index d0f1e0a..2b4007f 100644
--- a/src/appNotifications.js
+++ b/src/appNotifications.js
@@ -12,25 +12,24 @@ const AppNotification = new Lang.Class({
     Abstract: true,
 
     _init: function() {
-        this.widget = new Gtk.Revealer({ reveal_child: true });
+        this.widget = new Gtk.Revealer({ reveal_child: false });
         this.widget.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
-
-        this.widget.connect('notify::child-revealed',
-                            Lang.bind(this, this._onChildRevealed));
     },
 
     close: function() {
         this.widget.reveal_child = false;
+        this.widget.destroy();
+        this.widget = null;
+    },
+
+    open: function() {
+        this.widget.reveal_child = true;
     },
 
+
     get statusReason() {
         return this._statusReason;
     },
-
-    _onChildRevealed: function() {
-        if (!this.widget.child_revealed)
-            this.widget.destroy();
-    }
 });
 
 const CommandOutputNotification = new Lang.Class({
@@ -94,116 +93,126 @@ const GridOutput = new Lang.Class({
     }
 });
 
-const ConnectingNotification = new Lang.Class({
-    Name: 'ConnectingNotification',
+const ErrorNotification = new Lang.Class({
+    Name: 'ErrorNotification',
     Extends: AppNotification,
 
-    _init: function(account) {
-        //log('created a connecting notification..');
+    _init: function(account, window, error) {
         this.parent();
-        this._account = account;
+        //log('creating error notification..');
         this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
                                     column_spacing: 12 });
 
-        this._grid.add(new Gtk.Spinner({ active: true }));
-
-        let text = _("Connecting to %s").format(account.display_name);
-        let label = new Gtk.Label({ label: text });
-        this._grid.add(label);
-
+        this._grid.add(new Gtk.Image({icon_name: 'dialog-error-symbolic' }));
+        this._account = account;
+        this._window = window;
+        this._button = new Gtk.Button({ valign: Gtk.Align.CENTER });
+        this._label = new Gtk.Label({ max_width_chars: 30, wrap: true });
+        this._populateNotification(error);
+        this._grid.add(this._label);
+        this._grid.add(this._button);
         this.widget.add(this._grid);
         this.widget.show_all();
-
         let id = account.connect('notify::connection-status',
                                  Lang.bind(this, this._onConnectionStatusChanged));
         this.widget.connect('destroy',
             function() {
                 account.disconnect(id);
             });
-        this._statusReason = Tp.ConnectionStatus.CONNECTING;
+        this._statusReason = error;
     },
 
-    _onConnectionStatusChanged: function(account) {
-        if (account.connection_status == Tp.ConnectionStatus.CONNECTING)
-            return;
-        this.close();
-    },
+    _populateNotification: function(error) {
+        // Not sure if it is necessary to support all types of error messages.
+        // Telepathy-idle only emit a small subset of all of them..
 
-    close: function() {
-        this.parent();
-        this._account.notification = null;
+        if (error == Tp.error_get_dbus_name(Tp.Error.NETWORK_ERROR)) {
+            this._label.label = _("Unable to connect to %s").format(this._account.display_name);
+            let details = _("Polari disconnected due to a network error. Please check if the address field 
is correct.");
+            this._button.label =  "Edit Account";
+            this._button.connect('clicked', Lang.bind(this, this._editAccountAction, details));
+        } else if (error == Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED)) {
+            this._label.label = _("Authentication failed for %s").format(this._account.display_name);
+            this._button.label =  "Retry";
+            this._button.connect('clicked', Lang.bind(this, this._retryAccountAction));
+        } else if (error == Tp.error_get_dbus_name(Tp.Error.CHANNEL_BANNED)) {
+            this._label.label = _("You are banned from this room.");
+            this._button.label = "Retry";
+            this._button.connect('clicked', Lang.bind(this, this._retryRoomAction));
+        } else if (error == Tp.error_get_dbus_name(Tp.Error.CHANNEL_FULL)) {
+            this._label.label = _("The room is full.");
+            this._button.label = "Retry";
+            this._button.connect('clicked', Lang.bind(this, this._retryRoomAction));
+        } else if (error == Tp.error_get_dbus_name(Tp.Error.CHANNEL_INVITE_ONLY)) {
+            this._label.label = _("The room is invite-only.");
+            this._button.label = "Retry";
+            this._button.connect('clicked', Lang.bind(this, this._retryRoomAction));
+        } else {
+            log('no match for: ' + error);
+            this._label.label = _("Polari failed to connect for an unknown reason.");
+            this._button.label = "Retry";
+            this._button.connect('clicked', Lang.bind(this, this._retryAccountAction));
+        }
     },
 
-});
-
-const ErrorNotification = new Lang.Class({
-    Name: 'ErrorNotification',
-    Extends: AppNotification,
-
-    _init: function(account, window, statusReason) {
-        this.parent();
-        this._account = account;
-        this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
-                                    column_spacing: 12 });
-
-        this._grid.add(new Gtk.Image({icon_name: 'dialog-error-symbolic' }));
-        // Not sure if it is necessary to support all types of error messages.
-        // Telepathy-idle only emit a small subset of all of them..
-        this._connectionErrorMessages = {};
-        this._connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.NETWORK_ERROR)]
-          = _("Polari disconnected due to a network error. Please check if the address field is correct.");
-        this._connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED)]
-          = _("Authentication failed");
-
-        let button = new Gtk.Button({label: "Edit Account",
-                                     valign: Gtk.Align.CENTER });
-        button.connect('clicked', Lang.bind(this, function() {
-            log('clicked');
-            let error = {message: this._getMessage(account.connection_error),
-                         icon_name: 'dialog-error-symbolic', widget: 'serverEntry'};
-            account.error = error;
-            let dialog = new Connections.ConnectionDetailsDialog(account);
-            dialog.widget.transient_for = window;
-            dialog.widget.show();
-            dialog.widget.connect('response', Lang.bind(this,
-                    function(w, response) {
-                    dialog.widget.destroy();
-                    if (response == Gtk.ResponseType.OK)
-                        this.close();
-                        // should try to connect again but
-                        // we already try again when account info is updated in SSL patch
-                }));
+    _editAccountAction: function(button, details) {
+        //log('clicked');
+        let error = {message: details,
+                     icon_name: 'dialog-error-symbolic', widget: 'serverEntry'};
+        this._account.error = error;
+        let dialog = new Connections.ConnectionDetailsDialog(this._account);
+        dialog.widget.transient_for = this._window;
+        dialog.widget.show();
+        dialog.widget.connect('response', Lang.bind(this,
+            function(w, response) {
+                dialog.widget.destroy();
+                if (response == Gtk.ResponseType.OK)
+                    this.close();
+                    // should try to connect again but
+                    // we already try again when account info is updated in SSL patch
             }));
-        log('creating Connecting Notification..');
-        let text = _("Unable to connect to %s").format(account.display_name);
-        let label = new Gtk.Label({ label: text, max_width_chars: 30, wrap: true });
-        this._grid.add(label);
-        this._grid.add(button);
-        this.widget.add(this._grid);
-        this.widget.show_all();
-        let id = account.connect('notify::connection-status',
-                                 Lang.bind(this, this._onConnectionStatusChanged));
-        this.widget.connect('destroy',
-            function() {
-                account.disconnect(id);
-            });
-        this._statusReason = statusReason;
     },
 
-    _getMessage: function(connectionError) {
-        let message;
-        if (connectionError in this._connectionErrorMessages) {
-            message = this._connectionErrorMessages[connectionError];
-        } else {
-            message = _("Unknown reason");
-        }
-        return message;
+    _retryRoomAction: function() {
+        /*log('clicked');
+        let error = {message: this._getMessage(account.connection_error),
+                     icon_name: 'dialog-error-symbolic', widget: 'serverEntry'};
+        account.error = error;
+        let dialog = new Connections.ConnectionDetailsDialog(account);
+        dialog.widget.transient_for = window;
+        dialog.widget.show();
+        dialog.widget.connect('response', Lang.bind(this,
+                function(w, response) {
+                dialog.widget.destroy();
+                if (response == Gtk.ResponseType.OK)
+                    this.close();
+                    // should try to connect again but
+                    // we already try again when account info is updated in SSL patch
+            }));*/
+    },
+
+    _retryAccountAction: function() {
+        /*log('clicked');
+        let error = {message: this._getMessage(account.connection_error),
+                     icon_name: 'dialog-error-symbolic', widget: 'serverEntry'};
+        account.error = error;
+        let dialog = new Connections.ConnectionDetailsDialog(account);
+        dialog.widget.transient_for = window;
+        dialog.widget.show();
+        dialog.widget.connect('response', Lang.bind(this,
+                function(w, response) {
+                dialog.widget.destroy();
+                if (response == Gtk.ResponseType.OK)
+
+                    // should try to connect again but
+                    // we already try again when account info is updated in SSL patch
+            }));*/
     },
 
     _onConnectionStatusChanged: function(account) {
         if (account.connection_status == Tp.ConnectionStatus.DISCONNECTED)
             return;
-        this.close();
+        //this.close();
     },
 });
 
@@ -231,15 +240,17 @@ const NotificationQueue = new Lang.Class({
         this._notifications[params.identifier] = params;
         //log('checking if ' + params.identifier + ' is active..');
         //log('this._activeNotifications[' + params.type + '].identifier: ' + 
this._activeNotifications[params.type].identifier)
-        if (this._activeNotifications[params.type].identifier == params.identifier) {
-                //log('..true. calling displayNotification.');
-                this._displayNotification(params);
-        }
+        if (this._activeNotifications[params.type].identifier != params.identifier)
+            return;
+        if (this._activeNotifications[params.type].notification == params.notification)
+            return;
+        //log('..true. calling displayNotification.');
+        this._displayNotification(params);
     },
 
     loadNotifications: function(identifier, type) {
-        log('currently notifications are loaded for: ' + this._activeNotifications[type].identifier);
-        log('the notification is: ' + this._activeNotifications[type].notification);
+        //log('current notice is ' + this._activeNotifications[type].notification
+        //    + ' and is loaded for: ' + this._activeNotifications[type].identifier);
         // We only perform this check if activeNotification has already been initialized.
         // Otherwise we'll never be able to load notifications from this._activeNotifications.
         if (this._activeNotifications[type]) {
@@ -261,13 +272,20 @@ const NotificationQueue = new Lang.Class({
     },
 
     _displayNotification: function(params) {
-        log('now displaying ' + params.notification + ' for: ' + params.identifier);
+        //log('now displaying ' + params.notification + ' for: ' + params.identifier);
 
         //log('_displayNotification: checking if any notifications of that type is visible..');
         if (this._activeNotifications[params.type].notification) {
             //log('_displayNotification: true. removing visible notification');
             //this._activeNotifications[params.type].notification.close();
-            this._grid.remove(this._activeNotifications[params.type].notification.widget);
+            //log('grid children: ' + this._grid.get_children().length);
+            if (this._activeNotifications[params.type].notification.widget) {
+            //log('removing ' + this._activeNotifications[params.type].notification);
+                if (!params.notification)
+                    this._activeNotifications[params.type].notification.close();
+                else
+                    this._grid.remove(this._activeNotifications[params.type].notification.widget);
+            }
         }
         //log('storing parameters inside this._activeNotifications[' + params.type + ']..');
         this._activeNotifications[params.type] = params;
@@ -279,6 +297,7 @@ const NotificationQueue = new Lang.Class({
         }
 
         this._grid.add(params.notification.widget);
+        params.notification.open();
         params.notification.widget.connect('destroy',
                                     Lang.bind(this, this._updateVisibility));
         this.widget.show();
diff --git a/src/application.js b/src/application.js
index 7262bfd..d7634dc 100644
--- a/src/application.js
+++ b/src/application.js
@@ -284,22 +284,14 @@ const Application = new Lang.Class({
                                            this._onEnsureChannel, requestData));
     },
 
-    _retryRequest: function(requestData) {
-        let account = requestData.account;
-
-        // Try again with a different nick
-        let params = account.dup_parameters_vardict().deep_unpack();
-        let oldNick = params['account'].deep_unpack();
-        let nick = oldNick + '_';
-        this._updateAccountName(account, nick, Lang.bind(this,
-            function() {
-                this._ensureChannel(requestData);
-            }));
-    },
-
     _onEnsureChannel: function(req, res, requestData) {
         let account = req.account;
-
+        let roomError = { notification: null,
+                          type: 'room',
+                          identifier: requestData.roomId };
+        let accountError = { notification: null,
+                             type: 'account',
+                             identifier: account.get_path_suffix() };
         try {
             req.ensure_channel_finish(res);
 
@@ -307,18 +299,39 @@ const Application = new Lang.Class({
                 this._addSavedChannel(account, requestData.targetId);
         } catch (e if e.matches(Tp.Error, Tp.Error.DISCONNECTED)) {
             let error = account.connection_error;
+
             if (error == ConnectionError.ALREADY_CONNECTED &&
                 requestData.retry++ < MAX_RETRIES) {
-                    this._retryRequest(requestData);
+                    let params = account.dup_parameters_vardict().deep_unpack();
+                    let oldNick = params['account'].deep_unpack();
+                    let nick = oldNick + '_';
+                    this._updateAccountName(account, nick, Lang.bind(this,
+                        function() {
+                            this._ensureChannel(requestData);
+                        }));
                     return;
             }
 
-            if (error && error != ConnectionError.CANCELLED)
+            if (error && error != ConnectionError.CANCELLED) {
                 logError(e);
+                let notification =
+                    new AppNotifications.ErrorNotification(account, this._window.window, error);
+                notification.widget.connect('destroy',
+                    Lang.bind(this, function() {
+                        this._ensureChannel(requestData);
+                    }));
+                accountError.notification = notification;
+            }
         } catch (e if e.matches(Tp.Error, Tp.Error.CANCELLED)) {
             // interrupted by user request, don't log
         } catch (e) {
             logError(e, 'Failed to ensure channel');
+            let error = Tp.error_get_dbus_name(e.code);
+            roomError.notification =
+                new AppNotifications.ErrorNotification(account, this._window.window, error);
+        } finally {
+            this.notificationQueue.setNotification(roomError);
+            this.notificationQueue.setNotification(accountError);
         }
 
         if (requestData.retry > 0)
diff --git a/src/connections.js b/src/connections.js
index 4c9505c..e8cef0d 100644
--- a/src/connections.js
+++ b/src/connections.js
@@ -353,7 +353,7 @@ const ConnectionDetailsDialog = new Lang.Class({
                                     this._confirmButton, 'sensitive',
                                     GObject.BindingFlags.SYNC_CREATE);
         this.widget.get_content_area().add(this._details);
-        if (account.error)
+        if (account && account.error)
             this.widget.get_content_area().add(this._createErrorMessage(account.error));
     },
 
diff --git a/src/mainWindow.js b/src/mainWindow.js
index 2e6f86b..7de7347 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -55,10 +55,10 @@ const MainWindow = new Lang.Class({
         );
 
         this._accountsMonitor = AccountsMonitor.getDefault();
-        this._accountsMonitor.connect('account-status-changed',
+        /*this._accountsMonitor.connect('account-status-changed',
                                       Lang.bind(this, this._onAccountChanged));
         this._accountsMonitor.connect('account-added',
-                                      Lang.bind(this, this._onAccountChanged));
+                                      Lang.bind(this, this._onAccountChanged));*/
 
         this._roomManager = ChatroomManager.getDefault();
         this._roomManager.connect('active-changed',
@@ -120,7 +120,7 @@ const MainWindow = new Lang.Class({
     },
 
     _onAccountChanged: function(am, account) {
-        log('***********');
+        //log('***********');
         if (!account.connection_status_reason)
             return;
         let notification = null;
@@ -130,6 +130,7 @@ const MainWindow = new Lang.Class({
             //log(account.display_name + ': we are connecting to the server..');
             notification = new AppNotifications.ConnectingNotification(account);
         } else if (account.connection_status == Tp.ConnectionStatus.DISCONNECTED) {
+            return;
             if (statusReason == Tp.ConnectionStatusReason.REQUESTED)
                 return;
             notification = new AppNotifications.ErrorNotification(account,
@@ -157,8 +158,6 @@ const MainWindow = new Lang.Class({
         log(account.display_name + ': notification set to ' + notification + ' for ' + 
account.get_path_suffix());
 
         account.notification = notification;
-        if (!notification)
-            return;
     },
 
     _updateDecorations: function() {
@@ -208,7 +207,6 @@ const MainWindow = new Lang.Class({
         log('**********')
         log('loading archived notifications for: ' + room.account.get_path_suffix());
         app.notificationQueue.loadNotifications(room.account.get_path_suffix(), 'account');
-        log('**********')
         //log('loading archived notifications for: ' + room.id);
         app.notificationQueue.loadNotifications(room.id, 'room');
     },


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