Merge lp:~nataliabidart/ubuntuone-control-panel/handle-credentials-error into lp:ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 303
Merged at revision: 299
Proposed branch: lp:~nataliabidart/ubuntuone-control-panel/handle-credentials-error
Merge into: lp:ubuntuone-control-panel
Diff against target: 250 lines (+92/-22)
7 files modified
data/qt/ubuntuone.qss (+9/-0)
ubuntuone/controlpanel/gui/qt/__init__.py (+33/-5)
ubuntuone/controlpanel/gui/qt/tests/__init__.py (+11/-5)
ubuntuone/controlpanel/gui/qt/tests/test_common.py (+3/-2)
ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py (+1/-3)
ubuntuone/controlpanel/gui/qt/tests/test_wizard.py (+22/-1)
ubuntuone/controlpanel/gui/qt/wizard.py (+13/-6)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-control-panel/handle-credentials-error
Reviewer Review Type Date Requested Status
Diego Sarmentero (community) Approve
Roberto Alsina (community) Approve
Review via email: mp+99420@code.launchpad.net

Commit message

- Handle errors from backend on the signin wizard page (LP: #945078).
- Avoid the 'show/hide details' button to grow when focused (LP: #961348).

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1 I suggested connecting box.finished to box.deleteLater to avoid leaking it, but it's +1 with or without that.

review: Approve
303. By Natalia Bidart

- Also deleting the box that shows errors messages after is used.

Revision history for this message
Diego Sarmentero (diegosarmentero) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/qt/ubuntuone.qss'
2--- data/qt/ubuntuone.qss 2012-03-22 20:28:48 +0000
3+++ data/qt/ubuntuone.qss 2012-03-27 12:55:22 +0000
4@@ -365,3 +365,12 @@
5 background: #fcece7;
6 color: black;
7 }
8+
9+
10+QMessageBox > QWidget > QPushButton:focus {
11+ /* use the same padding from the original QPushButton:focus setting */
12+ /* hack to make the mild-orange focused box dissapear */
13+ padding-top: 5px;
14+ padding-bottom: 5px;
15+ /* end of hack */
16+}
17
18=== modified file 'ubuntuone/controlpanel/gui/qt/__init__.py'
19--- ubuntuone/controlpanel/gui/qt/__init__.py 2012-03-02 13:53:24 +0000
20+++ ubuntuone/controlpanel/gui/qt/__init__.py 2012-03-27 12:55:22 +0000
21@@ -70,6 +70,12 @@
22 return icon
23
24
25+# Invalid name "box"
26+# pylint: disable=C0103
27+box = None
28+# pylint: enable=C0103
29+
30+
31 def handle_errors(error_handler=None, logger=None):
32 """Decorator to handle errors when calling a function.
33
34@@ -107,13 +113,35 @@
35 else:
36 msgs = [e.__class__.__name__] + map(repr, e.args)
37 msg = '\n'.join(msgs)
38+
39+ # hack to avoid the QMessageBox being gargabe-collected too soon
40+ # Using the global statement, pylint: disable=W0603
41+ global box
42+ # pylint: enable=W0603
43 box = QtGui.QMessageBox(QtGui.QMessageBox.Critical,
44- GENERAL_ERROR_TITLE, GENERAL_ERROR_MSG,
45- QtGui.QMessageBox.Close,
46- parent=None)
47+ GENERAL_ERROR_TITLE, GENERAL_ERROR_MSG,
48+ QtGui.QMessageBox.Close, parent=None)
49+ box.setDefaultButton(QtGui.QMessageBox.Close)
50 box.setDetailedText(msg)
51- box.setDefaultButton(QtGui.QMessageBox.Close)
52- box.exec_()
53+
54+ # can not exec_() on the QMessageBox since that will block the Qt
55+ # mainloop
56+
57+ d = defer.Deferred()
58+
59+ def box_finished(result):
60+ """The QMessageBox finished."""
61+ logger.info('The warning dialog was shown and also closed '
62+ '(message was %r).', msg)
63+ box.finished.disconnect(box_finished)
64+ box.hide()
65+ box.deleteLater()
66+ d.callback(result)
67+
68+ box.finished.connect(box_finished)
69+ box.show()
70+
71+ yield d
72
73 return inner
74
75
76=== modified file 'ubuntuone/controlpanel/gui/qt/tests/__init__.py'
77--- ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-03-21 21:13:13 +0000
78+++ ubuntuone/controlpanel/gui/qt/tests/__init__.py 2012-03-27 12:55:22 +0000
79@@ -187,17 +187,16 @@
80 return inner
81
82
83-class FakedDialog(object):
84+class FakedDialog(QtGui.QMessageBox):
85 """Fake a confirmation dialog."""
86
87- Close = object()
88- Critical = object()
89 properties = response = args = kwargs = None
90
91 def __init__(self, *a, **kw):
92+ super(FakedDialog, self).__init__(*a, **kw)
93 FakedDialog.args = a
94 FakedDialog.kwargs = kw
95- FakedDialog.properties = {'exec_': 0}
96+ FakedDialog.properties = {'shown': 0}
97
98 @classmethod
99 def reset(cls, *a, **kw):
100@@ -216,17 +215,24 @@
101
102 def setDetailedText(self, text):
103 """Fake the setDetailedText."""
104+ super(FakedDialog, self).setDetailedText(text)
105 FakedDialog.properties['detailed_text'] = text
106
107 def setDefaultButton(self, button):
108 """Fake the setDefaultButton."""
109+ super(FakedDialog, self).setDefaultButton(button)
110 FakedDialog.properties['default_button'] = button
111
112 # pylint: enable=C0103
113
114+ def show(self):
115+ """Fake show."""
116+ FakedDialog.properties['shown'] += 1
117+ self.finished.emit(0)
118+
119 def exec_(self):
120 """Fake exec_."""
121- FakedDialog.properties['exec_'] += 1
122+ FakedDialog.properties['shown'] += 1
123
124
125 class FakedFileDialog(object):
126
127=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_common.py'
128--- ubuntuone/controlpanel/gui/qt/tests/test_common.py 2011-10-05 16:35:59 +0000
129+++ ubuntuone/controlpanel/gui/qt/tests/test_common.py 2012-03-27 12:55:22 +0000
130@@ -132,7 +132,8 @@
131 yield self.decorate_me()
132
133 logged = self.memento.check_exception(self.failure.__class__, msg)
134- recs = '\n'.join(rec.exc_text for rec in self.memento.records)
135+ recs = '\n'.join(rec.exc_text for rec in self.memento.records
136+ if rec.exc_text is not None)
137 self.assertTrue(logged, 'Exception must be logged, got:\n%s' % recs)
138
139 @defer.inlineCallbacks
140@@ -147,7 +148,7 @@
141 QtGui.QMessageBox.Close)
142 self.assertEqual(FakedDialog.args, args)
143 self.assertEqual(FakedDialog.kwargs, {'parent': None})
144- self.assertEqual(FakedDialog.properties['exec_'], 1)
145+ self.assertEqual(FakedDialog.properties['shown'], 1)
146
147 @defer.inlineCallbacks
148 def test_show_error_message_default_button(self):
149
150=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py'
151--- ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2012-03-21 20:27:38 +0000
152+++ ubuntuone/controlpanel/gui/qt/tests/test_controlpanel.py 2012-03-27 12:55:22 +0000
153@@ -1,8 +1,6 @@
154 # -*- coding: utf-8 -*-
155-
156-# Authors: Natalia B Bidart <natalia.bidart@canonical.com>
157 #
158-# Copyright 2011 Canonical Ltd.
159+# Copyright 2011-2012 Canonical Ltd.
160 #
161 # This program is free software: you can redistribute it and/or modify it
162 # under the terms of the GNU General Public License version 3, as published
163
164=== modified file 'ubuntuone/controlpanel/gui/qt/tests/test_wizard.py'
165--- ubuntuone/controlpanel/gui/qt/tests/test_wizard.py 2012-03-21 20:27:38 +0000
166+++ ubuntuone/controlpanel/gui/qt/tests/test_wizard.py 2012-03-27 12:55:22 +0000
167@@ -89,7 +89,7 @@
168 # Finish button is visible (and enabled if isComplete() returns true).
169
170 # After calling setFinalPage(false), isFinalPage() returns true if
171- #nextId() returns -1; otherwise, it returns false.
172+ # nextId() returns -1; otherwise, it returns false.
173
174 self.patch(self.ui, 'nextId', lambda *a: 0)
175 self.assertFalse(self.ui.isFinalPage())
176@@ -385,6 +385,27 @@
177 self.assertTrue(self.ui.signin_page.isEnabled())
178 self.assertFalse(self._called)
179
180+ @defer.inlineCallbacks
181+ def test_with_error(self):
182+ """Wizard is enabled after an error was handled."""
183+ self.ui.currentIdChanged.connect(self._set_called)
184+ d = defer.fail(ValueError())
185+
186+ def check():
187+ """Confirm the ui is disabled while processing."""
188+ self.assertFalse(self.ui.signin_page.isEnabled())
189+ return d
190+
191+ self.patch(self.ui.backend, self.method, check)
192+ button = getattr(self.ui.signin_page.panel.ui,
193+ '%s_button' % self.method)
194+ button.click()
195+
196+ yield d
197+
198+ self.assertTrue(self.ui.signin_page.isEnabled())
199+ self.assertFalse(self._called) # the wizard page was not changed
200+
201
202 class UbuntuOneWizardRegisterTestCase(UbuntuOneWizardLoginTestCase):
203 """Test the register through the wizard."""
204
205=== modified file 'ubuntuone/controlpanel/gui/qt/wizard.py'
206--- ubuntuone/controlpanel/gui/qt/wizard.py 2012-03-23 20:39:35 +0000
207+++ ubuntuone/controlpanel/gui/qt/wizard.py 2012-03-27 12:55:22 +0000
208@@ -44,6 +44,7 @@
209 LICENSE_LINK,
210 UBUNTUONE_LINK,
211 )
212+from ubuntuone.controlpanel.gui.qt import handle_errors
213 from ubuntuone.controlpanel.gui.qt.folders import (
214 RemoteFoldersPanel,
215 LocalFoldersPanel,
216@@ -300,22 +301,28 @@
217 self.next()
218
219 @QtCore.pyqtSlot()
220+ @handle_errors(logger=logger)
221 @defer.inlineCallbacks
222 def login(self):
223 """Show the login dialog."""
224 self.setEnabled(False)
225- credentials = yield self.backend.login()
226- self._process_credentials(credentials)
227- self.setEnabled(True)
228+ try:
229+ credentials = yield self.backend.login()
230+ self._process_credentials(credentials)
231+ finally:
232+ self.setEnabled(True)
233
234 @QtCore.pyqtSlot()
235+ @handle_errors(logger=logger)
236 @defer.inlineCallbacks
237 def register(self):
238 """Show the register dialog."""
239 self.setEnabled(False)
240- credentials = yield self.backend.register()
241- self._process_credentials(credentials)
242- self.setEnabled(True)
243+ try:
244+ credentials = yield self.backend.register()
245+ self._process_credentials(credentials)
246+ finally:
247+ self.setEnabled(True)
248
249 @QtCore.pyqtSlot()
250 def check_settings(self):

Subscribers

People subscribed via source and target branches