Merge lp:~nataliabidart/ubuntuone-control-panel/confirm-before-delete into lp:ubuntuone-control-panel
- confirm-before-delete
- Merge into trunk
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | Approve | ||
Roman Yepishev (community) | fieldtest | Approve | |
Review via email:
|
Commit message
- When removing a device, a confirmation dialog is raised (LP: #706888).
Description of the change
To post a comment you must log in.
- 54. By Natalia Bidart
-
Spacing to devices.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
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.
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 |
Control Panel has asked me whether I want to remove the device. I just could not say no!