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
=== modified file 'data/device.ui'
--- data/device.ui 2011-01-24 13:40:10 +0000
+++ data/device.ui 2011-01-25 12:57:15 +0000
@@ -12,65 +12,53 @@
12 </object>12 </object>
13 <object class="GtkVBox" id="itself">13 <object class="GtkVBox" id="itself">
14 <property name="visible">True</property>14 <property name="visible">True</property>
15 <property name="can_focus">False</property>15 <property name="border_width">10</property>
16 <property name="spacing">5</property>16 <property name="spacing">5</property>
17 <child>17 <child>
18 <object class="GtkHBox" id="hbox1">18 <object class="GtkHBox" id="hbox1">
19 <property name="visible">True</property>19 <property name="visible">True</property>
20 <property name="can_focus">False</property>20 <property name="spacing">10</property>
21 <property name="spacing">15</property>
22 <child>21 <child>
23 <object class="GtkVBox" id="vbox1">22 <object class="GtkVBox" id="vbox1">
24 <property name="visible">True</property>23 <property name="visible">True</property>
25 <property name="can_focus">False</property>
26 <property name="spacing">5</property>24 <property name="spacing">5</property>
27 <child>25 <child>
28 <object class="GtkHBox" id="hbox2">26 <object class="GtkHBox" id="hbox2">
29 <property name="visible">True</property>27 <property name="visible">True</property>
30 <property name="can_focus">False</property>
31 <child>28 <child>
32 <object class="GtkImage" id="device_type">29 <object class="GtkImage" id="device_type">
33 <property name="visible">True</property>30 <property name="visible">True</property>
34 <property name="can_focus">False</property>
35 <property name="icon_name">computer</property>31 <property name="icon_name">computer</property>
36 </object>32 </object>
37 <packing>33 <packing>
38 <property name="expand">False</property>34 <property name="expand">False</property>
39 <property name="fill">True</property>
40 <property name="position">0</property>35 <property name="position">0</property>
41 </packing>36 </packing>
42 </child>37 </child>
43 <child>38 <child>
44 <object class="GtkLabel" id="device_name">39 <object class="GtkLabel" id="device_name">
45 <property name="visible">True</property>40 <property name="visible">True</property>
46 <property name="can_focus">False</property>
47 <property name="xalign">0</property>41 <property name="xalign">0</property>
48 <property name="xpad">5</property>42 <property name="xpad">5</property>
49 <property name="label">My Laptop</property>43 <property name="label">My Laptop</property>
50 <property name="wrap">True</property>44 <property name="wrap">True</property>
51 </object>45 </object>
52 <packing>46 <packing>
53 <property name="expand">True</property>
54 <property name="fill">True</property>
55 <property name="position">1</property>47 <property name="position">1</property>
56 </packing>48 </packing>
57 </child>49 </child>
58 </object>50 </object>
59 <packing>51 <packing>
60 <property name="expand">True</property>
61 <property name="fill">True</property>
62 <property name="position">0</property>52 <property name="position">0</property>
63 </packing>53 </packing>
64 </child>54 </child>
65 <child>55 <child>
66 <object class="GtkAlignment" id="alignment1">56 <object class="GtkAlignment" id="alignment1">
67 <property name="visible">True</property>57 <property name="visible">True</property>
68 <property name="can_focus">False</property>
69 <property name="left_padding">25</property>58 <property name="left_padding">25</property>
70 <child>59 <child>
71 <object class="GtkTable" id="throttling">60 <object class="GtkTable" id="throttling">
72 <property name="visible">True</property>61 <property name="visible">True</property>
73 <property name="can_focus">False</property>
74 <property name="n_rows">3</property>62 <property name="n_rows">3</property>
75 <property name="n_columns">2</property>63 <property name="n_columns">2</property>
76 <property name="column_spacing">3</property>64 <property name="column_spacing">3</property>
@@ -81,15 +69,13 @@
81 <property name="visible">True</property>69 <property name="visible">True</property>
82 <property name="can_focus">True</property>70 <property name="can_focus">True</property>
83 <property name="receives_default">False</property>71 <property name="receives_default">False</property>
84 <property name="use_action_appearance">False</property>
85 <property name="draw_indicator">True</property>72 <property name="draw_indicator">True</property>
86 <signal name="toggled" handler="on_limit_bandwidth_toggled" swapped="no"/>73 <signal name="toggled" handler="on_limit_bandwidth_toggled"/>
87 </object>74 </object>
88 </child>75 </child>
89 <child>76 <child>
90 <object class="GtkLabel" id="max_upload_speed_label">77 <object class="GtkLabel" id="max_upload_speed_label">
91 <property name="visible">True</property>78 <property name="visible">True</property>
92 <property name="can_focus">False</property>
93 <property name="xalign">1</property>79 <property name="xalign">1</property>
94 <property name="xpad">5</property>80 <property name="xpad">5</property>
95 <property name="label" translatable="yes">Max upload speed (KiB/s)</property>81 <property name="label" translatable="yes">Max upload speed (KiB/s)</property>
@@ -103,7 +89,6 @@
103 <child>89 <child>
104 <object class="GtkLabel" id="max_download_speed_label">90 <object class="GtkLabel" id="max_download_speed_label">
105 <property name="visible">True</property>91 <property name="visible">True</property>
106 <property name="can_focus">False</property>
107 <property name="xalign">1</property>92 <property name="xalign">1</property>
108 <property name="xpad">5</property>93 <property name="xpad">5</property>
109 <property name="label" translatable="yes">Max download speed (KiB/s)</property>94 <property name="label" translatable="yes">Max download speed (KiB/s)</property>
@@ -121,7 +106,7 @@
121 <property name="activates_default">True</property>106 <property name="activates_default">True</property>
122 <property name="invisible_char_set">True</property>107 <property name="invisible_char_set">True</property>
123 <property name="adjustment">adjustment1</property>108 <property name="adjustment">adjustment1</property>
124 <signal name="value-changed" handler="on_max_upload_speed_value_changed" swapped="no"/>109 <signal name="value_changed" handler="on_max_upload_speed_value_changed"/>
125 </object>110 </object>
126 <packing>111 <packing>
127 <property name="left_attach">1</property>112 <property name="left_attach">1</property>
@@ -140,7 +125,7 @@
140 <property name="activates_default">True</property>125 <property name="activates_default">True</property>
141 <property name="invisible_char_set">True</property>126 <property name="invisible_char_set">True</property>
142 <property name="adjustment">adjustment2</property>127 <property name="adjustment">adjustment2</property>
143 <signal name="value-changed" handler="on_max_download_speed_value_changed" swapped="no"/>128 <signal name="value_changed" handler="on_max_download_speed_value_changed"/>
144 </object>129 </object>
145 <packing>130 <packing>
146 <property name="left_attach">1</property>131 <property name="left_attach">1</property>
@@ -157,31 +142,28 @@
157 </object>142 </object>
158 <packing>143 <packing>
159 <property name="expand">False</property>144 <property name="expand">False</property>
160 <property name="fill">True</property>
161 <property name="position">1</property>145 <property name="position">1</property>
162 </packing>146 </packing>
163 </child>147 </child>
164 </object>148 </object>
165 <packing>149 <packing>
166 <property name="expand">False</property>150 <property name="expand">False</property>
167 <property name="fill">True</property>
168 <property name="position">0</property>151 <property name="position">0</property>
169 </packing>152 </packing>
170 </child>153 </child>
171 <child>154 <child>
172 <object class="GtkVButtonBox" id="vbuttonbox1">155 <object class="GtkVButtonBox" id="vbuttonbox1">
173 <property name="visible">True</property>156 <property name="visible">True</property>
174 <property name="can_focus">False</property>
175 <property name="layout_style">center</property>157 <property name="layout_style">center</property>
176 <child>158 <child>
177 <object class="GtkButton" id="remove">159 <object class="GtkButton" id="remove">
178 <property name="label" translatable="yes">Remove from my personal cloud</property>160 <property name="label">gtk-remove</property>
179 <property name="visible">True</property>161 <property name="visible">True</property>
180 <property name="can_focus">True</property>162 <property name="can_focus">True</property>
181 <property name="receives_default">True</property>163 <property name="receives_default">True</property>
182 <property name="use_action_appearance">False</property>164 <property name="use_stock">True</property>
183 <signal name="activate" handler="on_remove_clicked" swapped="no"/>165 <signal name="clicked" handler="on_remove_clicked"/>
184 <signal name="clicked" handler="on_remove_clicked" swapped="no"/>166 <signal name="activate" handler="on_remove_clicked"/>
185 </object>167 </object>
186 <packing>168 <packing>
187 <property name="expand">False</property>169 <property name="expand">False</property>
@@ -192,7 +174,6 @@
192 </object>174 </object>
193 <packing>175 <packing>
194 <property name="expand">False</property>176 <property name="expand">False</property>
195 <property name="fill">True</property>
196 <property name="pack_type">end</property>177 <property name="pack_type">end</property>
197 <property name="position">1</property>178 <property name="position">1</property>
198 </packing>179 </packing>
@@ -200,18 +181,14 @@
200 </object>181 </object>
201 <packing>182 <packing>
202 <property name="expand">False</property>183 <property name="expand">False</property>
203 <property name="fill">True</property>
204 <property name="position">0</property>184 <property name="position">0</property>
205 </packing>185 </packing>
206 </child>186 </child>
207 <child>187 <child>
208 <object class="GtkLabel" id="warning_label">188 <object class="GtkLabel" id="warning_label">
209 <property name="visible">True</property>189 <property name="visible">True</property>
210 <property name="can_focus">False</property>
211 </object>190 </object>
212 <packing>191 <packing>
213 <property name="expand">True</property>
214 <property name="fill">True</property>
215 <property name="position">1</property>192 <property name="position">1</property>
216 </packing>193 </packing>
217 </child>194 </child>
218195
=== modified file 'data/management.ui'
--- data/management.ui 2011-01-21 21:43:01 +0000
+++ data/management.ui 2011-01-25 12:57:15 +0000
@@ -98,7 +98,7 @@
98 </child>98 </child>
99 <child>99 <child>
100 <object class="GtkRadioButton" id="volumes_button">100 <object class="GtkRadioButton" id="volumes_button">
101 <property name="label" translatable="yes">Cloud Storage</property>101 <property name="label" translatable="yes">Cloud Folders</property>
102 <property name="visible">True</property>102 <property name="visible">True</property>
103 <property name="can_focus">True</property>103 <property name="can_focus">True</property>
104 <property name="receives_default">False</property>104 <property name="receives_default">False</property>
105105
=== modified file 'ubuntuone/controlpanel/gtk/gui.py'
--- ubuntuone/controlpanel/gtk/gui.py 2011-01-24 14:09:48 +0000
+++ ubuntuone/controlpanel/gtk/gui.py 2011-01-25 12:57:15 +0000
@@ -182,7 +182,7 @@
182 self.connect('delete-event', lambda w, e: gtk.main_quit())182 self.connect('delete-event', lambda w, e: gtk.main_quit())
183 self.show()183 self.show()
184184
185 self.control_panel = ControlPanel(window_id=self.window.xid)185 self.control_panel = ControlPanel(main_window=self)
186 self.add(self.control_panel)186 self.add(self.control_panel)
187187
188 logger.info('Starting %s pointing at panel: %r.',188 logger.info('Starting %s pointing at panel: %r.',
@@ -209,17 +209,17 @@
209209
210 # should not be any larger than 736x525210 # should not be any larger than 736x525
211211
212 def __init__(self, window_id=0):212 def __init__(self, main_window):
213 gtk.Notebook.__init__(self)213 gtk.Notebook.__init__(self)
214 self._window_id = window_id214 self.main_window = main_window
215215
216 self.set_show_tabs(False)216 self.set_show_tabs(False)
217 self.set_show_border(False)217 self.set_show_border(False)
218218
219 self.overview = OverviewPanel(window_id=self._window_id)219 self.overview = OverviewPanel(main_window=main_window)
220 self.insert_page(self.overview, position=0)220 self.insert_page(self.overview, position=0)
221221
222 self.management = ManagementPanel()222 self.management = ManagementPanel(main_window=main_window)
223 self.insert_page(self.management, position=1)223 self.insert_page(self.management, position=1)
224224
225 self.overview.connect('credentials-found',225 self.overview.connect('credentials-found',
@@ -320,7 +320,7 @@
320 CONNECT = _('Connect to Ubuntu One')320 CONNECT = _('Connect to Ubuntu One')
321 BULLET = '<span foreground="%s">✔</span>' % ORANGE321 BULLET = '<span foreground="%s">✔</span>' % ORANGE
322322
323 def __init__(self, messages=None, window_id=0):323 def __init__(self, main_window, messages=None):
324 GreyableBin.__init__(self)324 GreyableBin.__init__(self)
325 ControlPanelMixin.__init__(self, filename='overview.ui')325 ControlPanelMixin.__init__(self, filename='overview.ui')
326 self.add(self.itself)326 self.add(self.itself)
@@ -332,9 +332,9 @@
332 self.join_now_button.get_child().set_markup(label)332 self.join_now_button.get_child().set_markup(label)
333 self.connect_button.set_uri(self.CONNECT)333 self.connect_button.set_uri(self.CONNECT)
334334
335 self.main_window = main_window
335 self._credentials_are_new = False336 self._credentials_are_new = False
336 self._messages = messages337 self._messages = messages
337 self._window_id = window_id
338 self._build_messages()338 self._build_messages()
339 self.show()339 self.show()
340340
@@ -404,7 +404,7 @@
404 def on_join_now_button_clicked(self, *a, **kw):404 def on_join_now_button_clicked(self, *a, **kw):
405 """User wants to join now."""405 """User wants to join now."""
406 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,406 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
407 WINDOW_ID_KEY: str(self._window_id),407 WINDOW_ID_KEY: str(self.main_window.window.xid),
408 PING_URL_KEY: U1_PING_URL}408 PING_URL_KEY: U1_PING_URL}
409 self.sso_backend.register(U1_APP_NAME, settings,409 self.sso_backend.register(U1_APP_NAME, settings,
410 reply_handler=NO_OP, error_handler=error_handler)410 reply_handler=NO_OP, error_handler=error_handler)
@@ -414,7 +414,7 @@
414 def on_connect_button_clicked(self, *a, **kw):414 def on_connect_button_clicked(self, *a, **kw):
415 """User wants to connect now."""415 """User wants to connect now."""
416 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,416 settings = {TC_URL_KEY: U1_TC_URL, HELP_TEXT_KEY: U1_DESCRIPTION,
417 WINDOW_ID_KEY: str(self._window_id),417 WINDOW_ID_KEY: str(self.main_window.window.xid),
418 PING_URL_KEY: U1_PING_URL}418 PING_URL_KEY: U1_PING_URL}
419 self.sso_backend.login(U1_APP_NAME, settings,419 self.sso_backend.login(U1_APP_NAME, settings,
420 reply_handler=NO_OP, error_handler=error_handler)420 reply_handler=NO_OP, error_handler=error_handler)
@@ -476,7 +476,7 @@
476 TYPE = _('Account type')476 TYPE = _('Account type')
477 EMAIL = _('Email address')477 EMAIL = _('Email address')
478478
479 def __init__(self):479 def __init__(self, main_window=None):
480 UbuntuOneBin.__init__(self)480 UbuntuOneBin.__init__(self)
481 ControlPanelMixin.__init__(self, filename='dashboard.ui')481 ControlPanelMixin.__init__(self, filename='dashboard.ui')
482 self.add(self.itself)482 self.add(self.itself)
@@ -512,10 +512,10 @@
512class VolumesPanel(UbuntuOneBin, ControlPanelMixin):512class VolumesPanel(UbuntuOneBin, ControlPanelMixin):
513 """The volumes panel."""513 """The volumes panel."""
514514
515 TITLE = _('Select which folders from your cloud you want synchronized '515 TITLE = _('Select the folders from your cloud that you want synchronized '
516 'on this device.')516 'in this device.')
517 MY_FOLDERS = _('Mine')517 MY_FOLDERS = _('My folders')
518 ALWAYS_SUBSCRIBED = _('Always in your personal cloud storage!')518 ALWAYS_SUBSCRIBED = _('Always in sync!')
519 FREE_SPACE = _('%(free_space)s available storage')519 FREE_SPACE = _('%(free_space)s available storage')
520 CONTACT_ICON_NAME = 'system-users'520 CONTACT_ICON_NAME = 'system-users'
521 FOLDER_ICON_NAME = 'folder'521 FOLDER_ICON_NAME = 'folder'
@@ -525,7 +525,7 @@
525 ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'525 ROOT = '%s - <span foreground="%s" font_size="small">%s</span>'
526 NO_VOLUMES = _('No folders to show.')526 NO_VOLUMES = _('No folders to show.')
527527
528 def __init__(self):528 def __init__(self, main_window=None):
529 UbuntuOneBin.__init__(self)529 UbuntuOneBin.__init__(self)
530 ControlPanelMixin.__init__(self, filename='volumes.ui')530 ControlPanelMixin.__init__(self, filename='volumes.ui')
531 self.add(self.itself)531 self.add(self.itself)
@@ -639,7 +639,7 @@
639639
640 TITLE = _('Manage permissions for shares made to other users.')640 TITLE = _('Manage permissions for shares made to other users.')
641641
642 def __init__(self):642 def __init__(self, main_window=None):
643 UbuntuOneBin.__init__(self)643 UbuntuOneBin.__init__(self)
644 ControlPanelMixin.__init__(self)644 ControlPanelMixin.__init__(self)
645 self.show_all()645 self.show_all()
@@ -652,11 +652,13 @@
652 DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n'652 DEVICE_CHANGE_ERROR = _('The settings could not be changed,\n'
653 'previous values were restored.')653 'previous values were restored.')
654 DEVICE_REMOVAL_ERROR = _('The device could not be removed.')654 DEVICE_REMOVAL_ERROR = _('The device could not be removed.')
655 REMOVABLE_PREFIX = 'Ubuntu One @ '
655656
656 def __init__(self):657 def __init__(self, confirm_remove_dialog=None):
657 gtk.EventBox.__init__(self)658 gtk.EventBox.__init__(self)
658 ControlPanelMixin.__init__(self, filename='device.ui')659 ControlPanelMixin.__init__(self, filename='device.ui')
659660
661 self.confirm_dialog = confirm_remove_dialog
660 self._updating = False662 self._updating = False
661 self._last_settings = {}663 self._last_settings = {}
662 self.id = None664 self.id = None
@@ -714,9 +716,15 @@
714716
715 def on_remove_clicked(self, widget):717 def on_remove_clicked(self, widget):
716 """Remove button was clicked or activated."""718 """Remove button was clicked or activated."""
717 self.backend.remove_device(self.id,719 response = gtk.RESPONSE_YES
718 reply_handler=NO_OP, error_handler=error_handler)720 if self.confirm_dialog is not None:
719 self.set_sensitive(False)721 response = self.confirm_dialog.run()
722 self.confirm_dialog.hide()
723
724 if response == gtk.RESPONSE_YES:
725 self.backend.remove_device(self.id,
726 reply_handler=NO_OP, error_handler=error_handler)
727 self.set_sensitive(False)
720728
721 @_block_signals729 @_block_signals
722 def update(self, **kwargs):730 def update(self, **kwargs):
@@ -738,8 +746,9 @@
738 self.id = kwargs['device_id']746 self.id = kwargs['device_id']
739747
740 if 'device_name' in kwargs:748 if 'device_name' in kwargs:
741 name = '<span font_size="large"><b>%s</b></span>'749 name = kwargs['device_name'].replace(self.REMOVABLE_PREFIX, '')
742 self.device_name.set_markup(name % kwargs['device_name'])750 name = '<span font_size="large"><b>%s</b></span>' % name
751 self.device_name.set_markup(name)
743752
744 if 'device_type' in kwargs:753 if 'device_type' in kwargs:
745 dtype = kwargs['device_type']754 dtype = kwargs['device_type']
@@ -818,16 +827,24 @@
818class DevicesPanel(UbuntuOneBin, ControlPanelMixin):827class DevicesPanel(UbuntuOneBin, ControlPanelMixin):
819 """The devices panel."""828 """The devices panel."""
820829
821 TITLE = _('The devices in your personal cloud are listed below.')830 TITLE = _('The devices synced with your personal cloud are listed below.')
822 NO_DEVICES = _('No devices to show.')831 NO_DEVICES = _('No devices to show.')
832 CONFIRM_REMOVE = _('Are you sure you want to remove this device '
833 'from Ubuntu One?')
823834
824 def __init__(self):835 def __init__(self, main_window=None):
825 UbuntuOneBin.__init__(self)836 UbuntuOneBin.__init__(self)
826 ControlPanelMixin.__init__(self, filename='devices.ui')837 ControlPanelMixin.__init__(self, filename='devices.ui')
827 self.add(self.itself)838 self.add(self.itself)
828 self.show()839 self.show()
829840
830 self._devices = {}841 self._devices = {}
842 kw = dict(parent=main_window,
843 flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
844 type=gtk.MESSAGE_WARNING,
845 buttons=gtk.BUTTONS_YES_NO,
846 message_format=self.CONFIRM_REMOVE)
847 self.confirm_remove_dialog = gtk.MessageDialog(**kw)
831848
832 self.backend.connect_to_signal('DevicesInfoReady',849 self.backend.connect_to_signal('DevicesInfoReady',
833 self.on_devices_info_ready)850 self.on_devices_info_ready)
@@ -849,7 +866,7 @@
849866
850 odd_row_color = self.message.style.bg[gtk.STATE_NORMAL]867 odd_row_color = self.message.style.bg[gtk.STATE_NORMAL]
851 for i, device_info in enumerate(info):868 for i, device_info in enumerate(info):
852 device = Device()869 device = Device(confirm_remove_dialog=self.confirm_remove_dialog)
853 device_info['device_name'] = device_info.pop('name', '')870 device_info['device_name'] = device_info.pop('name', '')
854 device_info['device_type'] = device_info.pop('type',871 device_info['device_type'] = device_info.pop('type',
855 DEVICE_TYPE_COMPUTER)872 DEVICE_TYPE_COMPUTER)
@@ -1086,7 +1103,7 @@
1086 CONTACTS = _('Contacts (Evolution)')1103 CONTACTS = _('Contacts (Evolution)')
1087 NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')1104 NO_PAIRING_RECORD = _('There is no Ubuntu One pairing record.')
10881105
1089 def __init__(self):1106 def __init__(self, main_window=None):
1090 UbuntuOneBin.__init__(self)1107 UbuntuOneBin.__init__(self)
1091 ControlPanelMixin.__init__(self, filename='services.ui')1108 ControlPanelMixin.__init__(self, filename='services.ui')
1092 self.add(self.itself)1109 self.add(self.itself)
@@ -1333,7 +1350,7 @@
13331350
1334 QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)')1351 QUOTA_LABEL = _('%(used)s used of %(total)s (%(percentage).1f%%)')
13351352
1336 def __init__(self):1353 def __init__(self, main_window=None):
1337 gtk.VBox.__init__(self)1354 gtk.VBox.__init__(self)
1338 ControlPanelMixin.__init__(self, filename='management.ui')1355 ControlPanelMixin.__init__(self, filename='management.ui')
1339 self.add(self.itself)1356 self.add(self.itself)
@@ -1353,11 +1370,11 @@
1353 self.status_label = FileSyncStatus()1370 self.status_label = FileSyncStatus()
1354 self.status_box.pack_end(self.status_label, expand=False)1371 self.status_box.pack_end(self.status_label, expand=False)
13551372
1356 self.dashboard = DashboardPanel()1373 self.dashboard = DashboardPanel(main_window=main_window)
1357 self.volumes = VolumesPanel()1374 self.volumes = VolumesPanel(main_window=main_window)
1358 self.shares = SharesPanel()1375 self.shares = SharesPanel(main_window=main_window)
1359 self.devices = DevicesPanel()1376 self.devices = DevicesPanel(main_window=main_window)
1360 self.services = ServicesPanel()1377 self.services = ServicesPanel(main_window=main_window)
13611378
1362 cb = lambda button, page_num: self.notebook.set_current_page(page_num)1379 cb = lambda button, page_num: self.notebook.set_current_page(page_num)
1363 self.tabs = (u'dashboard', u'volumes', u'shares',1380 self.tabs = (u'dashboard', u'volumes', u'shares',
13641381
=== modified file 'ubuntuone/controlpanel/gtk/tests/__init__.py'
--- ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-21 02:29:20 +0000
+++ ubuntuone/controlpanel/gtk/tests/__init__.py 2011-01-25 12:57:15 +0000
@@ -66,14 +66,14 @@
66}66}
6767
68FAKE_DEVICES_INFO = [68FAKE_DEVICES_INFO = [
69 {'device_id': '0', 'name': 'Foo', 'type': 'Computer',69 {'device_id': '0', 'name': 'Ubuntu One @ Foo', 'type': 'Computer',
70 'is_local': '', 'configurable': ''},70 'is_local': '', 'configurable': ''},
71 {'device_id': '1', 'name': 'Bar', 'type': 'Phone',71 {'device_id': '1', 'name': 'Ubuntu One @ Bar', 'type': 'Phone',
72 'is_local': '', 'configurable': ''},72 'is_local': '', 'configurable': ''},
73 {'device_id': '2', 'name': 'Z', 'type': 'Computer',73 {'device_id': '2', 'name': 'Ubuntu One @ Z', 'type': 'Computer',
74 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '',74 'is_local': '', 'configurable': 'True', 'limit_bandwidth': '',
75 'max_upload_speed': '0', 'max_download_speed': '0'},75 'max_upload_speed': '0', 'max_download_speed': '0'},
76 {'device_id': '1258-6854', 'name': 'Baz', 'type': 'Computer',76 {'device_id': '1258-6854', 'name': 'Ubuntu One @ Baz', 'type': 'Computer',
77 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True',77 'is_local': 'True', 'configurable': 'True', 'limit_bandwidth': 'True',
78 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local78 'max_upload_speed': '1000', 'max_download_speed': '72548'}, # local
79]79]
@@ -195,3 +195,21 @@
195 yield195 yield
196 self._installed[package_name] = True196 self._installed[package_name] = True
197 gui.package_manager.return_value(FakedTransaction([package_name]))197 gui.package_manager.return_value(FakedTransaction([package_name]))
198
199
200class FakedConfirmDialog(object):
201 """Fake a confirmation dialog."""
202
203 def __init__(self, *args, **kwargs):
204 self._args = args
205 self._kwargs = kwargs
206 self.was_run = False
207 self.is_visible = True
208 self.show = lambda: setattr(self, 'is_visible', True)
209 self.hide = lambda: setattr(self, 'is_visible', False)
210 self.response_code = None
211
212 def run(self):
213 """Set flag and return 'self.response_code'."""
214 self.was_run = True
215 return self.response_code
198216
=== modified file 'ubuntuone/controlpanel/gtk/tests/test_gui.py'
--- ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-21 21:43:01 +0000
+++ ubuntuone/controlpanel/gtk/tests/test_gui.py 2011-01-25 12:57:15 +0000
@@ -29,7 +29,7 @@
29 FAKE_DEVICE_INFO, FAKE_DEVICES_INFO,29 FAKE_DEVICE_INFO, FAKE_DEVICES_INFO,
30 FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, USER_HOME,30 FAKE_VOLUMES_INFO, FAKE_REPLICATIONS_INFO, USER_HOME,
31 FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface,31 FakedNMState, FakedSSOBackend, FakedSessionBus, FakedInterface,
32 FakedPackageManager,32 FakedPackageManager, FakedConfirmDialog,
33)33)
34from ubuntuone.controlpanel.tests import TOKEN, TestCase34from ubuntuone.controlpanel.tests import TOKEN, TestCase
35from ubuntuone.controlpanel.gtk.tests.test_package_manager import (35from ubuntuone.controlpanel.gtk.tests.test_package_manager import (
@@ -55,6 +55,7 @@
55 self.patch(gui.os.path, 'expanduser',55 self.patch(gui.os.path, 'expanduser',
56 lambda path: path.replace('~', USER_HOME))56 lambda path: path.replace('~', USER_HOME))
57 self.patch(gui.gtk, 'main', lambda: None)57 self.patch(gui.gtk, 'main', lambda: None)
58 self.patch(gui.gtk, 'MessageDialog', FakedConfirmDialog)
58 self.patch(gui.dbus, 'SessionBus', FakedSessionBus)59 self.patch(gui.dbus, 'SessionBus', FakedSessionBus)
59 self.patch(gui.dbus, 'Interface', FakedInterface)60 self.patch(gui.dbus, 'Interface', FakedInterface)
60 self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)61 self.patch(gui.networkstate, 'NetworkManagerState', FakedNMState)
@@ -171,11 +172,9 @@
171 self.assertIsInstance(self.ui.control_panel, gui.ControlPanel)172 self.assertIsInstance(self.ui.control_panel, gui.ControlPanel)
172 self.assertTrue(self.ui.control_panel.get_visible())173 self.assertTrue(self.ui.control_panel.get_visible())
173174
174 def test_window_id_is_passed_to_child(self):175 def test_main_window_is_passed_to_child(self):
175 """The child gets the window_id."""176 """The child gets the main_window."""
176 assert self.ui.window is not None177 self.assertEqual(self.ui.control_panel.main_window, self.ui)
177 self.assertEqual(self.ui.control_panel._window_id,
178 self.ui.window.xid)
179178
180 def test_icon_name_is_correct(self):179 def test_icon_name_is_correct(self):
181 """The icon name is correct."""180 """The icon name is correct."""
@@ -225,7 +224,7 @@
225 """The test suite for the control panel itself."""224 """The test suite for the control panel itself."""
226225
227 klass = gui.ControlPanel226 klass = gui.ControlPanel
228 kwargs = {'window_id': 7}227 kwargs = {'main_window': object()}
229228
230 def assert_current_tab_correct(self, expected_tab):229 def assert_current_tab_correct(self, expected_tab):
231 """Check that the wiget 'expected_tab' is the current page."""230 """Check that the wiget 'expected_tab' is the current page."""
@@ -251,9 +250,10 @@
251 self.assertIsInstance(self.ui.overview, gui.OverviewPanel)250 self.assertIsInstance(self.ui.overview, gui.OverviewPanel)
252 self.assert_current_tab_correct(self.ui.overview)251 self.assert_current_tab_correct(self.ui.overview)
253252
254 def test_window_id_is_passed_to_child(self):253 def test_main_window_is_passed_to_child(self):
255 """The child gets the window_id."""254 """The child gets the main_window."""
256 self.assertEqual(self.ui.overview._window_id, self.kwargs['window_id'])255 self.assertEqual(self.ui.overview.main_window,
256 self.kwargs['main_window'])
257257
258 def test_on_show_management_panel(self):258 def test_on_show_management_panel(self):
259 """A ManagementPanel is shown when the callback is executed."""259 """A ManagementPanel is shown when the callback is executed."""
@@ -392,7 +392,7 @@
392 """The test suite for the overview panel."""392 """The test suite for the overview panel."""
393393
394 klass = gui.OverviewPanel394 klass = gui.OverviewPanel
395 kwargs = {'messages': None, 'window_id': 8}395 kwargs = {'messages': None, 'main_window': gui.gtk.Window()}
396 ui_filename = 'overview.ui'396 ui_filename = 'overview.ui'
397397
398 def test_is_a_greyable_bin(self):398 def test_is_a_greyable_bin(self):
@@ -591,24 +591,32 @@
591591
592 def test_join_now_button_clicked(self):592 def test_join_now_button_clicked(self):
593 """Test the 'join now' button callback."""593 """Test the 'join now' button callback."""
594 self.kwargs['main_window'].show() # ensure parent window is realized
595 self.addCleanup(self.kwargs['main_window'].hide)
596
594 self.ui.join_now_button.clicked()597 self.ui.join_now_button.clicked()
595598
599 window_id = self.kwargs['main_window'].window.xid
596 args = (gui.U1_APP_NAME,600 args = (gui.U1_APP_NAME,
597 {gui.TC_URL_KEY: gui.U1_TC_URL,601 {gui.TC_URL_KEY: gui.U1_TC_URL,
598 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,602 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
599 gui.WINDOW_ID_KEY: str(self.kwargs['window_id']),603 gui.WINDOW_ID_KEY: str(window_id),
600 gui.PING_URL_KEY: gui.U1_PING_URL})604 gui.PING_URL_KEY: gui.U1_PING_URL})
601 self.assert_backend_called('register', args,605 self.assert_backend_called('register', args,
602 backend=self.ui.sso_backend)606 backend=self.ui.sso_backend)
603607
604 def test_connect_button_clicked(self):608 def test_connect_button_clicked(self):
605 """Test the 'join now' button callback."""609 """Test the 'join now' button callback."""
610 self.kwargs['main_window'].show() # ensure parent window is realized
611 self.addCleanup(self.kwargs['main_window'].hide)
612
606 self.ui.connect_button.clicked()613 self.ui.connect_button.clicked()
607614
615 window_id = self.kwargs['main_window'].window.xid
608 args = (gui.U1_APP_NAME,616 args = (gui.U1_APP_NAME,
609 {gui.TC_URL_KEY: gui.U1_TC_URL,617 {gui.TC_URL_KEY: gui.U1_TC_URL,
610 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,618 gui.HELP_TEXT_KEY: gui.U1_DESCRIPTION,
611 gui.WINDOW_ID_KEY: str(self.kwargs['window_id']),619 gui.WINDOW_ID_KEY: str(window_id),
612 gui.PING_URL_KEY: gui.U1_PING_URL})620 gui.PING_URL_KEY: gui.U1_PING_URL})
613 self.assert_backend_called('login', args,621 self.assert_backend_called('login', args,
614 backend=self.ui.sso_backend)622 backend=self.ui.sso_backend)
@@ -967,8 +975,8 @@
967 """Assert that the device has the values from expected."""975 """Assert that the device has the values from expected."""
968 self.assertEqual(device.id,976 self.assertEqual(device.id,
969 expected['device_id'])977 expected['device_id'])
970 self.assertEqual(device.device_name.get_text(),978 value = expected['device_name'].replace(self.ui.REMOVABLE_PREFIX, '')
971 expected['device_name'])979 self.assertEqual(device.device_name.get_text(), value)
972 self.assertEqual(device.device_type.get_icon_name()[0],980 self.assertEqual(device.device_type.get_icon_name()[0],
973 expected['device_type'].lower())981 expected['device_type'].lower())
974 self.assertEqual(device.is_local,982 self.assertEqual(device.is_local,
@@ -1040,13 +1048,13 @@
1040 def test_update_device_name(self):1048 def test_update_device_name(self):
1041 """A device can be updated from a dict."""1049 """A device can be updated from a dict."""
1042 value = 'The death star'1050 value = 'The death star'
1043 self.ui.update(device_name=value)1051 self.ui.update(device_name=self.ui.REMOVABLE_PREFIX + value)
1044 self.assertEqual(value, self.ui.device_name.get_text())1052 self.assertEqual(value, self.ui.device_name.get_text())
10451053
1046 def test_update_unicode_device_name(self):1054 def test_update_unicode_device_name(self):
1047 """A device can be updated from a dict."""1055 """A device can be updated from a dict."""
1048 value = u'Ñoño Ñandú'1056 value = u'Ñoño Ñandú'
1049 self.ui.update(device_name=value)1057 self.ui.update(device_name=self.ui.REMOVABLE_PREFIX + value)
1050 self.assertEqual(value, self.ui.device_name.get_text())1058 self.assertEqual(value, self.ui.device_name.get_text())
10511059
1052 def test_update_device_type_computer(self):1060 def test_update_device_type_computer(self):
@@ -1237,11 +1245,53 @@
1237 'Must be disabled after other device removal error.')1245 'Must be disabled after other device removal error.')
12381246
12391247
1248class RemoveDeviceTestCase(DeviceTestCase):
1249 """The test suite for the device widget when prompting for removal."""
1250
1251 confirm_dialog = FakedConfirmDialog()
1252 kwargs = {'confirm_remove_dialog': confirm_dialog}
1253
1254 def test_remove(self):
1255 """Clicking on remove calls the backend properly."""
1256 self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
1257 super(RemoveDeviceTestCase, self).test_remove()
1258
1259 def test_on_device_removal_error_other_id(self):
1260 """On other device removal error, do nothing."""
1261 self.confirm_dialog.response_code = gui.gtk.RESPONSE_YES
1262 parent_test = super(RemoveDeviceTestCase, self)
1263 parent_test.test_on_device_removal_error_other_id()
1264
1265 def test_remove_shows_confirmation_dialog(self):
1266 """Clicking on remove displays a confirmation dialog."""
1267 self.ui.remove.clicked()
1268
1269 self.assertTrue(self.confirm_dialog.was_run, 'dialog was run')
1270 self.assertFalse(self.confirm_dialog.is_visible, 'dialog was hid')
1271
1272 def test_remove_does_not_call_backend_if_dialog_closed(self):
1273 """Backend is not called if users closes the confirmation dialog."""
1274 self.confirm_dialog.response_code = gui.gtk.RESPONSE_DELETE_EVENT
1275 self.ui.remove.clicked()
1276
1277 self.assertNotIn('remove_device', self.ui.backend._called)
1278 self.assertTrue(self.ui.is_sensitive())
1279
1280 def test_remove_does_not_call_backend_if_answer_is_no(self):
1281 """Backend is not called if users clicks on 'No'."""
1282 self.confirm_dialog.response_code = gui.gtk.RESPONSE_NO
1283 self.ui.remove.clicked()
1284
1285 self.assertNotIn('remove_device', self.ui.backend._called)
1286 self.assertTrue(self.ui.is_sensitive())
1287
1288
1240class DevicesTestCase(ControlPanelMixinTestCase):1289class DevicesTestCase(ControlPanelMixinTestCase):
1241 """The test suite for the devices panel."""1290 """The test suite for the devices panel."""
12421291
1243 klass = gui.DevicesPanel1292 klass = gui.DevicesPanel
1244 ui_filename = 'devices.ui'1293 ui_filename = 'devices.ui'
1294 kwargs = {'main_window': object()}
12451295
1246 def setUp(self):1296 def setUp(self):
1247 super(DevicesTestCase, self).setUp()1297 super(DevicesTestCase, self).setUp()
@@ -1259,6 +1309,18 @@
1259 """Is visible."""1309 """Is visible."""
1260 self.assertTrue(self.ui.get_visible())1310 self.assertTrue(self.ui.get_visible())
12611311
1312 def test_confirm_remove_dialog(self):
1313 """The confirmation dialog is correct."""
1314 dialog = self.ui.confirm_remove_dialog
1315
1316 self.assertEqual(dialog._args, ())
1317 flags = gui.gtk.DIALOG_MODAL | gui.gtk.DIALOG_DESTROY_WITH_PARENT
1318 kwargs = dict(parent=self.kwargs['main_window'],
1319 flags=flags, type=gui.gtk.MESSAGE_WARNING,
1320 buttons=gui.gtk.BUTTONS_YES_NO,
1321 message_format=self.ui.CONFIRM_REMOVE)
1322 self.assertEqual(dialog._kwargs, kwargs)
1323
1262 def test_backend_signals(self):1324 def test_backend_signals(self):
1263 """The proper signals are connected to the backend."""1325 """The proper signals are connected to the backend."""
1264 self.assertEqual(self.ui.backend._signals['DevicesInfoReady'],1326 self.assertEqual(self.ui.backend._signals['DevicesInfoReady'],
@@ -1312,8 +1374,8 @@
1312 self.assertIsInstance(child, gui.Device)1374 self.assertIsInstance(child, gui.Device)
13131375
1314 self.assertEqual(device['device_id'], child.id)1376 self.assertEqual(device['device_id'], child.id)
1315 self.assertEqual(device['device_name'],1377 value = device['device_name'].replace(child.REMOVABLE_PREFIX, '')
1316 child.device_name.get_text())1378 self.assertEqual(value, child.device_name.get_text())
1317 self.assertEqual(device['device_type'].lower(),1379 self.assertEqual(device['device_type'].lower(),
1318 child.device_type.get_icon_name()[0])1380 child.device_type.get_icon_name()[0])
1319 self.assertEqual(bool(device['is_local']),1381 self.assertEqual(bool(device['is_local']),
@@ -1331,6 +1393,8 @@
1331 self.assertEqual(value,1393 self.assertEqual(value,
1332 child.max_download_speed.get_value_as_int())1394 child.max_download_speed.get_value_as_int())
13331395
1396 self.assertIs(child.confirm_dialog, self.ui.confirm_remove_dialog)
1397
1334 def test_on_devices_info_ready_have_devices_cached(self):1398 def test_on_devices_info_ready_have_devices_cached(self):
1335 """The devices are cached for further removal."""1399 """The devices are cached for further removal."""
1336 self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)1400 self.ui.on_devices_info_ready(FAKE_DEVICES_INFO)
13371401
=== modified file 'ubuntuone/controlpanel/tests/__init__.py'
--- ubuntuone/controlpanel/tests/__init__.py 2011-01-20 14:31:24 +0000
+++ ubuntuone/controlpanel/tests/__init__.py 2011-01-25 12:57:15 +0000
@@ -205,6 +205,8 @@
205class TestCase(BaseTestCase):205class TestCase(BaseTestCase):
206 """Basics for testing."""206 """Basics for testing."""
207207
208 assertIs = BaseTestCase.assertIdentical
209
208 def setUp(self):210 def setUp(self):
209 self._called = False211 self._called = False
210212

Subscribers

People subscribed via source and target branches