Merge lp:~nataliabidart/ubuntuone-control-panel/confirm-before-delete into lp:ubuntuone-control-panel

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 54
Merged at revision: 54
Proposed branch: lp:~nataliabidart/ubuntuone-control-panel/confirm-before-delete
Merge into: lp:ubuntuone-control-panel
Diff against target: 704 lines (+168/-90)
6 files modified
data/device.ui (+9/-32)
data/management.ui (+1/-1)
ubuntuone/controlpanel/gtk/gui.py (+49/-32)
ubuntuone/controlpanel/gtk/tests/__init__.py (+24/-6)
ubuntuone/controlpanel/gtk/tests/test_gui.py (+83/-19)
ubuntuone/controlpanel/tests/__init__.py (+2/-0)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-control-panel/confirm-before-delete
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Roman Yepishev (community) fieldtest Approve
Review via email: mp+47324@code.launchpad.net

Commit message

- When removing a device, a confirmation dialog is raised (LP: #706888).

To post a comment you must log in.
Revision history for this message
Roman Yepishev (rye) wrote :

Control Panel has asked me whether I want to remove the device. I just could not say no!

review: Approve (fieldtest)
54. By Natalia Bidart

Spacing to devices.

Revision history for this message
Roman Yepishev (rye) wrote :

To clarify possible confusion about my review here's a true and non-joking summary:
I ran this branch, i clicked on delete. If I confirm the removal then device gets removed. If I decline the removal then device is not removed. Result: Approve during fieldtest.

Revision history for this message
Roberto Alsina (ralsina) 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/device.ui'
2--- data/device.ui 2011-01-24 13:40:10 +0000
3+++ data/device.ui 2011-01-25 12:57:15 +0000
4@@ -12,65 +12,53 @@
5 </object>
6 <object class="GtkVBox" id="itself">
7 <property name="visible">True</property>
8- <property name="can_focus">False</property>
9+ <property name="border_width">10</property>
10 <property name="spacing">5</property>
11 <child>
12 <object class="GtkHBox" id="hbox1">
13 <property name="visible">True</property>
14- <property name="can_focus">False</property>
15- <property name="spacing">15</property>
16+ <property name="spacing">10</property>
17 <child>
18 <object class="GtkVBox" id="vbox1">
19 <property name="visible">True</property>
20- <property name="can_focus">False</property>
21 <property name="spacing">5</property>
22 <child>
23 <object class="GtkHBox" id="hbox2">
24 <property name="visible">True</property>
25- <property name="can_focus">False</property>
26 <child>
27 <object class="GtkImage" id="device_type">
28 <property name="visible">True</property>
29- <property name="can_focus">False</property>
30 <property name="icon_name">computer</property>
31 </object>
32 <packing>
33 <property name="expand">False</property>
34- <property name="fill">True</property>
35 <property name="position">0</property>
36 </packing>
37 </child>
38 <child>
39 <object class="GtkLabel" id="device_name">
40 <property name="visible">True</property>
41- <property name="can_focus">False</property>
42 <property name="xalign">0</property>
43 <property name="xpad">5</property>
44 <property name="label">My Laptop</property>
45 <property name="wrap">True</property>
46 </object>
47 <packing>
48- <property name="expand">True</property>
49- <property name="fill">True</property>
50 <property name="position">1</property>
51 </packing>
52 </child>
53 </object>
54 <packing>
55- <property name="expand">True</property>
56- <property name="fill">True</property>
57 <property name="position">0</property>
58 </packing>
59 </child>
60 <child>
61 <object class="GtkAlignment" id="alignment1">
62 <property name="visible">True</property>
63- <property name="can_focus">False</property>
64 <property name="left_padding">25</property>
65 <child>
66 <object class="GtkTable" id="throttling">
67 <property name="visible">True</property>
68- <property name="can_focus">False</property>
69 <property name="n_rows">3</property>
70 <property name="n_columns">2</property>
71 <property name="column_spacing">3</property>
72@@ -81,15 +69,13 @@
73 <property name="visible">True</property>
74 <property name="can_focus">True</property>
75 <property name="receives_default">False</property>
76- <property name="use_action_appearance">False</property>
77 <property name="draw_indicator">True</property>
78- <signal name="toggled" handler="on_limit_bandwidth_toggled" swapped="no"/>
79+ <signal name="toggled" handler="on_limit_bandwidth_toggled"/>
80 </object>
81 </child>
82 <child>
83 <object class="GtkLabel" id="max_upload_speed_label">
84 <property name="visible">True</property>
85- <property name="can_focus">False</property>
86 <property name="xalign">1</property>
87 <property name="xpad">5</property>
88 <property name="label" translatable="yes">Max upload speed (KiB/s)</property>
89@@ -103,7 +89,6 @@
90 <child>
91 <object class="GtkLabel" id="max_download_speed_label">
92 <property name="visible">True</property>
93- <property name="can_focus">False</property>
94 <property name="xalign">1</property>
95 <property name="xpad">5</property>
96 <property name="label" translatable="yes">Max download speed (KiB/s)</property>
97@@ -121,7 +106,7 @@
98 <property name="activates_default">True</property>
99 <property name="invisible_char_set">True</property>
100 <property name="adjustment">adjustment1</property>
101- <signal name="value-changed" handler="on_max_upload_speed_value_changed" swapped="no"/>
102+ <signal name="value_changed" handler="on_max_upload_speed_value_changed"/>
103 </object>
104 <packing>
105 <property name="left_attach">1</property>
106@@ -140,7 +125,7 @@
107 <property name="activates_default">True</property>
108 <property name="invisible_char_set">True</property>
109 <property name="adjustment">adjustment2</property>
110- <signal name="value-changed" handler="on_max_download_speed_value_changed" swapped="no"/>
111+ <signal name="value_changed" handler="on_max_download_speed_value_changed"/>
112 </object>
113 <packing>
114 <property name="left_attach">1</property>
115@@ -157,31 +142,28 @@
116 </object>
117 <packing>
118 <property name="expand">False</property>
119- <property name="fill">True</property>
120 <property name="position">1</property>
121 </packing>
122 </child>
123 </object>
124 <packing>
125 <property name="expand">False</property>
126- <property name="fill">True</property>
127 <property name="position">0</property>
128 </packing>
129 </child>
130 <child>
131 <object class="GtkVButtonBox" id="vbuttonbox1">
132 <property name="visible">True</property>
133- <property name="can_focus">False</property>
134 <property name="layout_style">center</property>
135 <child>
136 <object class="GtkButton" id="remove">
137- <property name="label" translatable="yes">Remove from my personal cloud</property>
138+ <property name="label">gtk-remove</property>
139 <property name="visible">True</property>
140 <property name="can_focus">True</property>
141 <property name="receives_default">True</property>
142- <property name="use_action_appearance">False</property>
143- <signal name="activate" handler="on_remove_clicked" swapped="no"/>
144- <signal name="clicked" handler="on_remove_clicked" swapped="no"/>
145+ <property name="use_stock">True</property>
146+ <signal name="clicked" handler="on_remove_clicked"/>
147+ <signal name="activate" handler="on_remove_clicked"/>
148 </object>
149 <packing>
150 <property name="expand">False</property>
151@@ -192,7 +174,6 @@
152 </object>
153 <packing>
154 <property name="expand">False</property>
155- <property name="fill">True</property>
156 <property name="pack_type">end</property>
157 <property name="position">1</property>
158 </packing>
159@@ -200,18 +181,14 @@
160 </object>
161 <packing>
162 <property name="expand">False</property>
163- <property name="fill">True</property>
164 <property name="position">0</property>
165 </packing>
166 </child>
167 <child>
168 <object class="GtkLabel" id="warning_label">
169 <property name="visible">True</property>
170- <property name="can_focus">False</property>
171 </object>
172 <packing>
173- <property name="expand">True</property>
174- <property name="fill">True</property>
175 <property name="position">1</property>
176 </packing>
177 </child>
178
179=== modified file 'data/management.ui'
180--- data/management.ui 2011-01-21 21:43:01 +0000
181+++ data/management.ui 2011-01-25 12:57:15 +0000
182@@ -98,7 +98,7 @@
183 </child>
184 <child>
185 <object class="GtkRadioButton" id="volumes_button">
186- <property name="label" translatable="yes">Cloud Storage</property>
187+ <property name="label" translatable="yes">Cloud Folders</property>
188 <property name="visible">True</property>
189 <property name="can_focus">True</property>
190 <property name="receives_default">False</property>
191
192=== modified file 'ubuntuone/controlpanel/gtk/gui.py'
193--- ubuntuone/controlpanel/gtk/gui.py 2011-01-24 14:09:48 +0000
194+++ ubuntuone/controlpanel/gtk/gui.py 2011-01-25 12:57:15 +0000
195@@ -182,7 +182,7 @@
196 self.connect('delete-event', lambda w, e: gtk.main_quit())
197 self.show()
198
199- self.control_panel = ControlPanel(window_id=self.window.xid)
200+ self.control_panel = ControlPanel(main_window=self)
201 self.add(self.control_panel)
202
203 logger.info('Starting %s pointing at panel: %r.',
204@@ -209,17 +209,17 @@
205
206 # should not be any larger than 736x525
207
208- def __init__(self, window_id=0):
209+ def __init__(self, main_window):
210 gtk.Notebook.__init__(self)
211- self._window_id = window_id
212+ self.main_window = main_window
213
214 self.set_show_tabs(False)
215 self.set_show_border(False)
216
217- self.overview = OverviewPanel(window_id=self._window_id)
218+ self.overview = OverviewPanel(main_window=main_window)
219 self.insert_page(self.overview, position=0)
220
221- self.management = ManagementPanel()
222+ self.management = ManagementPanel(main_window=main_window)
223 self.insert_page(self.management, position=1)
224
225 self.overview.connect('credentials-found',
226@@ -320,7 +320,7 @@
227 CONNECT = _('Connect to Ubuntu One')
228 BULLET = '<span foreground="%s">✔</span>' % ORANGE
229
230- def __init__(self, messages=None, window_id=0):
231+ def __init__(self, main_window, messages=None):
232 GreyableBin.__init__(self)
233 ControlPanelMixin.__init__(self, filename='overview.ui')
234 self.add(self.itself)
235@@ -332,9 +332,9 @@
236 self.join_now_button.get_child().set_markup(label)
237 self.connect_button.set_uri(self.CONNECT)
238
239+ self.main_window = main_window
240 self._credentials_are_new = False
241 self._messages = messages
242- self._window_id = window_id
243 self._build_messages()
244 self.show()
245
246@@ -404,7 +404,7 @@
247 def on_join_now_button_clicked(self, *a, **kw):
248 """User wants to join now."""
249 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
250- WINDOW_ID_KEY: str(self._window_id),
251+ WINDOW_ID_KEY: str(self.main_window.window.xid),
252 PING_URL_KEY: U1_PING_URL}
253 self.sso_backend.register(U1_APP_NAME, settings,
254 reply_handler=NO_OP, error_handler=error_handler)
255@@ -414,7 +414,7 @@
256 def on_connect_button_clicked(self, *a, **kw):
257 """User wants to connect now."""
258 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
259- WINDOW_ID_KEY: str(self._window_id),
260+ WINDOW_ID_KEY: str(self.main_window.window.xid),
261 PING_URL_KEY: U1_PING_URL}
262 self.sso_backend.login(U1_APP_NAME, settings,
263 reply_handler=NO_OP, error_handler=error_handler)
264@@ -476,7 +476,7 @@
265 TYPE = _('Account type')
266 EMAIL = _('Email address')
267
268- def __init__(self):
269+ def __init__(self, main_window=None):
270 UbuntuOneBin.__init__(self)
271 ControlPanelMixin.__init__(self, filename='dashboard.ui')
272 self.add(self.itself)
273@@ -512,10 +512,10 @@
274 class VolumesPanel(UbuntuOneBin, ControlPanelMixin):
275 """The volumes panel."""
276
277- TITLE = _('Select which folders from your cloud you want synchronized '
278- 'on this device.')
279- MY_FOLDERS = _('Mine')
280- ALWAYS_SUBSCRIBED = _('Always in your personal cloud storage!')
281+ TITLE = _('Select the folders from your cloud that you want synchronized '
282+ 'in this device.')
283+ MY_FOLDERS = _('My folders')
284+ ALWAYS_SUBSCRIBED = _('Always in sync!')
285 FREE_SPACE = _('%(free_space)s available storage')
286 CONTACT_ICON_NAME = 'system-users'
287 FOLDER_ICON_NAME = 'folder'
288@@ -525,7 +525,7 @@
289 ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'
290 NO_VOLUMES = _('No folders to show.')
291
292- def __init__(self):
293+ def __init__(self, main_window=None):
294 UbuntuOneBin.__init__(self)
295 ControlPanelMixin.__init__(self, filename='volumes.ui')
296 self.add(self.itself)
297@@ -639,7 +639,7 @@
298
299 TITLE = _('Manage permissions for shares made to other users.')
300
301- def __init__(self):
302+ def __init__(self, main_window=None):
303 UbuntuOneBin.__init__(self)
304 ControlPanelMixin.__init__(self)
305 self.show_all()
306@@ -652,11 +652,13 @@
307 DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n'
308 'previous values were restored.')
309 DEVICE_REMOVAL_ERROR = _('The device could not be removed.')
310+ REMOVABLE_PREFIX = 'Ubuntu One @ '
311
312- def __init__(self):
313+ def __init__(self, confirm_remove_dialog=None):
314 gtk.EventBox.__init__(self)
315 ControlPanelMixin.__init__(self, filename='device.ui')
316
317+ self.confirm_dialog = confirm_remove_dialog
318 self._updating = False
319 self._last_settings = {}
320 self.id = None
321@@ -714,9 +716,15 @@
322
323 def on_remove_clicked(self, widget):
324 """Remove button was clicked or activated."""
325- self.backend.remove_device(self.id,
326- reply_handler=NO_OP, error_handler=error_handler)
327- self.set_sensitive(False)
328+ response = gtk.RESPONSE_YES
329+ if self.confirm_dialog is not None:
330+ response = self.confirm_dialog.run()
331+ self.confirm_dialog.hide()
332+
333+ if response == gtk.RESPONSE_YES:
334+ self.backend.remove_device(self.id,
335+ reply_handler=NO_OP, error_handler=error_handler)
336+ self.set_sensitive(False)
337
338 @_block_signals
339 def update(self, **kwargs):
340@@ -738,8 +746,9 @@
341 self.id = kwargs['device_id']
342
343 if 'device_name' in kwargs:
344- name = '<span font_size="large"><b>%s</b></span>'
345- self.device_name.set_markup(name % kwargs['device_name'])
346+ name = kwargs['device_name'].replace(self.REMOVABLE_PREFIX, '')
347+ name = '<span font_size="large"><b>%s</b></span>' % name
348+ self.device_name.set_markup(name)
349
350 if 'device_type' in kwargs:
351 dtype = kwargs['device_type']
352@@ -818,16 +827,24 @@
353 class DevicesPanel(UbuntuOneBin, ControlPanelMixin):
354 """The devices panel."""
355
356- TITLE = _('The devices in your personal cloud are listed below.')
357+ TITLE = _('The devices synced with your personal cloud are listed below.')
358 NO_DEVICES = _('No devices to show.')
359+ CONFIRM_REMOVE = _('Are you sure you want to remove this device '
360+ 'from Ubuntu One?')
361
362- def __init__(self):
363+ def __init__(self, main_window=None):
364 UbuntuOneBin.__init__(self)
365 ControlPanelMixin.__init__(self, filename='devices.ui')
366 self.add(self.itself)
367 self.show()
368
369 self._devices = {}
370+ kw = dict(parent=main_window,
371+ flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
372+ type=gtk.MESSAGE_WARNING,
373+ buttons=gtk.BUTTONS_YES_NO,
374+ message_format=self.CONFIRM_REMOVE)
375+ self.confirm_remove_dialog = gtk.MessageDialog(**kw)
376
377 self.backend.connect_to_signal('DevicesInfoReady',
378 self.on_devices_info_ready)
379@@ -849,7 +866,7 @@
380
381 odd_row_color = self.message.style.bg[gtk.STATE_NORMAL]
382 for i, device_info in enumerate(info):
383- device = Device()
384+ device = Device(confirm_remove_dialog=self.confirm_remove_dialog)
385 device_info['device_name'] = device_info.pop('name', '')
386 device_info['device_type'] = device_info.pop('type',
387 DEVICE_TYPE_COMPUTER)
388@@ -1086,7 +1103,7 @@
389 CONTACTS = _('Contacts (Evolution)')
390 NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')
391
392- def __init__(self):
393+ def __init__(self, main_window=None):
394 UbuntuOneBin.__init__(self)
395 ControlPanelMixin.__init__(self, filename='services.ui')
396 self.add(self.itself)
397@@ -1333,7 +1350,7 @@
398
399 QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)')
400
401- def __init__(self):
402+ def __init__(self, main_window=None):
403 gtk.VBox.__init__(self)
404 ControlPanelMixin.__init__(self, filename='management.ui')
405 self.add(self.itself)
406@@ -1353,11 +1370,11 @@
407 self.status_label = FileSyncStatus()
408 self.status_box.pack_end(self.status_label, expand=False)
409
410- self.dashboard = DashboardPanel()
411- self.volumes = VolumesPanel()
412- self.shares = SharesPanel()
413- self.devices = DevicesPanel()
414- self.services = ServicesPanel()
415+ self.dashboard = DashboardPanel(main_window=main_window)
416+ self.volumes = VolumesPanel(main_window=main_window)
417+ self.shares = SharesPanel(main_window=main_window)
418+ self.devices = DevicesPanel(main_window=main_window)
419+ self.services = ServicesPanel(main_window=main_window)
420
421 cb = lambda button, page_num: self.notebook.set_current_page(page_num)
422 self.tabs = (u'dashboard', u'volumes', u'shares',
423
424=== modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py'
425--- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-21 02:29:20 +0000
426+++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-25 12:57:15 +0000
427@@ -66,14 +66,14 @@
428 }
429
430 FAKE_DEVICES_INFO = [
431- {'device_id': '0', 'name': 'Foo', 'type': 'Computer',
432- 'is_local': '', 'configurable': ''},
433- {'device_id': '1', 'name': 'Bar', 'type': 'Phone',
434- 'is_local': '', 'configurable': ''},
435- {'device_id': '2', 'name': 'Z', 'type': 'Computer',
436+ {'device_id': '0', 'name': 'Ubuntu One @ Foo', 'type': 'Computer',
437+ 'is_local': '', 'configurable': ''},
438+ {'device_id': '1', 'name': 'Ubuntu One @ Bar', 'type': 'Phone',
439+ 'is_local': '', 'configurable': ''},
440+ {'device_id': '2', 'name': 'Ubuntu One @ Z', 'type': 'Computer',
441 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '',
442 'max_upload_speed': '0', 'max_download_speed': '0'},
443- {'device_id': '1258-6854', 'name': 'Baz', 'type': 'Computer',
444+ {'device_id': '1258-6854', 'name': 'Ubuntu One @ Baz', 'type': 'Computer',
445 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True',
446 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local
447 ]
448@@ -195,3 +195,21 @@
449 yield
450 self._installed[package_name] = True
451 gui.package_manager.return_value(FakedTransaction([package_name]))
452+
453+
454+class FakedConfirmDialog(object):
455+ """Fake a confirmation dialog."""
456+
457+ def __init__(self, *args, **kwargs):
458+ self._args = args
459+ self._kwargs = kwargs
460+ self.was_run = False
461+ self.is_visible = True
462+ self.show = lambda: setattr(self, 'is_visible', True)
463+ self.hide = lambda: setattr(self, 'is_visible', False)
464+ self.response_code = None
465+
466+ def run(self):
467+ """Set flag and return 'self.response_code'."""
468+ self.was_run = True
469+ return self.response_code
470
471=== modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py'
472--- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-21 21:43:01 +0000
473+++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-25 12:57:15 +0000
474@@ -29,7 +29,7 @@
475 FAKE_DEVICE_INFO, FAKE_DEVICES_INFO,
476 FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, USER_HOME,
477 FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface,
478- FakedPackageManager,
479+ FakedPackageManager, FakedConfirmDialog,
480 )
481 from ubuntuone.controlpanel.tests import TOKEN, TestCase
482 from ubuntuone.controlpanel.gtk.tests.test_package_manager import (
483@@ -55,6 +55,7 @@
484 self.patch(gui.os.path, 'expanduser',
485 lambda path: path.replace('~', USER_HOME))
486 self.patch(gui.gtk, 'main', lambda: None)
487+ self.patch(gui.gtk, 'MessageDialog', FakedConfirmDialog)
488 self.patch(gui.dbus, 'SessionBus', FakedSessionBus)
489 self.patch(gui.dbus, 'Interface', FakedInterface)
490 self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)
491@@ -171,11 +172,9 @@
492 self.assertIsInstance(self.ui.control_panel, gui.ControlPanel)
493 self.assertTrue(self.ui.control_panel.get_visible())
494
495- def test_window_id_is_passed_to_child(self):
496- """The child gets the window_id."""
497- assert self.ui.window is not None
498- self.assertEqual(self.ui.control_panel._window_id,
499- self.ui.window.xid)
500+ def test_main_window_is_passed_to_child(self):
501+ """The child gets the main_window."""
502+ self.assertEqual(self.ui.control_panel.main_window, self.ui)
503
504 def test_icon_name_is_correct(self):
505 """The icon name is correct."""
506@@ -225,7 +224,7 @@
507 """The test suite for the control panel itself."""
508
509 klass = gui.ControlPanel
510- kwargs = {'window_id': 7}
511+ kwargs = {'main_window': object()}
512
513 def assert_current_tab_correct(self, expected_tab):
514 """Check that the wiget 'expected_tab' is the current page."""
515@@ -251,9 +250,10 @@
516 self.assertIsInstance(self.ui.overview, gui.OverviewPanel)
517 self.assert_current_tab_correct(self.ui.overview)
518
519- def test_window_id_is_passed_to_child(self):
520- """The child gets the window_id."""
521- self.assertEqual(self.ui.overview._window_id, self.kwargs['window_id'])
522+ def test_main_window_is_passed_to_child(self):
523+ """The child gets the main_window."""
524+ self.assertEqual(self.ui.overview.main_window,
525+ self.kwargs['main_window'])
526
527 def test_on_show_management_panel(self):
528 """A ManagementPanel is shown when the callback is executed."""
529@@ -392,7 +392,7 @@
530 """The test suite for the overview panel."""
531
532 klass = gui.OverviewPanel
533- kwargs = {'messages': None, 'window_id': 8}
534+ kwargs = {'messages': None, 'main_window': gui.gtk.Window()}
535 ui_filename = 'overview.ui'
536
537 def test_is_a_greyable_bin(self):
538@@ -591,24 +591,32 @@
539
540 def test_join_now_button_clicked(self):
541 """Test the 'join now' button callback."""
542+ self.kwargs['main_window'].show() # ensure parent window is realized
543+ self.addCleanup(self.kwargs['main_window'].hide)
544+
545 self.ui.join_now_button.clicked()
546
547+ window_id = self.kwargs['main_window'].window.xid
548 args = (gui.U1_APP_NAME,
549 {gui.TC_URL_KEY: gui.U1_TC_URL,
550 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
551- gui.WINDOW_ID_KEY: str(self.kwargs['window_id']),
552+ gui.WINDOW_ID_KEY: str(window_id),
553 gui.PING_URL_KEY: gui.U1_PING_URL})
554 self.assert_backend_called('register', args,
555 backend=self.ui.sso_backend)
556
557 def test_connect_button_clicked(self):
558 """Test the 'join now' button callback."""
559+ self.kwargs['main_window'].show() # ensure parent window is realized
560+ self.addCleanup(self.kwargs['main_window'].hide)
561+
562 self.ui.connect_button.clicked()
563
564+ window_id = self.kwargs['main_window'].window.xid
565 args = (gui.U1_APP_NAME,
566 {gui.TC_URL_KEY: gui.U1_TC_URL,
567 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
568- gui.WINDOW_ID_KEY: str(self.kwargs['window_id']),
569+ gui.WINDOW_ID_KEY: str(window_id),
570 gui.PING_URL_KEY: gui.U1_PING_URL})
571 self.assert_backend_called('login', args,
572 backend=self.ui.sso_backend)
573@@ -967,8 +975,8 @@
574 """Assert that the device has the values from expected."""
575 self.assertEqual(device.id,
576 expected['device_id'])
577- self.assertEqual(device.device_name.get_text(),
578- expected['device_name'])
579+ value = expected['device_name'].replace(self.ui.REMOVABLE_PREFIX, '')
580+ self.assertEqual(device.device_name.get_text(), value)
581 self.assertEqual(device.device_type.get_icon_name()[0],
582 expected['device_type'].lower())
583 self.assertEqual(device.is_local,
584@@ -1040,13 +1048,13 @@
585 def test_update_device_name(self):
586 """A device can be updated from a dict."""
587 value = 'The death star'
588- self.ui.update(device_name=value)
589+ self.ui.update(device_name=self.ui.REMOVABLE_PREFIX + value)
590 self.assertEqual(value, self.ui.device_name.get_text())
591
592 def test_update_unicode_device_name(self):
593 """A device can be updated from a dict."""
594 value = u'Ñoño Ñandú'
595- self.ui.update(device_name=value)
596+ self.ui.update(device_name=self.ui.REMOVABLE_PREFIX + value)
597 self.assertEqual(value, self.ui.device_name.get_text())
598
599 def test_update_device_type_computer(self):
600@@ -1237,11 +1245,53 @@
601 'Must be disabled after other device removal error.')
602
603
604+class RemoveDeviceTestCase(DeviceTestCase):
605+ """The test suite for the device widget when prompting for removal."""
606+
607+ confirm_dialog = FakedConfirmDialog()
608+ kwargs = {'confirm_remove_dialog': confirm_dialog}
609+
610+ def test_remove(self):
611+ """Clicking on remove calls the backend properly."""
612+ self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
613+ super(RemoveDeviceTestCase, self).test_remove()
614+
615+ def test_on_device_removal_error_other_id(self):
616+ """On other device removal error, do nothing."""
617+ self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
618+ parent_test = super(RemoveDeviceTestCase, self)
619+ parent_test.test_on_device_removal_error_other_id()
620+
621+ def test_remove_shows_confirmation_dialog(self):
622+ """Clicking on remove displays a confirmation dialog."""
623+ self.ui.remove.clicked()
624+
625+ self.assertTrue(self.confirm_dialog.was_run, 'dialog was run')
626+ self.assertFalse(self.confirm_dialog.is_visible, 'dialog was hid')
627+
628+ def test_remove_does_not_call_backend_if_dialog_closed(self):
629+ """Backend is not called if users closes the confirmation dialog."""
630+ self.confirm_dialog.response_code = gui.gtk.RESPONSE_DELETE_EVENT
631+ self.ui.remove.clicked()
632+
633+ self.assertNotIn('remove_device', self.ui.backend._called)
634+ self.assertTrue(self.ui.is_sensitive())
635+
636+ def test_remove_does_not_call_backend_if_answer_is_no(self):
637+ """Backend is not called if users clicks on 'No'."""
638+ self.confirm_dialog.response_code = gui.gtk.RESPONSE_NO
639+ self.ui.remove.clicked()
640+
641+ self.assertNotIn('remove_device', self.ui.backend._called)
642+ self.assertTrue(self.ui.is_sensitive())
643+
644+
645 class DevicesTestCase(ControlPanelMixinTestCase):
646 """The test suite for the devices panel."""
647
648 klass = gui.DevicesPanel
649 ui_filename = 'devices.ui'
650+ kwargs = {'main_window': object()}
651
652 def setUp(self):
653 super(DevicesTestCase, self).setUp()
654@@ -1259,6 +1309,18 @@
655 """Is visible."""
656 self.assertTrue(self.ui.get_visible())
657
658+ def test_confirm_remove_dialog(self):
659+ """The confirmation dialog is correct."""
660+ dialog = self.ui.confirm_remove_dialog
661+
662+ self.assertEqual(dialog._args, ())
663+ flags = gui.gtk.DIALOG_MODAL | gui.gtk.DIALOG_DESTROY_WITH_PARENT
664+ kwargs = dict(parent=self.kwargs['main_window'],
665+ flags=flags, type=gui.gtk.MESSAGE_WARNING,
666+ buttons=gui.gtk.BUTTONS_YES_NO,
667+ message_format=self.ui.CONFIRM_REMOVE)
668+ self.assertEqual(dialog._kwargs, kwargs)
669+
670 def test_backend_signals(self):
671 """The proper signals are connected to the backend."""
672 self.assertEqual(self.ui.backend._signals['DevicesInfoReady'],
673@@ -1312,8 +1374,8 @@
674 self.assertIsInstance(child, gui.Device)
675
676 self.assertEqual(device['device_id'], child.id)
677- self.assertEqual(device['device_name'],
678- child.device_name.get_text())
679+ value = device['device_name'].replace(child.REMOVABLE_PREFIX, '')
680+ self.assertEqual(value, child.device_name.get_text())
681 self.assertEqual(device['device_type'].lower(),
682 child.device_type.get_icon_name()[0])
683 self.assertEqual(bool(device['is_local']),
684@@ -1331,6 +1393,8 @@
685 self.assertEqual(value,
686 child.max_download_speed.get_value_as_int())
687
688+ self.assertIs(child.confirm_dialog, self.ui.confirm_remove_dialog)
689+
690 def test_on_devices_info_ready_have_devices_cached(self):
691 """The devices are cached for further removal."""
692 self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)
693
694=== modified file 'ubuntuone/controlpanel/tests/__init__.py'
695--- ubuntuone/controlpanel/tests/__init__.py 2011-01-20 14:31:24 +0000
696+++ ubuntuone/controlpanel/tests/__init__.py 2011-01-25 12:57:15 +0000
697@@ -205,6 +205,8 @@
698 class TestCase(BaseTestCase):
699 """Basics for testing."""
700
701+ assertIs = BaseTestCase.assertIdentical
702+
703 def setUp(self):
704 self._called = False
705

Subscribers

People subscribed via source and target branches